feat: view switcher improvements, header month option, kanban date/time, mobile fixes
- Swap simple/calendar icons in header view switcher - Add calendar view button to header view switcher - Reorder header: view switcher first, then days, hours, slot duration - Add header display setting: calendar week (KW) or month name - Show kanban stage color border on GridTaskBlock (week/simple views) - Show date, weekday, and time on kanban cards - Remove task swipe gestures on mobile (use container swipe for day nav) - Fix mobile landscape 3-day grid overflow - Add headerDisplay to schema, API, and settings UI v1.30.0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8703239f0f
commit
329f082ecf
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.29.0",
|
||||
"version": "1.30.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": {
|
||||
|
||||
@ -76,6 +76,7 @@ model User {
|
||||
mobileDateLayout String @default("below")
|
||||
dateAlignment String @default("center")
|
||||
dateVerticalAlign String? @default("middle")
|
||||
headerDisplay String? @default("kw")
|
||||
hourLabelFormat String @default("short")
|
||||
showSubHourSlots Boolean @default(true)
|
||||
allDayPosition String @default("above")
|
||||
|
||||
@ -45,6 +45,7 @@ export async function GET(request: NextRequest) {
|
||||
dateLayout: true,
|
||||
mobileDateLayout: true,
|
||||
dateVerticalAlign: true,
|
||||
headerDisplay: true,
|
||||
headlineFont: true,
|
||||
headlineFontSize: true,
|
||||
headlineFontWeight: true,
|
||||
@ -127,7 +128,7 @@ export async function PATCH(request: NextRequest) {
|
||||
weekdayColor, dateColor, taskColor, todayHighlightColor,
|
||||
pastDayColor, goalFallbackType, goalDefaultSentence,
|
||||
goalFontFamily, goalFontSize, goalFontWeight, goalScope,
|
||||
dateLayout, mobileDateLayout, dateVerticalAlign,
|
||||
dateLayout, mobileDateLayout, dateVerticalAlign, headerDisplay,
|
||||
hourLabelFormat, showSubHourSlots, allDayPosition,
|
||||
cwFontFamily, cwFontSize, cwFontWeight, cwColor,
|
||||
yearFontFamily, yearFontSize, yearFontWeight, yearColor,
|
||||
@ -192,6 +193,7 @@ export async function PATCH(request: NextRequest) {
|
||||
...(dateLayout !== undefined && { dateLayout }),
|
||||
...(mobileDateLayout !== undefined && { mobileDateLayout }),
|
||||
...(dateVerticalAlign !== undefined && { dateVerticalAlign }),
|
||||
...(headerDisplay !== undefined && { headerDisplay }),
|
||||
...(hourLabelFormat !== undefined && { hourLabelFormat }),
|
||||
...(showSubHourSlots !== undefined && { showSubHourSlots }),
|
||||
...(allDayPosition !== undefined && { allDayPosition }),
|
||||
@ -282,6 +284,7 @@ export async function PATCH(request: NextRequest) {
|
||||
dateLayout: true,
|
||||
mobileDateLayout: true,
|
||||
dateVerticalAlign: true,
|
||||
headerDisplay: true,
|
||||
cwFontFamily: true,
|
||||
cwFontSize: true,
|
||||
cwFontWeight: true,
|
||||
|
||||
@ -1855,6 +1855,11 @@ h3 {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.kanban-card-time {
|
||||
font-weight: 600;
|
||||
color: var(--weekly-text, #555);
|
||||
}
|
||||
|
||||
.kanban-card-project {
|
||||
font-size: 0.7rem;
|
||||
margin-top: 2px;
|
||||
@ -2233,6 +2238,16 @@ h3 {
|
||||
.side-nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Ensure grid respects viewDays columns on mobile landscape */
|
||||
.time-grid-wrapper {
|
||||
overflow: visible;
|
||||
min-width: 0;
|
||||
}
|
||||
.time-grid-wrapper .weekly-days-grid {
|
||||
overflow: visible;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* === Phone portrait (≤ 480px): 1-day view === */
|
||||
|
||||
@ -3,7 +3,7 @@ import { Repeat, Circle, X } from "lucide-react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faGoogle, faMicrosoft, faApple } from "@fortawesome/free-brands-svg-icons";
|
||||
import { faServer } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Task } from "./WeeklyView";
|
||||
import { Task, KanbanStage } from "./WeeklyView";
|
||||
|
||||
interface GridTaskBlockProps {
|
||||
task: Task;
|
||||
@ -35,6 +35,7 @@ interface GridTaskBlockProps {
|
||||
showTaskCheckboxes?: boolean;
|
||||
projects?: any[];
|
||||
onProjectAssign?: (taskId: string, projectId: string | null) => void;
|
||||
kanbanStages?: KanbanStage[];
|
||||
}
|
||||
|
||||
export function GridTaskBlock({
|
||||
@ -66,7 +67,8 @@ export function GridTaskBlock({
|
||||
workingHoursStart,
|
||||
showTaskCheckboxes,
|
||||
projects,
|
||||
onProjectAssign
|
||||
onProjectAssign,
|
||||
kanbanStages = []
|
||||
}: GridTaskBlockProps) {
|
||||
const [isNotesOpen, setIsNotesOpen] = useState(false);
|
||||
const [notesValue, setNotesValue] = useState(task.markdownContent || "");
|
||||
@ -198,9 +200,14 @@ export function GridTaskBlock({
|
||||
zIndex: isResizing || isNotesOpen || isSubTasksOpen ? 10 : 5,
|
||||
background: (isNotesOpen || isSubTasksOpen || isResizing) ? (darkMode ? "#2a2a2a" : "#ffffff") : "transparent",
|
||||
border: (isNotesOpen || isSubTasksOpen || isResizing) ? `1px solid ${darkMode ? "#404040" : "#e0e0e0"}` : "none",
|
||||
borderLeft: task.project?.color ? `4px solid ${task.project.color}` : (isNotesOpen || isSubTasksOpen || isResizing) ? `1px solid ${darkMode ? "#404040" : "#e0e0e0"}` : "none",
|
||||
borderLeft: (() => {
|
||||
const stageColor = task.kanbanStage ? kanbanStages.find(s => s.id === task.kanbanStage)?.color : null;
|
||||
if (stageColor) return `4px solid ${stageColor}`;
|
||||
if (task.project?.color) return `4px solid ${task.project.color}`;
|
||||
return (isNotesOpen || isSubTasksOpen || isResizing) ? `1px solid ${darkMode ? "#404040" : "#e0e0e0"}` : "none";
|
||||
})(),
|
||||
borderRadius: (isNotesOpen || isSubTasksOpen || isResizing) ? "4px" : "0",
|
||||
padding: task.project?.color ? "2px 4px 2px 8px" : "2px 4px",
|
||||
padding: (task.kanbanStage && kanbanStages.some(s => s.id === task.kanbanStage)) || task.project?.color ? "2px 4px 2px 8px" : "2px 4px",
|
||||
boxShadow: (isNotesOpen || isSubTasksOpen || isResizing) ? "0 1px 3px rgba(0,0,0,0.05)" : "none",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
|
||||
@ -258,6 +258,9 @@ const translations: Record<string, any> = {
|
||||
addStage: "Add stage",
|
||||
stageName: "Stage name",
|
||||
noStage: "No stage",
|
||||
headerDisplay: "Header Display",
|
||||
headerDisplayKW: "Calendar Week (KW)",
|
||||
headerDisplayMonth: "Month Name",
|
||||
language: "Language",
|
||||
dateFormat: "Date Format",
|
||||
timeFormat: "Time Format",
|
||||
@ -461,6 +464,9 @@ const translations: Record<string, any> = {
|
||||
addStage: "Phase hinzufügen",
|
||||
stageName: "Phasenname",
|
||||
noStage: "Keine Phase",
|
||||
headerDisplay: "Kopfzeile",
|
||||
headerDisplayKW: "Kalenderwoche (KW)",
|
||||
headerDisplayMonth: "Monatsname",
|
||||
listView: "Liste",
|
||||
notes: "Notizen",
|
||||
notesSidebar: "Notizen-Seitenleiste",
|
||||
@ -667,6 +673,9 @@ const translations: Record<string, any> = {
|
||||
addStage: "Ajouter une étape",
|
||||
stageName: "Nom de l'étape",
|
||||
noStage: "Aucune étape",
|
||||
headerDisplay: "Affichage en-tête",
|
||||
headerDisplayKW: "Semaine calendaire (KW)",
|
||||
headerDisplayMonth: "Nom du mois",
|
||||
language: "Langue",
|
||||
dateFormat: "Format de date",
|
||||
timeFormat: "Format d'heure",
|
||||
@ -871,6 +880,9 @@ const translations: Record<string, any> = {
|
||||
addStage: "Añadir etapa",
|
||||
stageName: "Nombre de etapa",
|
||||
noStage: "Sin etapa",
|
||||
headerDisplay: "Visualización de encabezado",
|
||||
headerDisplayKW: "Semana calendario (KW)",
|
||||
headerDisplayMonth: "Nombre del mes",
|
||||
language: "Idioma",
|
||||
dateFormat: "Formato de fecha",
|
||||
timeFormat: "Formato de hora",
|
||||
@ -1075,6 +1087,9 @@ const translations: Record<string, any> = {
|
||||
addStage: "Aggiungi fase",
|
||||
stageName: "Nome fase",
|
||||
noStage: "Nessuna fase",
|
||||
headerDisplay: "Visualizzazione intestazione",
|
||||
headerDisplayKW: "Settimana calendario (KW)",
|
||||
headerDisplayMonth: "Nome del mese",
|
||||
language: "Lingua",
|
||||
dateFormat: "Formato data",
|
||||
timeFormat: "Formato ora",
|
||||
@ -1756,6 +1771,7 @@ export default function WeeklyView() {
|
||||
weekdayCase?: "normal" | "capitalize" | "uppercase";
|
||||
customWeekdayNames?: string;
|
||||
dateVerticalAlign?: "top" | "middle" | "bottom";
|
||||
headerDisplay?: "kw" | "month";
|
||||
}>({
|
||||
name: session?.user?.name || "",
|
||||
email: session?.user?.email || "",
|
||||
@ -1903,7 +1919,7 @@ export default function WeeklyView() {
|
||||
const [isSearchOpen, setIsSearchOpen] = useState(false);
|
||||
const [isRecurringTasksOpen, setIsRecurringTasksOpen] = useState(false);
|
||||
const [showDatePicker, setShowDatePicker] = useState(false);
|
||||
const datePickerBtnRef = useRef<HTMLButtonElement>(null);
|
||||
const datePickerBtnRef = useRef<HTMLDivElement>(null);
|
||||
const [showQuickSettings, setShowQuickSettings] = useState(false);
|
||||
|
||||
const [focusTimerDuration, setFocusTimerDuration] = useState(25);
|
||||
@ -5454,29 +5470,39 @@ export default function WeeklyView() {
|
||||
|
||||
{/* Desktop Header: Left, Center, Right */}
|
||||
<header className="group relative flex items-center justify-between w-full px-4 py-2 border-b border-gray-200 bg-white dark:bg-gray-900 dark:border-gray-700 dark:text-white transition-colors duration-200" style={isMobile ? { display: "none" } : {}}>
|
||||
{/* LEFT SECTION: Slot Duration & Days to Show */}
|
||||
{/* LEFT SECTION: View Switcher, Days, Hours, Slot Duration */}
|
||||
<div className="weekly-header-controls flex items-center gap-4 transition-opacity duration-300 opacity-0 group-hover:opacity-100" style={{ zIndex: 1 }}>
|
||||
{/* Slot Duration */}
|
||||
{showTimeGrid && (
|
||||
<div
|
||||
className="flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1"
|
||||
title="Slot Duration"
|
||||
{/* View Switcher */}
|
||||
<div className="flex items-center gap-0.5 bg-gray-100 dark:bg-gray-800 rounded p-0.5" title={t.viewStyle}>
|
||||
<button
|
||||
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"}`}
|
||||
title={t.simpleView}
|
||||
>
|
||||
<Clock size={16} className="text-gray-500 mr-1" />
|
||||
{[15, 30, 60].map((duration) => (
|
||||
<button
|
||||
key={duration}
|
||||
onClick={() => {
|
||||
setCellDuration(duration as CellDuration);
|
||||
saveSetting("cellDuration", duration);
|
||||
}}
|
||||
className={`px-2 py-0.5 text-xs rounded transition-colors ${cellDuration === duration ? "bg-white shadow-sm font-bold text-black" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||
>
|
||||
{duration}m
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<Calendar size={16} />
|
||||
</button>
|
||||
<button
|
||||
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"}`}
|
||||
title={t.calendarView}
|
||||
>
|
||||
<CalendarDays size={16} />
|
||||
</button>
|
||||
<button
|
||||
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"}`}
|
||||
title={t.listView}
|
||||
>
|
||||
<ListTodo size={16} />
|
||||
</button>
|
||||
<button
|
||||
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"}`}
|
||||
title={t.kanbanView}
|
||||
>
|
||||
<Kanban size={16} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Days to Show */}
|
||||
<div
|
||||
@ -5542,30 +5568,27 @@ export default function WeeklyView() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* View Switcher */}
|
||||
<div className="flex items-center gap-0.5 bg-gray-100 dark:bg-gray-800 rounded p-0.5" title={t.viewStyle}>
|
||||
<button
|
||||
onClick={() => { setViewStyle("simple"); saveSetting("viewStyle", "simple"); }}
|
||||
className={`p-1.5 rounded transition-colors ${viewStyle !== "kanban" && 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.weekView}
|
||||
{/* Slot Duration */}
|
||||
{showTimeGrid && (
|
||||
<div
|
||||
className="flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1"
|
||||
title="Slot Duration"
|
||||
>
|
||||
<CalendarDays size={16} />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => { setViewStyle("list"); saveSetting("viewStyle", "list"); }}
|
||||
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"}`}
|
||||
title={t.listView}
|
||||
>
|
||||
<ListTodo size={16} />
|
||||
</button>
|
||||
<button
|
||||
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"}`}
|
||||
title={t.kanbanView}
|
||||
>
|
||||
<Kanban size={16} />
|
||||
</button>
|
||||
</div>
|
||||
<Clock size={16} className="text-gray-500 mr-1" />
|
||||
{[15, 30, 60].map((duration) => (
|
||||
<button
|
||||
key={duration}
|
||||
onClick={() => {
|
||||
setCellDuration(duration as CellDuration);
|
||||
saveSetting("cellDuration", duration);
|
||||
}}
|
||||
className={`px-2 py-0.5 text-xs rounded transition-colors ${cellDuration === duration ? "bg-white shadow-sm font-bold text-black" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||
>
|
||||
{duration}m
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
@ -5573,16 +5596,13 @@ export default function WeeklyView() {
|
||||
<div className="flex items-center justify-center gap-6 absolute left-1/2 transform -translate-x-1/2 group z-10 opacity-100" style={{ pointerEvents: "auto" }}>
|
||||
{/* Week & Year */}
|
||||
<div className="whitespace-nowrap flex items-center gap-2">
|
||||
{/* Date Picker Toggle - Moved to front */}
|
||||
<div className="relative">
|
||||
<button
|
||||
ref={datePickerBtnRef}
|
||||
className={`p-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-md transition-colors ${showDatePicker ? "text-teal-600 bg-teal-50 opacity-100" : "text-gray-500 hover:text-black opacity-0 group-hover:opacity-100"}`}
|
||||
onClick={() => setShowDatePicker(!showDatePicker)}
|
||||
title="Jump to date"
|
||||
>
|
||||
<Calendar size={18} />
|
||||
</button>
|
||||
{/* Clickable Week & Year */}
|
||||
<div
|
||||
ref={datePickerBtnRef}
|
||||
className="relative flex items-center gap-2 cursor-pointer hover:opacity-80"
|
||||
onClick={() => setShowDatePicker(!showDatePicker)}
|
||||
title="Jump to date"
|
||||
>
|
||||
{showDatePicker && (
|
||||
<SimpleDatePicker
|
||||
selected={currentWeekStart}
|
||||
@ -5595,14 +5615,6 @@ export default function WeeklyView() {
|
||||
anchorRef={datePickerBtnRef}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Clickable Week & Year */}
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer hover:opacity-80"
|
||||
onClick={() => setShowDatePicker(!showDatePicker)}
|
||||
title="Jump to date"
|
||||
>
|
||||
<span style={{
|
||||
fontFamily: profile.cwFontFamily || "Inter",
|
||||
fontSize: profile.cwFontSize || "1.125rem",
|
||||
@ -5610,7 +5622,10 @@ export default function WeeklyView() {
|
||||
color: adjustColorForDarkMode(profile.cwColor || "#333333", darkMode),
|
||||
filter: "brightness(var(--weekly-header-brightness, 1))"
|
||||
}}>
|
||||
KW {getWeekNumber(getCWReferenceDate(getVisibleDays())).toString().padStart(2, "0")}
|
||||
{profile.headerDisplay === "month"
|
||||
? getCWReferenceDate(getVisibleDays()).toLocaleDateString(language, { month: "long" })
|
||||
: `KW ${getWeekNumber(getCWReferenceDate(getVisibleDays())).toString().padStart(2, "0")}`
|
||||
}
|
||||
</span>
|
||||
<span className="text-gray-400">|</span>
|
||||
<span
|
||||
@ -5962,9 +5977,10 @@ export default function WeeklyView() {
|
||||
{task.title}
|
||||
</span>
|
||||
</div>
|
||||
{task.scheduledDate && (
|
||||
{(task.scheduledDate || task.startTime) && (
|
||||
<div className="kanban-card-date">
|
||||
{new Date(task.scheduledDate).toLocaleDateString(language, { month: "short", day: "numeric" })}
|
||||
{task.scheduledDate && new Date(task.scheduledDate).toLocaleDateString(language, { weekday: "short", month: "short", day: "numeric" })}
|
||||
{task.startTime && <span className="kanban-card-time"> {task.startTime}</span>}
|
||||
</div>
|
||||
)}
|
||||
{task.project && (
|
||||
@ -6410,6 +6426,7 @@ export default function WeeklyView() {
|
||||
showTaskCheckboxes={profile.showTaskCheckboxes}
|
||||
projects={projects}
|
||||
onProjectAssign={assignProject}
|
||||
kanbanStages={kanbanStages}
|
||||
/>
|
||||
))}
|
||||
{visibleSlots.map((slot) => {
|
||||
@ -8365,36 +8382,8 @@ function TaskItem({
|
||||
onEdit();
|
||||
}
|
||||
}}
|
||||
onTouchStart={(e) => {
|
||||
const touch = e.touches[0];
|
||||
swipeTouchStart.current = { x: touch.clientX, y: touch.clientY, swiping: false };
|
||||
setSwipeX(0);
|
||||
}}
|
||||
onTouchMove={(e) => {
|
||||
const touch = e.touches[0];
|
||||
const dx = touch.clientX - swipeTouchStart.current.x;
|
||||
const dy = touch.clientY - swipeTouchStart.current.y;
|
||||
// Only swipe if horizontal dominant and past 10px threshold
|
||||
if (!swipeTouchStart.current.swiping && Math.abs(dx) > 10 && Math.abs(dx) > Math.abs(dy) * 1.5) {
|
||||
swipeTouchStart.current.swiping = true;
|
||||
}
|
||||
if (swipeTouchStart.current.swiping) {
|
||||
e.preventDefault();
|
||||
setSwipeX(dx);
|
||||
}
|
||||
}}
|
||||
onTouchEnd={() => {
|
||||
if (Math.abs(swipeX) > 80) {
|
||||
if (swipeX > 0) {
|
||||
// Swipe right: toggle complete
|
||||
onToggle();
|
||||
} else {
|
||||
// Swipe left: delete
|
||||
onDelete();
|
||||
}
|
||||
}
|
||||
setSwipeX(0);
|
||||
swipeTouchStart.current.swiping = false;
|
||||
onTouchStart={() => {
|
||||
// No task-level swipe — container handles day navigation
|
||||
}}
|
||||
>
|
||||
{/* Swipe indicators */}
|
||||
@ -9565,6 +9554,7 @@ function SettingsSidebar({
|
||||
weekdayCase?: "normal" | "capitalize" | "uppercase";
|
||||
customWeekdayNames?: string;
|
||||
dateVerticalAlign?: "top" | "middle" | "bottom";
|
||||
headerDisplay?: "kw" | "month";
|
||||
}>({
|
||||
name: "",
|
||||
email: "",
|
||||
@ -10680,6 +10670,27 @@ function SettingsSidebar({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Header Display */}
|
||||
<div style={{ marginTop: "16px" }}>
|
||||
<label style={{ fontSize: "0.85rem", fontWeight: 600, color: "var(--weekly-settings-label)" }}>
|
||||
{t.headerDisplay}
|
||||
</label>
|
||||
<div className="flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1 mt-1" style={{ width: "fit-content" }}>
|
||||
<button
|
||||
onClick={() => setProfile({ ...profile, headerDisplay: "kw" })}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${(profile.headerDisplay || "kw") === "kw" ? "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.headerDisplayKW}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setProfile({ ...profile, headerDisplay: "month" })}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${profile.headerDisplay === "month" ? "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.headerDisplayMonth}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Kanban Stages Settings */}
|
||||
<div style={{ marginTop: "24px", borderTop: "1px solid var(--border-color, #e5e7eb)", paddingTop: "16px" }}>
|
||||
<h4 style={{ fontSize: "0.95rem", fontWeight: 700, marginBottom: "8px", display: "flex", alignItems: "center", gap: "6px" }}>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user