feat: view style tabs at top of settings as per-view context
Move view style selector (Simple/Calendar/List/Kanban) to the top of the general settings tab. Settings below now automatically apply to the selected view. Replaces the previous per-view badge approach with a cleaner tab-based UI: switch to a view tab, adjust its settings — done. Per-view settings: hour format, sub-hour labels, weather, checkboxes. v1.50.0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3eff24143c
commit
a26dc5efa6
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.49.1",
|
||||
"version": "1.50.0",
|
||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -8514,10 +8514,7 @@ export default function WeeklyView() {
|
||||
onEndHourChange: (h: number) => { setEndHour(h); saveSetting("endHour", h); },
|
||||
}}
|
||||
perView={{
|
||||
isPerView: isPerView as any,
|
||||
togglePerView: togglePerView as any,
|
||||
saveViewSetting: saveViewSetting as any,
|
||||
viewLabel: viewStyle === "simple" ? (language === "de" ? "Einfach" : "Simple") : viewStyle === "calendar" ? (language === "de" ? "Kalender" : "Calendar") : viewStyle === "list" ? (language === "de" ? "Liste" : "List") : "Kanban",
|
||||
}}
|
||||
/>
|
||||
)
|
||||
@ -10055,10 +10052,7 @@ interface SettingsSidebarProps {
|
||||
onEndHourChange: (h: number) => void;
|
||||
};
|
||||
perView: {
|
||||
isPerView: (key: string) => boolean;
|
||||
togglePerView: (key: string, globalVal: any) => void;
|
||||
saveViewSetting: (key: string, value: any, perView: boolean) => void;
|
||||
viewLabel: string;
|
||||
};
|
||||
}
|
||||
// Notes Sidebar Component
|
||||
@ -10286,31 +10280,6 @@ function SettingsSidebar({
|
||||
mobileActions,
|
||||
perView,
|
||||
}: SettingsSidebarProps) {
|
||||
// Per-view badge: shows which view a setting applies to, click to toggle
|
||||
const PerViewBadge = ({ settingKey, globalVal }: { settingKey: string; globalVal: any }) => {
|
||||
const isPV = perView.isPerView(settingKey);
|
||||
return (
|
||||
<button
|
||||
onClick={() => perView.togglePerView(settingKey, globalVal)}
|
||||
title={isPV ? (profile.language === "de" ? `Nur für ${perView.viewLabel} — klicken für alle Ansichten` : `Only for ${perView.viewLabel} — click for all views`) : (profile.language === "de" ? `Alle Ansichten — klicken für nur ${perView.viewLabel}` : `All views — click for ${perView.viewLabel} only`)}
|
||||
style={{
|
||||
fontSize: "0.55rem",
|
||||
padding: "1px 5px",
|
||||
borderRadius: "8px",
|
||||
border: isPV ? "1px solid #6366f1" : "1px solid #d1d5db",
|
||||
background: isPV ? "#eef2ff" : "transparent",
|
||||
color: isPV ? "#6366f1" : "#9ca3af",
|
||||
cursor: "pointer",
|
||||
fontWeight: 600,
|
||||
whiteSpace: "nowrap" as const,
|
||||
marginLeft: "4px",
|
||||
}}
|
||||
>
|
||||
{isPV ? perView.viewLabel : (profile.language === "de" ? "Alle" : "All")}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
const [activeTab, setActiveTab] = useState<
|
||||
"calendar" | "general" | "account" | "styling" | "motivation" | "about" | "localisation"
|
||||
>(initialTab || "general");
|
||||
@ -10837,6 +10806,33 @@ function SettingsSidebar({
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "column", gap: "20px" }}
|
||||
>
|
||||
{/* View Style Tabs — at top, acts as context for per-view settings */}
|
||||
<div>
|
||||
<label style={{ display: "block", fontSize: "0.9rem", fontWeight: 600, marginBottom: "8px" }}>
|
||||
{t.viewStyle}
|
||||
</label>
|
||||
<div className="flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1" style={{ width: "fit-content" }}>
|
||||
<button onClick={() => { setViewStyle("simple"); setShowTimeGrid(true); saveSetting("viewStyle", "simple"); saveSetting("showTimeGrid", true); }}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${showTimeGrid && viewStyle === "simple" ? "bg-white shadow-sm font-bold 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"}`}>
|
||||
{t.simpleView}
|
||||
</button>
|
||||
<button onClick={() => { setViewStyle("calendar"); setShowTimeGrid(true); saveSetting("viewStyle", "calendar"); saveSetting("showTimeGrid", true); }}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${showTimeGrid && viewStyle === "calendar" ? "bg-white shadow-sm font-bold 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"}`}>
|
||||
{t.calendarView}
|
||||
</button>
|
||||
<button onClick={() => { setViewStyle("list"); setShowTimeGrid(false); saveSetting("viewStyle", "list"); saveSetting("showTimeGrid", false); }}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${!showTimeGrid && viewStyle === "list" ? "bg-white shadow-sm font-bold 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"}`}>
|
||||
{t.listView}
|
||||
</button>
|
||||
<button onClick={() => { setViewStyle("kanban"); saveSetting("viewStyle", "kanban"); }}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${viewStyle === "kanban" ? "bg-white shadow-sm font-bold 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"}`}>
|
||||
{t.kanbanView}
|
||||
</button>
|
||||
</div>
|
||||
<p style={{ fontSize: "0.7rem", color: "#9ca3af", marginTop: "4px" }}>
|
||||
{profile.language === "de" ? "Einstellungen unten gelten für diese Ansicht" : "Settings below apply to this view"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{ display: "flex", alignItems: "center", gap: "8px" }}
|
||||
@ -10960,18 +10956,15 @@ function SettingsSidebar({
|
||||
checked={profile.showTaskCheckboxes || false}
|
||||
onChange={(e) => {
|
||||
setProfile({ ...profile, showTaskCheckboxes: e.target.checked });
|
||||
if (perView.isPerView("showTaskCheckboxes")) {
|
||||
perView.saveViewSetting("showTaskCheckboxes", e.target.checked, true);
|
||||
}
|
||||
perView.saveViewSetting("showTaskCheckboxes", e.target.checked, true);
|
||||
}}
|
||||
style={{ width: "16px", height: "16px" }}
|
||||
/>
|
||||
<label
|
||||
htmlFor="showTaskCheckboxes"
|
||||
style={{ fontSize: "0.9rem", fontWeight: 600, display: "flex", alignItems: "center" }}
|
||||
style={{ fontSize: "0.9rem", fontWeight: 600 }}
|
||||
>
|
||||
{t.showTaskCheckboxes}
|
||||
<PerViewBadge settingKey="showTaskCheckboxes" globalVal={profile.showTaskCheckboxes} />
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
@ -11180,26 +11173,20 @@ function SettingsSidebar({
|
||||
<div style={{ marginTop: "4px" }}>
|
||||
<label
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
display: "block",
|
||||
fontSize: "0.9rem",
|
||||
fontWeight: 600,
|
||||
marginBottom: "4px",
|
||||
}}
|
||||
>
|
||||
{t.hourLabelFormat}
|
||||
<PerViewBadge settingKey="hourLabelFormat" globalVal={hourLabelFormat} />
|
||||
</label>
|
||||
<select
|
||||
value={hourLabelFormat}
|
||||
onChange={(e) => {
|
||||
const fmt = e.target.value as "short" | "full";
|
||||
setHourLabelFormat(fmt);
|
||||
if (perView.isPerView("hourLabelFormat")) {
|
||||
perView.saveViewSetting("hourLabelFormat", fmt, true);
|
||||
} else {
|
||||
saveSetting("hourLabelFormat", fmt);
|
||||
}
|
||||
perView.saveViewSetting("hourLabelFormat", fmt, true);
|
||||
}}
|
||||
className="weekly-input"
|
||||
style={{
|
||||
@ -11224,20 +11211,15 @@ function SettingsSidebar({
|
||||
checked={showSubHourSlots}
|
||||
onChange={(e) => {
|
||||
setShowSubHourSlots(e.target.checked);
|
||||
if (perView.isPerView("showSubHourSlots")) {
|
||||
perView.saveViewSetting("showSubHourSlots", e.target.checked, true);
|
||||
} else {
|
||||
saveSetting("showSubHourSlots", e.target.checked);
|
||||
}
|
||||
perView.saveViewSetting("showSubHourSlots", e.target.checked, true);
|
||||
}}
|
||||
style={{ width: "16px", height: "16px" }}
|
||||
/>
|
||||
<label
|
||||
htmlFor="showSubHourSlots"
|
||||
style={{ fontSize: "0.9rem", fontWeight: 600, display: "flex", alignItems: "center" }}
|
||||
style={{ fontSize: "0.9rem", fontWeight: 600 }}
|
||||
>
|
||||
{t.showSubhourLabels}
|
||||
<PerViewBadge settingKey="showSubHourSlots" globalVal={showSubHourSlots} />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -11246,66 +11228,6 @@ function SettingsSidebar({
|
||||
|
||||
|
||||
|
||||
<div style={{ marginTop: "16px" }}>
|
||||
<label
|
||||
style={{
|
||||
display: "block",
|
||||
fontSize: "0.9rem",
|
||||
fontWeight: 600,
|
||||
marginBottom: "8px",
|
||||
}}
|
||||
>
|
||||
{t.viewStyle}
|
||||
</label>
|
||||
<div
|
||||
className="flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1"
|
||||
style={{ width: "fit-content" }}
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
setViewStyle("simple");
|
||||
setShowTimeGrid(true);
|
||||
saveSetting("viewStyle", "simple");
|
||||
saveSetting("showTimeGrid", true);
|
||||
}}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${showTimeGrid && viewStyle === "simple" ? "bg-white shadow-sm font-bold text-black" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||
>
|
||||
{t.simpleView}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setViewStyle("calendar");
|
||||
setShowTimeGrid(true);
|
||||
saveSetting("viewStyle", "calendar");
|
||||
saveSetting("showTimeGrid", true);
|
||||
}}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${showTimeGrid && viewStyle === "calendar" ? "bg-white shadow-sm font-bold text-black" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||
>
|
||||
{t.calendarView}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setViewStyle("list");
|
||||
setShowTimeGrid(false);
|
||||
saveSetting("viewStyle", "list");
|
||||
saveSetting("showTimeGrid", false);
|
||||
}}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${!showTimeGrid && viewStyle === "list" ? "bg-white shadow-sm font-bold text-black" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||
>
|
||||
{t.listView}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setViewStyle("kanban");
|
||||
saveSetting("viewStyle", "kanban");
|
||||
}}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${viewStyle === "kanban" ? "bg-white shadow-sm font-bold text-black" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||
>
|
||||
{t.kanbanView}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Header Display */}
|
||||
<div style={{ marginTop: "16px" }}>
|
||||
<label style={{ fontSize: "0.85rem", fontWeight: 600, color: "var(--weekly-settings-label)" }}>
|
||||
@ -11368,17 +11290,12 @@ function SettingsSidebar({
|
||||
checked={profile.weatherEnabled || false}
|
||||
onChange={(e) => {
|
||||
setProfile({ ...profile, weatherEnabled: e.target.checked });
|
||||
if (perView.isPerView("weatherEnabled")) {
|
||||
perView.saveViewSetting("weatherEnabled", e.target.checked, true);
|
||||
} else {
|
||||
saveSetting("weatherEnabled", e.target.checked);
|
||||
}
|
||||
perView.saveViewSetting("weatherEnabled", e.target.checked, true);
|
||||
}}
|
||||
style={{ width: "18px", height: "18px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "0.85rem", fontWeight: 500, display: "flex", alignItems: "center" }}>
|
||||
<span style={{ fontSize: "0.85rem", fontWeight: 500 }}>
|
||||
{profile.language === "de" ? "Wetter anzeigen" : "Show weather"}
|
||||
<PerViewBadge settingKey="weatherEnabled" globalVal={profile.weatherEnabled} />
|
||||
</span>
|
||||
</label>
|
||||
{profile.weatherEnabled && (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user