fix: 4 mobile issues — slot indicator, view days, list header, scroll sync

1. cellDuration indicator: compare against local `cellDuration` state
   (not effectiveCellDuration which reads stale profile.cellDuration
   since saveSetting bails early for DEVICE_SETTINGS_KEYS)

2. viewDays on mobile now uses orientation instead of fixed width:
   portrait (h > w) → 1 day, landscape → 3 days, for ≤768px.
   Applied consistently in useEffect, early profile load, and cookie
   override blocks so the responsive value is never overridden by
   the saved DB preference on mobile.

3. list-view day header on mobile: changed from sticky to
   position:relative so it flows with content and never covers tasks

4. time/day column scroll sync: weekly-days-grid was overflow-y:auto
   on mobile, creating an independent scroll container that drifted
   from the time column. Changed to overflow-y:visible so only
   time-grid-wrapper scrolls. Added touch-action:pan-y to day columns
   so iOS handles pan immediately without waiting for JS.

v1.81.7
This commit is contained in:
mARTin 2026-04-02 09:29:48 +02:00
parent 5ee99d6d2f
commit 676c5612ed
3 changed files with 28 additions and 20 deletions

View File

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

@ -3479,10 +3479,11 @@ h3 {
border-bottom-color: var(--weekly-border, #333);
}
/* On mobile, list-view day header must clear the sticky mobile header bar (~48px) */
/* On mobile, list-view day header is not sticky — it just flows with content */
@media (max-width: 768px) {
.weekly-container.list-view .weekly-day-header {
top: calc(48px + env(safe-area-inset-top, 0px));
position: relative !important;
top: auto !important;
}
}
@ -4943,16 +4944,17 @@ h3 {
min-height: 100% !important;
}
}
/* Mobile: allow scroll on grid but keep day columns visible for sticky headers */
/* Mobile: all inner containers stay non-scrolling — time-grid-wrapper is the sole scroll container */
@media (max-width: 768px) {
.time-grid-on .weekly-days-grid {
overflow-y: auto !important;
overflow-y: visible !important;
overflow-x: clip !important;
}
.time-grid-on .weekly-day-column {
overflow-y: visible !important;
overflow-x: visible !important;
max-height: none !important;
touch-action: pan-y;
}
.time-grid-on .time-slots-container,
.time-grid-on .time-column-slots,

View File

@ -569,17 +569,19 @@ export default function WeeklyView() {
const savedViewDaysRef = useRef(7); // Track user's saved preference for restoring on resize
const [isLoading, setIsLoading] = useState(true);
// Responsive: auto-adjust viewDays based on screen width
// Responsive: auto-adjust viewDays based on screen orientation / width
useEffect(() => {
const getResponsiveViewDays = (width: number): number => {
if (width <= 480) return 1;
if (width <= 768) return 3;
const getResponsiveViewDays = (width: number, height: number): number => {
if (width <= 768) {
// Mobile: portrait → 1 day, landscape → 3 days
return height > width ? 1 : 3;
}
if (width <= 1024) return Math.min(savedViewDaysRef.current, 5);
return savedViewDaysRef.current;
};
const handleResize = () => {
const responsiveDays = getResponsiveViewDays(window.innerWidth);
const responsiveDays = getResponsiveViewDays(window.innerWidth, window.innerHeight);
setViewDays(responsiveDays);
};
@ -1249,7 +1251,13 @@ export default function WeeklyView() {
// Sync individual states to profile data
if (profileData.viewStyle) setViewStyle(profileData.viewStyle);
if (profileData.viewDays) setViewDays(profileData.viewDays);
if (profileData.viewDays) {
savedViewDaysRef.current = profileData.viewDays;
const w = window.innerWidth, h = window.innerHeight;
if (w <= 768) setViewDays(h > w ? 1 : 3);
else if (w <= 1024) setViewDays(Math.min(profileData.viewDays, 5));
else setViewDays(profileData.viewDays);
}
if (profileData.showTimeGrid !== undefined) setShowTimeGrid(profileData.showTimeGrid);
if (profileData.showSomeday !== undefined) setShowSomeday(profileData.showSomeday);
if (profileData.showAllDayEvents !== undefined) setShowAllDay(profileData.showAllDayEvents);
@ -2244,10 +2252,9 @@ export default function WeeklyView() {
}
if (data.user.viewDays !== undefined) {
savedViewDaysRef.current = data.user.viewDays;
const width = window.innerWidth;
if (width <= 480) setViewDays(1);
else if (width <= 768) setViewDays(3);
else if (width <= 1024) setViewDays(Math.min(data.user.viewDays, 5));
const w = window.innerWidth, h = window.innerHeight;
if (w <= 768) setViewDays(h > w ? 1 : 3);
else if (w <= 1024) setViewDays(Math.min(data.user.viewDays, 5));
else setViewDays(data.user.viewDays);
}
if (data.user.cellDuration !== undefined)
@ -2258,10 +2265,9 @@ export default function WeeklyView() {
if (cookieViewDays) {
const v = Number(cookieViewDays);
savedViewDaysRef.current = v;
const width = window.innerWidth;
if (width <= 480) setViewDays(1);
else if (width <= 768) setViewDays(3);
else if (width <= 1024) setViewDays(Math.min(v, 5));
const w = window.innerWidth, h = window.innerHeight;
if (w <= 768) setViewDays(h > w ? 1 : 3);
else if (w <= 1024) setViewDays(Math.min(v, 5));
else setViewDays(v);
}
if (data.user.weekdayFormat) {
@ -5442,7 +5448,7 @@ export default function WeeklyView() {
<div style={{ display: "flex", gap: "4px" }}>
{[15, 30, 60].map((d) => (
<button key={d} onClick={() => { setCellDuration(d as CellDuration); 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: cellDuration === d ? 700 : 400, background: cellDuration === d ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: cellDuration === d ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
{d}m
</button>
))}