refactor: Phase 2 — consolidate profile state reads
Replace all individual useState reads (viewStyle, timeFormat, language, cellDuration, showTimeGrid, showNextTask, showSomeday, showAllDay, etc.) with profile.fieldName reads. Individual useState declarations remain; only read sites are migrated. No UI logic changed. - getEffective() calls use profile.fieldName as global fallback - workingHoursStart/End derived from profile.startHour/endHour - All JSX reads (className, conditionals, child props) use profile.* - SettingsSidebar value props use profile.* (setters unchanged) - Add weekStartDay: 1 to profile defaults - ProjectsSidebar function body reverted (uses language prop, not profile) - darkMode excluded: localStorage-only, not an API profile field v1.80.1
This commit is contained in:
parent
a5f6edd82d
commit
bfb749a8a6
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "my-weekly-todo-list",
|
"name": "my-weekly-todo-list",
|
||||||
"version": "1.80.0",
|
"version": "1.80.1",
|
||||||
"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": {
|
||||||
|
|||||||
@ -849,6 +849,7 @@ export default function WeeklyView() {
|
|||||||
dayHeaderGap: "0.75em",
|
dayHeaderGap: "0.75em",
|
||||||
dateVerticalAlign: "middle",
|
dateVerticalAlign: "middle",
|
||||||
allDayPosition: "above",
|
allDayPosition: "above",
|
||||||
|
weekStartDay: 1,
|
||||||
focusTimerDuration: 25,
|
focusTimerDuration: 25,
|
||||||
focusBreakDuration: 5,
|
focusBreakDuration: 5,
|
||||||
headlineFont: "Oswald",
|
headlineFont: "Oswald",
|
||||||
@ -951,18 +952,18 @@ export default function WeeklyView() {
|
|||||||
viewSettingsRef.current = viewSettings;
|
viewSettingsRef.current = viewSettings;
|
||||||
|
|
||||||
const getEffective = <K extends keyof PerViewOverrides>(key: K, globalVal: PerViewOverrides[K]): PerViewOverrides[K] => {
|
const getEffective = <K extends keyof PerViewOverrides>(key: K, globalVal: PerViewOverrides[K]): PerViewOverrides[K] => {
|
||||||
const vs = viewSettingsRef.current[viewStyle];
|
const vs = viewSettingsRef.current[profile.viewStyle];
|
||||||
if (vs && vs[key] !== undefined) return vs[key] as PerViewOverrides[K];
|
if (vs && vs[key] !== undefined) return vs[key] as PerViewOverrides[K];
|
||||||
return globalVal;
|
return globalVal;
|
||||||
};
|
};
|
||||||
const isPerView = (key: keyof PerViewOverrides): boolean => {
|
const isPerView = (key: keyof PerViewOverrides): boolean => {
|
||||||
const vs = viewSettingsRef.current[viewStyle];
|
const vs = viewSettingsRef.current[profile.viewStyle];
|
||||||
return !!(vs && vs[key] !== undefined);
|
return !!(vs && vs[key] !== undefined);
|
||||||
};
|
};
|
||||||
const saveViewSetting = async <K extends keyof PerViewOverrides>(key: K, value: PerViewOverrides[K], perView: boolean) => {
|
const saveViewSetting = async <K extends keyof PerViewOverrides>(key: K, value: PerViewOverrides[K], perView: boolean) => {
|
||||||
const updated = { ...viewSettingsRef.current };
|
const updated = { ...viewSettingsRef.current };
|
||||||
if (perView) {
|
if (perView) {
|
||||||
updated[viewStyle] = { ...(updated[viewStyle] || {}), [key]: value };
|
updated[profile.viewStyle] = { ...(updated[profile.viewStyle] || {}), [key]: value };
|
||||||
} else {
|
} else {
|
||||||
// Remove per-view overrides for this key from ALL views and set globally
|
// Remove per-view overrides for this key from ALL views and set globally
|
||||||
for (const v of Object.keys(updated)) {
|
for (const v of Object.keys(updated)) {
|
||||||
@ -987,9 +988,9 @@ export default function WeeklyView() {
|
|||||||
if (isPerView(key)) {
|
if (isPerView(key)) {
|
||||||
// Remove per-view override (revert to global)
|
// Remove per-view override (revert to global)
|
||||||
const updated = { ...viewSettingsRef.current };
|
const updated = { ...viewSettingsRef.current };
|
||||||
if (updated[viewStyle]) {
|
if (updated[profile.viewStyle]) {
|
||||||
const { [key]: _, ...rest } = updated[viewStyle] as any;
|
const { [key]: _, ...rest } = updated[profile.viewStyle] as any;
|
||||||
updated[viewStyle] = rest;
|
updated[profile.viewStyle] = rest;
|
||||||
}
|
}
|
||||||
viewSettingsRef.current = updated;
|
viewSettingsRef.current = updated;
|
||||||
setViewSettings(updated);
|
setViewSettings(updated);
|
||||||
@ -1011,17 +1012,17 @@ export default function WeeklyView() {
|
|||||||
const [showAllDay, setShowAllDay] = useState(true);
|
const [showAllDay, setShowAllDay] = useState(true);
|
||||||
|
|
||||||
// Effective per-view values (override if set for current view, else global)
|
// Effective per-view values (override if set for current view, else global)
|
||||||
const effectiveHourLabelFormat = getEffective("hourLabelFormat", hourLabelFormat);
|
const effectiveHourLabelFormat = getEffective("hourLabelFormat", profile.hourLabelFormat ?? "short");
|
||||||
const effectiveShowSubHourSlots = getEffective("showSubHourSlots", showSubHourSlots);
|
const effectiveShowSubHourSlots = getEffective("showSubHourSlots", profile.showSubHourSlots ?? true);
|
||||||
const effectiveWeatherEnabled = getEffective("weatherEnabled", profile.weatherEnabled);
|
const effectiveWeatherEnabled = getEffective("weatherEnabled", profile.weatherEnabled);
|
||||||
const effectiveWeatherDisplay = (getEffective("weatherDisplay", WEATHER_DISPLAY_DEFAULTS) || WEATHER_DISPLAY_DEFAULTS) as WeatherDisplayKey[];
|
const effectiveWeatherDisplay = (getEffective("weatherDisplay", WEATHER_DISPLAY_DEFAULTS) || WEATHER_DISPLAY_DEFAULTS) as WeatherDisplayKey[];
|
||||||
const effectiveShowTaskCheckboxes = getEffective("showTaskCheckboxes", profile.showTaskCheckboxes);
|
const effectiveShowTaskCheckboxes = getEffective("showTaskCheckboxes", profile.showTaskCheckboxes);
|
||||||
const effectiveShowProjectIcons = getEffective("showProjectIcons", profile.showProjectIcons);
|
const effectiveShowProjectIcons = getEffective("showProjectIcons", profile.showProjectIcons);
|
||||||
const effectiveShowSomeday = getEffective("showSomeday", showSomeday);
|
const effectiveShowSomeday = getEffective("showSomeday", profile.showSomeday ?? true);
|
||||||
const effectiveShowAllDay = getEffective("showAllDayEvents", showAllDay);
|
const effectiveShowAllDay = getEffective("showAllDayEvents", profile.showAllDayEvents ?? true);
|
||||||
const effectiveAllDayPosition = getEffective("allDayPosition", allDayPosition) || "above";
|
const effectiveAllDayPosition = getEffective("allDayPosition", profile.allDayPosition ?? "above") || "above";
|
||||||
const effectiveShowCompletedTasks = getEffective("showCompletedTasks", profile.showCompletedTasks !== false);
|
const effectiveShowCompletedTasks = getEffective("showCompletedTasks", profile.showCompletedTasks !== false);
|
||||||
const effectiveCellDuration = getEffective("cellDuration", cellDuration) as CellDuration;
|
const effectiveCellDuration = getEffective("cellDuration", profile.cellDuration ?? 30) as CellDuration;
|
||||||
const effectiveStartHour = getEffective("startHour", profile.startHour ?? 8) ?? 8;
|
const effectiveStartHour = getEffective("startHour", profile.startHour ?? 8) ?? 8;
|
||||||
const effectiveEndHour = getEffective("endHour", profile.endHour ?? 18) ?? 18;
|
const effectiveEndHour = getEffective("endHour", profile.endHour ?? 18) ?? 18;
|
||||||
|
|
||||||
@ -1321,14 +1322,14 @@ export default function WeeklyView() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
localStorage.setItem("weekly-week-start", String(weekStartDay));
|
localStorage.setItem("weekly-week-start", String(profile.weekStartDay ?? 1));
|
||||||
// REMOVED: Re-align current week start when start day changes
|
// REMOVED: Re-align current week start when start day changes
|
||||||
// This was forcing the view to snap to Monday, breaking the "Yesterday as first column" setting.
|
// This was forcing the view to snap to Monday, breaking the "Yesterday as first column" setting.
|
||||||
// setCurrentWeekStart(prev => getStartOfWeek(prev, weekStartDay));
|
// setCurrentWeekStart(prev => getStartOfWeek(prev, weekStartDay));
|
||||||
}, [weekStartDay, mounted]);
|
}, [profile.weekStartDay, mounted]);
|
||||||
|
|
||||||
// Translation helper
|
// Translation helper
|
||||||
const t = translations[language] || translations["en"];
|
const t = translations[profile.language] || translations["en"];
|
||||||
|
|
||||||
// Refs for scroll
|
// Refs for scroll
|
||||||
const dayColumnsRef = useRef<HTMLDivElement[]>([]);
|
const dayColumnsRef = useRef<HTMLDivElement[]>([]);
|
||||||
@ -1371,7 +1372,7 @@ export default function WeeklyView() {
|
|||||||
window.removeEventListener('resize', updateHeight);
|
window.removeEventListener('resize', updateHeight);
|
||||||
if (resizeObserver) resizeObserver.disconnect();
|
if (resizeObserver) resizeObserver.disconnect();
|
||||||
};
|
};
|
||||||
}, [dayHeaderRef.current, cellDuration, viewDays, isMobile, profile.mobileDateLayout, profile.dateLayout, profile.dateAlignment, profile.dayHeaderGap, profile.headlineFontSize, profile.headlineFontWeight, profile.dateFontSize, profile.dateVerticalAlign, profile.headerDisplay, profile.weekdayFormat, viewStyle]);
|
}, [dayHeaderRef.current, profile.cellDuration, viewDays, isMobile, profile.mobileDateLayout, profile.dateLayout, profile.dateAlignment, profile.dayHeaderGap, profile.headlineFontSize, profile.headlineFontWeight, profile.dateFontSize, profile.dateVerticalAlign, profile.headerDisplay, profile.weekdayFormat, profile.viewStyle]);
|
||||||
const somedaySectionRef = useRef<HTMLElement | null>(null);
|
const somedaySectionRef = useRef<HTMLElement | null>(null);
|
||||||
|
|
||||||
// Unified scroll sync handlers
|
// Unified scroll sync handlers
|
||||||
@ -1383,8 +1384,8 @@ export default function WeeklyView() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const jumpToHour = (hour: number) => {
|
const jumpToHour = (hour: number) => {
|
||||||
const slotsPerHour = 60 / cellDuration;
|
const slotsPerHour = 60 / effectiveCellDuration;
|
||||||
const slotHeight = getSlotHeight(cellDuration);
|
const slotHeight = getSlotHeight(effectiveCellDuration);
|
||||||
const scrollOffset = hour * slotsPerHour * slotHeight;
|
const scrollOffset = hour * slotsPerHour * slotHeight;
|
||||||
|
|
||||||
console.log(`[SCROLL] Jumping to hour ${hour} (offset ${scrollOffset}px)`);
|
console.log(`[SCROLL] Jumping to hour ${hour} (offset ${scrollOffset}px)`);
|
||||||
@ -1449,8 +1450,8 @@ export default function WeeklyView() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Working hours range (configurable)
|
// Working hours range (configurable)
|
||||||
const workingHoursStart = startHour;
|
const workingHoursStart = profile.startHour ?? 8;
|
||||||
const workingHoursEnd = endHour;
|
const workingHoursEnd = profile.endHour ?? 18;
|
||||||
|
|
||||||
// Fetch calendar events
|
// Fetch calendar events
|
||||||
// Find connectionId for a given calendarId
|
// Find connectionId for a given calendarId
|
||||||
@ -1984,7 +1985,7 @@ export default function WeeklyView() {
|
|||||||
|
|
||||||
// Mobile: show a sticky day bar by reading scroll position on the actual grid scroll container
|
// Mobile: show a sticky day bar by reading scroll position on the actual grid scroll container
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isMobile || !showTimeGrid) return;
|
if (!isMobile || !profile.showTimeGrid) return;
|
||||||
const grid = gridRef.current;
|
const grid = gridRef.current;
|
||||||
if (!grid) return;
|
if (!grid) return;
|
||||||
|
|
||||||
@ -2009,7 +2010,7 @@ export default function WeeklyView() {
|
|||||||
const dateStr = (currentCol as Element).getAttribute('data-date');
|
const dateStr = (currentCol as Element).getAttribute('data-date');
|
||||||
if (dateStr) {
|
if (dateStr) {
|
||||||
const d = new Date(dateStr + 'T00:00:00');
|
const d = new Date(dateStr + 'T00:00:00');
|
||||||
const dayNames = language === 'de'
|
const dayNames = profile.language === 'de'
|
||||||
? ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']
|
? ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']
|
||||||
: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||||||
const label = `${dayNames[d.getDay()]} ${d.getDate()}.${d.getMonth() + 1}.`;
|
const label = `${dayNames[d.getDay()]} ${d.getDate()}.${d.getMonth() + 1}.`;
|
||||||
@ -2021,7 +2022,7 @@ export default function WeeklyView() {
|
|||||||
grid.addEventListener('scroll', updateStickyDay, { passive: true });
|
grid.addEventListener('scroll', updateStickyDay, { passive: true });
|
||||||
updateStickyDay();
|
updateStickyDay();
|
||||||
return () => grid.removeEventListener('scroll', updateStickyDay);
|
return () => grid.removeEventListener('scroll', updateStickyDay);
|
||||||
}, [isMobile, showTimeGrid, currentWeekStart, viewDays, language]);
|
}, [isMobile, profile.showTimeGrid, currentWeekStart, viewDays, profile.language]);
|
||||||
|
|
||||||
// Compute the goal date key: for "week" scope, normalize to Monday of that week; for "day", use the exact date
|
// Compute the goal date key: for "week" scope, normalize to Monday of that week; for "day", use the exact date
|
||||||
const getGoalDateKey = useCallback(
|
const getGoalDateKey = useCallback(
|
||||||
@ -2212,7 +2213,7 @@ export default function WeeklyView() {
|
|||||||
setStartHour(data.user.startHour);
|
setStartHour(data.user.startHour);
|
||||||
if (data.user.endHour !== undefined)
|
if (data.user.endHour !== undefined)
|
||||||
setEndHour(data.user.endHour);
|
setEndHour(data.user.endHour);
|
||||||
if (data.user.viewStyle !== undefined) {
|
if (data.user.profile.viewStyle !== undefined) {
|
||||||
setViewStyle(data.user.viewStyle as ViewStyle);
|
setViewStyle(data.user.viewStyle as ViewStyle);
|
||||||
setShowTimeGrid(data.user.showTimeGrid ?? true);
|
setShowTimeGrid(data.user.showTimeGrid ?? true);
|
||||||
}
|
}
|
||||||
@ -5029,7 +5030,7 @@ export default function WeeklyView() {
|
|||||||
24,
|
24,
|
||||||
);
|
);
|
||||||
|
|
||||||
const fontSizeScale = fontSize === "S" ? 0.85 : fontSize === "L" ? 1.15 : 1;
|
const fontSizeScale = profile.fontSize === "S" ? 0.85 : profile.fontSize === "L" ? 1.15 : 1;
|
||||||
const mobileScale = isMobile ? (profile.mobileFontScale || 1.0) : 1.0;
|
const mobileScale = isMobile ? (profile.mobileFontScale || 1.0) : 1.0;
|
||||||
const fontVal = (v: string | undefined) => v && v !== "__custom__" ? v : "";
|
const fontVal = (v: string | undefined) => v && v !== "__custom__" ? v : "";
|
||||||
const scaleRem = (base: string) => {
|
const scaleRem = (base: string) => {
|
||||||
@ -5049,8 +5050,8 @@ export default function WeeklyView() {
|
|||||||
"--weekly-item-hover": activeTheme.color0,
|
"--weekly-item-hover": activeTheme.color0,
|
||||||
} : {}),
|
} : {}),
|
||||||
"--weekly-font-headline":
|
"--weekly-font-headline":
|
||||||
fontVal(profile.headlineFont) || headlineFont
|
fontVal(profile.headlineFont)
|
||||||
? `"${fontVal(profile.headlineFont) || headlineFont}", sans-serif`
|
? `"${fontVal(profile.headlineFont)}", sans-serif`
|
||||||
: "var(--font-headline)",
|
: "var(--font-headline)",
|
||||||
"--weekly-headline-size": scaleRem(profile.headlineFontSize || "1.25rem"),
|
"--weekly-headline-size": scaleRem(profile.headlineFontSize || "1.25rem"),
|
||||||
"--weekly-headline-weight": profile.headlineFontWeight || "900",
|
"--weekly-headline-weight": profile.headlineFontWeight || "900",
|
||||||
@ -5088,13 +5089,12 @@ export default function WeeklyView() {
|
|||||||
"--weekly-task-size": scaleRem(profile.taskFontSize || "0.9rem"),
|
"--weekly-task-size": scaleRem(profile.taskFontSize || "0.9rem"),
|
||||||
"--weekly-task-weight": profile.taskFontWeight || "400",
|
"--weekly-task-weight": profile.taskFontWeight || "400",
|
||||||
"--weekly-event-font":
|
"--weekly-event-font":
|
||||||
fontVal(profile.eventFontFamily) || eventFontFamily
|
fontVal(profile.eventFontFamily)
|
||||||
? `"${fontVal(profile.eventFontFamily) || eventFontFamily}", sans-serif`
|
? `"${fontVal(profile.eventFontFamily)}", sans-serif`
|
||||||
: "var(--weekly-font)",
|
: "var(--weekly-font)",
|
||||||
"--weekly-event-size": scaleRem(profile.eventFontSize || eventFontSize || "0.85rem"),
|
"--weekly-event-size": scaleRem(profile.eventFontSize || "0.85rem"),
|
||||||
"--weekly-event-weight":
|
"--weekly-event-weight": profile.eventFontWeight || "400",
|
||||||
profile.eventFontWeight || eventFontWeight || "400",
|
"--font-weight-body": profile.fontWeight || "400",
|
||||||
"--font-weight-body": profile.fontWeight || fontWeight || "400",
|
|
||||||
"--weekly-weekend-sat": activeTheme?.color3 || (darkMode
|
"--weekly-weekend-sat": activeTheme?.color3 || (darkMode
|
||||||
? invertColor(profile.weekendColorSat || "#666666")
|
? invertColor(profile.weekendColorSat || "#666666")
|
||||||
: profile.weekendColorSat || "#666666"),
|
: profile.weekendColorSat || "#666666"),
|
||||||
@ -5125,7 +5125,7 @@ export default function WeeklyView() {
|
|||||||
style={{ alignItems: "center", justifyContent: "center" }}
|
style={{ alignItems: "center", justifyContent: "center" }}
|
||||||
>
|
>
|
||||||
<div style={{ color: "var(--weekly-text-light)" }}>
|
<div style={{ color: "var(--weekly-text-light)" }}>
|
||||||
{translations[language]?.loading || translations["en"].loading}
|
{translations[profile.language]?.loading || translations["en"].loading}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -5172,7 +5172,7 @@ export default function WeeklyView() {
|
|||||||
style={isAllDayExpanded && allDayHeight ? { height: `${allDayHeight}px`, overflowY: 'auto' } : undefined}
|
style={isAllDayExpanded && allDayHeight ? { height: `${allDayHeight}px`, overflowY: 'auto' } : undefined}
|
||||||
>
|
>
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||||
{showTimeGrid && (
|
{profile.showTimeGrid && (
|
||||||
<div
|
<div
|
||||||
className="all-day-label-column"
|
className="all-day-label-column"
|
||||||
onClick={() => setIsAllDayExpanded(!isAllDayExpanded)}
|
onClick={() => setIsAllDayExpanded(!isAllDayExpanded)}
|
||||||
@ -5293,7 +5293,7 @@ export default function WeeklyView() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`weekly-container ${darkMode ? "dark-mode" : ""} font-size-${fontSize.toLowerCase()} ${viewStyle}-view ${showTimeGrid ? "time-grid-on" : "time-grid-off"}`}
|
className={`weekly-container ${darkMode ? "dark-mode" : ""} font-size-${(profile.fontSize ?? "M").toLowerCase()} ${profile.viewStyle}-view ${profile.showTimeGrid ? "time-grid-on" : "time-grid-off"}`}
|
||||||
style={containerStyle}
|
style={containerStyle}
|
||||||
>
|
>
|
||||||
{/* Mobile sticky day indicator */}
|
{/* Mobile sticky day indicator */}
|
||||||
@ -5349,30 +5349,30 @@ export default function WeeklyView() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ fontSize: "0.85rem", fontWeight: 700, color: darkMode ? "#e5e7eb" : "#333", marginBottom: "2px" }}>
|
<div style={{ fontSize: "0.85rem", fontWeight: 700, color: darkMode ? "#e5e7eb" : "#333", marginBottom: "2px" }}>
|
||||||
{language === "de" ? "Einstellungen" : "Preferences"}
|
{profile.language === "de" ? "Einstellungen" : "Preferences"}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Navigation Row */}
|
{/* Navigation Row */}
|
||||||
<div style={{ display: "flex", justifyContent: "center", gap: "4px", padding: "4px 0", borderBottom: `1px solid ${darkMode ? "#333" : "#e5e7eb"}`, paddingBottom: "10px" }}>
|
<div style={{ display: "flex", justifyContent: "center", gap: "4px", padding: "4px 0", borderBottom: `1px solid ${darkMode ? "#333" : "#e5e7eb"}`, paddingBottom: "10px" }}>
|
||||||
<button onClick={() => { goToPrevWeek(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Previous Week"><ChevronsLeft size={16} /></button>
|
<button onClick={() => { goToPrevWeek(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Previous Week"><ChevronsLeft size={16} /></button>
|
||||||
<button onClick={() => { goToPrevDay(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Previous Day"><ChevronLeft size={16} /></button>
|
<button onClick={() => { goToPrevDay(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Previous Day"><ChevronLeft size={16} /></button>
|
||||||
<button onClick={() => { goToToday(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "56px", fontWeight: 700, fontSize: "0.7rem" }} title="Today">{language === "de" ? "Heute" : "Today"}</button>
|
<button onClick={() => { goToToday(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "56px", fontWeight: 700, fontSize: "0.7rem" }} title="Today">{profile.language === "de" ? "Heute" : "Today"}</button>
|
||||||
<button onClick={() => { goToNextDay(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Next Day"><ChevronRight size={16} /></button>
|
<button onClick={() => { goToNextDay(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Next Day"><ChevronRight size={16} /></button>
|
||||||
<button onClick={() => { goToNextWeek(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Next Week"><ChevronsRight size={16} /></button>
|
<button onClick={() => { goToNextWeek(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Next Week"><ChevronsRight size={16} /></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Quick Actions */}
|
{/* Quick Actions */}
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: "1px" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: "1px" }}>
|
||||||
<button onClick={() => { setIsSearchOpen(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Search size={16} /> <span>{language === "de" ? "Suche" : "Search"}</span></button>
|
<button onClick={() => { setIsSearchOpen(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Search size={16} /> <span>{profile.language === "de" ? "Suche" : "Search"}</span></button>
|
||||||
<button onClick={() => { setShowDatePicker(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Calendar size={16} /> <span>{language === "de" ? "Datum wählen" : "Jump to date"}</span></button>
|
<button onClick={() => { setShowDatePicker(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Calendar size={16} /> <span>{profile.language === "de" ? "Datum wählen" : "Jump to date"}</span></button>
|
||||||
<button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Plus size={16} /> <span>{language === "de" ? "Kalendereintrag" : "Calendar Event"}</span></button>
|
<button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Plus size={16} /> <span>{profile.language === "de" ? "Kalendereintrag" : "Calendar Event"}</span></button>
|
||||||
<button onClick={() => { setShowProjectsSidebar(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><FolderPlus size={16} /> <span>{language === "de" ? "Projekte" : "Projects"}</span></button>
|
<button onClick={() => { setShowProjectsSidebar(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><FolderPlus size={16} /> <span>{profile.language === "de" ? "Projekte" : "Projects"}</span></button>
|
||||||
<button onClick={() => { setIsRecurringTasksOpen(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Repeat size={16} /> <span>{language === "de" ? "Wiederkehrend" : "Recurring Tasks"}</span></button>
|
<button onClick={() => { setIsRecurringTasksOpen(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Repeat size={16} /> <span>{profile.language === "de" ? "Wiederkehrend" : "Recurring Tasks"}</span></button>
|
||||||
<button onClick={() => { const nv = !showNextTask; setShowNextTask(nv); saveSetting("showNextTask", nv); }} style={qsActionStyle(darkMode)}>
|
<button onClick={() => { const nv = !profile.showNextTask; setShowNextTask(nv); saveSetting("showNextTask", nv); }} style={qsActionStyle(darkMode)}>
|
||||||
{showNextTask ? <Play size={16} /> : <Target size={16} />}
|
{profile.showNextTask ? <Play size={16} /> : <Target size={16} />}
|
||||||
<span>{showNextTask ? (language === "de" ? "Nächste Aufgabe" : "Next Task") : (language === "de" ? "Ziel" : "Goal")}</span>
|
<span>{profile.showNextTask ? (profile.language === "de" ? "Nächste Aufgabe" : "Next Task") : (profile.language === "de" ? "Ziel" : "Goal")}</span>
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => { setShowFocusMode(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Zap size={16} /> <span>{language === "de" ? "Fokus" : "Focus"}</span></button>
|
<button onClick={() => { setShowFocusMode(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Zap size={16} /> <span>{profile.language === "de" ? "Fokus" : "Focus"}</span></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Separator */}
|
{/* Separator */}
|
||||||
@ -5381,7 +5381,7 @@ export default function WeeklyView() {
|
|||||||
{/* View Style */}
|
{/* View Style */}
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
||||||
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
||||||
{language === "de" ? "Ansicht" : "View"}
|
{profile.language === "de" ? "Ansicht" : "View"}
|
||||||
</span>
|
</span>
|
||||||
<div style={{ display: "flex", gap: "4px" }}>
|
<div style={{ display: "flex", gap: "4px" }}>
|
||||||
{[
|
{[
|
||||||
@ -5391,7 +5391,7 @@ export default function WeeklyView() {
|
|||||||
{ key: "kanban", icon: <Kanban size={13} /> },
|
{ key: "kanban", icon: <Kanban size={13} /> },
|
||||||
].map((v) => (
|
].map((v) => (
|
||||||
<button key={v.key} onClick={() => { setViewStyle(v.key as any); saveSetting("viewStyle", v.key); }}
|
<button key={v.key} onClick={() => { setViewStyle(v.key as any); saveSetting("viewStyle", v.key); }}
|
||||||
style={{ flex: 1, padding: "5px 0", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: viewStyle === v.key ? 700 : 400, background: viewStyle === v.key ? "#0ea5e9" : (darkMode ? "#1f2937" : "#e5e7eb"), color: viewStyle === v.key ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
|
style={{ flex: 1, padding: "5px 0", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: profile.viewStyle ===v.key ? 700 : 400, background: profile.viewStyle ===v.key ? "#0ea5e9" : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.viewStyle ===v.key ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
|
||||||
{v.icon}
|
{v.icon}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
@ -5401,7 +5401,7 @@ export default function WeeklyView() {
|
|||||||
{/* Columns / Days */}
|
{/* Columns / Days */}
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
||||||
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
||||||
{language === "de" ? "Spalten" : "Days"}
|
{profile.language === "de" ? "Spalten" : "Days"}
|
||||||
</span>
|
</span>
|
||||||
<div style={{ display: "flex", gap: "4px" }}>
|
<div style={{ display: "flex", gap: "4px" }}>
|
||||||
{[1, 2, 3, 5, 7].map((num) => (
|
{[1, 2, 3, 5, 7].map((num) => (
|
||||||
@ -5414,10 +5414,10 @@ export default function WeeklyView() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Slot Duration (only with time grid) */}
|
{/* Slot Duration (only with time grid) */}
|
||||||
{showTimeGrid && (
|
{profile.showTimeGrid && (
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
||||||
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
||||||
{language === "de" ? "Zeitfenster" : "Slot"}
|
{profile.language === "de" ? "Zeitfenster" : "Slot"}
|
||||||
</span>
|
</span>
|
||||||
<div style={{ display: "flex", gap: "4px" }}>
|
<div style={{ display: "flex", gap: "4px" }}>
|
||||||
{[15, 30, 60].map((d) => (
|
{[15, 30, 60].map((d) => (
|
||||||
@ -5433,12 +5433,12 @@ export default function WeeklyView() {
|
|||||||
{/* Text size */}
|
{/* Text size */}
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
||||||
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
||||||
{language === "de" ? "Textgröße" : "Text size"}
|
{profile.language === "de" ? "Textgröße" : "Text size"}
|
||||||
</span>
|
</span>
|
||||||
<div style={{ display: "flex", gap: "4px" }}>
|
<div style={{ display: "flex", gap: "4px" }}>
|
||||||
{(["S", "M", "L"] as const).map((size) => (
|
{(["S", "M", "L"] as const).map((size) => (
|
||||||
<button key={size} onClick={() => { setFontSize(size); saveSetting("fontSize", size); }}
|
<button key={size} onClick={() => { setFontSize(size); saveSetting("fontSize", size); }}
|
||||||
style={{ padding: "4px 10px", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: fontSize === size ? 700 : 400, background: fontSize === size ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: fontSize === size ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
|
style={{ padding: "4px 10px", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.fontSize === size ? 700 : 400, background: profile.fontSize === size ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.fontSize === size ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
|
||||||
{size}
|
{size}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
@ -5450,31 +5450,31 @@ export default function WeeklyView() {
|
|||||||
|
|
||||||
{/* Toggle switches */}
|
{/* Toggle switches */}
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
<span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{language === "de" ? "Irgendwann" : "Someday"}</span>
|
<span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Irgendwann" : "Someday"}</span>
|
||||||
<button onClick={() => { const v = !showSomeday; setShowSomeday(v); saveSetting("showSomeday", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
<button onClick={() => { const v = !profile.showSomeday; setShowSomeday(v); saveSetting("showSomeday", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
||||||
{effectiveShowSomeday ? <Eye size={16} /> : <EyeOff size={16} />}
|
{effectiveShowSomeday ? <Eye size={16} /> : <EyeOff size={16} />}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
<span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{language === "de" ? "Zeitplan" : "Schedule"}</span>
|
<span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Zeitplan" : "Schedule"}</span>
|
||||||
<button onClick={() => { const v = !showTimeGrid; setShowTimeGrid(v); saveSetting("showTimeGrid", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
<button onClick={() => { const v = !profile.showTimeGrid; setShowTimeGrid(v); saveSetting("showTimeGrid", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
||||||
{showTimeGrid ? <Eye size={16} /> : <EyeOff size={16} />}
|
{profile.showTimeGrid ? <Eye size={16} /> : <EyeOff size={16} />}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
<span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{language === "de" ? "Ganztägig" : "All-day"}</span>
|
<span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Ganztägig" : "All-day"}</span>
|
||||||
<button onClick={() => { const v = !showAllDay; setShowAllDay(v); saveSetting("showAllDayEvents", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
<button onClick={() => { const v = !profile.showAllDayEvents; setShowAllDay(v); saveSetting("showAllDayEvents", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
||||||
{effectiveShowAllDay ? <Eye size={16} /> : <EyeOff size={16} />}
|
{effectiveShowAllDay ? <Eye size={16} /> : <EyeOff size={16} />}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
<span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{language === "de" ? "Checkboxen" : "Checkboxes"}</span>
|
<span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Checkboxen" : "Checkboxes"}</span>
|
||||||
<button onClick={() => { const v = !profile.showTaskCheckboxes; setProfile({ ...profile, showTaskCheckboxes: v }); saveSetting("showTaskCheckboxes", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
<button onClick={() => { const v = !profile.showTaskCheckboxes; setProfile({ ...profile, showTaskCheckboxes: v }); saveSetting("showTaskCheckboxes", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
||||||
{effectiveShowTaskCheckboxes ? <Eye size={16} /> : <EyeOff size={16} />}
|
{effectiveShowTaskCheckboxes ? <Eye size={16} /> : <EyeOff size={16} />}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
<span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{language === "de" ? "Projekt-Icons" : "Project Icons"}</span>
|
<span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Projekt-Icons" : "Project Icons"}</span>
|
||||||
<button onClick={() => { const v = !profile.showProjectIcons; setProfile({ ...profile, showProjectIcons: v }); saveSetting("showProjectIcons", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
<button onClick={() => { const v = !profile.showProjectIcons; setProfile({ ...profile, showProjectIcons: v }); saveSetting("showProjectIcons", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>
|
||||||
{effectiveShowProjectIcons ? <Eye size={16} /> : <EyeOff size={16} />}
|
{effectiveShowProjectIcons ? <Eye size={16} /> : <EyeOff size={16} />}
|
||||||
</button>
|
</button>
|
||||||
@ -5482,30 +5482,30 @@ export default function WeeklyView() {
|
|||||||
|
|
||||||
{/* Start on */}
|
{/* Start on */}
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
||||||
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{language === "de" ? "Starten mit" : "Start on"}</span>
|
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Starten mit" : "Start on"}</span>
|
||||||
<div style={{ display: "flex", gap: "4px" }}>
|
<div style={{ display: "flex", gap: "4px" }}>
|
||||||
<button onClick={() => { setProfile({ ...profile, startDayOffset: 0 }); saveSetting("startDayOffset", 0); const d = new Date(); d.setHours(0, 0, 0, 0); setCurrentWeekStart(d); }}
|
<button onClick={() => { setProfile({ ...profile, startDayOffset: 0 }); saveSetting("startDayOffset", 0); const d = new Date(); d.setHours(0, 0, 0, 0); setCurrentWeekStart(d); }}
|
||||||
style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: (profile.startDayOffset || 0) === 0 ? 700 : 400, background: (profile.startDayOffset || 0) === 0 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.startDayOffset || 0) === 0 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
|
style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: (profile.startDayOffset || 0) === 0 ? 700 : 400, background: (profile.startDayOffset || 0) === 0 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.startDayOffset || 0) === 0 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
|
||||||
{language === "de" ? "Heute" : "Today"}
|
{profile.language === "de" ? "Heute" : "Today"}
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => { setProfile({ ...profile, startDayOffset: -1 }); saveSetting("startDayOffset", -1); const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() - 1); setCurrentWeekStart(d); }}
|
<button onClick={() => { setProfile({ ...profile, startDayOffset: -1 }); saveSetting("startDayOffset", -1); const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() - 1); setCurrentWeekStart(d); }}
|
||||||
style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.startDayOffset === -1 ? 700 : 400, background: profile.startDayOffset === -1 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.startDayOffset === -1 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
|
style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.startDayOffset === -1 ? 700 : 400, background: profile.startDayOffset === -1 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.startDayOffset === -1 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
|
||||||
{language === "de" ? "Gestern" : "Yesterday"}
|
{profile.language === "de" ? "Gestern" : "Yesterday"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Display mode */}
|
{/* Display mode */}
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
|
||||||
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{language === "de" ? "Anzeige" : "Display"}</span>
|
<span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Anzeige" : "Display"}</span>
|
||||||
<div style={{ display: "flex", gap: "4px" }}>
|
<div style={{ display: "flex", gap: "4px" }}>
|
||||||
<button onClick={() => setDarkMode(false)}
|
<button onClick={() => setDarkMode(false)}
|
||||||
style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "4px", fontWeight: !darkMode ? 700 : 400, background: !darkMode ? "#333" : (darkMode ? "#1f2937" : "#e5e7eb"), color: !darkMode ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
|
style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "4px", fontWeight: !darkMode ? 700 : 400, background: !darkMode ? "#333" : (darkMode ? "#1f2937" : "#e5e7eb"), color: !darkMode ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>
|
||||||
<Sun size={12} /> {language === "de" ? "Hell" : "Light"}
|
<Sun size={12} /> {profile.language === "de" ? "Hell" : "Light"}
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => setDarkMode(true)}
|
<button onClick={() => setDarkMode(true)}
|
||||||
style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "4px", fontWeight: darkMode ? 700 : 400, background: darkMode ? "#374151" : "#e5e7eb", color: darkMode ? "#fff" : "#6b7280" }}>
|
style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "4px", fontWeight: darkMode ? 700 : 400, background: darkMode ? "#374151" : "#e5e7eb", color: darkMode ? "#fff" : "#6b7280" }}>
|
||||||
<Moon size={12} /> {language === "de" ? "Dunkel" : "Dark"}
|
<Moon size={12} /> {profile.language === "de" ? "Dunkel" : "Dark"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -5529,7 +5529,7 @@ export default function WeeklyView() {
|
|||||||
style={{ display: "flex", alignItems: "center", gap: "6px", background: "none", border: "none", cursor: "pointer", fontSize: "0.75rem", color: darkMode ? "#6b7280" : "#9ca3af", padding: "4px 0" }}
|
style={{ display: "flex", alignItems: "center", gap: "6px", background: "none", border: "none", cursor: "pointer", fontSize: "0.75rem", color: darkMode ? "#6b7280" : "#9ca3af", padding: "4px 0" }}
|
||||||
>
|
>
|
||||||
<PanelLeftClose size={16} />
|
<PanelLeftClose size={16} />
|
||||||
{language === "de" ? "Ausblenden" : "Hide"}
|
{profile.language === "de" ? "Ausblenden" : "Hide"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -5539,7 +5539,7 @@ export default function WeeklyView() {
|
|||||||
{showProjectsSidebar && (
|
{showProjectsSidebar && (
|
||||||
<ProjectsSidebar
|
<ProjectsSidebar
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
language={language}
|
language={profile.language}
|
||||||
projects={projects}
|
projects={projects}
|
||||||
onProjectsChanged={fetchProjects}
|
onProjectsChanged={fetchProjects}
|
||||||
onClose={() => setShowProjectsSidebar(false)}
|
onClose={() => setShowProjectsSidebar(false)}
|
||||||
@ -5608,14 +5608,14 @@ export default function WeeklyView() {
|
|||||||
d.getFullYear() === today.getFullYear()
|
d.getFullYear() === today.getFullYear()
|
||||||
);
|
);
|
||||||
const refDate = isTodayInWeek ? today : getCWReferenceDate(getVisibleDays());
|
const refDate = isTodayInWeek ? today : getCWReferenceDate(getVisibleDays());
|
||||||
return refDate.toLocaleDateString(language, { day: '2-digit', month: '2-digit', year: 'numeric' });
|
return refDate.toLocaleDateString(profile.language, { day: '2-digit', month: '2-digit', year: 'numeric' });
|
||||||
})() :
|
})() :
|
||||||
profile.headerDisplay === "month_year" ?
|
profile.headerDisplay === "month_year" ?
|
||||||
getCWReferenceDate(getVisibleDays()).toLocaleDateString(language, { month: 'long', year: 'numeric' }) :
|
getCWReferenceDate(getVisibleDays()).toLocaleDateString(profile.language, { month: 'long', year: 'numeric' }) :
|
||||||
profile.headerDisplay === "custom" ?
|
profile.headerDisplay === "custom" ?
|
||||||
formatCustomHeader(profile.headerCustomFormat || "KW WW | YYYY", getVisibleDays(), language, t) :
|
formatCustomHeader(profile.headerCustomFormat || "KW WW | YYYY", getVisibleDays(), profile.language, t) :
|
||||||
profile.headerDisplay === "month" ?
|
profile.headerDisplay === "month" ?
|
||||||
getCWReferenceDate(getVisibleDays()).toLocaleDateString(language, { month: "long" }) :
|
getCWReferenceDate(getVisibleDays()).toLocaleDateString(profile.language, { month: "long" }) :
|
||||||
`KW ${getWeekNumber(getCWReferenceDate(getVisibleDays())).toString().padStart(2, "0")} | ${getCWReferenceDate(getVisibleDays()).getFullYear()}`
|
`KW ${getWeekNumber(getCWReferenceDate(getVisibleDays())).toString().padStart(2, "0")} | ${getCWReferenceDate(getVisibleDays()).getFullYear()}`
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
@ -5638,7 +5638,7 @@ export default function WeeklyView() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => setShowQuickSettings(true)}
|
onClick={() => setShowQuickSettings(true)}
|
||||||
className="p-1.5 rounded text-gray-400 hover:text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:hover:bg-gray-700 transition-colors"
|
className="p-1.5 rounded text-gray-400 hover:text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:hover:bg-gray-700 transition-colors"
|
||||||
title={language === "de" ? "Schnelleinstellungen" : "Quick Settings"}
|
title={profile.language === "de" ? "Schnelleinstellungen" : "Quick Settings"}
|
||||||
>
|
>
|
||||||
<PanelLeftOpen size={16} />
|
<PanelLeftOpen size={16} />
|
||||||
</button>
|
</button>
|
||||||
@ -5647,28 +5647,28 @@ export default function WeeklyView() {
|
|||||||
<div className="flex items-center gap-0.5 bg-gray-100 dark:bg-gray-800 rounded p-0.5" title={t.viewStyle}>
|
<div className="flex items-center gap-0.5 bg-gray-100 dark:bg-gray-800 rounded p-0.5" title={t.viewStyle}>
|
||||||
<button
|
<button
|
||||||
onClick={() => { setViewStyle("simple"); setShowTimeGrid(true); saveSetting("viewStyle", "simple"); saveSetting("showTimeGrid", true); }}
|
onClick={() => { setViewStyle("simple"); setShowTimeGrid(true); saveSetting("viewStyle", "simple"); saveSetting("showTimeGrid", true); }}
|
||||||
className={`p-1.5 rounded transition-colors ${viewStyle === "simple" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
className={`p-1.5 rounded transition-colors ${profile.viewStyle ==="simple" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||||
title={t.simpleView}
|
title={t.simpleView}
|
||||||
>
|
>
|
||||||
<Calendar size={16} />
|
<Calendar size={16} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => { setViewStyle("calendar"); setShowTimeGrid(true); saveSetting("viewStyle", "calendar"); saveSetting("showTimeGrid", true); }}
|
onClick={() => { setViewStyle("calendar"); setShowTimeGrid(true); saveSetting("viewStyle", "calendar"); saveSetting("showTimeGrid", true); }}
|
||||||
className={`p-1.5 rounded transition-colors ${viewStyle === "calendar" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
className={`p-1.5 rounded transition-colors ${profile.viewStyle ==="calendar" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||||
title={t.calendarView}
|
title={t.calendarView}
|
||||||
>
|
>
|
||||||
<CalendarDays size={16} />
|
<CalendarDays size={16} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => { setViewStyle("list"); setShowTimeGrid(false); saveSetting("viewStyle", "list"); saveSetting("showTimeGrid", false); }}
|
onClick={() => { setViewStyle("list"); setShowTimeGrid(false); saveSetting("viewStyle", "list"); saveSetting("showTimeGrid", false); }}
|
||||||
className={`p-1.5 rounded transition-colors ${viewStyle === "list" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
className={`p-1.5 rounded transition-colors ${profile.viewStyle ==="list" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||||
title={t.listView}
|
title={t.listView}
|
||||||
>
|
>
|
||||||
<ListTodo size={16} />
|
<ListTodo size={16} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => { setViewStyle("kanban"); saveSetting("viewStyle", "kanban"); }}
|
onClick={() => { setViewStyle("kanban"); saveSetting("viewStyle", "kanban"); }}
|
||||||
className={`p-1.5 rounded transition-colors ${viewStyle === "kanban" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
className={`p-1.5 rounded transition-colors ${profile.viewStyle ==="kanban" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||||
title={t.kanbanView}
|
title={t.kanbanView}
|
||||||
>
|
>
|
||||||
<Kanban size={16} />
|
<Kanban size={16} />
|
||||||
@ -5697,7 +5697,7 @@ export default function WeeklyView() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Slot Duration — desktop only (available in sidebar on tablet) */}
|
{/* Slot Duration — desktop only (available in sidebar on tablet) */}
|
||||||
{showTimeGrid && (
|
{profile.showTimeGrid && (
|
||||||
<div
|
<div
|
||||||
className="header-desktop-only items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1"
|
className="header-desktop-only items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1"
|
||||||
title="Slot Duration"
|
title="Slot Duration"
|
||||||
@ -5739,7 +5739,7 @@ export default function WeeklyView() {
|
|||||||
setShowDatePicker(false);
|
setShowDatePicker(false);
|
||||||
}}
|
}}
|
||||||
onClose={() => setShowDatePicker(false)}
|
onClose={() => setShowDatePicker(false)}
|
||||||
language={language}
|
language={profile.language}
|
||||||
anchorRef={datePickerBtnRef}
|
anchorRef={datePickerBtnRef}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -5754,9 +5754,9 @@ export default function WeeklyView() {
|
|||||||
profile.headerDisplay === "none"
|
profile.headerDisplay === "none"
|
||||||
? ""
|
? ""
|
||||||
: profile.headerDisplay === "month"
|
: profile.headerDisplay === "month"
|
||||||
? getCWReferenceDate(getVisibleDays()).toLocaleDateString(language, { month: "long" })
|
? getCWReferenceDate(getVisibleDays()).toLocaleDateString(profile.language, { month: "long" })
|
||||||
: profile.headerDisplay === "month_year"
|
: profile.headerDisplay === "month_year"
|
||||||
? getCWReferenceDate(getVisibleDays()).toLocaleDateString(language, { month: "long", year: "numeric" })
|
? getCWReferenceDate(getVisibleDays()).toLocaleDateString(profile.language, { month: "long", year: "numeric" })
|
||||||
: profile.headerDisplay === "date"
|
: profile.headerDisplay === "date"
|
||||||
? (() => {
|
? (() => {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
@ -5766,10 +5766,10 @@ export default function WeeklyView() {
|
|||||||
d.getFullYear() === today.getFullYear()
|
d.getFullYear() === today.getFullYear()
|
||||||
);
|
);
|
||||||
const refDate = isTodayInWeek ? today : getCWReferenceDate(getVisibleDays());
|
const refDate = isTodayInWeek ? today : getCWReferenceDate(getVisibleDays());
|
||||||
return refDate.toLocaleDateString(language, { day: '2-digit', month: '2-digit', year: 'numeric' });
|
return refDate.toLocaleDateString(profile.language, { day: '2-digit', month: '2-digit', year: 'numeric' });
|
||||||
})()
|
})()
|
||||||
: profile.headerDisplay === "custom"
|
: profile.headerDisplay === "custom"
|
||||||
? formatCustomHeader(profile.headerCustomFormat || "KW WW | YYYY", getVisibleDays(), language, t)
|
? formatCustomHeader(profile.headerCustomFormat || "KW WW | YYYY", getVisibleDays(), profile.language, t)
|
||||||
: `KW ${getWeekNumber(getCWReferenceDate(getVisibleDays())).toString().padStart(2, "0")}`
|
: `KW ${getWeekNumber(getCWReferenceDate(getVisibleDays())).toString().padStart(2, "0")}`
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
@ -5833,9 +5833,9 @@ export default function WeeklyView() {
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<span
|
<span
|
||||||
onClick={() => !showNextTask && setIsEditingGoal(true)}
|
onClick={() => !profile.showNextTask && setIsEditingGoal(true)}
|
||||||
className={`cursor-pointer font-medium italic transition-colors ${showNextTask ? "cursor-default text-gray-600 dark:text-white hover:text-black dark:hover:text-gray-100" : "text-gray-600 dark:text-yellow-400 hover:text-black dark:hover:text-yellow-300"}`}
|
className={`cursor-pointer font-medium italic transition-colors ${profile.showNextTask ? "cursor-default text-gray-600 dark:text-white hover:text-black dark:hover:text-gray-100" : "text-gray-600 dark:text-yellow-400 hover:text-black dark:hover:text-yellow-300"}`}
|
||||||
title={showNextTask ? "Next task" : "Edit goal"}
|
title={profile.showNextTask ? "Next task" : "Edit goal"}
|
||||||
style={{
|
style={{
|
||||||
fontFamily: profile.goalFontFamily
|
fontFamily: profile.goalFontFamily
|
||||||
? `"${profile.goalFontFamily}", sans-serif`
|
? `"${profile.goalFontFamily}", sans-serif`
|
||||||
@ -5852,7 +5852,7 @@ export default function WeeklyView() {
|
|||||||
WebkitBoxOrient: "vertical" as const,
|
WebkitBoxOrient: "vertical" as const,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{showNextTask
|
{profile.showNextTask
|
||||||
? (() => {
|
? (() => {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
today.setHours(0, 0, 0, 0);
|
today.setHours(0, 0, 0, 0);
|
||||||
@ -5900,8 +5900,8 @@ export default function WeeklyView() {
|
|||||||
<button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); }} className="weekly-btn-icon" title="Add Calendar Event">
|
<button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); }} className="weekly-btn-icon" title="Add Calendar Event">
|
||||||
<Plus size={17} className="text-gray-600 hover:text-black transition-colors" />
|
<Plus size={17} className="text-gray-600 hover:text-black transition-colors" />
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => { const newVal = !showNextTask; setShowNextTask(newVal); saveSetting("showNextTask", newVal); }} className={`weekly-btn-icon ${showNextTask ? "active" : ""}`} title={showNextTask ? "Showing Next Task" : "Showing Goal"}>
|
<button onClick={() => { const newVal = !profile.showNextTask; setShowNextTask(newVal); saveSetting("showNextTask", newVal); }} className={`weekly-btn-icon ${profile.showNextTask ? "active" : ""}`} title={profile.showNextTask ? "Showing Next Task" : "Showing Goal"}>
|
||||||
{showNextTask ? <Play size={17} className="text-teal-600" /> : <Target size={17} className="text-gray-400" />}
|
{profile.showNextTask ? <Play size={17} className="text-teal-600" /> : <Target size={17} className="text-gray-400" />}
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => setShowFocusMode(true)} className="weekly-btn-icon" title="Enter Focus Mode">
|
<button onClick={() => setShowFocusMode(true)} className="weekly-btn-icon" title="Enter Focus Mode">
|
||||||
<Zap size={17} className="text-gray-600 hover:text-yellow-500 transition-colors" />
|
<Zap size={17} className="text-gray-600 hover:text-yellow-500 transition-colors" />
|
||||||
@ -5935,15 +5935,15 @@ export default function WeeklyView() {
|
|||||||
<div className="header-overflow-menu">
|
<div className="header-overflow-menu">
|
||||||
<button onClick={() => { handleUndo(); setShowHeaderMore(false); }} disabled={undoCount === 0}><Undo2 size={16} /> <span>Undo</span></button>
|
<button onClick={() => { handleUndo(); setShowHeaderMore(false); }} disabled={undoCount === 0}><Undo2 size={16} /> <span>Undo</span></button>
|
||||||
<button onClick={() => { handleRedo(); setShowHeaderMore(false); }} disabled={redoCount === 0}><Redo2 size={16} /> <span>Redo</span></button>
|
<button onClick={() => { handleRedo(); setShowHeaderMore(false); }} disabled={redoCount === 0}><Redo2 size={16} /> <span>Redo</span></button>
|
||||||
<button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); setShowHeaderMore(false); }}><Plus size={16} /> <span>{language === "de" ? "Termin erstellen" : "Add Event"}</span></button>
|
<button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); setShowHeaderMore(false); }}><Plus size={16} /> <span>{profile.language === "de" ? "Termin erstellen" : "Add Event"}</span></button>
|
||||||
<button onClick={() => { setIsRecurringTasksOpen(true); setShowHeaderMore(false); }}><Repeat size={16} /> <span>{language === "de" ? "Wiederkehrend" : "Recurring"}</span></button>
|
<button onClick={() => { setIsRecurringTasksOpen(true); setShowHeaderMore(false); }}><Repeat size={16} /> <span>{profile.language === "de" ? "Wiederkehrend" : "Recurring"}</span></button>
|
||||||
<button onClick={() => { const nv = !showNextTask; setShowNextTask(nv); saveSetting("showNextTask", nv); setShowHeaderMore(false); }}>{showNextTask ? <Play size={16} /> : <Target size={16} />} <span>{showNextTask ? "Next Task" : "Goal"}</span></button>
|
<button onClick={() => { const nv = !showNextTask; setShowNextTask(nv); saveSetting("showNextTask", nv); setShowHeaderMore(false); }}>{showNextTask ? <Play size={16} /> : <Target size={16} />} <span>{showNextTask ? "Next Task" : "Goal"}</span></button>
|
||||||
<button onClick={() => { setShowFocusMode(true); setShowHeaderMore(false); }}><Zap size={16} /> <span>{language === "de" ? "Fokus" : "Focus"}</span></button>
|
<button onClick={() => { setShowFocusMode(true); setShowHeaderMore(false); }}><Zap size={16} /> <span>{profile.language === "de" ? "Fokus" : "Focus"}</span></button>
|
||||||
<button onClick={() => { setDarkMode(!darkMode); setShowHeaderMore(false); }}>{darkMode ? <Sun size={16} /> : <Moon size={16} />} <span>{darkMode ? "Light" : "Dark"}</span></button>
|
<button onClick={() => { setDarkMode(!darkMode); setShowHeaderMore(false); }}>{darkMode ? <Sun size={16} /> : <Moon size={16} />} <span>{darkMode ? "Light" : "Dark"}</span></button>
|
||||||
<button onClick={() => { setShowProjectsSidebar(true); setShowHeaderMore(false); }}><FolderPlus size={16} /> <span>{language === "de" ? "Neues Projekt" : "New Project"}</span></button>
|
<button onClick={() => { setShowProjectsSidebar(true); setShowHeaderMore(false); }}><FolderPlus size={16} /> <span>{profile.language === "de" ? "Neues Projekt" : "New Project"}</span></button>
|
||||||
<div style={{ borderTop: "1px solid var(--border-color, #e5e7eb)", margin: "2px 0" }} />
|
<div style={{ borderTop: "1px solid var(--border-color, #e5e7eb)", margin: "2px 0" }} />
|
||||||
<div style={{ padding: "6px 12px", display: "flex", alignItems: "center", gap: "6px", flexWrap: "wrap" }}>
|
<div style={{ padding: "6px 12px", display: "flex", alignItems: "center", gap: "6px", flexWrap: "wrap" }}>
|
||||||
<span style={{ fontSize: "12px", color: "#888", marginRight: "4px" }}>{language === "de" ? "Tage" : "Days"}:</span>
|
<span style={{ fontSize: "12px", color: "#888", marginRight: "4px" }}>{profile.language === "de" ? "Tage" : "Days"}:</span>
|
||||||
{[1, 2, 3, 5, 7].map((num) => (
|
{[1, 2, 3, 5, 7].map((num) => (
|
||||||
<button
|
<button
|
||||||
key={num}
|
key={num}
|
||||||
@ -5954,9 +5954,9 @@ export default function WeeklyView() {
|
|||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{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" }}>{language === "de" ? "Slot" : "Slot"}:</span>
|
<span style={{ fontSize: "12px", color: "#888", marginRight: "4px" }}>{profile.language === "de" ? "Slot" : "Slot"}:</span>
|
||||||
{[15, 30, 60].map((duration) => (
|
{[15, 30, 60].map((duration) => (
|
||||||
<button
|
<button
|
||||||
key={duration}
|
key={duration}
|
||||||
@ -5988,10 +5988,10 @@ export default function WeeklyView() {
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* All-Day Events Section (above position) — hidden in kanban */}
|
{/* All-Day Events Section (above position) — hidden in kanban */}
|
||||||
{viewStyle !== "kanban" && effectiveAllDayPosition === "above" && allDaySection}
|
{profile.viewStyle !== "kanban" && effectiveAllDayPosition === "above" && allDaySection}
|
||||||
|
|
||||||
{/* Kanban Board View */}
|
{/* Kanban Board View */}
|
||||||
{viewStyle === "kanban" && (() => {
|
{profile.viewStyle ==="kanban" && (() => {
|
||||||
// Combine all tasks (weekly + someday) for kanban
|
// Combine all tasks (weekly + someday) for kanban
|
||||||
const allSomedayTasks = somedayLists.flatMap(l => l.tasks);
|
const allSomedayTasks = somedayLists.flatMap(l => l.tasks);
|
||||||
const allKanbanTasks = [...tasks, ...allSomedayTasks];
|
const allKanbanTasks = [...tasks, ...allSomedayTasks];
|
||||||
@ -6007,7 +6007,7 @@ export default function WeeklyView() {
|
|||||||
if (!weeks.has(key)) {
|
if (!weeks.has(key)) {
|
||||||
const weekEnd = new Date(weekStart);
|
const weekEnd = new Date(weekStart);
|
||||||
weekEnd.setDate(weekEnd.getDate() + 6);
|
weekEnd.setDate(weekEnd.getDate() + 6);
|
||||||
weeks.set(key, `${weekStart.toLocaleDateString(language, { month: "short", day: "numeric" })} - ${weekEnd.toLocaleDateString(language, { month: "short", day: "numeric" })}`);
|
weeks.set(key, `${weekStart.toLocaleDateString(profile.language, { month: "short", day: "numeric" })} - ${weekEnd.toLocaleDateString(profile.language, { month: "short", day: "numeric" })}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -6125,12 +6125,12 @@ export default function WeeklyView() {
|
|||||||
)}
|
)}
|
||||||
{task.markdownContent && (
|
{task.markdownContent && (
|
||||||
<div className="kanban-card-has-notes" style={{ fontSize: "0.65rem", color: "#9ca3af", marginTop: "2px", display: "flex", alignItems: "center", gap: "3px" }}>
|
<div className="kanban-card-has-notes" style={{ fontSize: "0.65rem", color: "#9ca3af", marginTop: "2px", display: "flex", alignItems: "center", gap: "3px" }}>
|
||||||
<FileText size={10} /> {language === "de" ? "Notizen" : "Notes"}
|
<FileText size={10} /> {profile.language === "de" ? "Notizen" : "Notes"}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{(task.scheduledDate || task.startTime) && (
|
{(task.scheduledDate || task.startTime) && (
|
||||||
<div className="kanban-card-date">
|
<div className="kanban-card-date">
|
||||||
{task.scheduledDate && new Date(task.scheduledDate).toLocaleDateString(language, { weekday: "short", month: "short", day: "numeric" })}
|
{task.scheduledDate && new Date(task.scheduledDate).toLocaleDateString(profile.language, { weekday: "short", month: "short", day: "numeric" })}
|
||||||
{task.startTime && <span className="kanban-card-time"> {task.startTime}</span>}
|
{task.startTime && <span className="kanban-card-time"> {task.startTime}</span>}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -6213,7 +6213,7 @@ export default function WeeklyView() {
|
|||||||
{projects.length > 0 && (
|
{projects.length > 0 && (
|
||||||
<div className="kanban-project-chip" style={{ background: darkMode ? "#1f2937" : "#f3f4f6", color: "#9ca3af" }} {...kanbanProjectDrop(null)}>
|
<div className="kanban-project-chip" style={{ background: darkMode ? "#1f2937" : "#f3f4f6", color: "#9ca3af" }} {...kanbanProjectDrop(null)}>
|
||||||
<X size={12} />
|
<X size={12} />
|
||||||
<span>{language === "de" ? "Kein Projekt" : "No project"}</span>
|
<span>{profile.language === "de" ? "Kein Projekt" : "No project"}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{/* Spacer pushes filters to right */}
|
{/* Spacer pushes filters to right */}
|
||||||
@ -6286,7 +6286,7 @@ export default function WeeklyView() {
|
|||||||
const updated = kanbanStages.map((s, i) => i === idx ? { ...s, color: e.target.value } : s);
|
const updated = kanbanStages.map((s, i) => i === idx ? { ...s, color: e.target.value } : s);
|
||||||
saveKanbanStages(updated);
|
saveKanbanStages(updated);
|
||||||
}}
|
}}
|
||||||
title={language === "de" ? "Farbe ändern" : "Change color"}
|
title={profile.language === "de" ? "Farbe ändern" : "Change color"}
|
||||||
style={{ width: "14px", height: "14px", border: "none", cursor: "pointer", padding: 0, borderRadius: "50%", flexShrink: 0 }}
|
style={{ width: "14px", height: "14px", border: "none", cursor: "pointer", padding: 0, borderRadius: "50%", flexShrink: 0 }}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
@ -6319,12 +6319,12 @@ export default function WeeklyView() {
|
|||||||
}}
|
}}
|
||||||
style={{ padding: "2px 6px", fontSize: "0.65rem", borderRadius: "4px", border: "none", cursor: "pointer", background: "#ef4444", color: "#fff", fontWeight: 600, whiteSpace: "nowrap" }}
|
style={{ padding: "2px 6px", fontSize: "0.65rem", borderRadius: "4px", border: "none", cursor: "pointer", background: "#ef4444", color: "#fff", fontWeight: 600, whiteSpace: "nowrap" }}
|
||||||
>
|
>
|
||||||
{language === "de" ? "Ja, löschen" : "Confirm"}
|
{profile.language === "de" ? "Ja, löschen" : "Confirm"}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setKanbanDeleteStageId(null)}
|
onClick={() => setKanbanDeleteStageId(null)}
|
||||||
style={{ padding: "2px", background: "none", border: "none", cursor: "pointer", color: "#9ca3af", display: "flex" }}
|
style={{ padding: "2px", background: "none", border: "none", cursor: "pointer", color: "#9ca3af", display: "flex" }}
|
||||||
title={language === "de" ? "Abbrechen" : "Cancel"}
|
title={profile.language === "de" ? "Abbrechen" : "Cancel"}
|
||||||
>
|
>
|
||||||
<X size={12} />
|
<X size={12} />
|
||||||
</button>
|
</button>
|
||||||
@ -6333,7 +6333,7 @@ export default function WeeklyView() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => setKanbanDeleteStageId(stage.id)}
|
onClick={() => setKanbanDeleteStageId(stage.id)}
|
||||||
className="kanban-column-delete"
|
className="kanban-column-delete"
|
||||||
title={language === "de" ? "Phase löschen" : "Delete stage"}
|
title={profile.language === "de" ? "Phase löschen" : "Delete stage"}
|
||||||
>
|
>
|
||||||
<Trash2 size={12} />
|
<Trash2 size={12} />
|
||||||
</button>
|
</button>
|
||||||
@ -6346,7 +6346,7 @@ export default function WeeklyView() {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
autoFocus
|
autoFocus
|
||||||
placeholder={language === "de" ? "Aufgabe eingeben..." : "Enter task..."}
|
placeholder={profile.language === "de" ? "Aufgabe eingeben..." : "Enter task..."}
|
||||||
value={kanbanNewTaskTitle}
|
value={kanbanNewTaskTitle}
|
||||||
onChange={(e) => setKanbanNewTaskTitle(e.target.value)}
|
onChange={(e) => setKanbanNewTaskTitle(e.target.value)}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
@ -6401,7 +6401,7 @@ export default function WeeklyView() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Plus size={12} />
|
<Plus size={12} />
|
||||||
{language === "de" ? "Aufgabe" : "Add task"}
|
{profile.language === "de" ? "Aufgabe" : "Add task"}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -6438,7 +6438,7 @@ export default function WeeklyView() {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
autoFocus
|
autoFocus
|
||||||
placeholder={language === "de" ? "Aufgabe eingeben..." : "Enter task..."}
|
placeholder={profile.language === "de" ? "Aufgabe eingeben..." : "Enter task..."}
|
||||||
value={kanbanNewTaskTitle}
|
value={kanbanNewTaskTitle}
|
||||||
onChange={(e) => setKanbanNewTaskTitle(e.target.value)}
|
onChange={(e) => setKanbanNewTaskTitle(e.target.value)}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
@ -6493,7 +6493,7 @@ export default function WeeklyView() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Plus size={12} />
|
<Plus size={12} />
|
||||||
{language === "de" ? "Aufgabe" : "Add task"}
|
{profile.language === "de" ? "Aufgabe" : "Add task"}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -6506,15 +6506,15 @@ export default function WeeklyView() {
|
|||||||
})()}
|
})()}
|
||||||
|
|
||||||
{/* Main Grid with Time Column */}
|
{/* Main Grid with Time Column */}
|
||||||
{viewStyle !== "kanban" && <div style={{ position: "relative", flex: 1, minHeight: 0, overflow: 'hidden' }}>
|
{profile.viewStyle !== "kanban" && <div style={{ position: "relative", flex: 1, minHeight: 0, overflow: 'hidden' }}>
|
||||||
<div className="time-grid-wrapper" ref={gridRef as React.Ref<HTMLDivElement>} onScroll={handleGridScroll} style={showTimeGrid ? {
|
<div className="time-grid-wrapper" ref={gridRef as React.Ref<HTMLDivElement>} onScroll={handleGridScroll} style={profile.showTimeGrid ? {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
overflowX: 'hidden',
|
overflowX: 'hidden',
|
||||||
WebkitOverflowScrolling: 'touch' as any,
|
WebkitOverflowScrolling: 'touch' as any,
|
||||||
} : undefined}>
|
} : undefined}>
|
||||||
{/* Time Column */}
|
{/* Time Column */}
|
||||||
{showTimeGrid && (
|
{profile.showTimeGrid && (
|
||||||
<div
|
<div
|
||||||
className="time-column"
|
className="time-column"
|
||||||
style={{
|
style={{
|
||||||
@ -6611,14 +6611,14 @@ export default function WeeklyView() {
|
|||||||
title={isHourStart ? `Jump to ${hour}:00` : undefined}
|
title={isHourStart ? `Jump to ${hour}:00` : undefined}
|
||||||
>
|
>
|
||||||
{(isHourStart || effectiveShowSubHourSlots) && (
|
{(isHourStart || effectiveShowSubHourSlots) && (
|
||||||
<span>{formatHour(hour, parseInt(minutes), (isHourStart ? effectiveHourLabelFormat : 'full') as "short" | "full", timeFormat)}</span>
|
<span>{formatHour(hour, parseInt(minutes), (isHourStart ? effectiveHourLabelFormat : 'full') as "short" | "full", profile.timeFormat)}</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{/* End-of-day 24:00 label */}
|
{/* End-of-day 24:00 label */}
|
||||||
<div className="time-slot-label hour-start" style={{ height: '0px', lineHeight: 0 }}>
|
<div className="time-slot-label hour-start" style={{ height: '0px', lineHeight: 0 }}>
|
||||||
<span>{timeFormat === '24h' ? '24' : '12 AM'}</span>
|
<span>{profile.timeFormat === '24h' ? '24' : '12 AM'}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -6629,7 +6629,7 @@ export default function WeeklyView() {
|
|||||||
className={`weekly-days-grid cols-${viewDays}`}
|
className={`weekly-days-grid cols-${viewDays}`}
|
||||||
data-slide-direction={slideDirection}
|
data-slide-direction={slideDirection}
|
||||||
data-nav-type={viewDays > 1 ? "week" : "day"}
|
data-nav-type={viewDays > 1 ? "week" : "day"}
|
||||||
style={showTimeGrid ? {
|
style={profile.showTimeGrid ? {
|
||||||
height: `${24 * (60 / effectiveCellDuration) * getSlotHeight(effectiveCellDuration) + getHeaderHeight(effectiveCellDuration)}px`,
|
height: `${24 * (60 / effectiveCellDuration) * getSlotHeight(effectiveCellDuration) + getHeaderHeight(effectiveCellDuration)}px`,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
alignSelf: "flex-start",
|
alignSelf: "flex-start",
|
||||||
@ -6693,21 +6693,21 @@ export default function WeeklyView() {
|
|||||||
<>
|
<>
|
||||||
{activeDateLayout === "left" && (
|
{activeDateLayout === "left" && (
|
||||||
<span className="weekly-day-date" style={dateStyle}>
|
<span className="weekly-day-date" style={dateStyle}>
|
||||||
{formatDateHeader(date, language)}
|
{formatDateHeader(date, profile.language)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<h3
|
<h3
|
||||||
className={`weekly-day-name ${isSameDay(date, new Date()) ? "is-today" : ""}`}
|
className={`weekly-day-name ${isSameDay(date, new Date()) ? "is-today" : ""}`}
|
||||||
style={{ marginBottom: 0, flexShrink: 0 }}
|
style={{ marginBottom: 0, flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
{getDayName(date, language, weekdayFormat, customWeekdayNames, weekStartDay, weekdayCase)}
|
{getDayName(date, profile.language, profile.weekdayFormat, profile.customWeekdayNames, profile.weekStartDay, profile.weekdayCase)}
|
||||||
</h3>
|
</h3>
|
||||||
{(activeDateLayout === "right" ||
|
{(activeDateLayout === "right" ||
|
||||||
activeDateLayout === "above" ||
|
activeDateLayout === "above" ||
|
||||||
activeDateLayout === "below" ||
|
activeDateLayout === "below" ||
|
||||||
activeDateLayout === undefined) && (
|
activeDateLayout === undefined) && (
|
||||||
<span className="weekly-day-date" style={dateStyle}>
|
<span className="weekly-day-date" style={dateStyle}>
|
||||||
{formatDateHeader(date, language)}
|
{formatDateHeader(date, profile.language)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
@ -6717,14 +6717,14 @@ export default function WeeklyView() {
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Time Grid or Simple List */}
|
{/* Time Grid or Simple List */}
|
||||||
{showTimeGrid ? (
|
{profile.showTimeGrid ? (
|
||||||
<div
|
<div
|
||||||
className="time-slots-container"
|
className="time-slots-container"
|
||||||
onDragLeave={handleDragLeave}
|
onDragLeave={handleDragLeave}
|
||||||
style={{ position: "relative" }}
|
style={{ position: "relative" }}
|
||||||
>
|
>
|
||||||
{/* Calendar Fetching Indicator */}
|
{/* Calendar Fetching Indicator */}
|
||||||
{showTimeGrid && colIndex === 0 && isFetchingCalendar && (
|
{profile.showTimeGrid && colIndex === 0 && isFetchingCalendar && (
|
||||||
<div className="absolute top-2 left-2 z-[60] flex items-center gap-2 bg-white/90 dark:bg-zinc-800/90 px-3 py-1.5 rounded-full shadow-sm border border-zinc-200 dark:border-zinc-700 text-xs text-zinc-600 dark:text-zinc-300 pointer-events-none">
|
<div className="absolute top-2 left-2 z-[60] flex items-center gap-2 bg-white/90 dark:bg-zinc-800/90 px-3 py-1.5 rounded-full shadow-sm border border-zinc-200 dark:border-zinc-700 text-xs text-zinc-600 dark:text-zinc-300 pointer-events-none">
|
||||||
<div className="w-3 h-3 border-2 border-zinc-400 border-t-transparent rounded-full animate-spin"></div>
|
<div className="w-3 h-3 border-2 border-zinc-400 border-t-transparent rounded-full animate-spin"></div>
|
||||||
Syncing Calendar...
|
Syncing Calendar...
|
||||||
@ -7319,7 +7319,7 @@ export default function WeeklyView() {
|
|||||||
</div>}
|
</div>}
|
||||||
|
|
||||||
{/* All-Day Events Section (below position) — hidden in kanban */}
|
{/* All-Day Events Section (below position) — hidden in kanban */}
|
||||||
{viewStyle !== "kanban" && effectiveAllDayPosition === "below" && allDaySection}
|
{profile.viewStyle !== "kanban" && effectiveAllDayPosition === "below" && allDaySection}
|
||||||
|
|
||||||
{/* Someday Section */}
|
{/* Someday Section */}
|
||||||
{effectiveShowSomeday && (<>
|
{effectiveShowSomeday && (<>
|
||||||
@ -8383,8 +8383,8 @@ export default function WeeklyView() {
|
|||||||
initialStartTime={calendarEventModal.initialStartTime}
|
initialStartTime={calendarEventModal.initialStartTime}
|
||||||
initialEndTime={calendarEventModal.initialEndTime}
|
initialEndTime={calendarEventModal.initialEndTime}
|
||||||
connections={connections}
|
connections={connections}
|
||||||
weekStartDay={weekStartDay}
|
weekStartDay={profile.weekStartDay ?? 1}
|
||||||
language={language}
|
language={profile.language}
|
||||||
onClose={() =>
|
onClose={() =>
|
||||||
setCalendarEventModal({ ...calendarEventModal, isOpen: false })
|
setCalendarEventModal({ ...calendarEventModal, isOpen: false })
|
||||||
}
|
}
|
||||||
@ -8411,13 +8411,13 @@ export default function WeeklyView() {
|
|||||||
padding: '16px 20px 12px', fontWeight: 700, fontSize: '0.95rem',
|
padding: '16px 20px 12px', fontWeight: 700, fontSize: '0.95rem',
|
||||||
borderBottom: '2px solid #3b82f6',
|
borderBottom: '2px solid #3b82f6',
|
||||||
}}>
|
}}>
|
||||||
{language === 'de' ? 'Wiederkehrendes Ereignis bearbeiten' : 'Edit recurring event'}
|
{profile.language === 'de' ? 'Wiederkehrendes Ereignis bearbeiten' : 'Edit recurring event'}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ padding: '12px 20px' }}>
|
<div style={{ padding: '12px 20px' }}>
|
||||||
{([
|
{([
|
||||||
{ value: 'this' as const, title: language === 'de' ? 'Nur dieses Ereignis' : 'This event', desc: language === 'de' ? 'Alle anderen Ereignisse der Serie bleiben unverändert.' : 'All other events in the series stay the same.' },
|
{ value: 'this' as const, title: profile.language === 'de' ? 'Nur dieses Ereignis' : 'This event', desc: profile.language === 'de' ? 'Alle anderen Ereignisse der Serie bleiben unverändert.' : 'All other events in the series stay the same.' },
|
||||||
{ value: 'future' as const, title: language === 'de' ? 'Dieses und folgende Ereignisse' : 'This and following events', desc: language === 'de' ? 'Dieses und alle zukünftigen Ereignisse der Serie werden geändert.' : 'This and all future events in the series will be changed.' },
|
{ value: 'future' as const, title: profile.language === 'de' ? 'Dieses und folgende Ereignisse' : 'This and following events', desc: profile.language === 'de' ? 'Dieses und alle zukünftigen Ereignisse der Serie werden geändert.' : 'This and all future events in the series will be changed.' },
|
||||||
{ value: 'all' as const, title: language === 'de' ? 'Alle Ereignisse' : 'All events', desc: language === 'de' ? 'Alle Ereignisse der Serie werden geändert.' : 'All events in the series will be changed.' },
|
{ value: 'all' as const, title: profile.language === 'de' ? 'Alle Ereignisse' : 'All events', desc: profile.language === 'de' ? 'Alle Ereignisse der Serie werden geändert.' : 'All events in the series will be changed.' },
|
||||||
]).map(opt => (
|
]).map(opt => (
|
||||||
<label key={opt.value} style={{
|
<label key={opt.value} style={{
|
||||||
display: 'flex', gap: 12, padding: '10px 4px', cursor: 'pointer',
|
display: 'flex', gap: 12, padding: '10px 4px', cursor: 'pointer',
|
||||||
@ -8444,12 +8444,12 @@ export default function WeeklyView() {
|
|||||||
padding: '8px 16px', fontSize: '0.85rem', fontWeight: 600,
|
padding: '8px 16px', fontSize: '0.85rem', fontWeight: 600,
|
||||||
background: 'none', border: 'none', cursor: 'pointer',
|
background: 'none', border: 'none', cursor: 'pointer',
|
||||||
color: darkMode ? '#aaa' : '#666',
|
color: darkMode ? '#aaa' : '#666',
|
||||||
}}>{language === 'de' ? 'Abbrechen' : 'Cancel'}</button>
|
}}>{profile.language === 'de' ? 'Abbrechen' : 'Cancel'}</button>
|
||||||
<button onClick={() => handleRecurringDragConfirm(recurringDragEditMode)} style={{
|
<button onClick={() => handleRecurringDragConfirm(recurringDragEditMode)} style={{
|
||||||
padding: '8px 20px', fontSize: '0.85rem', fontWeight: 600,
|
padding: '8px 20px', fontSize: '0.85rem', fontWeight: 600,
|
||||||
background: '#3b82f6', color: 'white', border: 'none',
|
background: '#3b82f6', color: 'white', border: 'none',
|
||||||
borderRadius: 8, cursor: 'pointer',
|
borderRadius: 8, cursor: 'pointer',
|
||||||
}}>{language === 'de' ? 'Speichern' : 'Save'}</button>
|
}}>{profile.language === 'de' ? 'Speichern' : 'Save'}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -8485,7 +8485,7 @@ export default function WeeklyView() {
|
|||||||
t.dayOfWeek === now.getDay() &&
|
t.dayOfWeek === now.getDay() &&
|
||||||
isSameDay(
|
isSameDay(
|
||||||
currentWeekStart,
|
currentWeekStart,
|
||||||
getStartOfWeek(now, weekStartDay),
|
getStartOfWeek(now, profile.weekStartDay ?? 1),
|
||||||
))),
|
))),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -8520,19 +8520,19 @@ export default function WeeklyView() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onSettingsChanged={handleSettingsChanged}
|
onSettingsChanged={handleSettingsChanged}
|
||||||
showTimeGrid={showTimeGrid}
|
showTimeGrid={profile.showTimeGrid ?? true}
|
||||||
setShowTimeGrid={setShowTimeGrid}
|
setShowTimeGrid={setShowTimeGrid}
|
||||||
cellDuration={cellDuration}
|
cellDuration={profile.cellDuration ?? 30}
|
||||||
setCellDuration={setCellDuration}
|
setCellDuration={setCellDuration}
|
||||||
weekStartDay={weekStartDay}
|
weekStartDay={profile.weekStartDay ?? 1}
|
||||||
setWeekStartDay={setWeekStartDay}
|
setWeekStartDay={setWeekStartDay}
|
||||||
viewStyle={viewStyle}
|
viewStyle={profile.viewStyle ?? "simple"}
|
||||||
setViewStyle={setViewStyle}
|
setViewStyle={setViewStyle}
|
||||||
showSomeday={showSomeday}
|
showSomeday={profile.showSomeday ?? true}
|
||||||
setShowSomeday={setShowSomeday}
|
setShowSomeday={setShowSomeday}
|
||||||
showAllDay={showAllDay}
|
showAllDay={profile.showAllDayEvents ?? true}
|
||||||
setShowAllDay={setShowAllDay}
|
setShowAllDay={setShowAllDay}
|
||||||
showSchedule={showSchedule}
|
showSchedule={profile.showSchedule ?? true}
|
||||||
setShowSchedule={setShowSchedule}
|
setShowSchedule={setShowSchedule}
|
||||||
goal={goal}
|
goal={goal}
|
||||||
setGoal={setGoal}
|
setGoal={setGoal}
|
||||||
@ -8543,26 +8543,26 @@ export default function WeeklyView() {
|
|||||||
setFocusTimerDuration={setFocusTimerDuration}
|
setFocusTimerDuration={setFocusTimerDuration}
|
||||||
focusBreakDuration={focusBreakDuration}
|
focusBreakDuration={focusBreakDuration}
|
||||||
setFocusBreakDuration={setFocusBreakDuration}
|
setFocusBreakDuration={setFocusBreakDuration}
|
||||||
fontSize={fontSize}
|
fontSize={profile.fontSize ?? "M"}
|
||||||
setFontSize={setFontSize}
|
setFontSize={setFontSize}
|
||||||
showNextTask={showNextTask}
|
showNextTask={profile.showNextTask ?? false}
|
||||||
setShowNextTask={setShowNextTask}
|
setShowNextTask={setShowNextTask}
|
||||||
headlineFont={headlineFont}
|
headlineFont={profile.headlineFont ?? "Inter"}
|
||||||
headlineFontSize={headlineFontSize}
|
headlineFontSize={profile.headlineFontSize ?? "1.25rem"}
|
||||||
headlineFontWeight={headlineFontWeight}
|
headlineFontWeight={profile.headlineFontWeight ?? "900"}
|
||||||
dateFontFamily={dateFontFamily}
|
dateFontFamily={profile.dateFontFamily ?? "Inter"}
|
||||||
dateFontSize={dateFontSize}
|
dateFontSize={profile.dateFontSize ?? "0.65rem"}
|
||||||
dateFontWeight={dateFontWeight}
|
dateFontWeight={profile.dateFontWeight ?? "400"}
|
||||||
timeTaskFontFamily={timeTaskFontFamily}
|
timeTaskFontFamily={profile.timeTaskFontFamily ?? "Inter"}
|
||||||
timeTaskFontSize={timeTaskFontSize}
|
timeTaskFontSize={profile.timeTaskFontSize ?? "0.75rem"}
|
||||||
timeTaskFontWeight={timeTaskFontWeight}
|
timeTaskFontWeight={profile.timeTaskFontWeight ?? "500"}
|
||||||
bodyFont={bodyFont}
|
bodyFont={profile.bodyFont ?? "Inter"}
|
||||||
taskFontFamily={taskFontFamily}
|
taskFontFamily={profile.taskFontFamily ?? "Inter"}
|
||||||
taskFontSize={taskFontSize}
|
taskFontSize={profile.taskFontSize ?? "0.9rem"}
|
||||||
taskFontWeight={taskFontWeight}
|
taskFontWeight={profile.taskFontWeight ?? "400"}
|
||||||
fontWeight={fontWeight}
|
fontWeight={profile.fontWeight ?? "400"}
|
||||||
weekendColorSat={weekendColorSat}
|
weekendColorSat={profile.weekendColorSat ?? "#666666"}
|
||||||
weekendColorSun={weekendColorSun}
|
weekendColorSun={profile.weekendColorSun ?? "#dc2626"}
|
||||||
protectEventTimes={protectEventTimes}
|
protectEventTimes={protectEventTimes}
|
||||||
setProtectEventTimes={setProtectEventTimes}
|
setProtectEventTimes={setProtectEventTimes}
|
||||||
goalFontWeight={profile.goalFontWeight || "500"}
|
goalFontWeight={profile.goalFontWeight || "500"}
|
||||||
@ -8572,11 +8572,11 @@ export default function WeeklyView() {
|
|||||||
executeImport={executeImport}
|
executeImport={executeImport}
|
||||||
onImportLists={(lists) => doImport("apple", lists)}
|
onImportLists={(lists) => doImport("apple", lists)}
|
||||||
importStatusMsg={importStatusMsg}
|
importStatusMsg={importStatusMsg}
|
||||||
hourLabelFormat={hourLabelFormat}
|
hourLabelFormat={profile.hourLabelFormat ?? "short"}
|
||||||
setHourLabelFormat={setHourLabelFormat}
|
setHourLabelFormat={setHourLabelFormat}
|
||||||
showSubHourSlots={showSubHourSlots}
|
showSubHourSlots={profile.showSubHourSlots ?? true}
|
||||||
setShowSubHourSlots={setShowSubHourSlots}
|
setShowSubHourSlots={setShowSubHourSlots}
|
||||||
allDayPosition={allDayPosition}
|
allDayPosition={profile.allDayPosition ?? "above"}
|
||||||
setAllDayPosition={setAllDayPosition}
|
setAllDayPosition={setAllDayPosition}
|
||||||
saveSetting={saveSetting}
|
saveSetting={saveSetting}
|
||||||
availableTaskLists={availableTaskLists}
|
availableTaskLists={availableTaskLists}
|
||||||
@ -8609,7 +8609,7 @@ export default function WeeklyView() {
|
|||||||
},
|
},
|
||||||
onAddProject: () => { setShowProjectsSidebar(true); },
|
onAddProject: () => { setShowProjectsSidebar(true); },
|
||||||
onRecurringTasks: () => setIsRecurringTasksOpen(true),
|
onRecurringTasks: () => setIsRecurringTasksOpen(true),
|
||||||
onToggleNextTask: () => { const newVal = !showNextTask; setShowNextTask(newVal); saveSetting("showNextTask", newVal); },
|
onToggleNextTask: () => { const newVal = !profile.showNextTask; setShowNextTask(newVal); saveSetting("showNextTask", newVal); },
|
||||||
onFocusMode: () => setShowFocusMode(true),
|
onFocusMode: () => setShowFocusMode(true),
|
||||||
onToggleDarkMode: () => setDarkMode(!darkMode),
|
onToggleDarkMode: () => setDarkMode(!darkMode),
|
||||||
onSearch: () => setIsSearchOpen(true),
|
onSearch: () => setIsSearchOpen(true),
|
||||||
@ -8617,18 +8617,18 @@ export default function WeeklyView() {
|
|||||||
onRedo: handleRedo,
|
onRedo: handleRedo,
|
||||||
onRefresh: () => { fetchCalendarEvents(true); fetchTasks(); },
|
onRefresh: () => { fetchCalendarEvents(true); fetchTasks(); },
|
||||||
darkMode,
|
darkMode,
|
||||||
showNextTask,
|
showNextTask: profile.showNextTask ?? false,
|
||||||
undoCount,
|
undoCount,
|
||||||
redoCount,
|
redoCount,
|
||||||
viewDays,
|
viewDays,
|
||||||
onViewDaysChange: (num: number) => { setViewDays(num); savedViewDaysRef.current = num; saveSetting("viewDays", num); },
|
onViewDaysChange: (num: number) => { setViewDays(num); savedViewDaysRef.current = num; saveSetting("viewDays", num); },
|
||||||
showTimeGrid,
|
showTimeGrid: profile.showTimeGrid ?? true,
|
||||||
cellDuration,
|
cellDuration: profile.cellDuration ?? 30,
|
||||||
onCellDurationChange: (d: CellDuration) => { setCellDuration(d); saveSetting("cellDuration", d); },
|
onCellDurationChange: (d: CellDuration) => { setCellDuration(d); saveSetting("cellDuration", d); },
|
||||||
viewStyle,
|
viewStyle: profile.viewStyle ?? "simple",
|
||||||
onViewStyleChange: (s: string) => { setViewStyle(s as any); saveSetting("viewStyle", s); },
|
onViewStyleChange: (s: string) => { setViewStyle(s as any); saveSetting("viewStyle", s); },
|
||||||
startHour,
|
startHour: profile.startHour ?? 8,
|
||||||
endHour,
|
endHour: profile.endHour ?? 18,
|
||||||
onStartHourChange: (h: number) => { setStartHour(h); saveSetting("startHour", h); },
|
onStartHourChange: (h: number) => { setStartHour(h); saveSetting("startHour", h); },
|
||||||
onEndHourChange: (h: number) => { setEndHour(h); saveSetting("endHour", h); },
|
onEndHourChange: (h: number) => { setEndHour(h); saveSetting("endHour", h); },
|
||||||
}}
|
}}
|
||||||
@ -8647,7 +8647,7 @@ export default function WeeklyView() {
|
|||||||
task={selectedTaskForRecurrence}
|
task={selectedTaskForRecurrence}
|
||||||
onClose={() => setSelectedTaskForRecurrence(null)}
|
onClose={() => setSelectedTaskForRecurrence(null)}
|
||||||
onSave={handleRecurrenceSave}
|
onSave={handleRecurrenceSave}
|
||||||
language={language}
|
language={profile.language}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -8657,7 +8657,7 @@ export default function WeeklyView() {
|
|||||||
<OnboardingWizard
|
<OnboardingWizard
|
||||||
profile={profile}
|
profile={profile}
|
||||||
darkMode={darkMode}
|
darkMode={darkMode}
|
||||||
language={language}
|
language={profile.language}
|
||||||
connections={connections}
|
connections={connections}
|
||||||
onComplete={async () => { await saveSetting("hasCompletedOnboarding", true); setShowOnboarding(false); await fetchProfile(); }}
|
onComplete={async () => { await saveSetting("hasCompletedOnboarding", true); setShowOnboarding(false); await fetchProfile(); }}
|
||||||
onSkip={async () => { await saveSetting("hasCompletedOnboarding", true); setShowOnboarding(false); await fetchProfile(); }}
|
onSkip={async () => { await saveSetting("hasCompletedOnboarding", true); setShowOnboarding(false); await fetchProfile(); }}
|
||||||
@ -8808,7 +8808,7 @@ export default function WeeklyView() {
|
|||||||
setKanbanDetailTask({ ...liveTask, markdownContent: val });
|
setKanbanDetailTask({ ...liveTask, markdownContent: val });
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
placeholder={language === "de" ? "Notizen hinzufügen..." : "Add notes..."}
|
placeholder={profile.language === "de" ? "Notizen hinzufügen..." : "Add notes..."}
|
||||||
className="kanban-detail-notes"
|
className="kanban-detail-notes"
|
||||||
rows={4}
|
rows={4}
|
||||||
/>
|
/>
|
||||||
@ -8863,7 +8863,7 @@ export default function WeeklyView() {
|
|||||||
<input
|
<input
|
||||||
name="newSub"
|
name="newSub"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={language === "de" ? "Unteraufgabe hinzufügen..." : "Add subtask..."}
|
placeholder={profile.language === "de" ? "Unteraufgabe hinzufügen..." : "Add subtask..."}
|
||||||
className="kanban-detail-subtask-input"
|
className="kanban-detail-subtask-input"
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
@ -8876,7 +8876,7 @@ export default function WeeklyView() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => { deleteTask(liveTask.id); setKanbanDetailTask(null); }}
|
onClick={() => { deleteTask(liveTask.id); setKanbanDetailTask(null); }}
|
||||||
className="kanban-detail-delete"
|
className="kanban-detail-delete"
|
||||||
title={language === "de" ? "Löschen" : "Delete"}
|
title={profile.language === "de" ? "Löschen" : "Delete"}
|
||||||
>
|
>
|
||||||
<Trash2 size={16} />
|
<Trash2 size={16} />
|
||||||
</button>
|
</button>
|
||||||
@ -8885,7 +8885,7 @@ export default function WeeklyView() {
|
|||||||
onClick={() => setKanbanDetailTask(null)}
|
onClick={() => setKanbanDetailTask(null)}
|
||||||
className="kanban-detail-btn kanban-detail-btn-cancel"
|
className="kanban-detail-btn kanban-detail-btn-cancel"
|
||||||
>
|
>
|
||||||
{language === "de" ? "Abbrechen" : "Cancel"}
|
{profile.language === "de" ? "Abbrechen" : "Cancel"}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setKanbanDetailTask(null)}
|
onClick={() => setKanbanDetailTask(null)}
|
||||||
@ -8919,7 +8919,7 @@ export default function WeeklyView() {
|
|||||||
<div className="mobile-fab-menu">
|
<div className="mobile-fab-menu">
|
||||||
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowMobileFabSheet(true); }}>
|
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowMobileFabSheet(true); }}>
|
||||||
<div className="mobile-fab-menu-icon" style={{ background: "#0ea5e9" }}><Plus size={18} /></div>
|
<div className="mobile-fab-menu-icon" style={{ background: "#0ea5e9" }}><Plus size={18} /></div>
|
||||||
<span>{language === "de" ? "Aufgabe" : "Task"}</span>
|
<span>{profile.language === "de" ? "Aufgabe" : "Task"}</span>
|
||||||
</button>
|
</button>
|
||||||
<button className="mobile-fab-menu-item" onClick={() => {
|
<button className="mobile-fab-menu-item" onClick={() => {
|
||||||
setShowMobileFabMenu(false);
|
setShowMobileFabMenu(false);
|
||||||
@ -8927,19 +8927,19 @@ export default function WeeklyView() {
|
|||||||
setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` });
|
setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` });
|
||||||
}}>
|
}}>
|
||||||
<div className="mobile-fab-menu-icon" style={{ background: "#8b5cf6" }}><Calendar size={18} /></div>
|
<div className="mobile-fab-menu-icon" style={{ background: "#8b5cf6" }}><Calendar size={18} /></div>
|
||||||
<span>{language === "de" ? "Termin" : "Event"}</span>
|
<span>{profile.language === "de" ? "Termin" : "Event"}</span>
|
||||||
</button>
|
</button>
|
||||||
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowProjectsSidebar(true); }}>
|
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowProjectsSidebar(true); }}>
|
||||||
<div className="mobile-fab-menu-icon" style={{ background: "#6366f1" }}><FolderPlus size={18} /></div>
|
<div className="mobile-fab-menu-icon" style={{ background: "#6366f1" }}><FolderPlus size={18} /></div>
|
||||||
<span>{language === "de" ? "Projekt" : "Project"}</span>
|
<span>{profile.language === "de" ? "Projekt" : "Project"}</span>
|
||||||
</button>
|
</button>
|
||||||
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowFocusMode(true); }}>
|
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowFocusMode(true); }}>
|
||||||
<div className="mobile-fab-menu-icon" style={{ background: "#f59e0b" }}><Zap size={18} /></div>
|
<div className="mobile-fab-menu-icon" style={{ background: "#f59e0b" }}><Zap size={18} /></div>
|
||||||
<span>{language === "de" ? "Fokus" : "Focus"}</span>
|
<span>{profile.language === "de" ? "Fokus" : "Focus"}</span>
|
||||||
</button>
|
</button>
|
||||||
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setIsSearchOpen(true); }}>
|
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setIsSearchOpen(true); }}>
|
||||||
<div className="mobile-fab-menu-icon" style={{ background: "#10b981" }}><Search size={18} /></div>
|
<div className="mobile-fab-menu-icon" style={{ background: "#10b981" }}><Search size={18} /></div>
|
||||||
<span>{language === "de" ? "Suchen" : "Search"}</span>
|
<span>{profile.language === "de" ? "Suchen" : "Search"}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -9026,7 +9026,7 @@ export default function WeeklyView() {
|
|||||||
setShowDatePicker(false);
|
setShowDatePicker(false);
|
||||||
}}
|
}}
|
||||||
onClose={() => setShowDatePicker(false)}
|
onClose={() => setShowDatePicker(false)}
|
||||||
language={language}
|
language={profile.language}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user