feat: add 45m slot option, replace 60m in sub-hour controls

- CellDuration now includes 45 (15 | 20 | 30 | 45 | 60)
- getTimeSlots rewritten to use minutes-based generation so 45-min slots
  work correctly (08:00, 08:45, 09:30, 10:15...) — also cleaner for all
  other durations
- getSlotHeight(45) = 45px (1px per minute, proportional)
- All three slot button groups (sidebar, desktop header, mobile) now show
  [15, 20, 30, 45] instead of [15, 20, 30, 60]

v1.81.16
This commit is contained in:
mARTin 2026-04-02 22:43:01 +02:00
parent 09caf5ffa0
commit 6f45140d26
2 changed files with 12 additions and 13 deletions

View File

@ -1,6 +1,6 @@
{
"name": "my-weekly-todo-list",
"version": "1.81.15",
"version": "1.81.16",
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
"main": "index.js",
"scripts": {

View File

@ -196,7 +196,7 @@ export interface SomedayList {
}
// Time grid configuration options
export type CellDuration = 15 | 20 | 30 | 60;
export type CellDuration = 15 | 20 | 30 | 45 | 60;
const DEFAULT_SOMEDAY_SLOT_COUNT = 5;
const getSomedaySlotCount = (tasks: Task[]) => {
@ -339,14 +339,12 @@ function getTimeSlots(
endHour: number,
): string[] {
const slots: string[] = [];
const slotsPerHour = 60 / cellDuration;
for (let hour = startHour; hour < endHour; hour++) {
for (let slot = 0; slot < slotsPerHour; slot++) {
const minutes = slot * cellDuration;
slots.push(
`${hour.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`,
);
}
const startMins = startHour * 60;
const endMins = endHour * 60;
for (let mins = startMins; mins < endMins; mins += cellDuration) {
const h = Math.floor(mins / 60);
const m = mins % 60;
slots.push(`${h.toString().padStart(2, "0")}:${m.toString().padStart(2, "0")}`);
}
return slots;
}
@ -1460,6 +1458,7 @@ export default function WeeklyView() {
case 15: return 25;
case 20: return 30;
case 30: return 35;
case 45: return 45;
case 60: return 50;
default: return 50;
}
@ -5451,7 +5450,7 @@ export default function WeeklyView() {
{profile.language === "de" ? "Zeitfenster" : "Slot"}
</span>
<div style={{ display: "flex", gap: "4px" }}>
{([15, 20, 30, 60] as CellDuration[]).map((d) => (
{(([15, 20, 30, 45] as CellDuration[])).map((d) => (
<button key={d} onClick={() => { setCellDuration(d); saveSetting("cellDuration", d); }}
style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: effectiveCellDuration === d ? 700 : 400, background: effectiveCellDuration === d ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: effectiveCellDuration === d ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
{d}m
@ -5746,7 +5745,7 @@ export default function WeeklyView() {
title="Slot Duration"
>
<Clock size={16} className="text-gray-500 mr-1" />
{([15, 20, 30, 60] as CellDuration[]).map((duration) => (
{(([15, 20, 30, 45] as CellDuration[])).map((duration) => (
<button
key={duration}
onClick={() => {
@ -5994,7 +5993,7 @@ export default function WeeklyView() {
{profile.showTimeGrid && (
<div style={{ padding: "6px 12px", display: "flex", alignItems: "center", gap: "6px" }}>
<span style={{ fontSize: "12px", color: "#888", marginRight: "4px" }}>{profile.language === "de" ? "Slot" : "Slot"}:</span>
{([15, 20, 30, 60] as CellDuration[]).map((duration) => (
{(([15, 20, 30, 45] as CellDuration[])).map((duration) => (
<button
key={duration}
onClick={() => { setCellDuration(duration); saveSetting("cellDuration", duration); }}