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", "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", "description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -196,7 +196,7 @@ export interface SomedayList {
} }
// Time grid configuration options // 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 DEFAULT_SOMEDAY_SLOT_COUNT = 5;
const getSomedaySlotCount = (tasks: Task[]) => { const getSomedaySlotCount = (tasks: Task[]) => {
@ -339,14 +339,12 @@ function getTimeSlots(
endHour: number, endHour: number,
): string[] { ): string[] {
const slots: string[] = []; const slots: string[] = [];
const slotsPerHour = 60 / cellDuration; const startMins = startHour * 60;
for (let hour = startHour; hour < endHour; hour++) { const endMins = endHour * 60;
for (let slot = 0; slot < slotsPerHour; slot++) { for (let mins = startMins; mins < endMins; mins += cellDuration) {
const minutes = slot * cellDuration; const h = Math.floor(mins / 60);
slots.push( const m = mins % 60;
`${hour.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`, slots.push(`${h.toString().padStart(2, "0")}:${m.toString().padStart(2, "0")}`);
);
}
} }
return slots; return slots;
} }
@ -1460,6 +1458,7 @@ export default function WeeklyView() {
case 15: return 25; case 15: return 25;
case 20: return 30; case 20: return 30;
case 30: return 35; case 30: return 35;
case 45: return 45;
case 60: return 50; case 60: return 50;
default: return 50; default: return 50;
} }
@ -5451,7 +5450,7 @@ export default function WeeklyView() {
{profile.language === "de" ? "Zeitfenster" : "Slot"} {profile.language === "de" ? "Zeitfenster" : "Slot"}
</span> </span>
<div style={{ display: "flex", gap: "4px" }}> <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); }} <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") }}> 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 {d}m
@ -5746,7 +5745,7 @@ export default function WeeklyView() {
title="Slot Duration" title="Slot Duration"
> >
<Clock size={16} className="text-gray-500 mr-1" /> <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 <button
key={duration} key={duration}
onClick={() => { onClick={() => {
@ -5994,7 +5993,7 @@ export default function WeeklyView() {
{profile.showTimeGrid && ( {profile.showTimeGrid && (
<div style={{ padding: "6px 12px", display: "flex", alignItems: "center", gap: "6px" }}> <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> <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 <button
key={duration} key={duration}
onClick={() => { setCellDuration(duration); saveSetting("cellDuration", duration); }} onClick={() => { setCellDuration(duration); saveSetting("cellDuration", duration); }}