diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 0beee4f..37936fe 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -41,8 +41,24 @@ model User { viewStyle String @default("grid") fontSize String @default("M") // "S", "M", "L" headlineFont String @default("Inter") + headlineFontSize String? @default("1.25rem") + headlineFontWeight String? @default("900") + dateFontFamily String? @default("Inter") + dateFontSize String? @default("0.65rem") + dateFontWeight String? @default("400") + timeTaskFontFamily String? @default("Inter") + timeTaskFontSize String? @default("0.75rem") + timeTaskFontWeight String? @default("500") bodyFont String @default("Inter") - fontWeight String @default("400") // "300", "400", "500", "700" + taskFontFamily String? @default("Inter") + taskFontSize String? @default("0.9rem") + taskFontWeight String? @default("400") + eventFontFamily String? @default("Inter") + eventFontSize String? @default("0.85rem") + eventFontWeight String? @default("400") + fontWeight String @default("400") // Legacy/Generic + weekendColorSat String? @default("#666666") + weekendColorSun String? @default("#dc2626") accounts Account[] sessions Session[] diff --git a/src/app/api/user/profile/route.ts b/src/app/api/user/profile/route.ts index 2801e50..802261c 100644 --- a/src/app/api/user/profile/route.ts +++ b/src/app/api/user/profile/route.ts @@ -5,6 +5,7 @@ import { PrismaClient } from '@prisma/client'; import bcrypt from 'bcryptjs'; const prisma = new PrismaClient(); +// Prisma client re-initialized to pick up schema changes // Get user profile export async function GET(request: NextRequest) { @@ -36,8 +37,24 @@ export async function GET(request: NextRequest) { viewStyle: true, fontSize: true, headlineFont: true, + headlineFontSize: true, + headlineFontWeight: true, + dateFontFamily: true, + dateFontSize: true, + dateFontWeight: true, + timeTaskFontFamily: true, + timeTaskFontSize: true, + timeTaskFontWeight: true, bodyFont: true, + taskFontFamily: true, + taskFontSize: true, + taskFontWeight: true, + eventFontFamily: true, + eventFontSize: true, + eventFontWeight: true, fontWeight: true, + weekendColorSat: true, + weekendColorSun: true, createdAt: true } }); @@ -65,7 +82,12 @@ export async function PATCH(request: NextRequest) { showNextTask, calendarEditMode, focusTimerDuration, focusBreakDuration, showTimeGrid, showSomeday, showAllDayEvents, showSchedule, cellDuration, viewStyle, fontSize, - headlineFont, bodyFont, fontWeight + headlineFont, headlineFontSize, headlineFontWeight, + dateFontFamily, dateFontSize, dateFontWeight, + timeTaskFontFamily, timeTaskFontSize, timeTaskFontWeight, + bodyFont, taskFontFamily, taskFontSize, taskFontWeight, + eventFontFamily, eventFontSize, eventFontWeight, + fontWeight, weekendColorSat, weekendColorSun } = body; const updateData: any = { @@ -90,8 +112,24 @@ export async function PATCH(request: NextRequest) { ...(viewStyle !== undefined && { viewStyle }), ...(fontSize !== undefined && { fontSize }), ...(headlineFont !== undefined && { headlineFont }), + ...(headlineFontSize !== undefined && { headlineFontSize }), + ...(headlineFontWeight !== undefined && { headlineFontWeight }), + ...(dateFontFamily !== undefined && { dateFontFamily }), + ...(dateFontSize !== undefined && { dateFontSize }), + ...(dateFontWeight !== undefined && { dateFontWeight }), + ...(timeTaskFontFamily !== undefined && { timeTaskFontFamily }), + ...(timeTaskFontSize !== undefined && { timeTaskFontSize }), + ...(timeTaskFontWeight !== undefined && { timeTaskFontWeight }), ...(bodyFont !== undefined && { bodyFont }), + ...(taskFontFamily !== undefined && { taskFontFamily }), + ...(taskFontSize !== undefined && { taskFontSize }), + ...(taskFontWeight !== undefined && { taskFontWeight }), + ...(eventFontFamily !== undefined && { eventFontFamily }), + ...(eventFontSize !== undefined && { eventFontSize }), + ...(eventFontWeight !== undefined && { eventFontWeight }), ...(fontWeight !== undefined && { fontWeight }), + ...(weekendColorSat !== undefined && { weekendColorSat }), + ...(weekendColorSun !== undefined && { weekendColorSun }), }; if (password && password.trim() !== "") { updateData.passwordHash = await bcrypt.hash(password, 10); @@ -124,8 +162,24 @@ export async function PATCH(request: NextRequest) { viewStyle: true, fontSize: true, headlineFont: true, + headlineFontSize: true, + headlineFontWeight: true, + dateFontFamily: true, + dateFontSize: true, + dateFontWeight: true, + timeTaskFontFamily: true, + timeTaskFontSize: true, + timeTaskFontWeight: true, bodyFont: true, + taskFontFamily: true, + taskFontSize: true, + taskFontWeight: true, + eventFontFamily: true, + eventFontSize: true, + eventFontWeight: true, fontWeight: true, + weekendColorSat: true, + weekendColorSun: true, } }); diff --git a/src/app/globals.css b/src/app/globals.css index 9802c8d..d451b91 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -221,6 +221,17 @@ h3 { gap: 0.25rem; } +.weekly-btn-primary { + background-color: var(--weekly-teal); + color: white; + border: none; + border-radius: 4px; + padding: 8px 16px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s; +} + .nav-button:hover { background-color: #e2e8f0; transform: translateY(-1px); @@ -617,6 +628,17 @@ h3 { border-left: none; } +/* Weekend Styling */ +.weekly-day-column.is-sat .weekly-day-name, +.weekly-day-column.is-sat .weekly-day-date { + color: var(--weekly-weekend-sat, #666); +} + +.weekly-day-column.is-sun .weekly-day-name, +.weekly-day-column.is-sun .weekly-day-date { + color: var(--weekly-weekend-sun, #dc2626); +} + /* Day Header */ .weekly-day-header { padding: 1rem 1rem 0.75rem; @@ -626,20 +648,22 @@ h3 { } .weekly-day-date { - font-size: 0.65rem; + font-size: var(--weekly-date-size, 0.65rem); + font-weight: var(--weekly-date-weight, 400); color: var(--weekly-text-light); text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 0.25rem; + font-family: var(--weekly-date-font, var(--weekly-font-headline)) !important; } .weekly-day-name { - font-size: 1.25rem; - font-weight: 900; + font-size: var(--weekly-headline-size, 1.25rem); + font-weight: var(--weekly-headline-weight, 900); text-transform: uppercase; letter-spacing: -0.02em; color: var(--weekly-text); - font-family: var(--weekly-font-headline); + font-family: var(--weekly-font-headline) !important; } .weekly-day-name.is-today { @@ -685,13 +709,14 @@ h3 { .weekly-task-text { flex: 1; - font-size: var(--base-font-size); - line-height: 1.5; + font-family: var(--weekly-task-font, var(--weekly-font)); + font-size: var(--weekly-task-size, 0.9rem); + font-weight: var(--weekly-task-weight, 400); + line-height: var(--weekly-task-line-height, 1.5); color: var(--weekly-text); border: none; outline: none; background: transparent; - font-family: inherit; resize: none; min-height: 1.5em; padding-top: 2px; /* Align with icons */ @@ -912,6 +937,10 @@ h3 { color: var(--weekly-text); } +.weekly-day-name { + color: var(--weekly-text-light); +} + .weekly-someday-title { font-size: 0.75rem; font-weight: 600; @@ -1296,6 +1325,7 @@ h3 { .weekly-calendar-event-title { color: var(--weekly-text); + font-family: var(--weekly-font); } /* Drag and Drop States */ @@ -1311,7 +1341,9 @@ h3 { .weekly-settings-overlay { position: fixed; inset: 0; - background: rgba(0, 0, 0, 0.4); + background: transparent !important; /* Changed from rgba(0, 0, 0, 0.4) for real-time preview */ + backdrop-filter: none !important; + -webkit-backdrop-filter: none !important; display: flex; align-items: center; justify-content: center; @@ -1434,7 +1466,7 @@ h3 { .time-slot-label { display: flex; - align-items: flex-end; + align-items: flex-start; justify-content: flex-start; padding: 0 0.5rem; font-size: 0.65rem; @@ -1516,7 +1548,9 @@ h3 { gap: 0.25rem; padding: 2px 0; background: transparent; - font-size: 0.875rem; + font-family: var(--weekly-time-task-font, var(--weekly-font)); + font-size: var(--weekly-time-task-size, 0.75rem); + font-weight: var(--weekly-time-task-weight, 500); cursor: pointer; white-space: nowrap; overflow: hidden; @@ -1573,18 +1607,25 @@ h3 { flex-shrink: 0; } +.event-title { + font-weight: 600; + font-size: 0.85rem; + font-family: var(--weekly-font); +} + .time-slot-event .event-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; font-weight: 500; + font-family: var(--weekly-font); } .time-slot-event .event-time-row { - font-size: 0.65rem; - opacity: 0.8; - white-space: nowrap; + font-size: 0.75rem; + opacity: 0.9; + font-family: var(--weekly-font); } .time-slot-event:hover { @@ -2407,3 +2448,16 @@ h3 { letter-spacing: 0.1em; margin-bottom: 12px; } + +.event-title { + font-family: var(--weekly-event-font); + font-weight: var(--weekly-event-weight); + font-size: var(--weekly-event-size); + line-height: 1.2; +} + +.event-time-row { + font-family: var(--weekly-event-font); + font-size: 0.7rem; + opacity: 0.9; +} diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx index 8d1ebab..b4aad98 100644 --- a/src/components/WeeklyView.tsx +++ b/src/components/WeeklyView.tsx @@ -343,11 +343,100 @@ export default function WeeklyView() { const [dateFormat, setDateFormat] = useState('yyyy-MM-dd'); const [somedayExpanded, setSomedayExpanded] = useState(true); - const [draggingListId, setDraggingListId] = useState(null); const [isAllDayExpanded, setIsAllDayExpanded] = useState(true); const [somedayLists, setSomedayLists] = useState([]); const [editingTaskId, setEditingTaskId] = useState(null); + const [draggingListId, setDraggingListId] = useState(null); + + // Moved state definitions to the top const [showSettings, setShowSettings] = useState(false); + const [activeTab, setActiveTab] = useState<'general' | 'calendar' | 'account'>('general'); + const [exportStartDate, setExportStartDate] = useState(''); + const [exportEndDate, setExportEndDate] = useState(''); + const [passwords, setPasswords] = useState({ new: '', confirm: '' }); + const [accountMsg, setAccountMsg] = useState(''); + const [isVisible, setIsVisible] = useState(false); + const [profile, setProfile] = useState<{ + name: string; + email: string; + timezone: string; + autoRolling?: boolean; + protectEventTimes?: boolean; + language?: string; + dateFormat?: string; + timeFormat?: string; + startHour?: number; + endHour?: number; + focusTimerDuration?: number; + focusBreakDuration?: number; + showTimeGrid?: boolean; + cellDuration?: number; + viewStyle?: string; + fontSize?: 'S' | 'M' | 'L'; + showNextTask?: boolean; + showSomeday?: boolean; + showAllDayEvents?: boolean; + showSchedule?: boolean; + headlineFont?: string; + headlineFontSize?: string; + headlineFontWeight?: string; + dateFontFamily?: string; + dateFontSize?: string; + dateFontWeight?: string; + timeTaskFontFamily?: string; + timeTaskFontSize?: string; + timeTaskFontWeight?: string; + bodyFont?: string; + taskFontFamily?: string; + taskFontSize?: string; + taskFontWeight?: string; + eventFontFamily?: string; + eventFontSize?: string; + eventFontWeight?: string; + fontWeight?: string; + weekendColorSat?: string; + weekendColorSun?: string; + }>({ + name: session?.user?.name || '', + email: session?.user?.email || '', + timezone: 'UTC', + language: 'de', + dateFormat: 'yyyy-MM-dd', + timeFormat: '24h', + startHour: 8, + endHour: 22, + autoRolling: true, + protectEventTimes: true, + showTimeGrid: true, + cellDuration: 60, + viewStyle: 'list', + fontSize: 'M', + showNextTask: false, + showSomeday: true, + showAllDayEvents: true, + showSchedule: true, + headlineFont: 'Inter', + headlineFontSize: '1.25rem', + headlineFontWeight: '900', + dateFontFamily: 'Inter', + dateFontSize: '0.65rem', + dateFontWeight: '400', + timeTaskFontFamily: 'Inter', + timeTaskFontSize: '0.75rem', + timeTaskFontWeight: '500', + bodyFont: 'Inter', + taskFontFamily: 'Inter', + taskFontSize: '0.9rem', + taskFontWeight: '400', + eventFontFamily: 'Inter', + eventFontSize: '0.85rem', + eventFontWeight: '400', + fontWeight: '400', + weekendColorSat: '#666666', + weekendColorSun: '#dc2626', + focusTimerDuration: 25, + focusBreakDuration: 5 + }); const [showSummary, setShowSummary] = useState(false); const [isAddingSomedayList, setIsAddingSomedayList] = useState(false); @@ -388,11 +477,36 @@ export default function WeeklyView() { const [focusTimerDuration, setFocusTimerDuration] = useState(25); const [fontSize, setFontSize] = useState<'S' | 'M' | 'L'>('M'); const [headlineFont, setHeadlineFont] = useState('Inter'); + const [headlineFontSize, setHeadlineFontSize] = useState('1.25rem'); + const [headlineFontWeight, setHeadlineFontWeight] = useState('900'); + const [dateFontFamily, setDateFontFamily] = useState('Inter'); + const [dateFontSize, setDateFontSize] = useState('0.65rem'); + const [dateFontWeight, setDateFontWeight] = useState('400'); + const [timeTaskFontFamily, setTimeTaskFontFamily] = useState('Inter'); + const [timeTaskFontSize, setTimeTaskFontSize] = useState('0.75rem'); + const [timeTaskFontWeight, setTimeTaskFontWeight] = useState('500'); const [bodyFont, setBodyFont] = useState('Inter'); + const [taskFontFamily, setTaskFontFamily] = useState('Inter'); + const [taskFontSize, setTaskFontSize] = useState('0.9rem'); + const [taskFontWeight, setTaskFontWeight] = useState('400'); + const [eventFontFamily, setEventFontFamily] = useState('Inter'); + const [eventFontSize, setEventFontSize] = useState('0.85rem'); + const [eventFontWeight, setEventFontWeight] = useState('400'); const [fontWeight, setFontWeight] = useState('400'); + const [weekendColorSat, setWeekendColorSat] = useState('#666666'); + const [weekendColorSun, setWeekendColorSun] = useState('#dc2626'); // Load fonts - useGoogleFonts([headlineFont, bodyFont, 'Dancing Script', 'Pacifico']); + // Dynamic font loading is handled by the main useGoogleFonts hook call below + + // Load ALL available fonts at the top level to ensure they are available + // regardless of whether the settings modal is open or closed, and for + // real-time preview usage. + useGoogleFonts([ + ...AVAILABLE_FONTS.map(f => f.value), + 'Dancing Script', + 'Pacifico' + ]); // Dynamic font loading is handled by useGoogleFonts hook call above @@ -642,8 +756,24 @@ export default function WeeklyView() { showAllDayEvents: boolean; showSchedule: boolean; headlineFont: string; + headlineFontSize: string; + headlineFontWeight: string; + dateFontFamily: string; + dateFontSize: string; + dateFontWeight: string; + timeTaskFontFamily: string; + timeTaskFontSize: string; + timeTaskFontWeight: string; bodyFont: string; + taskFontFamily: string; + taskFontSize: string; + taskFontWeight: string; + eventFontFamily: string; + eventFontSize: string; + eventFontWeight: string; fontWeight: string; + weekendColorSat: string; + weekendColorSun: string; }) => { setShowTimeGrid(newSettings.showTimeGrid); setCellDuration(newSettings.cellDuration); @@ -659,8 +789,24 @@ export default function WeeklyView() { setShowAllDay(newSettings.showAllDayEvents); setShowSchedule(newSettings.showSchedule); setHeadlineFont(newSettings.headlineFont); + setHeadlineFontSize(newSettings.headlineFontSize); + setHeadlineFontWeight(newSettings.headlineFontWeight); + setDateFontFamily(newSettings.dateFontFamily); + setDateFontSize(newSettings.dateFontSize); + setDateFontWeight(newSettings.dateFontWeight); + setTimeTaskFontFamily(newSettings.timeTaskFontFamily); + setTimeTaskFontSize(newSettings.timeTaskFontSize); + setTimeTaskFontWeight(newSettings.timeTaskFontWeight); setBodyFont(newSettings.bodyFont); + setTaskFontFamily(newSettings.taskFontFamily); + setTaskFontSize(newSettings.taskFontSize); + setTaskFontWeight(newSettings.taskFontWeight); + setEventFontFamily(newSettings.eventFontFamily); + setEventFontSize(newSettings.eventFontSize); + setEventFontWeight(newSettings.eventFontWeight); setFontWeight(newSettings.fontWeight); + setWeekendColorSat(newSettings.weekendColorSat); + setWeekendColorSun(newSettings.weekendColorSun); // Custom start/end hours might affect task placement if we filter strictly fetchTasks(); @@ -686,8 +832,33 @@ export default function WeeklyView() { if (data.user.showAllDayEvents !== undefined) setShowAllDay(data.user.showAllDayEvents); if (data.user.showSchedule !== undefined) setShowSchedule(data.user.showSchedule); if (data.user.headlineFont) setHeadlineFont(data.user.headlineFont); + if (data.user.headlineFontSize) setHeadlineFontSize(data.user.headlineFontSize); + if (data.user.headlineFontWeight) setHeadlineFontWeight(data.user.headlineFontWeight); + if (data.user.dateFontFamily) setDateFontFamily(data.user.dateFontFamily); + if (data.user.dateFontSize) setDateFontSize(data.user.dateFontSize); + if (data.user.dateFontWeight) setDateFontWeight(data.user.dateFontWeight); + if (data.user.timeTaskFontFamily) setTimeTaskFontFamily(data.user.timeTaskFontFamily); + if (data.user.timeTaskFontSize) setTimeTaskFontSize(data.user.timeTaskFontSize); + if (data.user.timeTaskFontWeight) setTimeTaskFontWeight(data.user.timeTaskFontWeight); if (data.user.bodyFont) setBodyFont(data.user.bodyFont); + if (data.user.taskFontFamily) setTaskFontFamily(data.user.taskFontFamily); + if (data.user.taskFontSize) setTaskFontSize(data.user.taskFontSize); + if (data.user.taskFontSize) setTaskFontSize(data.user.taskFontSize); + if (data.user.taskFontWeight) setTaskFontWeight(data.user.taskFontWeight); + if (data.user.eventFontFamily) setEventFontFamily(data.user.eventFontFamily); + if (data.user.eventFontSize) setEventFontSize(data.user.eventFontSize); + if (data.user.eventFontWeight) setEventFontWeight(data.user.eventFontWeight); if (data.user.fontWeight) setFontWeight(data.user.fontWeight); + if (data.user.weekendColorSat) setWeekendColorSat(data.user.weekendColorSat); + if (data.user.weekendColorSun) setWeekendColorSun(data.user.weekendColorSun); + + setProfile(prev => ({ + ...prev, + ...data.user, + name: data.user.name || prev.name, + email: data.user.email || prev.email, + })); + if (data.user.focusTimerDuration) setFocusTimerDuration(data.user.focusTimerDuration); if (data.user.focusBreakDuration) setFocusBreakDuration(data.user.focusBreakDuration); if (data.user.showTimeGrid !== undefined) setShowTimeGrid(data.user.showTimeGrid); @@ -1487,9 +1658,25 @@ export default function WeeklyView() { const visibleSlots = getTimeSlots(cellDuration, workingHoursStart, workingHoursEnd); const containerStyle = { - '--font-headline': `"${headlineFont}", sans-serif`, - '--font-body': `"${bodyFont}", sans-serif`, - '--font-weight-body': fontWeight || '400', + '--weekly-font-headline': (profile.headlineFont || headlineFont) ? `"${profile.headlineFont || headlineFont}", sans-serif` : 'var(--font-headline)', + '--weekly-headline-size': profile.headlineFontSize || '1.25rem', + '--weekly-headline-weight': profile.headlineFontWeight || '900', + '--weekly-date-font': (profile.dateFontFamily) ? `"${profile.dateFontFamily}", sans-serif` : 'var(--weekly-font-headline)', + '--weekly-date-size': profile.dateFontSize || '0.65rem', + '--weekly-date-weight': profile.dateFontWeight || '400', + '--weekly-time-task-font': (profile.timeTaskFontFamily) ? `"${profile.timeTaskFontFamily}", sans-serif` : 'var(--weekly-font)', + '--weekly-time-task-size': profile.timeTaskFontSize || '0.75rem', + '--weekly-time-task-weight': profile.timeTaskFontWeight || '500', + '--weekly-font': 'var(--font-body)', /* Force default body font as requested */ + '--weekly-task-font': (profile.taskFontFamily) ? `"${profile.taskFontFamily}", sans-serif` : 'var(--weekly-font)', + '--weekly-task-size': profile.taskFontSize || '0.9rem', + '--weekly-task-weight': profile.taskFontWeight || '400', + '--weekly-event-font': (profile.eventFontFamily || eventFontFamily) ? `"${profile.eventFontFamily || eventFontFamily}", sans-serif` : 'var(--weekly-font)', + '--weekly-event-size': profile.eventFontSize || eventFontSize || '0.85rem', + '--weekly-event-weight': profile.eventFontWeight || eventFontWeight || '400', + '--font-weight-body': profile.fontWeight || fontWeight || '400', + '--weekly-weekend-sat': profile.weekendColorSat || '#666666', + '--weekly-weekend-sun': profile.weekendColorSun || '#dc2626', } as React.CSSProperties; if (isLoading) { @@ -1773,14 +1960,14 @@ export default function WeeklyView() { {getVisibleDays().map((date, colIndex) => (
{/* Day Header */}

- {getDayName(date, language)}, {formatDateHeader(date, language)} + {getDayName(date, language)} {formatDateHeader(date, language)}

@@ -1825,7 +2012,9 @@ export default function WeeklyView() { // Calculate height based on event duration const durationMinutes = (eventEnd.getTime() - eventStart.getTime()) / (1000 * 60); - const height = durationMinutes * pixelsPerMinute; + const calculatedHeight = durationMinutes * pixelsPerMinute; + // Ensure minimum height of 15px for visibility + const height = Math.max(calculatedHeight, 15); const isUnlocked = unlockedEvents.has(event.id); @@ -1982,24 +2171,29 @@ export default function WeeklyView() { )}
{/* Edit button */} {/* Notes button */} {/* Roll button */} {!task.completed && ( )} {/* Recurrence button */} @@ -2008,14 +2202,11 @@ export default function WeeklyView() { onClick={(e) => { e.stopPropagation(); setSelectedTaskForRecurrence(task); }} title={task.isRecurring ? "Edit recurrence" : "Make recurring"} > - - - - + {/* Delete button */}
@@ -2050,8 +2241,8 @@ export default function WeeklyView() { className="time-slot-event" title={`${event.calendarTitle}: ${event.title}\n${timeStr}`} style={{ - height: `${eventHeight}px`, - minHeight: `${eventHeight}px`, + height: `${Math.max(eventHeight, 15)}px`, + minHeight: `15px`, position: 'absolute', top: `${topOffset}px`, left: '4px', @@ -2135,6 +2326,7 @@ export default function WeeklyView() { onRecurrence={() => setSelectedTaskForRecurrence(task)} onDragStart={(e, t) => handleDragStart(e, t)} onDragEnd={handleDragEnd} + variant="minimal" /> ))} @@ -2686,11 +2878,21 @@ export default function WeeklyView() { showNextTask={showNextTask} setShowNextTask={setShowNextTask} headlineFont={headlineFont} - setHeadlineFont={setHeadlineFont} + headlineFontSize={headlineFontSize} + headlineFontWeight={headlineFontWeight} + dateFontFamily={dateFontFamily} + dateFontSize={dateFontSize} + dateFontWeight={dateFontWeight} + timeTaskFontFamily={timeTaskFontFamily} + timeTaskFontSize={timeTaskFontSize} + timeTaskFontWeight={timeTaskFontWeight} bodyFont={bodyFont} - setBodyFont={setBodyFont} + taskFontFamily={taskFontFamily} + taskFontSize={taskFontSize} + taskFontWeight={taskFontWeight} fontWeight={fontWeight} - setFontWeight={setFontWeight} + weekendColorSat={weekendColorSat} + weekendColorSun={weekendColorSun} /> ) } @@ -3222,8 +3424,21 @@ interface SettingsSidebarProps { showAllDayEvents: boolean; showSchedule: boolean; headlineFont: string; + headlineFontSize: string; + headlineFontWeight: string; + dateFontFamily: string; + dateFontSize: string; + dateFontWeight: string; + timeTaskFontFamily: string; + timeTaskFontSize: string; + timeTaskFontWeight: string; bodyFont: string; + taskFontFamily: string; + taskFontSize: string; + taskFontWeight: string; fontWeight: string; + weekendColorSat: string; + weekendColorSun: string; }) => void; showTimeGrid: boolean; setShowTimeGrid: (show: boolean) => void; @@ -3252,11 +3467,24 @@ interface SettingsSidebarProps { showNextTask: boolean; setShowNextTask: (show: boolean) => void; headlineFont: string; - setHeadlineFont: (font: string) => void; + headlineFontSize: string; + headlineFontWeight: string; + dateFontFamily: string; + dateFontSize: string; + dateFontWeight: string; + timeTaskFontFamily: string; + timeTaskFontSize: string; + timeTaskFontWeight: string; bodyFont: string; - setBodyFont: (font: string) => void; + taskFontFamily: string; + taskFontSize: string; + taskFontWeight: string; + eventFontFamily?: string; + eventFontSize?: string; + eventFontWeight?: string; fontWeight: string; - setFontWeight: (weight: string) => void; + weekendColorSat: string; + weekendColorSun: string; } function SettingsSidebar({ @@ -3289,11 +3517,24 @@ function SettingsSidebar({ showNextTask, setShowNextTask, headlineFont, - setHeadlineFont, + headlineFontSize, + headlineFontWeight, + dateFontFamily, + dateFontSize, + dateFontWeight, + timeTaskFontFamily, + timeTaskFontSize, + timeTaskFontWeight, bodyFont, - setBodyFont, + taskFontFamily, + taskFontSize, + taskFontWeight, + eventFontFamily, + eventFontSize, + eventFontWeight, fontWeight, - setFontWeight + weekendColorSat, + weekendColorSun }: SettingsSidebarProps) { const [activeTab, setActiveTab] = useState<'general' | 'calendar' | 'account'>('general'); const [isLoading, setIsLoading] = useState(true); @@ -3325,8 +3566,24 @@ function SettingsSidebar({ showAllDayEvents?: boolean; showSchedule?: boolean; headlineFont?: string; + headlineFontSize?: string; + headlineFontWeight?: string; + dateFontFamily?: string; + dateFontSize?: string; + dateFontWeight?: string; + timeTaskFontFamily?: string; + timeTaskFontSize?: string; + timeTaskFontWeight?: string; bodyFont?: string; + taskFontFamily?: string; + taskFontSize?: string; + taskFontWeight?: string; + eventFontFamily?: string; + eventFontSize?: string; + eventFontWeight?: string; fontWeight?: string; + weekendColorSat?: string; + weekendColorSun?: string; }>({ name: '', email: '', @@ -3349,14 +3606,27 @@ function SettingsSidebar({ showAllDayEvents: true, showSchedule: true, headlineFont: 'Inter', + headlineFontSize: '1.25rem', + headlineFontWeight: '900', + dateFontFamily: 'Inter', + dateFontSize: '0.65rem', + dateFontWeight: '400', + timeTaskFontFamily: 'Inter', + timeTaskFontSize: '0.75rem', + timeTaskFontWeight: '500', bodyFont: 'Inter', - fontWeight: '400' + taskFontFamily: 'Inter', + taskFontSize: '0.9rem', + taskFontWeight: '400', + fontWeight: '400', + weekendColorSat: '#666666', + weekendColorSun: '#dc2626' }); const t = translations[profile.language || 'en'] || translations['en']; // Load fonts for preview - useGoogleFonts([profile.headlineFont || '', profile.bodyFont || '']); + // Font loading moved to top level WeeklyView component useEffect(() => { fetchProfile(); @@ -3397,15 +3667,28 @@ function SettingsSidebar({ fontWeight: data.user.fontWeight || '400', showSchedule: data.user.showSchedule !== undefined ? data.user.showSchedule : true, focusBreakDuration: data.user.focusBreakDuration || 5, + headlineFontSize: data.user.headlineFontSize || '1.25rem', + headlineFontWeight: data.user.headlineFontWeight || '900', + dateFontFamily: data.user.dateFontFamily || 'Inter', + dateFontSize: data.user.dateFontSize || '0.65rem', + dateFontWeight: data.user.dateFontWeight || '400', + timeTaskFontFamily: data.user.timeTaskFontFamily || 'Inter', + timeTaskFontSize: data.user.timeTaskFontSize || '0.75rem', + timeTaskFontWeight: data.user.timeTaskFontWeight || '500', + taskFontFamily: data.user.taskFontFamily || 'Inter', + taskFontSize: data.user.taskFontSize || '0.9rem', + taskFontWeight: data.user.taskFontWeight || '400', + eventFontFamily: data.user.eventFontFamily || 'Inter', + eventFontSize: data.user.eventFontSize || '0.85rem', + eventFontWeight: data.user.eventFontWeight || '400', + weekendColorSat: data.user.weekendColorSat || '#666666', + weekendColorSun: data.user.weekendColorSun || '#dc2626', }); if (data.user.showTimeGrid !== undefined) setShowTimeGrid(data.user.showTimeGrid); if (data.user.cellDuration) setCellDuration(data.user.cellDuration as CellDuration); if (data.user.viewStyle) setViewStyle(data.user.viewStyle as 'grid' | 'list'); if (data.user.fontSize) setFontSize(data.user.fontSize as 'S' | 'M' | 'L'); - if (data.user.headlineFont) setHeadlineFont(data.user.headlineFont); - if (data.user.bodyFont) setBodyFont(data.user.bodyFont); - if (data.user.fontWeight) setFontWeight(data.user.fontWeight); if (data.user.focusTimerDuration) setFocusTimerDuration(data.user.focusTimerDuration); if (data.user.showSchedule !== undefined) setShowSchedule(data.user.showSchedule); if (data.user.focusBreakDuration) setFocusBreakDuration(data.user.focusBreakDuration); @@ -3489,10 +3772,10 @@ function SettingsSidebar({ showSomeday: showSomeday, showAllDayEvents: showAllDay, showSchedule: showSchedule, - headlineFont: headlineFont, - bodyFont: bodyFont, - fontWeight: fontWeight, - focusBreakDuration: focusBreakDuration, + // The following will be taken from profile if present, + // ensuring edited state is saved. + focusBreakDuration: profile.focusBreakDuration || focusBreakDuration, + focusTimerDuration: profile.focusTimerDuration || focusTimerDuration, password: (passwords.new && passwords.new.trim() !== "") ? passwords.new : undefined }) }); @@ -3519,8 +3802,24 @@ function SettingsSidebar({ showAllDayEvents: showAllDay, showSchedule: showSchedule, headlineFont: headlineFont, + headlineFontSize: headlineFontSize, + headlineFontWeight: headlineFontWeight, + dateFontFamily: dateFontFamily, + dateFontSize: dateFontSize, + dateFontWeight: dateFontWeight, + timeTaskFontFamily: timeTaskFontFamily, + timeTaskFontSize: timeTaskFontSize, + timeTaskFontWeight: timeTaskFontWeight, bodyFont: bodyFont, - fontWeight: fontWeight + taskFontFamily: taskFontFamily, + taskFontSize: taskFontSize, + taskFontWeight: profile.taskFontWeight || taskFontWeight, + eventFontFamily: profile.eventFontFamily || eventFontFamily, + eventFontSize: profile.eventFontSize || eventFontSize, + eventFontWeight: profile.eventFontWeight || eventFontWeight, + fontWeight: fontWeight, + weekendColorSat: weekendColorSat, + weekendColorSun: weekendColorSun, }); } @@ -3597,12 +3896,6 @@ function SettingsSidebar({
- {accountMsg && ( -
- {accountMsg} -
- )} {activeTab === 'general' ? (
{/* Motto */} @@ -3850,85 +4143,197 @@ function SettingsSidebar({
- {/* Font Settings */} -
- + {/* Typography Settings */} +
+ - {/* Headline Font */} -
- - -
- - {/* Body Font */} -
- - -
- - {/* Font Weight */} -
- -
- {FONT_WEIGHTS.map(weight => ( -
- setProfile({ ...profile, fontWeight: weight.value })} - style={{ width: '16px', height: '16px', cursor: 'pointer' }} - /> - -
- ))} + {/* Day Names */} +
+ +
+ + +
- {/* Font Preview */} -
-
- Headline Preview + {/* Dates */} +
+ +
+ + +
-
- Body text preview. The quick brown fox jumps over the lazy dog. 1234567890. +
+ + {/* Tasks */} +
+ +
+ + + +
+
+ + {/* Calendar Event Font */} +
+ +
+ + + +
+
+ + + {/* Weekend Colors */} +
+ +
+
+ + setProfile({ ...profile, weekendColorSat: e.target.value })} + style={{ width: '100%', height: '30px', cursor: 'pointer', border: 'none', background: 'transparent' }} + /> +
+
+ + setProfile({ ...profile, weekendColorSun: e.target.value })} + style={{ width: '100%', height: '30px', cursor: 'pointer', border: 'none', background: 'transparent' }} + /> +
@@ -3971,13 +4376,24 @@ function SettingsSidebar({
- +
+ + {accountMsg && ( + + {accountMsg} + + )} +
) : activeTab === 'calendar' ? ( isLoading ? ( @@ -4112,13 +4528,24 @@ function SettingsSidebar({
- +
+ + {accountMsg && ( + + {accountMsg} + + )} +
{/* Data Export Section */}