feat: Add Start Week setting, update date header format, and refine Someday styling
This commit is contained in:
parent
e9a0a706b7
commit
bccadb34ce
@ -174,12 +174,29 @@ const translations: Record<string, any> = {
|
|||||||
function getStartOfWeek(date: Date, startDay: number = 0): Date {
|
function getStartOfWeek(date: Date, startDay: number = 0): Date {
|
||||||
const d = new Date(date);
|
const d = new Date(date);
|
||||||
const day = d.getDay();
|
const day = d.getDay();
|
||||||
const diff = d.getDate() - day + startDay;
|
const diff = d.getDate() - day + (day < startDay ? -7 : 0) + startDay; // if today is sun(0) and start is mon(1), day < start (0 < 1) -> -7 + 1 = -6. 0 - 6 = -6. Correct.
|
||||||
return new Date(d.setDate(diff));
|
// Wait, let's re-verify:
|
||||||
|
// Start Mon(1). Today Sun(0). day=0. diff = date - 0 + (-7) + 1 = date - 6. Correct (last Monday).
|
||||||
|
// Start Mon(1). Today Mon(1). day=1. diff = date - 1 + (0) + 1 = date. Correct.
|
||||||
|
// Start Sun(0). Today Mon(1). day=1. diff = date - 1 + (0) + 0 = date - 1. Correct (last Sunday).
|
||||||
|
// Start Sun(0). Today Sun(0). day=0. diff = date - 0 + (0) + 0 = date. Correct.
|
||||||
|
// What if Start Mon(1), Today Tue(2). day=2. diff = date - 2 + 0 + 1 = date - 1. Correct.
|
||||||
|
|
||||||
|
// Better logic:
|
||||||
|
// const day = d.getDay();
|
||||||
|
// const diff = (day < startDay ? 7 : 0) + day - startDay;
|
||||||
|
// d.setDate(d.getDate() - diff);
|
||||||
|
//
|
||||||
|
// Let's stick to a robust one:
|
||||||
|
const currentDay = d.getDay();
|
||||||
|
const distance = (currentDay - startDay + 7) % 7;
|
||||||
|
d.setDate(d.getDate() - distance);
|
||||||
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDateHeader(date: Date, locale: string = 'en-US'): string {
|
function formatDateHeader(date: Date, locale: string = 'en-US'): string {
|
||||||
return date.toLocaleDateString(locale, { day: 'numeric', month: 'short', year: 'numeric' });
|
const datePart = date.toLocaleDateString(locale, { day: 'numeric', month: 'short' }); // e.g. 12. Feb.
|
||||||
|
return `| ${datePart}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDayName(date: Date, locale: string = 'en-US'): string {
|
function getDayName(date: Date, locale: string = 'en-US'): string {
|
||||||
@ -272,7 +289,7 @@ export default function WeeklyView() {
|
|||||||
return { ...event, editable: isEditable };
|
return { ...event, editable: isEditable };
|
||||||
});
|
});
|
||||||
}, [rawCalendarEvents, connections]);
|
}, [rawCalendarEvents, connections]);
|
||||||
const [currentWeekStart, setCurrentWeekStart] = useState(getStartOfWeek(new Date()));
|
const [currentWeekStart, setCurrentWeekStart] = useState(getStartOfWeek(new Date(), 1)); // Default align to Monday initially
|
||||||
const [viewDays, setViewDays] = useState(7);
|
const [viewDays, setViewDays] = useState(7);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [darkMode, setDarkMode] = useState(false);
|
const [darkMode, setDarkMode] = useState(false);
|
||||||
@ -306,6 +323,7 @@ export default function WeeklyView() {
|
|||||||
|
|
||||||
const [startHour, setStartHour] = useState(8);
|
const [startHour, setStartHour] = useState(8);
|
||||||
const [endHour, setEndHour] = useState(22);
|
const [endHour, setEndHour] = useState(22);
|
||||||
|
const [weekStartDay, setWeekStartDay] = useState(1); // 1 = Monday, 0 = Sunday
|
||||||
const [showSomeday, setShowSomeday] = useState(true);
|
const [showSomeday, setShowSomeday] = useState(true);
|
||||||
const [showAllDay, setShowAllDay] = useState(true);
|
const [showAllDay, setShowAllDay] = useState(true);
|
||||||
const [motto, setMotto] = useState('Focus and Execute');
|
const [motto, setMotto] = useState('Focus and Execute');
|
||||||
@ -339,6 +357,10 @@ export default function WeeklyView() {
|
|||||||
if (savedDarkMode) {
|
if (savedDarkMode) {
|
||||||
setDarkMode(JSON.parse(savedDarkMode));
|
setDarkMode(JSON.parse(savedDarkMode));
|
||||||
}
|
}
|
||||||
|
const savedWeekStart = localStorage.getItem('weekly-week-start');
|
||||||
|
if (savedWeekStart) {
|
||||||
|
setWeekStartDay(Number(savedWeekStart));
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -351,6 +373,13 @@ export default function WeeklyView() {
|
|||||||
}
|
}
|
||||||
}, [darkMode, mounted]);
|
}, [darkMode, mounted]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!mounted) return;
|
||||||
|
localStorage.setItem('weekly-week-start', String(weekStartDay));
|
||||||
|
// Re-align current week start when start day changes
|
||||||
|
setCurrentWeekStart(prev => getStartOfWeek(prev, weekStartDay));
|
||||||
|
}, [weekStartDay, mounted]);
|
||||||
|
|
||||||
// Translation helper
|
// Translation helper
|
||||||
const t = translations[language] || translations['en'];
|
const t = translations[language] || translations['en'];
|
||||||
|
|
||||||
@ -860,7 +889,7 @@ export default function WeeklyView() {
|
|||||||
const goToNextWeek = () => navigate(new Date(currentWeekStart.getTime() + 7 * 24 * 60 * 60 * 1000), 'left', 'week');
|
const goToNextWeek = () => navigate(new Date(currentWeekStart.getTime() + 7 * 24 * 60 * 60 * 1000), 'left', 'week');
|
||||||
const goToPrevDay = () => navigate(new Date(currentWeekStart.getTime() - 24 * 60 * 60 * 1000), 'right', 'day');
|
const goToPrevDay = () => navigate(new Date(currentWeekStart.getTime() - 24 * 60 * 60 * 1000), 'right', 'day');
|
||||||
const goToNextDay = () => navigate(new Date(currentWeekStart.getTime() + 24 * 60 * 60 * 1000), 'left', 'day');
|
const goToNextDay = () => navigate(new Date(currentWeekStart.getTime() + 24 * 60 * 60 * 1000), 'left', 'day');
|
||||||
const goToToday = () => setCurrentWeekStart(getStartOfWeek(new Date()));
|
const goToToday = () => setCurrentWeekStart(getStartOfWeek(new Date(), weekStartDay));
|
||||||
|
|
||||||
// Task CRUD operations
|
// Task CRUD operations
|
||||||
const addTask = async (date: Date, title: string, startTime?: string) => {
|
const addTask = async (date: Date, title: string, startTime?: string) => {
|
||||||
@ -1498,7 +1527,7 @@ export default function WeeklyView() {
|
|||||||
<SimpleDatePicker
|
<SimpleDatePicker
|
||||||
selected={currentWeekStart}
|
selected={currentWeekStart}
|
||||||
onSelect={(date) => {
|
onSelect={(date) => {
|
||||||
setCurrentWeekStart(getStartOfWeek(date));
|
setCurrentWeekStart(getStartOfWeek(date, weekStartDay));
|
||||||
setShowDatePicker(false);
|
setShowDatePicker(false);
|
||||||
}}
|
}}
|
||||||
onClose={() => setShowDatePicker(false)}
|
onClose={() => setShowDatePicker(false)}
|
||||||
@ -2315,7 +2344,7 @@ export default function WeeklyView() {
|
|||||||
}} />
|
}} />
|
||||||
{Array.from({ length: Math.max(0, 5 - list.tasks.length) }).map((_, i) => (
|
{Array.from({ length: Math.max(0, 5 - list.tasks.length) }).map((_, i) => (
|
||||||
<li key={`filler-${i}`} className="weekly-task-item minimal filler" style={{
|
<li key={`filler-${i}`} className="weekly-task-item minimal filler" style={{
|
||||||
borderBottom: '1px dashed #eee',
|
borderBottom: '1px solid #eee',
|
||||||
height: '32px',
|
height: '32px',
|
||||||
margin: '0 0.5rem',
|
margin: '0 0.5rem',
|
||||||
pointerEvents: 'none'
|
pointerEvents: 'none'
|
||||||
@ -2427,7 +2456,7 @@ export default function WeeklyView() {
|
|||||||
(t.isRolling && (!t.scheduledDate || new Date(t.scheduledDate) <= now)) ||
|
(t.isRolling && (!t.scheduledDate || new Date(t.scheduledDate) <= now)) ||
|
||||||
// Or implicitly today if within current view logic (e.g. dayOfWeek match in current week)
|
// Or implicitly today if within current view logic (e.g. dayOfWeek match in current week)
|
||||||
// But let's stick to explicit date or rolling for Focus Mode to be precise.
|
// But let's stick to explicit date or rolling for Focus Mode to be precise.
|
||||||
(!t.scheduledDate && t.dayOfWeek === now.getDay() && isSameDay(currentWeekStart, getStartOfWeek(now)))
|
(!t.scheduledDate && t.dayOfWeek === now.getDay() && isSameDay(currentWeekStart, getStartOfWeek(now, weekStartDay)))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2458,6 +2487,8 @@ export default function WeeklyView() {
|
|||||||
setShowTimeGrid={setShowTimeGrid}
|
setShowTimeGrid={setShowTimeGrid}
|
||||||
cellDuration={cellDuration}
|
cellDuration={cellDuration}
|
||||||
setCellDuration={setCellDuration}
|
setCellDuration={setCellDuration}
|
||||||
|
weekStartDay={weekStartDay}
|
||||||
|
setWeekStartDay={setWeekStartDay}
|
||||||
viewStyle={viewStyle}
|
viewStyle={viewStyle}
|
||||||
setViewStyle={setViewStyle}
|
setViewStyle={setViewStyle}
|
||||||
showSomeday={showSomeday}
|
showSomeday={showSomeday}
|
||||||
@ -2739,7 +2770,7 @@ function SomedayAddTask({ listId, onAdd }: { listId: string; onAdd: (title: stri
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="weekly-task-item minimal" style={{ borderBottom: '1px dashed #eee', margin: '0 0.5rem' }}>
|
<li className="weekly-task-item minimal" style={{ borderBottom: '1px solid #eee', margin: '0 0.5rem' }}>
|
||||||
<form onSubmit={(e) => { e.preventDefault(); handleSubmit(); }} style={{ width: '100%' }}>
|
<form onSubmit={(e) => { e.preventDefault(); handleSubmit(); }} style={{ width: '100%' }}>
|
||||||
<input
|
<input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
@ -3111,6 +3142,8 @@ interface SettingsModalProps {
|
|||||||
setShowTimeGrid: (show: boolean) => void;
|
setShowTimeGrid: (show: boolean) => void;
|
||||||
cellDuration: CellDuration;
|
cellDuration: CellDuration;
|
||||||
setCellDuration: (duration: CellDuration) => void;
|
setCellDuration: (duration: CellDuration) => void;
|
||||||
|
weekStartDay: number;
|
||||||
|
setWeekStartDay: (day: number) => void;
|
||||||
viewStyle: 'grid' | 'list';
|
viewStyle: 'grid' | 'list';
|
||||||
setViewStyle: (style: 'grid' | 'list') => void;
|
setViewStyle: (style: 'grid' | 'list') => void;
|
||||||
showSomeday: boolean;
|
showSomeday: boolean;
|
||||||
@ -3136,6 +3169,8 @@ function SettingsModal({
|
|||||||
setShowTimeGrid,
|
setShowTimeGrid,
|
||||||
cellDuration,
|
cellDuration,
|
||||||
setCellDuration,
|
setCellDuration,
|
||||||
|
weekStartDay,
|
||||||
|
setWeekStartDay,
|
||||||
viewStyle,
|
viewStyle,
|
||||||
setViewStyle,
|
setViewStyle,
|
||||||
showSomeday,
|
showSomeday,
|
||||||
@ -3620,6 +3655,25 @@ function SettingsModal({
|
|||||||
<div style={{ borderTop: '1px solid #eee', marginTop: '16px', paddingTop: '16px' }}></div>
|
<div style={{ borderTop: '1px solid #eee', marginTop: '16px', paddingTop: '16px' }}></div>
|
||||||
<h4 style={{ fontSize: '1rem', fontWeight: 600, margin: 0 }}>{t.localization}</h4>
|
<h4 style={{ fontSize: '1rem', fontWeight: 600, margin: 0 }}>{t.localization}</h4>
|
||||||
|
|
||||||
|
{/* Start Week Setting */}
|
||||||
|
<div>
|
||||||
|
<label style={{ display: 'block', fontSize: '0.9rem', fontWeight: 600, marginBottom: '4px' }}>Start week on</label>
|
||||||
|
<div style={{ display: 'flex', gap: '8px' }}>
|
||||||
|
<button
|
||||||
|
className={`px-3 py-2 rounded text-sm ${weekStartDay === 1 ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300'}`}
|
||||||
|
onClick={() => setWeekStartDay(1)}
|
||||||
|
>
|
||||||
|
Monday
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`px-3 py-2 rounded text-sm ${weekStartDay === 0 ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300'}`}
|
||||||
|
onClick={() => setWeekStartDay(0)}
|
||||||
|
>
|
||||||
|
Sunday
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label style={{ display: 'block', fontSize: '0.9rem', fontWeight: 600, marginBottom: '4px' }}>{t.language}</label>
|
<label style={{ display: 'block', fontSize: '0.9rem', fontWeight: 600, marginBottom: '4px' }}>{t.language}</label>
|
||||||
<select
|
<select
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user