Refine sidebar header controls and resize handles
This commit is contained in:
parent
07401d3dfa
commit
5ebdf6d751
@ -3270,26 +3270,29 @@ h3 {
|
|||||||
|
|
||||||
/* Resize handle for draggable section borders */
|
/* Resize handle for draggable section borders */
|
||||||
.resize-handle {
|
.resize-handle {
|
||||||
height: 7px;
|
height: 2px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
cursor: ns-resize;
|
cursor: ns-resize;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 10;
|
z-index: 30;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border-top: 1px solid var(--weekly-border, #e5e7eb);
|
overflow: visible;
|
||||||
border-bottom: 1px solid var(--weekly-border, #e5e7eb);
|
background-color: #ddd;
|
||||||
}
|
}
|
||||||
.resize-handle:hover {
|
.resize-handle:hover {
|
||||||
background: rgba(59, 130, 246, 0.08);
|
background-color: #d7d7d7;
|
||||||
border-color: var(--weekly-accent, #3b82f6);
|
border-color: #b8b8b8;
|
||||||
}
|
}
|
||||||
.resize-handle:active {
|
.resize-handle:active {
|
||||||
background: rgba(59, 130, 246, 0.12);
|
background-color: #d1d1d1;
|
||||||
border-color: var(--weekly-accent, #3b82f6);
|
border-color: #aaa;
|
||||||
}
|
}
|
||||||
.resize-handle-bar {
|
.resize-handle-bar {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
@ -3299,10 +3302,50 @@ h3 {
|
|||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
transition: background 0.15s, opacity 0.15s;
|
transition: background 0.15s, opacity 0.15s;
|
||||||
}
|
}
|
||||||
|
.resize-handle-anyday {
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
.resize-handle-allday {
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
.resize-handle-anyday .resize-handle-bar {
|
||||||
|
width: 23px;
|
||||||
|
height: 9px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: radial-gradient(circle, color-mix(in srgb, var(--weekly-text, #333) 48%, transparent) 1.25px, transparent 1.35px) 2px 1.5px / 6px 5px repeat;
|
||||||
|
background-color: #ddd;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
opacity: 1;
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: visible;
|
||||||
|
z-index: 50;
|
||||||
|
}
|
||||||
|
.resize-handle-allday .resize-handle-bar {
|
||||||
|
width: 23px;
|
||||||
|
height: 9px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: radial-gradient(circle, color-mix(in srgb, var(--weekly-text, #333) 48%, transparent) 1.25px, transparent 1.35px) 2px 1.5px / 6px 5px repeat;
|
||||||
|
background-color: #ddd;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
opacity: 1;
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: visible;
|
||||||
|
z-index: 50;
|
||||||
|
}
|
||||||
.resize-handle:hover .resize-handle-bar,
|
.resize-handle:hover .resize-handle-bar,
|
||||||
.resize-handle:active .resize-handle-bar {
|
.resize-handle:active .resize-handle-bar {
|
||||||
background: var(--weekly-accent, #3b82f6);
|
opacity: 1;
|
||||||
opacity: 0.5;
|
}
|
||||||
|
.resize-handle-anyday:hover .resize-handle-bar,
|
||||||
|
.resize-handle-anyday:active .resize-handle-bar,
|
||||||
|
.resize-handle-allday:hover .resize-handle-bar,
|
||||||
|
.resize-handle-allday:active .resize-handle-bar {
|
||||||
|
background: radial-gradient(circle, var(--weekly-accent, #3b82f6) 1.25px, transparent 1.35px) 2px 1.5px / 6px 5px repeat;
|
||||||
|
background-color: #d7d7d7;
|
||||||
|
border-color: #b8b8b8;
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.all-day-events-header {
|
.all-day-events-header {
|
||||||
|
|||||||
@ -1045,6 +1045,41 @@ function SettingsSidebar({
|
|||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div style={{ marginTop: "10px" }}>
|
||||||
|
<label style={{ fontSize: "0.78rem", fontWeight: 600, color: "var(--weekly-settings-label)" }}>
|
||||||
|
{profile.language === "de" ? "Steuerung in der Kopfleiste" : "Header Controls"}
|
||||||
|
</label>
|
||||||
|
<div className="mt-1 flex gap-2">
|
||||||
|
{[
|
||||||
|
{ value: true, label: profile.language === "de" ? "Anzeigen" : "Show" },
|
||||||
|
{ value: false, label: profile.language === "de" ? "Ausblenden" : "Hide" },
|
||||||
|
].map(({ value, label }) => {
|
||||||
|
const isActive = (profile.showHeaderControls !== false) === value;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={String(value)}
|
||||||
|
onClick={() => {
|
||||||
|
setProfile((p: any) => ({ ...p, showHeaderControls: value }));
|
||||||
|
saveSetting("showHeaderControls", value);
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
padding: "6px 10px",
|
||||||
|
fontSize: "0.8rem",
|
||||||
|
borderRadius: "6px",
|
||||||
|
border: "1px solid var(--weekly-border, #e5e7eb)",
|
||||||
|
cursor: "pointer",
|
||||||
|
fontWeight: isActive ? 700 : 400,
|
||||||
|
background: isActive ? "var(--weekly-text, #333)" : "transparent",
|
||||||
|
color: isActive ? "#fff" : "var(--weekly-settings-label)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Header Display */}
|
{/* Header Display */}
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -128,6 +128,7 @@ type DeviceViewSettingKey = typeof DEVICE_VIEW_SETTINGS_KEYS[number];
|
|||||||
|
|
||||||
// Settings that save to DB (cross-device default) AND to cookie (device override wins on load)
|
// Settings that save to DB (cross-device default) AND to cookie (device override wins on load)
|
||||||
const DEVICE_ALSO_COOKIE_KEYS = ["viewStyle", "showTimeGrid", "startDayOffset"];
|
const DEVICE_ALSO_COOKIE_KEYS = ["viewStyle", "showTimeGrid", "startDayOffset"];
|
||||||
|
const VIEW_SETTINGS_PROFILE_KEYS = ["menuPosition", "showHeaderControls"];
|
||||||
|
|
||||||
function getCookie(name: string): string | null {
|
function getCookie(name: string): string | null {
|
||||||
if (typeof document === "undefined") return null;
|
if (typeof document === "undefined") return null;
|
||||||
@ -918,6 +919,7 @@ export default function WeeklyView() {
|
|||||||
// Mobile detection
|
// Mobile detection
|
||||||
const [isMobile, setIsMobile] = useState(false);
|
const [isMobile, setIsMobile] = useState(false);
|
||||||
const [isPortrait, setIsPortrait] = useState(false);
|
const [isPortrait, setIsPortrait] = useState(false);
|
||||||
|
const [isCompactHeight, setIsCompactHeight] = useState(false);
|
||||||
|
|
||||||
// Tracks the last day column the user interacted with (for "selected day" header display)
|
// Tracks the last day column the user interacted with (for "selected day" header display)
|
||||||
const [selectedDay, setSelectedDay] = useState<Date | null>(null);
|
const [selectedDay, setSelectedDay] = useState<Date | null>(null);
|
||||||
@ -1037,6 +1039,8 @@ export default function WeeklyView() {
|
|||||||
weatherLon: null,
|
weatherLon: null,
|
||||||
weatherLocation: "",
|
weatherLocation: "",
|
||||||
showCalendarProviderIcon: false,
|
showCalendarProviderIcon: false,
|
||||||
|
menuPosition: "left",
|
||||||
|
showHeaderControls: true,
|
||||||
});
|
});
|
||||||
const [motivationalQuote, setMotivationalQuote] = useState("");
|
const [motivationalQuote, setMotivationalQuote] = useState("");
|
||||||
const [showSummary, setShowSummary] = useState(false);
|
const [showSummary, setShowSummary] = useState(false);
|
||||||
@ -1400,6 +1404,7 @@ export default function WeeklyView() {
|
|||||||
const check = () => {
|
const check = () => {
|
||||||
setIsMobile(window.innerWidth <= 768);
|
setIsMobile(window.innerWidth <= 768);
|
||||||
setIsPortrait(window.innerHeight > window.innerWidth);
|
setIsPortrait(window.innerHeight > window.innerWidth);
|
||||||
|
setIsCompactHeight(window.innerHeight <= 720);
|
||||||
};
|
};
|
||||||
check();
|
check();
|
||||||
window.addEventListener("resize", check);
|
window.addEventListener("resize", check);
|
||||||
@ -1416,7 +1421,12 @@ export default function WeeklyView() {
|
|||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data && data.user) {
|
if (data && data.user) {
|
||||||
const profileData = data.user;
|
const viewPrefs = (data.user.viewSettings || {}) as any;
|
||||||
|
const profileData = {
|
||||||
|
...data.user,
|
||||||
|
menuPosition: viewPrefs.menuPosition ?? data.user.menuPosition ?? "left",
|
||||||
|
showHeaderControls: viewPrefs.showHeaderControls ?? data.user.showHeaderControls ?? true,
|
||||||
|
};
|
||||||
setProfile(profileData);
|
setProfile(profileData);
|
||||||
|
|
||||||
// Sync individual states to profile data
|
// Sync individual states to profile data
|
||||||
@ -2403,6 +2413,22 @@ export default function WeeklyView() {
|
|||||||
somedayWheelCleanup.current = () => node.removeEventListener("wheel", handler);
|
somedayWheelCleanup.current = () => node.removeEventListener("wheel", handler);
|
||||||
}, []);
|
}, []);
|
||||||
const saveSetting = async (key: string, value: any) => {
|
const saveSetting = async (key: string, value: any) => {
|
||||||
|
if (VIEW_SETTINGS_PROFILE_KEYS.includes(key)) {
|
||||||
|
const updated = { ...(viewSettingsRef.current as any), [key]: value };
|
||||||
|
viewSettingsRef.current = updated;
|
||||||
|
setViewSettings(updated as any);
|
||||||
|
setProfile((p: any) => ({ ...p, [key]: value }));
|
||||||
|
try {
|
||||||
|
await fetch("/api/user/profile", {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ viewSettings: updated }),
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Failed to save setting ${key}:`, err);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Per-device settings: save to cookie ONLY (not DB) so each device keeps its own value
|
// Per-device settings: save to cookie ONLY (not DB) so each device keeps its own value
|
||||||
if (DEVICE_SETTINGS_KEYS.includes(key)) {
|
if (DEVICE_SETTINGS_KEYS.includes(key)) {
|
||||||
setCookie(`setting_${key}`, String(value));
|
setCookie(`setting_${key}`, String(value));
|
||||||
@ -5383,6 +5409,10 @@ export default function WeeklyView() {
|
|||||||
};
|
};
|
||||||
const activeTheme = (darkMode ? profile.darkTheme : profile.lightTheme) as Record<string, string> | null;
|
const activeTheme = (darkMode ? profile.darkTheme : profile.lightTheme) as Record<string, string> | null;
|
||||||
const useLeftRail = !isMobile && profile.menuPosition !== "top";
|
const useLeftRail = !isMobile && profile.menuPosition !== "top";
|
||||||
|
const showHeaderControls = profile.showHeaderControls !== false;
|
||||||
|
const compactRail = useLeftRail && isCompactHeight;
|
||||||
|
const collapsedRailWidth = compactRail ? 38 : 44;
|
||||||
|
const expandedRailWidth = compactRail ? 220 : 240;
|
||||||
|
|
||||||
const containerStyle = {
|
const containerStyle = {
|
||||||
...(activeTheme ? {
|
...(activeTheme ? {
|
||||||
@ -5461,7 +5491,7 @@ export default function WeeklyView() {
|
|||||||
"--weekly-past-color": activeTheme?.color8 || (darkMode
|
"--weekly-past-color": activeTheme?.color8 || (darkMode
|
||||||
? invertColor(profile.pastDayColor || "#a6a6a7")
|
? invertColor(profile.pastDayColor || "#a6a6a7")
|
||||||
: profile.pastDayColor || "#a6a6a7"),
|
: profile.pastDayColor || "#a6a6a7"),
|
||||||
...(useLeftRail ? { paddingLeft: leftRailExpanded ? "240px" : "44px", transition: "padding-left 0.2s ease" } : {}),
|
...(useLeftRail ? { paddingLeft: leftRailExpanded ? `${expandedRailWidth}px` : `${collapsedRailWidth}px`, transition: "padding-left 0.2s ease" } : {}),
|
||||||
} as React.CSSProperties;
|
} as React.CSSProperties;
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@ -5492,12 +5522,12 @@ export default function WeeklyView() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const railIconBtnStyle: React.CSSProperties = {
|
const railIconBtnStyle: React.CSSProperties = {
|
||||||
width: "36px", height: "36px", display: "flex", alignItems: "center", justifyContent: "center",
|
width: compactRail ? "30px" : "36px", height: compactRail ? "30px" : "36px", display: "flex", alignItems: "center", justifyContent: "center",
|
||||||
background: "none", border: "none", cursor: "pointer", borderRadius: "8px",
|
background: "none", border: "none", cursor: "pointer", borderRadius: compactRail ? "7px" : "8px",
|
||||||
color: darkMode ? "#9ca3af" : "#6b7280", flexShrink: 0,
|
color: darkMode ? "#9ca3af" : "#6b7280", flexShrink: 0,
|
||||||
};
|
};
|
||||||
const flyoutPanelStyle: React.CSSProperties = {
|
const flyoutPanelStyle: React.CSSProperties = {
|
||||||
position: "fixed", left: "48px",
|
position: "fixed", left: `${collapsedRailWidth + 4}px`,
|
||||||
top: `${Math.min(flyoutY, (typeof window !== "undefined" ? window.innerHeight : 800) - 260)}px`,
|
top: `${Math.min(flyoutY, (typeof window !== "undefined" ? window.innerHeight : 800) - 260)}px`,
|
||||||
background: darkMode ? "#1a1a2e" : "var(--paper)",
|
background: darkMode ? "#1a1a2e" : "var(--paper)",
|
||||||
border: "1px solid var(--line)", borderRadius: "10px", padding: "12px 14px",
|
border: "1px solid var(--line)", borderRadius: "10px", padding: "12px 14px",
|
||||||
@ -5521,7 +5551,7 @@ export default function WeeklyView() {
|
|||||||
if (flyoutTimerRef.current) clearTimeout(flyoutTimerRef.current);
|
if (flyoutTimerRef.current) clearTimeout(flyoutTimerRef.current);
|
||||||
};
|
};
|
||||||
const railSep = (
|
const railSep = (
|
||||||
<div style={{ height: "1px", background: "var(--line)", width: "28px", margin: "3px 0", flexShrink: 0, alignSelf: "center" }} />
|
<div style={{ height: "1px", background: "var(--line)", width: compactRail ? "22px" : "28px", margin: compactRail ? "1px 0" : "3px 0", flexShrink: 0, alignSelf: "center" }} />
|
||||||
);
|
);
|
||||||
|
|
||||||
// All-Day Events Section (reusable for above/below positioning)
|
// All-Day Events Section (reusable for above/below positioning)
|
||||||
@ -5535,7 +5565,7 @@ export default function WeeklyView() {
|
|||||||
const handleOnTop = effectiveAllDayPosition === "below";
|
const handleOnTop = effectiveAllDayPosition === "below";
|
||||||
const resizeHandle = isAllDayExpanded ? (
|
const resizeHandle = isAllDayExpanded ? (
|
||||||
<div
|
<div
|
||||||
className="resize-handle"
|
className="resize-handle resize-handle-allday"
|
||||||
onMouseDown={(e) => startResize(e, 'allday', handleOnTop)}
|
onMouseDown={(e) => startResize(e, 'allday', handleOnTop)}
|
||||||
onTouchStart={(e) => startResize(e, 'allday', handleOnTop)}
|
onTouchStart={(e) => startResize(e, 'allday', handleOnTop)}
|
||||||
>
|
>
|
||||||
@ -5830,10 +5860,10 @@ export default function WeeklyView() {
|
|||||||
{useLeftRail && (
|
{useLeftRail && (
|
||||||
<>
|
<>
|
||||||
{/* The rail panel */}
|
{/* The rail panel */}
|
||||||
<div style={{ position: "fixed", left: 0, top: 0, bottom: 0, width: leftRailExpanded ? "240px" : "44px", transition: "width 0.2s ease", background: darkMode ? "#1a1a2e" : "var(--paper)", borderRight: "1px solid var(--line)", zIndex: 100, display: "flex", flexDirection: "column", overflow: "hidden" }}>
|
<div className={`weekly-left-sidebar ${leftRailExpanded ? "expanded" : "collapsed"} ${compactRail ? "compact-height" : ""}`} style={{ position: "fixed", left: 0, top: 0, bottom: 0, width: leftRailExpanded ? `${expandedRailWidth}px` : `${collapsedRailWidth}px`, transition: "width 0.2s ease", background: darkMode ? "#1a1a2e" : "var(--paper)", borderRight: "1px solid var(--line)", zIndex: 100, display: "flex", flexDirection: "column", overflow: "hidden" }}>
|
||||||
{leftRailExpanded ? (
|
{leftRailExpanded ? (
|
||||||
// ── EXPANDED MODE ──
|
// ── EXPANDED MODE ──
|
||||||
<div style={{ padding: "16px 14px", display: "flex", flexDirection: "column", gap: "10px", overflowY: "auto", flex: 1 }}>
|
<div style={{ padding: compactRail ? "10px 10px" : "16px 14px", display: "flex", flexDirection: "column", gap: compactRail ? "6px" : "10px", overflowY: "auto", flex: 1 }}>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
<span style={{ fontSize: "0.85rem", fontWeight: 700, color: darkMode ? "#e5e7eb" : "#333" }}>{profile.language === "de" ? "Einstellungen" : "Preferences"}</span>
|
<span style={{ fontSize: "0.85rem", fontWeight: 700, color: darkMode ? "#e5e7eb" : "#333" }}>{profile.language === "de" ? "Einstellungen" : "Preferences"}</span>
|
||||||
<button onClick={() => setLeftRailExpanded(false)} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#6b7280" : "#9ca3af", padding: "2px", display: "flex" }} title="Collapse">
|
<button onClick={() => setLeftRailExpanded(false)} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#6b7280" : "#9ca3af", padding: "2px", display: "flex" }} title="Collapse">
|
||||||
@ -5902,7 +5932,7 @@ export default function WeeklyView() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
// ── COLLAPSED MODE — icon strip ──
|
// ── COLLAPSED MODE — icon strip ──
|
||||||
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", paddingTop: "6px", paddingBottom: "8px", height: "100%", overflowY: "auto", overflowX: "visible" }}>
|
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", paddingTop: compactRail ? "4px" : "6px", paddingBottom: compactRail ? "4px" : "8px", height: "100%", overflowY: compactRail ? "hidden" : "auto", overflowX: "visible" }}>
|
||||||
{/* Expand toggle */}
|
{/* Expand toggle */}
|
||||||
<button onClick={() => setLeftRailExpanded(true)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Erweitern" : "Expand"}><PanelLeftOpen size={16} /></button>
|
<button onClick={() => setLeftRailExpanded(true)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Erweitern" : "Expand"}><PanelLeftOpen size={16} /></button>
|
||||||
{railSep}
|
{railSep}
|
||||||
@ -6243,7 +6273,7 @@ export default function WeeklyView() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Desktop Header: Left, Center, Right */}
|
{/* Desktop Header: Left, Center, Right */}
|
||||||
<header className="group relative flex items-center justify-between w-full px-4 py-1.5 border-b bg-white dark:bg-gray-900 dark:text-white transition-colors duration-200" style={isMobile ? { display: "none" } : { borderBottomColor: 'var(--line)', minHeight: useLeftRail ? "44px" : undefined }}>
|
<header className="group relative flex items-center justify-between w-full px-4 py-1.5 border-b bg-white dark:bg-gray-900 dark:text-white transition-colors duration-200" style={isMobile ? { display: "none" } : { borderBottomColor: 'var(--line)', minHeight: useLeftRail ? (compactRail ? "40px" : "44px") : undefined }}>
|
||||||
{/* LEFT SECTION: View Switcher, Days, Hours, Slot Duration — only shown in top-toolbar mode */}
|
{/* LEFT SECTION: View Switcher, Days, Hours, Slot Duration — only shown in top-toolbar mode */}
|
||||||
<div className={`weekly-header-controls flex items-center gap-4 transition-opacity duration-700 ${!useLeftRail ? "opacity-0 group-hover:opacity-100" : ""}`} style={{ zIndex: 1, display: useLeftRail ? "none" : undefined, ...(showIntroHints ? { opacity: 1 } : {}) }}>
|
<div className={`weekly-header-controls flex items-center gap-4 transition-opacity duration-700 ${!useLeftRail ? "opacity-0 group-hover:opacity-100" : ""}`} style={{ zIndex: 1, display: useLeftRail ? "none" : undefined, ...(showIntroHints ? { opacity: 1 } : {}) }}>
|
||||||
{/* Quick-settings button (top mode only) */}
|
{/* Quick-settings button (top mode only) */}
|
||||||
@ -6503,28 +6533,30 @@ export default function WeeklyView() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* RIGHT SECTION: Navigation & Tools */}
|
{/* RIGHT SECTION: Navigation & Tools */}
|
||||||
<div className="weekly-header-controls flex-shrink-0 flex items-center gap-1.5 sm:gap-2 transition-opacity duration-700 opacity-0 group-hover:opacity-100" style={{ zIndex: 10, display: useLeftRail ? "none" : undefined, ...(showIntroHints ? { opacity: 1 } : {}) }}>
|
<div className={`weekly-header-controls flex-shrink-0 flex items-center gap-1.5 sm:gap-2 transition-opacity duration-700 ${useLeftRail ? "opacity-100" : "opacity-0 group-hover:opacity-100"}`} style={{ zIndex: 10, marginLeft: useLeftRail ? "auto" : undefined, display: useLeftRail && !showHeaderControls ? "none" : undefined, ...(showIntroHints ? { opacity: 1 } : {}) }}>
|
||||||
{/* Secondary actions — hidden on tablet, visible on desktop */}
|
{/* Secondary actions — hidden on tablet, visible on desktop */}
|
||||||
<div className="header-desktop-only flex items-center gap-1.5">
|
{!useLeftRail && (
|
||||||
<button onClick={handleUndo} disabled={undoCount === 0} className="weekly-btn-icon disabled:opacity-30 disabled:cursor-default" title="Undo (Ctrl+Z)">
|
<div className="header-desktop-only flex items-center gap-1.5">
|
||||||
<Undo2 size={17} className="text-gray-600 hover:text-black transition-colors" />
|
<button onClick={handleUndo} disabled={undoCount === 0} className="weekly-btn-icon disabled:opacity-30 disabled:cursor-default" title="Undo (Ctrl+Z)">
|
||||||
</button>
|
<Undo2 size={17} className="text-gray-600 hover:text-black transition-colors" />
|
||||||
<button onClick={handleRedo} disabled={redoCount === 0} className="weekly-btn-icon disabled:opacity-30 disabled:cursor-default" title="Redo (Ctrl+Y)">
|
</button>
|
||||||
<Redo2 size={17} className="text-gray-600 hover:text-black transition-colors" />
|
<button onClick={handleRedo} disabled={redoCount === 0} className="weekly-btn-icon disabled:opacity-30 disabled:cursor-default" title="Redo (Ctrl+Y)">
|
||||||
</button>
|
<Redo2 size={17} className="text-gray-600 hover:text-black transition-colors" />
|
||||||
<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>
|
||||||
<Plus size={17} className="text-gray-600 hover:text-black transition-colors" />
|
<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>
|
<Plus size={17} className="text-gray-600 hover:text-black transition-colors" />
|
||||||
<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"}>
|
</button>
|
||||||
{profile.showNextTask ? <Play size={17} className="text-teal-600" /> : <Target size={17} className="text-gray-400" />}
|
<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"}>
|
||||||
</button>
|
{profile.showNextTask ? <Play size={17} className="text-teal-600" /> : <Target size={17} className="text-gray-400" />}
|
||||||
<button onClick={() => setShowFocusMode(true)} className="weekly-btn-icon" title="Enter Focus Mode">
|
</button>
|
||||||
<Zap size={17} className="text-gray-600 hover:text-yellow-500 transition-colors" />
|
<button onClick={() => setShowFocusMode(true)} className="weekly-btn-icon" title="Enter Focus Mode">
|
||||||
</button>
|
<Zap size={17} className="text-gray-600 hover:text-yellow-500 transition-colors" />
|
||||||
<button onClick={() => setDarkMode(!darkMode)} className="weekly-btn-icon" title={darkMode ? "Light Mode" : "Dark Mode"}>
|
</button>
|
||||||
{darkMode ? <Sun size={17} className="text-yellow-500" /> : <Moon size={17} className="text-gray-500" />}
|
<button onClick={() => setDarkMode(!darkMode)} className="weekly-btn-icon" title={darkMode ? "Light Mode" : "Dark Mode"}>
|
||||||
</button>
|
{darkMode ? <Sun size={17} className="text-yellow-500" /> : <Moon size={17} className="text-gray-500" />}
|
||||||
</div>
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Navigation Controls — always visible */}
|
{/* Navigation Controls — always visible */}
|
||||||
<div className="flex items-center bg-gray-100 dark:bg-gray-800 rounded-lg p-0.5">
|
<div className="flex items-center bg-gray-100 dark:bg-gray-800 rounded-lg p-0.5">
|
||||||
@ -6540,7 +6572,7 @@ export default function WeeklyView() {
|
|||||||
<button className="weekly-btn-icon" onClick={() => setShowSettings(true)} title="Settings"><Settings size={17} /></button>
|
<button className="weekly-btn-icon" onClick={() => setShowSettings(true)} title="Settings"><Settings size={17} /></button>
|
||||||
|
|
||||||
{/* Overflow menu — visible on tablet, hidden on desktop */}
|
{/* Overflow menu — visible on tablet, hidden on desktop */}
|
||||||
<div className="header-tablet-only" style={{ position: "relative" }}>
|
<div className={useLeftRail ? "" : "header-tablet-only"} style={{ position: "relative" }}>
|
||||||
<button className="weekly-btn-icon" onClick={() => setShowHeaderMore(!showHeaderMore)} title="More">
|
<button className="weekly-btn-icon" onClick={() => setShowHeaderMore(!showHeaderMore)} title="More">
|
||||||
<MoreVertical size={17} />
|
<MoreVertical size={17} />
|
||||||
</button>
|
</button>
|
||||||
@ -6589,9 +6621,13 @@ export default function WeeklyView() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Desktop only: Recurring Tasks + New Project */}
|
{/* Desktop only: Recurring Tasks + New Project */}
|
||||||
<button className="weekly-btn-icon header-desktop-only" onClick={() => setIsRecurringTasksOpen(true)} title="Recurring Tasks"><Repeat size={17} /></button>
|
{!useLeftRail && (
|
||||||
<button className="weekly-btn-icon header-desktop-only" onClick={() => setShowProjectsSidebar(true)} title="New Project"><FolderPlus size={17} /></button>
|
<>
|
||||||
<button className="weekly-btn-icon header-desktop-only" onClick={() => setShowWeekPrintModal(true)} title={profile.language === "de" ? "Woche drucken / exportieren" : "Print / export week"}><Printer size={17} /></button>
|
<button className="weekly-btn-icon header-desktop-only" onClick={() => setIsRecurringTasksOpen(true)} title="Recurring Tasks"><Repeat size={17} /></button>
|
||||||
|
<button className="weekly-btn-icon header-desktop-only" onClick={() => setShowProjectsSidebar(true)} title="New Project"><FolderPlus size={17} /></button>
|
||||||
|
<button className="weekly-btn-icon header-desktop-only" onClick={() => setShowWeekPrintModal(true)} title={profile.language === "de" ? "Woche drucken / exportieren" : "Print / export week"}><Printer size={17} /></button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* User Menu */}
|
{/* User Menu */}
|
||||||
<UserMenu
|
<UserMenu
|
||||||
@ -8031,7 +8067,7 @@ export default function WeeklyView() {
|
|||||||
{/* Resize handle - on top border of someday section */}
|
{/* Resize handle - on top border of someday section */}
|
||||||
{somedayExpanded && (
|
{somedayExpanded && (
|
||||||
<div
|
<div
|
||||||
className="resize-handle"
|
className="resize-handle resize-handle-anyday"
|
||||||
onMouseDown={(e) => startResize(e, 'someday', true)}
|
onMouseDown={(e) => startResize(e, 'someday', true)}
|
||||||
onTouchStart={(e) => startResize(e, 'someday', true)}
|
onTouchStart={(e) => startResize(e, 'someday', true)}
|
||||||
>
|
>
|
||||||
@ -11782,5 +11818,3 @@ function NotesSidebar({ task, onClose, updateTaskNotes, updateTaskUrl }: NotesSi
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user