feat: visual updates and settings
This commit is contained in:
parent
dcd2e75537
commit
779181ddde
@ -41,8 +41,24 @@ model User {
|
|||||||
viewStyle String @default("grid")
|
viewStyle String @default("grid")
|
||||||
fontSize String @default("M") // "S", "M", "L"
|
fontSize String @default("M") // "S", "M", "L"
|
||||||
headlineFont String @default("Inter")
|
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")
|
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[]
|
accounts Account[]
|
||||||
sessions Session[]
|
sessions Session[]
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { PrismaClient } from '@prisma/client';
|
|||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from 'bcryptjs';
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
// Prisma client re-initialized to pick up schema changes
|
||||||
|
|
||||||
// Get user profile
|
// Get user profile
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
@ -36,8 +37,24 @@ export async function GET(request: NextRequest) {
|
|||||||
viewStyle: true,
|
viewStyle: true,
|
||||||
fontSize: true,
|
fontSize: true,
|
||||||
headlineFont: true,
|
headlineFont: true,
|
||||||
|
headlineFontSize: true,
|
||||||
|
headlineFontWeight: true,
|
||||||
|
dateFontFamily: true,
|
||||||
|
dateFontSize: true,
|
||||||
|
dateFontWeight: true,
|
||||||
|
timeTaskFontFamily: true,
|
||||||
|
timeTaskFontSize: true,
|
||||||
|
timeTaskFontWeight: true,
|
||||||
bodyFont: true,
|
bodyFont: true,
|
||||||
|
taskFontFamily: true,
|
||||||
|
taskFontSize: true,
|
||||||
|
taskFontWeight: true,
|
||||||
|
eventFontFamily: true,
|
||||||
|
eventFontSize: true,
|
||||||
|
eventFontWeight: true,
|
||||||
fontWeight: true,
|
fontWeight: true,
|
||||||
|
weekendColorSat: true,
|
||||||
|
weekendColorSun: true,
|
||||||
createdAt: true
|
createdAt: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -65,7 +82,12 @@ export async function PATCH(request: NextRequest) {
|
|||||||
showNextTask, calendarEditMode, focusTimerDuration, focusBreakDuration,
|
showNextTask, calendarEditMode, focusTimerDuration, focusBreakDuration,
|
||||||
showTimeGrid, showSomeday, showAllDayEvents, showSchedule,
|
showTimeGrid, showSomeday, showAllDayEvents, showSchedule,
|
||||||
cellDuration, viewStyle, fontSize,
|
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;
|
} = body;
|
||||||
|
|
||||||
const updateData: any = {
|
const updateData: any = {
|
||||||
@ -90,8 +112,24 @@ export async function PATCH(request: NextRequest) {
|
|||||||
...(viewStyle !== undefined && { viewStyle }),
|
...(viewStyle !== undefined && { viewStyle }),
|
||||||
...(fontSize !== undefined && { fontSize }),
|
...(fontSize !== undefined && { fontSize }),
|
||||||
...(headlineFont !== undefined && { headlineFont }),
|
...(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 }),
|
...(bodyFont !== undefined && { bodyFont }),
|
||||||
|
...(taskFontFamily !== undefined && { taskFontFamily }),
|
||||||
|
...(taskFontSize !== undefined && { taskFontSize }),
|
||||||
|
...(taskFontWeight !== undefined && { taskFontWeight }),
|
||||||
|
...(eventFontFamily !== undefined && { eventFontFamily }),
|
||||||
|
...(eventFontSize !== undefined && { eventFontSize }),
|
||||||
|
...(eventFontWeight !== undefined && { eventFontWeight }),
|
||||||
...(fontWeight !== undefined && { fontWeight }),
|
...(fontWeight !== undefined && { fontWeight }),
|
||||||
|
...(weekendColorSat !== undefined && { weekendColorSat }),
|
||||||
|
...(weekendColorSun !== undefined && { weekendColorSun }),
|
||||||
};
|
};
|
||||||
if (password && password.trim() !== "") {
|
if (password && password.trim() !== "") {
|
||||||
updateData.passwordHash = await bcrypt.hash(password, 10);
|
updateData.passwordHash = await bcrypt.hash(password, 10);
|
||||||
@ -124,8 +162,24 @@ export async function PATCH(request: NextRequest) {
|
|||||||
viewStyle: true,
|
viewStyle: true,
|
||||||
fontSize: true,
|
fontSize: true,
|
||||||
headlineFont: true,
|
headlineFont: true,
|
||||||
|
headlineFontSize: true,
|
||||||
|
headlineFontWeight: true,
|
||||||
|
dateFontFamily: true,
|
||||||
|
dateFontSize: true,
|
||||||
|
dateFontWeight: true,
|
||||||
|
timeTaskFontFamily: true,
|
||||||
|
timeTaskFontSize: true,
|
||||||
|
timeTaskFontWeight: true,
|
||||||
bodyFont: true,
|
bodyFont: true,
|
||||||
|
taskFontFamily: true,
|
||||||
|
taskFontSize: true,
|
||||||
|
taskFontWeight: true,
|
||||||
|
eventFontFamily: true,
|
||||||
|
eventFontSize: true,
|
||||||
|
eventFontWeight: true,
|
||||||
fontWeight: true,
|
fontWeight: true,
|
||||||
|
weekendColorSat: true,
|
||||||
|
weekendColorSun: true,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -221,6 +221,17 @@ h3 {
|
|||||||
gap: 0.25rem;
|
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 {
|
.nav-button:hover {
|
||||||
background-color: #e2e8f0;
|
background-color: #e2e8f0;
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
@ -617,6 +628,17 @@ h3 {
|
|||||||
border-left: none;
|
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 */
|
/* Day Header */
|
||||||
.weekly-day-header {
|
.weekly-day-header {
|
||||||
padding: 1rem 1rem 0.75rem;
|
padding: 1rem 1rem 0.75rem;
|
||||||
@ -626,20 +648,22 @@ h3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.weekly-day-date {
|
.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);
|
color: var(--weekly-text-light);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
|
font-family: var(--weekly-date-font, var(--weekly-font-headline)) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.weekly-day-name {
|
.weekly-day-name {
|
||||||
font-size: 1.25rem;
|
font-size: var(--weekly-headline-size, 1.25rem);
|
||||||
font-weight: 900;
|
font-weight: var(--weekly-headline-weight, 900);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: -0.02em;
|
letter-spacing: -0.02em;
|
||||||
color: var(--weekly-text);
|
color: var(--weekly-text);
|
||||||
font-family: var(--weekly-font-headline);
|
font-family: var(--weekly-font-headline) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.weekly-day-name.is-today {
|
.weekly-day-name.is-today {
|
||||||
@ -685,13 +709,14 @@ h3 {
|
|||||||
|
|
||||||
.weekly-task-text {
|
.weekly-task-text {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: var(--base-font-size);
|
font-family: var(--weekly-task-font, var(--weekly-font));
|
||||||
line-height: 1.5;
|
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);
|
color: var(--weekly-text);
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
font-family: inherit;
|
|
||||||
resize: none;
|
resize: none;
|
||||||
min-height: 1.5em;
|
min-height: 1.5em;
|
||||||
padding-top: 2px; /* Align with icons */
|
padding-top: 2px; /* Align with icons */
|
||||||
@ -912,6 +937,10 @@ h3 {
|
|||||||
color: var(--weekly-text);
|
color: var(--weekly-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.weekly-day-name {
|
||||||
|
color: var(--weekly-text-light);
|
||||||
|
}
|
||||||
|
|
||||||
.weekly-someday-title {
|
.weekly-someday-title {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@ -1296,6 +1325,7 @@ h3 {
|
|||||||
|
|
||||||
.weekly-calendar-event-title {
|
.weekly-calendar-event-title {
|
||||||
color: var(--weekly-text);
|
color: var(--weekly-text);
|
||||||
|
font-family: var(--weekly-font);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drag and Drop States */
|
/* Drag and Drop States */
|
||||||
@ -1311,7 +1341,9 @@ h3 {
|
|||||||
.weekly-settings-overlay {
|
.weekly-settings-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
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;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -1434,7 +1466,7 @@ h3 {
|
|||||||
|
|
||||||
.time-slot-label {
|
.time-slot-label {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-start;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
padding: 0 0.5rem;
|
padding: 0 0.5rem;
|
||||||
font-size: 0.65rem;
|
font-size: 0.65rem;
|
||||||
@ -1516,7 +1548,9 @@ h3 {
|
|||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
padding: 2px 0;
|
padding: 2px 0;
|
||||||
background: transparent;
|
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;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -1573,18 +1607,25 @@ h3 {
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.event-title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-family: var(--weekly-font);
|
||||||
|
}
|
||||||
|
|
||||||
.time-slot-event .event-title {
|
.time-slot-event .event-title {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
font-family: var(--weekly-font);
|
||||||
}
|
}
|
||||||
|
|
||||||
.time-slot-event .event-time-row {
|
.time-slot-event .event-time-row {
|
||||||
font-size: 0.65rem;
|
font-size: 0.75rem;
|
||||||
opacity: 0.8;
|
opacity: 0.9;
|
||||||
white-space: nowrap;
|
font-family: var(--weekly-font);
|
||||||
}
|
}
|
||||||
|
|
||||||
.time-slot-event:hover {
|
.time-slot-event:hover {
|
||||||
@ -2407,3 +2448,16 @@ h3 {
|
|||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
margin-bottom: 12px;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -343,11 +343,100 @@ export default function WeeklyView() {
|
|||||||
const [dateFormat, setDateFormat] = useState('yyyy-MM-dd');
|
const [dateFormat, setDateFormat] = useState('yyyy-MM-dd');
|
||||||
|
|
||||||
const [somedayExpanded, setSomedayExpanded] = useState(true);
|
const [somedayExpanded, setSomedayExpanded] = useState(true);
|
||||||
const [draggingListId, setDraggingListId] = useState<string | null>(null);
|
|
||||||
const [isAllDayExpanded, setIsAllDayExpanded] = useState(true);
|
const [isAllDayExpanded, setIsAllDayExpanded] = useState(true);
|
||||||
const [somedayLists, setSomedayLists] = useState<SomedayList[]>([]);
|
const [somedayLists, setSomedayLists] = useState<SomedayList[]>([]);
|
||||||
const [editingTaskId, setEditingTaskId] = useState<string | null>(null);
|
const [editingTaskId, setEditingTaskId] = useState<string | null>(null);
|
||||||
|
const [draggingListId, setDraggingListId] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// Moved state definitions to the top
|
||||||
const [showSettings, setShowSettings] = useState(false);
|
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 [showSummary, setShowSummary] = useState(false);
|
||||||
|
|
||||||
const [isAddingSomedayList, setIsAddingSomedayList] = useState(false);
|
const [isAddingSomedayList, setIsAddingSomedayList] = useState(false);
|
||||||
@ -388,11 +477,36 @@ export default function WeeklyView() {
|
|||||||
const [focusTimerDuration, setFocusTimerDuration] = useState(25);
|
const [focusTimerDuration, setFocusTimerDuration] = useState(25);
|
||||||
const [fontSize, setFontSize] = useState<'S' | 'M' | 'L'>('M');
|
const [fontSize, setFontSize] = useState<'S' | 'M' | 'L'>('M');
|
||||||
const [headlineFont, setHeadlineFont] = useState('Inter');
|
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 [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 [fontWeight, setFontWeight] = useState('400');
|
||||||
|
const [weekendColorSat, setWeekendColorSat] = useState('#666666');
|
||||||
|
const [weekendColorSun, setWeekendColorSun] = useState('#dc2626');
|
||||||
|
|
||||||
// Load fonts
|
// 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
|
// Dynamic font loading is handled by useGoogleFonts hook call above
|
||||||
|
|
||||||
@ -642,8 +756,24 @@ export default function WeeklyView() {
|
|||||||
showAllDayEvents: boolean;
|
showAllDayEvents: boolean;
|
||||||
showSchedule: boolean;
|
showSchedule: boolean;
|
||||||
headlineFont: string;
|
headlineFont: string;
|
||||||
|
headlineFontSize: string;
|
||||||
|
headlineFontWeight: string;
|
||||||
|
dateFontFamily: string;
|
||||||
|
dateFontSize: string;
|
||||||
|
dateFontWeight: string;
|
||||||
|
timeTaskFontFamily: string;
|
||||||
|
timeTaskFontSize: string;
|
||||||
|
timeTaskFontWeight: string;
|
||||||
bodyFont: string;
|
bodyFont: string;
|
||||||
|
taskFontFamily: string;
|
||||||
|
taskFontSize: string;
|
||||||
|
taskFontWeight: string;
|
||||||
|
eventFontFamily: string;
|
||||||
|
eventFontSize: string;
|
||||||
|
eventFontWeight: string;
|
||||||
fontWeight: string;
|
fontWeight: string;
|
||||||
|
weekendColorSat: string;
|
||||||
|
weekendColorSun: string;
|
||||||
}) => {
|
}) => {
|
||||||
setShowTimeGrid(newSettings.showTimeGrid);
|
setShowTimeGrid(newSettings.showTimeGrid);
|
||||||
setCellDuration(newSettings.cellDuration);
|
setCellDuration(newSettings.cellDuration);
|
||||||
@ -659,8 +789,24 @@ export default function WeeklyView() {
|
|||||||
setShowAllDay(newSettings.showAllDayEvents);
|
setShowAllDay(newSettings.showAllDayEvents);
|
||||||
setShowSchedule(newSettings.showSchedule);
|
setShowSchedule(newSettings.showSchedule);
|
||||||
setHeadlineFont(newSettings.headlineFont);
|
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);
|
setBodyFont(newSettings.bodyFont);
|
||||||
|
setTaskFontFamily(newSettings.taskFontFamily);
|
||||||
|
setTaskFontSize(newSettings.taskFontSize);
|
||||||
|
setTaskFontWeight(newSettings.taskFontWeight);
|
||||||
|
setEventFontFamily(newSettings.eventFontFamily);
|
||||||
|
setEventFontSize(newSettings.eventFontSize);
|
||||||
|
setEventFontWeight(newSettings.eventFontWeight);
|
||||||
setFontWeight(newSettings.fontWeight);
|
setFontWeight(newSettings.fontWeight);
|
||||||
|
setWeekendColorSat(newSettings.weekendColorSat);
|
||||||
|
setWeekendColorSun(newSettings.weekendColorSun);
|
||||||
|
|
||||||
// Custom start/end hours might affect task placement if we filter strictly
|
// Custom start/end hours might affect task placement if we filter strictly
|
||||||
fetchTasks();
|
fetchTasks();
|
||||||
@ -686,8 +832,33 @@ export default function WeeklyView() {
|
|||||||
if (data.user.showAllDayEvents !== undefined) setShowAllDay(data.user.showAllDayEvents);
|
if (data.user.showAllDayEvents !== undefined) setShowAllDay(data.user.showAllDayEvents);
|
||||||
if (data.user.showSchedule !== undefined) setShowSchedule(data.user.showSchedule);
|
if (data.user.showSchedule !== undefined) setShowSchedule(data.user.showSchedule);
|
||||||
if (data.user.headlineFont) setHeadlineFont(data.user.headlineFont);
|
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.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.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.focusTimerDuration) setFocusTimerDuration(data.user.focusTimerDuration);
|
||||||
if (data.user.focusBreakDuration) setFocusBreakDuration(data.user.focusBreakDuration);
|
if (data.user.focusBreakDuration) setFocusBreakDuration(data.user.focusBreakDuration);
|
||||||
if (data.user.showTimeGrid !== undefined) setShowTimeGrid(data.user.showTimeGrid);
|
if (data.user.showTimeGrid !== undefined) setShowTimeGrid(data.user.showTimeGrid);
|
||||||
@ -1487,9 +1658,25 @@ export default function WeeklyView() {
|
|||||||
const visibleSlots = getTimeSlots(cellDuration, workingHoursStart, workingHoursEnd);
|
const visibleSlots = getTimeSlots(cellDuration, workingHoursStart, workingHoursEnd);
|
||||||
|
|
||||||
const containerStyle = {
|
const containerStyle = {
|
||||||
'--font-headline': `"${headlineFont}", sans-serif`,
|
'--weekly-font-headline': (profile.headlineFont || headlineFont) ? `"${profile.headlineFont || headlineFont}", sans-serif` : 'var(--font-headline)',
|
||||||
'--font-body': `"${bodyFont}", sans-serif`,
|
'--weekly-headline-size': profile.headlineFontSize || '1.25rem',
|
||||||
'--font-weight-body': fontWeight || '400',
|
'--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;
|
} as React.CSSProperties;
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@ -1773,14 +1960,14 @@ export default function WeeklyView() {
|
|||||||
{getVisibleDays().map((date, colIndex) => (
|
{getVisibleDays().map((date, colIndex) => (
|
||||||
<div
|
<div
|
||||||
key={date.toISOString()}
|
key={date.toISOString()}
|
||||||
className="weekly-day-column"
|
className={`weekly-day-column ${date.getDay() === 6 ? 'is-sat' : ''} ${date.getDay() === 0 ? 'is-sun' : ''}`}
|
||||||
style={{ viewTransitionName: `day-${date.getFullYear()}-${date.getMonth()}-${date.getDate()}` } as any}
|
style={{ viewTransitionName: `day-${date.getFullYear()}-${date.getMonth()}-${date.getDate()}` } as any}
|
||||||
>
|
>
|
||||||
{/* Day Header */}
|
{/* Day Header */}
|
||||||
<header className="weekly-day-header">
|
<header className="weekly-day-header">
|
||||||
<div style={{ display: 'flex', alignItems: 'baseline', gap: '4px' }}>
|
<div style={{ display: 'flex', alignItems: 'baseline', gap: '4px' }}>
|
||||||
<h3 className={`weekly-day-name ${isSameDay(date, new Date()) ? 'is-today' : ''}`} style={{ marginBottom: 0 }}>
|
<h3 className={`weekly-day-name ${isSameDay(date, new Date()) ? 'is-today' : ''}`} style={{ marginBottom: 0 }}>
|
||||||
{getDayName(date, language)}, <span style={{ fontWeight: 400 }}>{formatDateHeader(date, language)}</span>
|
{getDayName(date, language)} <span className="weekly-day-date">{formatDateHeader(date, language)}</span>
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@ -1825,7 +2012,9 @@ export default function WeeklyView() {
|
|||||||
|
|
||||||
// Calculate height based on event duration
|
// Calculate height based on event duration
|
||||||
const durationMinutes = (eventEnd.getTime() - eventStart.getTime()) / (1000 * 60);
|
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);
|
const isUnlocked = unlockedEvents.has(event.id);
|
||||||
|
|
||||||
@ -1982,24 +2171,29 @@ export default function WeeklyView() {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<div className="task-actions" style={{
|
<div className="task-actions" style={{
|
||||||
display: 'grid',
|
display: 'flex',
|
||||||
gridTemplateColumns: 'repeat(2, 1fr)',
|
alignItems: 'center',
|
||||||
gap: '2px',
|
gap: '2px',
|
||||||
marginLeft: '4px',
|
marginLeft: '4px',
|
||||||
flexShrink: 0
|
flexShrink: 0,
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
background: darkMode ? 'rgba(0,0,0,0.6)' : 'rgba(255,255,255,0.8)',
|
||||||
|
padding: '1px 3px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
|
||||||
}}>
|
}}>
|
||||||
{/* Edit button */}
|
{/* Edit button */}
|
||||||
<button className="task-action-btn" onClick={(e) => { e.stopPropagation(); setEditingTaskId(task.id); }} title="Edit">
|
<button className="task-action-btn" onClick={(e) => { e.stopPropagation(); setEditingTaskId(task.id); }} title="Edit">
|
||||||
<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
|
<svg viewBox="0 0 24 24" width="12" height="12" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
|
||||||
</button>
|
</button>
|
||||||
{/* Notes button */}
|
{/* Notes button */}
|
||||||
<button className="task-action-btn" onClick={(e) => { e.stopPropagation(); setSelectedTaskForNotes(task); }} title="Notes">
|
<button className="task-action-btn" onClick={(e) => { e.stopPropagation(); setSelectedTaskForNotes(task); }} title="Notes">
|
||||||
<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
|
<svg viewBox="0 0 24 24" width="12" height="12" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
|
||||||
</button>
|
</button>
|
||||||
{/* Roll button */}
|
{/* Roll button */}
|
||||||
{!task.completed && (
|
{!task.completed && (
|
||||||
<button className={`task-action-btn ${task.isRolling ? 'active' : ''}`} onClick={(e) => { e.stopPropagation(); toggleTaskRolling(task.id); }} title={task.isRolling ? "Disable rolling" : "Enable rolling"}>
|
<button className={`task-action-btn ${task.isRolling ? 'active' : ''}`} onClick={(e) => { e.stopPropagation(); toggleTaskRolling(task.id); }} title={task.isRolling ? "Disable rolling" : "Enable rolling"}>
|
||||||
<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>
|
<svg viewBox="0 0 24 24" width="12" height="12" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{/* Recurrence button */}
|
{/* Recurrence button */}
|
||||||
@ -2008,14 +2202,11 @@ export default function WeeklyView() {
|
|||||||
onClick={(e) => { e.stopPropagation(); setSelectedTaskForRecurrence(task); }}
|
onClick={(e) => { e.stopPropagation(); setSelectedTaskForRecurrence(task); }}
|
||||||
title={task.isRecurring ? "Edit recurrence" : "Make recurring"}
|
title={task.isRecurring ? "Edit recurrence" : "Make recurring"}
|
||||||
>
|
>
|
||||||
<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round">
|
<Repeat size={12} strokeWidth={2.5} />
|
||||||
<polyline points="23 4 23 10 17 10"></polyline>
|
|
||||||
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
{/* Delete button */}
|
{/* Delete button */}
|
||||||
<button className="task-action-btn delete" onClick={(e) => { e.stopPropagation(); deleteTask(task.id); }} title="Delete">
|
<button className="task-action-btn delete" onClick={(e) => { e.stopPropagation(); deleteTask(task.id); }} title="Delete">
|
||||||
<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line></svg>
|
<svg viewBox="0 0 24 24" width="12" height="12" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -2050,8 +2241,8 @@ export default function WeeklyView() {
|
|||||||
className="time-slot-event"
|
className="time-slot-event"
|
||||||
title={`${event.calendarTitle}: ${event.title}\n${timeStr}`}
|
title={`${event.calendarTitle}: ${event.title}\n${timeStr}`}
|
||||||
style={{
|
style={{
|
||||||
height: `${eventHeight}px`,
|
height: `${Math.max(eventHeight, 15)}px`,
|
||||||
minHeight: `${eventHeight}px`,
|
minHeight: `15px`,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: `${topOffset}px`,
|
top: `${topOffset}px`,
|
||||||
left: '4px',
|
left: '4px',
|
||||||
@ -2135,6 +2326,7 @@ export default function WeeklyView() {
|
|||||||
onRecurrence={() => setSelectedTaskForRecurrence(task)}
|
onRecurrence={() => setSelectedTaskForRecurrence(task)}
|
||||||
onDragStart={(e, t) => handleDragStart(e, t)}
|
onDragStart={(e, t) => handleDragStart(e, t)}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
|
variant="minimal"
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -2686,11 +2878,21 @@ export default function WeeklyView() {
|
|||||||
showNextTask={showNextTask}
|
showNextTask={showNextTask}
|
||||||
setShowNextTask={setShowNextTask}
|
setShowNextTask={setShowNextTask}
|
||||||
headlineFont={headlineFont}
|
headlineFont={headlineFont}
|
||||||
setHeadlineFont={setHeadlineFont}
|
headlineFontSize={headlineFontSize}
|
||||||
|
headlineFontWeight={headlineFontWeight}
|
||||||
|
dateFontFamily={dateFontFamily}
|
||||||
|
dateFontSize={dateFontSize}
|
||||||
|
dateFontWeight={dateFontWeight}
|
||||||
|
timeTaskFontFamily={timeTaskFontFamily}
|
||||||
|
timeTaskFontSize={timeTaskFontSize}
|
||||||
|
timeTaskFontWeight={timeTaskFontWeight}
|
||||||
bodyFont={bodyFont}
|
bodyFont={bodyFont}
|
||||||
setBodyFont={setBodyFont}
|
taskFontFamily={taskFontFamily}
|
||||||
|
taskFontSize={taskFontSize}
|
||||||
|
taskFontWeight={taskFontWeight}
|
||||||
fontWeight={fontWeight}
|
fontWeight={fontWeight}
|
||||||
setFontWeight={setFontWeight}
|
weekendColorSat={weekendColorSat}
|
||||||
|
weekendColorSun={weekendColorSun}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -3222,8 +3424,21 @@ interface SettingsSidebarProps {
|
|||||||
showAllDayEvents: boolean;
|
showAllDayEvents: boolean;
|
||||||
showSchedule: boolean;
|
showSchedule: boolean;
|
||||||
headlineFont: string;
|
headlineFont: string;
|
||||||
|
headlineFontSize: string;
|
||||||
|
headlineFontWeight: string;
|
||||||
|
dateFontFamily: string;
|
||||||
|
dateFontSize: string;
|
||||||
|
dateFontWeight: string;
|
||||||
|
timeTaskFontFamily: string;
|
||||||
|
timeTaskFontSize: string;
|
||||||
|
timeTaskFontWeight: string;
|
||||||
bodyFont: string;
|
bodyFont: string;
|
||||||
|
taskFontFamily: string;
|
||||||
|
taskFontSize: string;
|
||||||
|
taskFontWeight: string;
|
||||||
fontWeight: string;
|
fontWeight: string;
|
||||||
|
weekendColorSat: string;
|
||||||
|
weekendColorSun: string;
|
||||||
}) => void;
|
}) => void;
|
||||||
showTimeGrid: boolean;
|
showTimeGrid: boolean;
|
||||||
setShowTimeGrid: (show: boolean) => void;
|
setShowTimeGrid: (show: boolean) => void;
|
||||||
@ -3252,11 +3467,24 @@ interface SettingsSidebarProps {
|
|||||||
showNextTask: boolean;
|
showNextTask: boolean;
|
||||||
setShowNextTask: (show: boolean) => void;
|
setShowNextTask: (show: boolean) => void;
|
||||||
headlineFont: string;
|
headlineFont: string;
|
||||||
setHeadlineFont: (font: string) => void;
|
headlineFontSize: string;
|
||||||
|
headlineFontWeight: string;
|
||||||
|
dateFontFamily: string;
|
||||||
|
dateFontSize: string;
|
||||||
|
dateFontWeight: string;
|
||||||
|
timeTaskFontFamily: string;
|
||||||
|
timeTaskFontSize: string;
|
||||||
|
timeTaskFontWeight: string;
|
||||||
bodyFont: string;
|
bodyFont: string;
|
||||||
setBodyFont: (font: string) => void;
|
taskFontFamily: string;
|
||||||
|
taskFontSize: string;
|
||||||
|
taskFontWeight: string;
|
||||||
|
eventFontFamily?: string;
|
||||||
|
eventFontSize?: string;
|
||||||
|
eventFontWeight?: string;
|
||||||
fontWeight: string;
|
fontWeight: string;
|
||||||
setFontWeight: (weight: string) => void;
|
weekendColorSat: string;
|
||||||
|
weekendColorSun: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SettingsSidebar({
|
function SettingsSidebar({
|
||||||
@ -3289,11 +3517,24 @@ function SettingsSidebar({
|
|||||||
showNextTask,
|
showNextTask,
|
||||||
setShowNextTask,
|
setShowNextTask,
|
||||||
headlineFont,
|
headlineFont,
|
||||||
setHeadlineFont,
|
headlineFontSize,
|
||||||
|
headlineFontWeight,
|
||||||
|
dateFontFamily,
|
||||||
|
dateFontSize,
|
||||||
|
dateFontWeight,
|
||||||
|
timeTaskFontFamily,
|
||||||
|
timeTaskFontSize,
|
||||||
|
timeTaskFontWeight,
|
||||||
bodyFont,
|
bodyFont,
|
||||||
setBodyFont,
|
taskFontFamily,
|
||||||
|
taskFontSize,
|
||||||
|
taskFontWeight,
|
||||||
|
eventFontFamily,
|
||||||
|
eventFontSize,
|
||||||
|
eventFontWeight,
|
||||||
fontWeight,
|
fontWeight,
|
||||||
setFontWeight
|
weekendColorSat,
|
||||||
|
weekendColorSun
|
||||||
}: SettingsSidebarProps) {
|
}: SettingsSidebarProps) {
|
||||||
const [activeTab, setActiveTab] = useState<'general' | 'calendar' | 'account'>('general');
|
const [activeTab, setActiveTab] = useState<'general' | 'calendar' | 'account'>('general');
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
@ -3325,8 +3566,24 @@ function SettingsSidebar({
|
|||||||
showAllDayEvents?: boolean;
|
showAllDayEvents?: boolean;
|
||||||
showSchedule?: boolean;
|
showSchedule?: boolean;
|
||||||
headlineFont?: string;
|
headlineFont?: string;
|
||||||
|
headlineFontSize?: string;
|
||||||
|
headlineFontWeight?: string;
|
||||||
|
dateFontFamily?: string;
|
||||||
|
dateFontSize?: string;
|
||||||
|
dateFontWeight?: string;
|
||||||
|
timeTaskFontFamily?: string;
|
||||||
|
timeTaskFontSize?: string;
|
||||||
|
timeTaskFontWeight?: string;
|
||||||
bodyFont?: string;
|
bodyFont?: string;
|
||||||
|
taskFontFamily?: string;
|
||||||
|
taskFontSize?: string;
|
||||||
|
taskFontWeight?: string;
|
||||||
|
eventFontFamily?: string;
|
||||||
|
eventFontSize?: string;
|
||||||
|
eventFontWeight?: string;
|
||||||
fontWeight?: string;
|
fontWeight?: string;
|
||||||
|
weekendColorSat?: string;
|
||||||
|
weekendColorSun?: string;
|
||||||
}>({
|
}>({
|
||||||
name: '',
|
name: '',
|
||||||
email: '',
|
email: '',
|
||||||
@ -3349,14 +3606,27 @@ function SettingsSidebar({
|
|||||||
showAllDayEvents: true,
|
showAllDayEvents: true,
|
||||||
showSchedule: true,
|
showSchedule: true,
|
||||||
headlineFont: 'Inter',
|
headlineFont: 'Inter',
|
||||||
|
headlineFontSize: '1.25rem',
|
||||||
|
headlineFontWeight: '900',
|
||||||
|
dateFontFamily: 'Inter',
|
||||||
|
dateFontSize: '0.65rem',
|
||||||
|
dateFontWeight: '400',
|
||||||
|
timeTaskFontFamily: 'Inter',
|
||||||
|
timeTaskFontSize: '0.75rem',
|
||||||
|
timeTaskFontWeight: '500',
|
||||||
bodyFont: 'Inter',
|
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'];
|
const t = translations[profile.language || 'en'] || translations['en'];
|
||||||
|
|
||||||
// Load fonts for preview
|
// Load fonts for preview
|
||||||
useGoogleFonts([profile.headlineFont || '', profile.bodyFont || '']);
|
// Font loading moved to top level WeeklyView component
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchProfile();
|
fetchProfile();
|
||||||
@ -3397,15 +3667,28 @@ function SettingsSidebar({
|
|||||||
fontWeight: data.user.fontWeight || '400',
|
fontWeight: data.user.fontWeight || '400',
|
||||||
showSchedule: data.user.showSchedule !== undefined ? data.user.showSchedule : true,
|
showSchedule: data.user.showSchedule !== undefined ? data.user.showSchedule : true,
|
||||||
focusBreakDuration: data.user.focusBreakDuration || 5,
|
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.showTimeGrid !== undefined) setShowTimeGrid(data.user.showTimeGrid);
|
||||||
if (data.user.cellDuration) setCellDuration(data.user.cellDuration as CellDuration);
|
if (data.user.cellDuration) setCellDuration(data.user.cellDuration as CellDuration);
|
||||||
if (data.user.viewStyle) setViewStyle(data.user.viewStyle as 'grid' | 'list');
|
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.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.focusTimerDuration) setFocusTimerDuration(data.user.focusTimerDuration);
|
||||||
if (data.user.showSchedule !== undefined) setShowSchedule(data.user.showSchedule);
|
if (data.user.showSchedule !== undefined) setShowSchedule(data.user.showSchedule);
|
||||||
if (data.user.focusBreakDuration) setFocusBreakDuration(data.user.focusBreakDuration);
|
if (data.user.focusBreakDuration) setFocusBreakDuration(data.user.focusBreakDuration);
|
||||||
@ -3489,10 +3772,10 @@ function SettingsSidebar({
|
|||||||
showSomeday: showSomeday,
|
showSomeday: showSomeday,
|
||||||
showAllDayEvents: showAllDay,
|
showAllDayEvents: showAllDay,
|
||||||
showSchedule: showSchedule,
|
showSchedule: showSchedule,
|
||||||
headlineFont: headlineFont,
|
// The following will be taken from profile if present,
|
||||||
bodyFont: bodyFont,
|
// ensuring edited state is saved.
|
||||||
fontWeight: fontWeight,
|
focusBreakDuration: profile.focusBreakDuration || focusBreakDuration,
|
||||||
focusBreakDuration: focusBreakDuration,
|
focusTimerDuration: profile.focusTimerDuration || focusTimerDuration,
|
||||||
password: (passwords.new && passwords.new.trim() !== "") ? passwords.new : undefined
|
password: (passwords.new && passwords.new.trim() !== "") ? passwords.new : undefined
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@ -3519,8 +3802,24 @@ function SettingsSidebar({
|
|||||||
showAllDayEvents: showAllDay,
|
showAllDayEvents: showAllDay,
|
||||||
showSchedule: showSchedule,
|
showSchedule: showSchedule,
|
||||||
headlineFont: headlineFont,
|
headlineFont: headlineFont,
|
||||||
|
headlineFontSize: headlineFontSize,
|
||||||
|
headlineFontWeight: headlineFontWeight,
|
||||||
|
dateFontFamily: dateFontFamily,
|
||||||
|
dateFontSize: dateFontSize,
|
||||||
|
dateFontWeight: dateFontWeight,
|
||||||
|
timeTaskFontFamily: timeTaskFontFamily,
|
||||||
|
timeTaskFontSize: timeTaskFontSize,
|
||||||
|
timeTaskFontWeight: timeTaskFontWeight,
|
||||||
bodyFont: bodyFont,
|
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({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="weekly-settings-content" style={{ flex: 1, overflowY: 'auto', padding: '24px' }}>
|
<div className="weekly-settings-content" style={{ flex: 1, overflowY: 'auto', padding: '24px' }}>
|
||||||
{accountMsg && (
|
|
||||||
<div className={`weekly-auth-message ${accountMsg.toLowerCase().includes('success') ? 'success' : 'error'}`}
|
|
||||||
style={{ marginBottom: '20px', padding: '10px', borderRadius: '4px', textAlign: 'center', fontWeight: 600 }}>
|
|
||||||
{accountMsg}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{activeTab === 'general' ? (
|
{activeTab === 'general' ? (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
|
||||||
{/* Motto */}
|
{/* Motto */}
|
||||||
@ -3850,85 +4143,197 @@ function SettingsSidebar({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Font Settings */}
|
{/* Typography Settings */}
|
||||||
<div style={{ marginBottom: '1.5rem' }}>
|
<div style={{ marginBottom: '1.5rem', borderBottom: '1px solid #eee', paddingBottom: '1rem' }}>
|
||||||
<label style={{ display: 'block', fontSize: '0.9rem', fontWeight: 600, marginBottom: '8px' }}>Typography</label>
|
<label style={{ display: 'block', fontSize: '1rem', fontWeight: 700, marginBottom: '12px', color: '#111827' }}>Font Customization</label>
|
||||||
|
|
||||||
{/* Headline Font */}
|
{/* Day Names */}
|
||||||
<div style={{ marginBottom: '12px' }}>
|
<div style={{ background: '#f8fafc', padding: '12px', borderRadius: '8px', marginBottom: '12px' }}>
|
||||||
<label style={{ display: 'block', fontSize: '0.85rem', color: '#666', marginBottom: '4px' }}>Headline Font</label>
|
<label style={{ display: 'block', fontSize: '0.85rem', fontWeight: 600, color: '#475569', marginBottom: '8px' }}>Weekday Font (e.g. MONTAG)</label>
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr 1fr', gap: '8px' }}>
|
||||||
<select
|
<select
|
||||||
value={profile.headlineFont || 'Inter'}
|
value={profile.headlineFont || 'Inter'}
|
||||||
onChange={(e) => setProfile({ ...profile, headlineFont: e.target.value })}
|
onChange={(e) => setProfile({ ...profile, headlineFont: e.target.value })}
|
||||||
className="weekly-input"
|
className="weekly-input"
|
||||||
style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px', fontFamily: profile.headlineFont || 'Inter' }}
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
>
|
>
|
||||||
{AVAILABLE_FONTS.map(font => (
|
{AVAILABLE_FONTS.map(font => (
|
||||||
<option key={font.value} value={font.value} style={{ fontFamily: font.value }}>{font.name}</option>
|
<option key={font.value} value={font.value} style={{ fontFamily: font.value }}>{font.name}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Body Font */}
|
|
||||||
<div style={{ marginBottom: '12px' }}>
|
|
||||||
<label style={{ display: 'block', fontSize: '0.85rem', color: '#666', marginBottom: '4px' }}>Body Font</label>
|
|
||||||
<select
|
<select
|
||||||
value={profile.bodyFont || 'Inter'}
|
value={profile.headlineFontSize || '1.25rem'}
|
||||||
onChange={(e) => setProfile({ ...profile, bodyFont: e.target.value })}
|
onChange={(e) => setProfile({ ...profile, headlineFontSize: e.target.value })}
|
||||||
className="weekly-input"
|
className="weekly-input"
|
||||||
style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px', fontFamily: profile.bodyFont || 'Inter' }}
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
|
>
|
||||||
|
<option value="1rem">Small 16px</option>
|
||||||
|
<option value="1.25rem">Normal 20px</option>
|
||||||
|
<option value="1.5rem">Large 24px</option>
|
||||||
|
<option value="1.75rem">XL 28px</option>
|
||||||
|
<option value="2rem">Huge 32px</option>
|
||||||
|
</select>
|
||||||
|
<select
|
||||||
|
value={profile.headlineFontWeight || '900'}
|
||||||
|
onChange={(e) => setProfile({ ...profile, headlineFontWeight: e.target.value })}
|
||||||
|
className="weekly-input"
|
||||||
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
|
>
|
||||||
|
<option value="300">Light</option>
|
||||||
|
<option value="400">Normal</option>
|
||||||
|
<option value="500">Medium</option>
|
||||||
|
<option value="600">Semi</option>
|
||||||
|
<option value="700">Bold</option>
|
||||||
|
<option value="900">Black</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Dates */}
|
||||||
|
<div style={{ background: '#f8fafc', padding: '12px', borderRadius: '8px', marginBottom: '12px' }}>
|
||||||
|
<label style={{ display: 'block', fontSize: '0.85rem', fontWeight: 600, color: '#475569', marginBottom: '8px' }}>Date Font (e.g. 12. Feb.)</label>
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr 1fr', gap: '8px' }}>
|
||||||
|
<select
|
||||||
|
value={profile.dateFontFamily || 'Inter'}
|
||||||
|
onChange={(e) => setProfile({ ...profile, dateFontFamily: e.target.value })}
|
||||||
|
className="weekly-input"
|
||||||
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
>
|
>
|
||||||
{AVAILABLE_FONTS.map(font => (
|
{AVAILABLE_FONTS.map(font => (
|
||||||
<option key={font.value} value={font.value} style={{ fontFamily: font.value }}>{font.name}</option>
|
<option key={font.value} value={font.value} style={{ fontFamily: font.value }}>{font.name}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
<select
|
||||||
|
value={profile.dateFontSize || '0.65rem'}
|
||||||
|
onChange={(e) => setProfile({ ...profile, dateFontSize: e.target.value })}
|
||||||
|
className="weekly-input"
|
||||||
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
|
>
|
||||||
|
<option value="0.55rem">XS 9px</option>
|
||||||
|
<option value="0.65rem">Normal 10px</option>
|
||||||
|
<option value="0.75rem">Small 12px</option>
|
||||||
|
<option value="0.85rem">Medium 14px</option>
|
||||||
|
<option value="1rem">Large 16px</option>
|
||||||
|
</select>
|
||||||
|
<select
|
||||||
|
value={profile.dateFontWeight || '400'}
|
||||||
|
onChange={(e) => setProfile({ ...profile, dateFontWeight: e.target.value })}
|
||||||
|
className="weekly-input"
|
||||||
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
|
>
|
||||||
|
<option value="300">Light</option>
|
||||||
|
<option value="400">Normal</option>
|
||||||
|
<option value="500">Medium</option>
|
||||||
|
<option value="600">Semi</option>
|
||||||
|
<option value="700">Bold</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Font Weight */}
|
{/* Tasks */}
|
||||||
<div>
|
<div style={{ background: '#f8fafc', padding: '12px', borderRadius: '8px', marginBottom: '12px' }}>
|
||||||
<label style={{ display: 'block', fontSize: '0.85rem', color: '#666', marginBottom: '4px' }}>Body Font Weight</label>
|
<label style={{ display: 'block', fontSize: '0.85rem', fontWeight: 600, color: '#475569', marginBottom: '8px' }}>Task Font</label>
|
||||||
<div style={{ display: 'flex', gap: '12px', flexWrap: 'wrap' }}>
|
<div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr 1fr', gap: '8px' }}>
|
||||||
{FONT_WEIGHTS.map(weight => (
|
<select
|
||||||
<div key={weight.value} style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>
|
value={profile.taskFontFamily || 'Inter'}
|
||||||
<input
|
onChange={(e) => setProfile({ ...profile, taskFontFamily: e.target.value, timeTaskFontFamily: e.target.value })}
|
||||||
type="checkbox"
|
className="weekly-input"
|
||||||
checked={profile.fontWeight === weight.value}
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
onChange={() => setProfile({ ...profile, fontWeight: weight.value })}
|
>
|
||||||
style={{ width: '16px', height: '16px', cursor: 'pointer' }}
|
{AVAILABLE_FONTS.map(font => (
|
||||||
/>
|
<option key={font.value} value={font.value} style={{ fontFamily: font.value }}>{font.name}</option>
|
||||||
<label onClick={() => setProfile({ ...profile, fontWeight: weight.value })} style={{ cursor: 'pointer', fontSize: '0.9rem' }}>
|
|
||||||
{weight.name}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
|
</select>
|
||||||
|
<select
|
||||||
|
value={profile.taskFontSize || '0.9rem'}
|
||||||
|
onChange={(e) => setProfile({ ...profile, taskFontSize: e.target.value, timeTaskFontSize: e.target.value })}
|
||||||
|
className="weekly-input"
|
||||||
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
|
>
|
||||||
|
<option value="0.75rem">Small 12px</option>
|
||||||
|
<option value="0.9rem">Normal 14px</option>
|
||||||
|
<option value="1rem">Medium 16px</option>
|
||||||
|
<option value="1.1rem">Large 18px</option>
|
||||||
|
<option value="1.25rem">XL 20px</option>
|
||||||
|
</select>
|
||||||
|
<select
|
||||||
|
value={profile.taskFontWeight || '400'}
|
||||||
|
onChange={(e) => setProfile({ ...profile, taskFontWeight: e.target.value, timeTaskFontWeight: e.target.value })}
|
||||||
|
className="weekly-input"
|
||||||
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
|
>
|
||||||
|
<option value="300">Light</option>
|
||||||
|
<option value="400">Normal</option>
|
||||||
|
<option value="500">Medium</option>
|
||||||
|
<option value="600">Semi</option>
|
||||||
|
<option value="700">Bold</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Font Preview */}
|
{/* Calendar Event Font */}
|
||||||
<div style={{
|
<div style={{ background: '#f8fafc', padding: '12px', borderRadius: '8px', marginBottom: '12px' }}>
|
||||||
marginTop: '1rem',
|
<label style={{ display: 'block', fontSize: '0.85rem', fontWeight: 600, color: '#475569', marginBottom: '8px' }}>Calendar Event Font</label>
|
||||||
padding: '1rem',
|
<div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr 1fr', gap: '8px' }}>
|
||||||
border: '1px solid #e5e7eb',
|
<select
|
||||||
borderRadius: '8px',
|
value={profile.eventFontFamily || 'Inter'}
|
||||||
background: '#f9fafb'
|
onChange={(e) => setProfile({ ...profile, eventFontFamily: e.target.value })}
|
||||||
}}>
|
className="weekly-input"
|
||||||
<div style={{
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
fontFamily: profile.headlineFont || 'Inter',
|
>
|
||||||
fontSize: '1.25rem',
|
{AVAILABLE_FONTS.map(font => (
|
||||||
fontWeight: 700,
|
<option key={font.value} value={font.value} style={{ fontFamily: font.value }}>{font.name}</option>
|
||||||
marginBottom: '0.5rem',
|
))}
|
||||||
color: '#111827'
|
</select>
|
||||||
}}>
|
<select
|
||||||
Headline Preview
|
value={profile.eventFontSize || '0.85rem'}
|
||||||
|
onChange={(e) => setProfile({ ...profile, eventFontSize: e.target.value })}
|
||||||
|
className="weekly-input"
|
||||||
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
|
>
|
||||||
|
<option value="0.75rem">Small 12px</option>
|
||||||
|
<option value="0.85rem">Normal 14px</option>
|
||||||
|
<option value="1rem">Medium 16px</option>
|
||||||
|
<option value="1.1rem">Large 18px</option>
|
||||||
|
</select>
|
||||||
|
<select
|
||||||
|
value={profile.eventFontWeight || '400'}
|
||||||
|
onChange={(e) => setProfile({ ...profile, eventFontWeight: e.target.value })}
|
||||||
|
className="weekly-input"
|
||||||
|
style={{ width: '100%', padding: '8px', fontSize: '0.9rem' }}
|
||||||
|
>
|
||||||
|
<option value="300">Light</option>
|
||||||
|
<option value="400">Normal</option>
|
||||||
|
<option value="500">Medium</option>
|
||||||
|
<option value="600">Semi</option>
|
||||||
|
<option value="700">Bold</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{/* Weekend Colors */}
|
||||||
|
<div style={{ background: '#f8fafc', padding: '12px', borderRadius: '8px', marginBottom: '12px' }}>
|
||||||
|
<label style={{ display: 'block', fontSize: '0.85rem', fontWeight: 600, color: '#475569', marginBottom: '8px' }}>Weekend Highlight Colors</label>
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }}>
|
||||||
|
<div>
|
||||||
|
<label style={{ display: 'block', fontSize: '0.75rem', color: '#666', marginBottom: '4px' }}>Saturday</label>
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
value={profile.weekendColorSat || '#666666'}
|
||||||
|
onChange={(e) => setProfile({ ...profile, weekendColorSat: e.target.value })}
|
||||||
|
style={{ width: '100%', height: '30px', cursor: 'pointer', border: 'none', background: 'transparent' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label style={{ display: 'block', fontSize: '0.75rem', color: '#666', marginBottom: '4px' }}>Sunday</label>
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
value={profile.weekendColorSun || '#dc2626'}
|
||||||
|
onChange={(e) => setProfile({ ...profile, weekendColorSun: e.target.value })}
|
||||||
|
style={{ width: '100%', height: '30px', cursor: 'pointer', border: 'none', background: 'transparent' }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{
|
|
||||||
fontFamily: profile.bodyFont || 'Inter',
|
|
||||||
fontWeight: parseInt(profile.fontWeight || '400'),
|
|
||||||
fontSize: '0.95rem',
|
|
||||||
color: '#374151',
|
|
||||||
lineHeight: 1.5
|
|
||||||
}}>
|
|
||||||
Body text preview. The quick brown fox jumps over the lazy dog. 1234567890.
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -3971,13 +4376,24 @@ function SettingsSidebar({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginTop: '16px', display: 'flex', alignItems: 'center', gap: '12px' }}>
|
||||||
<button
|
<button
|
||||||
onClick={handleUpdateProfile}
|
onClick={handleUpdateProfile}
|
||||||
className="weekly-btn-primary"
|
className="weekly-btn-primary"
|
||||||
style={{ marginTop: '8px', padding: '10px', alignSelf: 'flex-start' }}
|
style={{ padding: '10px 20px' }}
|
||||||
>
|
>
|
||||||
{t.saveChanges}
|
{t.saveChanges}
|
||||||
</button>
|
</button>
|
||||||
|
{accountMsg && (
|
||||||
|
<span style={{
|
||||||
|
fontSize: '0.9rem',
|
||||||
|
color: accountMsg.toLowerCase().includes('success') ? '#059669' : '#dc2626',
|
||||||
|
fontWeight: 600
|
||||||
|
}}>
|
||||||
|
{accountMsg}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : activeTab === 'calendar' ? (
|
) : activeTab === 'calendar' ? (
|
||||||
isLoading ? (
|
isLoading ? (
|
||||||
@ -4112,13 +4528,24 @@ function SettingsSidebar({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style={{ marginTop: '16px', display: 'flex', alignItems: 'center', gap: '12px' }}>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="weekly-auth-button primary"
|
className="weekly-btn-primary"
|
||||||
style={{ marginTop: '8px' }}
|
style={{ padding: '10px 20px' }}
|
||||||
>
|
>
|
||||||
{t.saveChanges}
|
{t.saveChanges}
|
||||||
</button>
|
</button>
|
||||||
|
{accountMsg && (
|
||||||
|
<span style={{
|
||||||
|
fontSize: '0.9rem',
|
||||||
|
color: accountMsg.toLowerCase().includes('success') ? '#059669' : '#dc2626',
|
||||||
|
fontWeight: 600
|
||||||
|
}}>
|
||||||
|
{accountMsg}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* Data Export Section */}
|
{/* Data Export Section */}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user