feat: fix iPhone Today button, add all settings to sidebar, fix layout

- Fix goToToday landing on yesterday in single-day view (skip startDayOffset)
- Add quick actions panel to settings sidebar for all screen sizes (not just mobile)
- Add view style switcher, visible hours, search, and new project to sidebar
- Change weekly-container to height:100vh for proper flex layout
- Someday/all-day sections use flex-shrink:0 for stable resize behavior
- Collapse uses height:30px!important to override inline styles

v1.40.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
mARTin 2026-03-17 10:41:12 +01:00
parent afa2695e0c
commit 85982f06a5
3 changed files with 112 additions and 13 deletions

View File

@ -1,6 +1,6 @@
{
"name": "my-weekly-todo-list",
"version": "1.39.4",
"version": "1.40.0",
"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

@ -478,11 +478,12 @@ h3 {
/* Weekly Main Container */
.weekly-container {
min-height: 100vh;
height: 100vh;
background: var(--weekly-bg);
font-family: var(--weekly-font);
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Weekly Header */
@ -497,6 +498,7 @@ h3 {
align-items: center;
justify-content: space-between;
position: relative;
flex-shrink: 0;
}
.weekly-logo {
flex-shrink: 0;
@ -1179,11 +1181,11 @@ h3 {
/* Someday Section */
.weekly-someday {
background-color: #f9f9f9;
background-color: #f9f9f9;
width: 100%;
padding: 0 1rem;
transition: max-height 0.3s ease;
position: relative;
flex-shrink: 0;
}
.weekly-container.dark-mode .weekly-someday {
@ -1191,6 +1193,8 @@ h3 {
}
.weekly-someday.collapsed {
height: 30px !important;
min-height: 30px;
max-height: 30px;
overflow: hidden;
}
@ -2652,6 +2656,7 @@ h3 {
border-top: 1px solid var(--weekly-border);
padding: 2px 0;
position: relative;
flex-shrink: 0;
}
/* Resize handle for draggable section borders */
@ -2665,6 +2670,7 @@ h3 {
touch-action: none;
position: relative;
z-index: 10;
flex-shrink: 0;
border-top: 1px solid var(--weekly-border, #e5e7eb);
border-bottom: 1px solid var(--weekly-border, #e5e7eb);
}

View File

@ -1641,6 +1641,7 @@ export default function WeeklyView() {
const startResize = useCallback((e: React.MouseEvent | React.TouchEvent, target: 'someday' | 'allday') => {
e.preventDefault();
e.stopPropagation();
const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY;
const section = target === 'someday' ? somedaySectionRef.current : (document.querySelector('.all-day-events-section') as HTMLElement);
if (!section) return;
@ -3589,7 +3590,10 @@ export default function WeeklyView() {
const goToToday = () => {
const d = new Date();
d.setHours(0, 0, 0, 0);
d.setDate(d.getDate() + (profile?.startDayOffset || 0));
// Only apply startDayOffset for multi-day views; on single-day view, go directly to today
if (viewDays > 1) {
d.setDate(d.getDate() + (profile?.startDayOffset || 0));
}
setCurrentWeekStart(d);
};
@ -6395,9 +6399,9 @@ export default function WeeklyView() {
})()}
{/* Main Grid with Time Column */}
{viewStyle !== "kanban" && <div style={{ position: "relative" }}>
{viewStyle !== "kanban" && <div style={{ position: "relative", flex: 1, minHeight: 0, overflow: 'hidden' }}>
<div className="time-grid-wrapper" ref={timeGridWrapperRef} style={showTimeGrid && !isMobile ? {
maxHeight: `${(endHour - startHour) * (60 / cellDuration) * getSlotHeight(cellDuration) + measuredHeaderHeight}px`,
maxHeight: '100%',
} : undefined}>
{/* Time Column */}
{showTimeGrid && (
@ -8279,7 +8283,7 @@ export default function WeeklyView() {
profile={profile}
setProfile={setProfile}
isMobile={isMobile}
mobileActions={isMobile ? {
mobileActions={{
goToPrevWeek,
goToPrevDay,
goToToday,
@ -8290,10 +8294,12 @@ export default function WeeklyView() {
const now = new Date();
setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` });
},
onAddProject: () => { setShowSettings(true); setActiveTab("general"); },
onRecurringTasks: () => setIsRecurringTasksOpen(true),
onToggleNextTask: () => { const newVal = !showNextTask; setShowNextTask(newVal); saveSetting("showNextTask", newVal); },
onFocusMode: () => setShowFocusMode(true),
onToggleDarkMode: () => setDarkMode(!darkMode),
onSearch: () => setIsSearchOpen(true),
onUndo: handleUndo,
onRedo: handleRedo,
onRefresh: () => { fetchCalendarEvents(true); fetchTasks(); },
@ -8306,7 +8312,13 @@ export default function WeeklyView() {
showTimeGrid,
cellDuration,
onCellDurationChange: (d: CellDuration) => { setCellDuration(d); saveSetting("cellDuration", d); },
} : undefined}
viewStyle,
onViewStyleChange: (s: string) => { setViewStyle(s as any); saveSetting("viewStyle", s); },
startHour,
endHour,
onStartHourChange: (h: number) => { setStartHour(h); saveSetting("startHour", h); },
onEndHourChange: (h: number) => { setEndHour(h); saveSetting("endHour", h); },
}}
/>
)
}
@ -9583,7 +9595,7 @@ interface SettingsSidebarProps {
onProjectsChanged: () => void;
kanbanStages: KanbanStage[];
saveKanbanStages: (stages: KanbanStage[]) => Promise<void>;
// Mobile quick actions
// Quick actions
isMobile?: boolean;
mobileActions?: {
goToPrevWeek: () => void;
@ -9593,10 +9605,12 @@ interface SettingsSidebarProps {
goToNextWeek: () => void;
onJumpToDate: () => void;
onAddCalendarEvent: () => void;
onAddProject: () => void;
onRecurringTasks: () => void;
onToggleNextTask: () => void;
onFocusMode: () => void;
onToggleDarkMode: () => void;
onSearch: () => void;
onUndo: () => void;
onRedo: () => void;
onRefresh: () => void;
@ -9609,6 +9623,12 @@ interface SettingsSidebarProps {
showTimeGrid: boolean;
cellDuration: CellDuration;
onCellDurationChange: (d: CellDuration) => void;
viewStyle: string;
onViewStyleChange: (style: string) => void;
startHour: number;
endHour: number;
onStartHourChange: (h: number) => void;
onEndHourChange: (h: number) => void;
};
}
// Notes Sidebar Component
@ -10294,8 +10314,8 @@ function SettingsSidebar({
</button>
</header>
{/* Mobile Quick Actions Panel */}
{isMobileSidebar && mobileActions && (
{/* Quick Actions Panel */}
{mobileActions && (
<div className="mobile-quick-actions" style={{
padding: "12px 16px",
borderBottom: "1px solid var(--weekly-border, #eee)",
@ -10325,12 +10345,18 @@ function SettingsSidebar({
{/* Quick Action Buttons */}
<div style={{ display: "flex", flexDirection: "column", gap: "2px" }}>
<button className="mobile-quick-action-btn" onClick={() => { mobileActions.onSearch(); handleClose(); }}>
<Search size={18} /> <span>{t.search || "Search"}</span>
</button>
<button className="mobile-quick-action-btn" onClick={() => { mobileActions.onJumpToDate(); handleClose(); }}>
<Calendar size={18} /> <span>{t.jumpToDate || "Jump to date"}</span>
</button>
<button className="mobile-quick-action-btn" onClick={() => { mobileActions.onAddCalendarEvent(); handleClose(); }}>
<Plus size={18} /> <span>{t.addCalendarEvent || "Add Calendar Event"}</span>
</button>
<button className="mobile-quick-action-btn" onClick={() => { mobileActions.onAddProject(); }}>
<FolderPlus size={18} /> <span>{t.addProject || "New Project"}</span>
</button>
<button className="mobile-quick-action-btn" onClick={() => { mobileActions.onRecurringTasks(); handleClose(); }}>
<Repeat size={18} /> <span>{t.recurringTasks || "Recurring Tasks"}</span>
</button>
@ -10347,8 +10373,36 @@ function SettingsSidebar({
</button>
</div>
{/* View Controls */}
{/* View Style */}
<div style={{ display: "flex", flexDirection: "column", gap: "8px", padding: "4px 0" }}>
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<span style={{ fontSize: "0.75rem", color: "var(--weekly-text-light, #9ca3af)", minWidth: "40px" }}>{t.view || "View"}</span>
<div style={{ display: "flex", gap: "4px", flex: 1 }}>
{[
{ key: "simple", icon: <CalendarDays size={14} />, label: "Simple" },
{ key: "calendar", icon: <Calendar size={14} />, label: "Calendar" },
{ key: "list", icon: <ListTodo size={14} />, label: "List" },
{ key: "kanban", icon: <Kanban size={14} />, label: "Kanban" },
].map((v) => (
<button
key={v.key}
onClick={() => { mobileActions.onViewStyleChange(v.key); }}
title={v.label}
style={{
flex: 1, padding: "6px 0", borderRadius: "6px", border: "none", cursor: "pointer",
display: "flex", alignItems: "center", justifyContent: "center",
fontWeight: mobileActions.viewStyle === v.key ? 700 : 400,
background: mobileActions.viewStyle === v.key ? "#0ea5e9" : "var(--weekly-settings-toggle-bg, #f3f4f6)",
color: mobileActions.viewStyle === v.key ? "#fff" : "var(--weekly-text, #333)",
}}
>
{v.icon}
</button>
))}
</div>
</div>
{/* Days */}
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<span style={{ fontSize: "0.75rem", color: "var(--weekly-text-light, #9ca3af)", minWidth: "40px" }}>{t.days || "Days"}</span>
<div style={{ display: "flex", gap: "4px", flex: 1 }}>
@ -10368,6 +10422,8 @@ function SettingsSidebar({
))}
</div>
</div>
{/* Slot Duration */}
{mobileActions.showTimeGrid && (
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<span style={{ fontSize: "0.75rem", color: "var(--weekly-text-light, #9ca3af)", minWidth: "40px" }}>{t.slot || "Slot"}</span>
@ -10389,6 +10445,43 @@ function SettingsSidebar({
</div>
</div>
)}
{/* Visible Hours */}
{mobileActions.showTimeGrid && (
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<span style={{ fontSize: "0.75rem", color: "var(--weekly-text-light, #9ca3af)", minWidth: "40px" }}>
<Clock size={14} />
</span>
<div style={{ display: "flex", alignItems: "center", gap: "4px", flex: 1 }}>
<input
type="number"
min={0}
max={23}
value={mobileActions.startHour}
onChange={(e) => mobileActions.onStartHourChange(Math.max(0, Math.min(23, parseInt(e.target.value) || 0)))}
style={{
width: "48px", padding: "4px 6px", borderRadius: "6px", border: "1px solid var(--weekly-border, #e5e7eb)",
background: "var(--weekly-settings-toggle-bg, #f3f4f6)", color: "var(--weekly-text, #333)",
fontSize: "0.8rem", textAlign: "center", outline: "none",
}}
/>
<span style={{ fontSize: "0.75rem", color: "var(--weekly-text-light, #9ca3af)" }}></span>
<input
type="number"
min={1}
max={24}
value={mobileActions.endHour}
onChange={(e) => mobileActions.onEndHourChange(Math.max(1, Math.min(24, parseInt(e.target.value) || 24)))}
style={{
width: "48px", padding: "4px 6px", borderRadius: "6px", border: "1px solid var(--weekly-border, #e5e7eb)",
background: "var(--weekly-settings-toggle-bg, #f3f4f6)", color: "var(--weekly-text, #333)",
fontSize: "0.8rem", textAlign: "center", outline: "none",
}}
/>
<span style={{ fontSize: "0.7rem", color: "var(--weekly-text-light, #9ca3af)" }}>h</span>
</div>
</div>
)}
</div>
{/* Utility Row */}