fix: mobile sync icon no longer shifts date; selected day tracks last clicked column

- Mobile header: removed spinner/error from inside the date button,
  placed as a fixed-width (24px) sibling slot after the button — date
  text position is now stable regardless of sync state
- Selected day: added selectedDay state tracking the last day column
  the user clicked; passed to getSelectedDay() so "Selektierter Tag"
  in the header reflects the actual cursor position, not just visibleDays[0]
- getSelectedDay() priority: explicit selection → today if visible → first visible day
- Navigating to a new week resets selectedDay so the header stays accurate

v1.81.1
This commit is contained in:
mARTin 2026-03-31 09:31:36 +02:00
parent e800d87235
commit 5bcf281502
2 changed files with 22 additions and 10 deletions

View File

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

@ -415,8 +415,10 @@ function formatCustomHeader(format: string, days: Date[], language: string, t: a
return format.replace(regex, (match) => tokens[match] || match);
}
// Get the "selected" day for current_day header: today if visible, otherwise first visible day
function getSelectedDay(days: Date[]): Date {
// Get the "selected" day for current_day header.
// Priority: explicit selection → today if visible → first visible day
function getSelectedDay(days: Date[], explicitSelection?: Date | null): Date {
if (explicitSelection) return explicitSelection;
const today = new Date();
return days.some(d =>
d.getDate() === today.getDate() &&
@ -792,6 +794,9 @@ export default function WeeklyView() {
const [isMobile, setIsMobile] = useState(false);
const [isPortrait, setIsPortrait] = useState(false);
// Tracks the last day column the user interacted with (for "selected day" header display)
const [selectedDay, setSelectedDay] = useState<Date | null>(null);
const [showMobileFabSheet, setShowMobileFabSheet] = useState(false);
const [showMobileFabMenu, setShowMobileFabMenu] = useState(false);
const [mobileStickyDay, setMobileStickyDay] = useState<string | null>(null);
@ -3429,6 +3434,7 @@ export default function WeeklyView() {
}
setCurrentWeekStart(newDate);
setSlideDirection(direction === "left" ? "next" : "prev");
setSelectedDay(null); // reset so header shows the new week's today/first day
};
const goToPrevWeek = () =>
@ -5601,17 +5607,13 @@ export default function WeeklyView() {
<PanelLeftOpen size={22} />
</button>
{/* Center: Date display (tap to jump to date) */}
{/* Center: Date display (tap to jump to date) + fixed-width sync slot */}
<button className="mobile-header-date" onClick={() => setShowDatePicker(true)} style={{
fontFamily: profile.cwFontFamily || "Inter",
fontSize: scaleRem(profile.cwFontSize || "0.9rem"),
fontWeight: Number(profile.cwFontWeight || "700"),
color: adjustColorForDarkMode(profile.cwColor || (darkMode ? "#e5e7eb" : "#333333"), darkMode),
}}>
{(isLoading || isSyncing || syncStatus === "syncing") && (
<div className="weekly-spinner" title="Syncing..." style={{ width: 14, height: 14 }}></div>
)}
{syncError && <AlertCircle size={14} className="text-red-500" />}
<span>
{(() => {
const visibleDays = getVisibleDays();
@ -5621,7 +5623,7 @@ export default function WeeklyView() {
if (mobileDisplay === "none") return "";
if (mobileDisplay === "current_day") {
const fmt = profile.headerCurrentDayFormat || "DDD, DD. MMMM YYYY";
return formatCustomHeader(fmt, visibleDays, profile.language, t, getSelectedDay(visibleDays));
return formatCustomHeader(fmt, visibleDays, profile.language, t, getSelectedDay(visibleDays, selectedDay));
}
if (mobileDisplay === "date") return new Date().toLocaleDateString(profile.language, { day: '2-digit', month: '2-digit', year: 'numeric' });
if (mobileDisplay === "month_year") return getCWReferenceDate(visibleDays).toLocaleDateString(profile.language, { month: 'long', year: 'numeric' });
@ -5633,6 +5635,15 @@ export default function WeeklyView() {
<ChevronDown size={12} style={{ opacity: 0.5 }} />
</button>
{/* Sync status indicator — fixed width so date never shifts */}
<div style={{ width: 24, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
{syncError
? <AlertCircle size={14} className="text-red-500" title={syncError} />
: (isLoading || isSyncing || syncStatus === "syncing")
? <div className="weekly-spinner" title="Syncing..." style={{ width: 14, height: 14 }}></div>
: null}
</div>
{/* Right: Settings menu */}
<button className="mobile-header-btn" onClick={() => setShowSettings(true)} title="Settings" style={{ color: darkMode ? "#e5e7eb" : "#6b7280" }}>
<Menu size={22} />
@ -5767,7 +5778,7 @@ export default function WeeklyView() {
if (effectiveDisplay === "none") return "";
if (effectiveDisplay === "current_day") {
const fmt = profile.headerCurrentDayFormat || "DDD, DD. MMMM YYYY";
return formatCustomHeader(fmt, visibleDays, profile.language, t, getSelectedDay(visibleDays));
return formatCustomHeader(fmt, visibleDays, profile.language, t, getSelectedDay(visibleDays, selectedDay));
}
if (effectiveDisplay === "month") return getCWReferenceDate(visibleDays).toLocaleDateString(profile.language, { month: "long" });
if (effectiveDisplay === "month_year") return getCWReferenceDate(visibleDays).toLocaleDateString(profile.language, { month: "long", year: "numeric" });
@ -6653,6 +6664,7 @@ export default function WeeklyView() {
key={date.toISOString()}
className={`weekly-day-column ${date.getDay() === 6 ? "is-sat" : ""} ${date.getDay() === 0 ? "is-sun" : ""} ${isToday ? "is-today" : ""} ${isPast ? "is-past" : ""}`}
data-date={`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`}
onClick={() => setSelectedDay(date)}
>
{/* Day Header */}
<header className="weekly-day-header" ref={colIndex === 0 ? dayHeaderRef : undefined}>