feat: add calendar hover preview settings and functionality

This commit is contained in:
Linus Rath
2026-03-29 14:10:28 +02:00
parent 375c0a7339
commit 02577c7502
4 changed files with 46 additions and 9 deletions
+16 -8
View File
@@ -69,7 +69,7 @@ export default function CalendarPage() {
setSelectedDate, setViewMode, toggleCalendarVisibility, updateCalendar,
refreshAllSubscriptions,
} = useCalendarStore();
const { firstDayOfWeek, timeFormat, showWeekNumbers, enableCalendarTasks, showTasksOnCalendar } = useSettingsStore();
const { firstDayOfWeek, timeFormat, showWeekNumbers, enableCalendarTasks, showTasksOnCalendar, calendarHoverPreview } = useSettingsStore();
const taskStore = useTaskStore();
const fetchTasksFn = useTaskStore(state => state.fetchTasks);
const { identities } = useIdentityStore();
@@ -338,18 +338,26 @@ export default function CalendarPage() {
const handleHoverEvent = useCallback((event: CalendarEvent, anchorRect: DOMRect) => {
if (isMobile) return;
if (calendarHoverPreview === 'off') return;
if (hoverTimerRef.current) { clearTimeout(hoverTimerRef.current); hoverTimerRef.current = null; }
// Don't show hover popover if the sidebar is already open for this event
if (showEventModal && editEvent?.id === event.id) return;
setDetailEvent(event);
setDetailAnchorRect(anchorRect);
}, [isMobile, showEventModal, editEvent]);
if (calendarHoverPreview === 'delay-500ms' || calendarHoverPreview === 'delay-1s' || calendarHoverPreview === 'delay-2s') {
const ms = calendarHoverPreview === 'delay-500ms' ? 500 : calendarHoverPreview === 'delay-1s' ? 1000 : 2000;
hoverTimerRef.current = setTimeout(() => {
setDetailEvent(event);
setDetailAnchorRect(anchorRect);
}, ms);
} else {
setDetailEvent(event);
setDetailAnchorRect(anchorRect);
}
}, [isMobile, calendarHoverPreview, showEventModal, editEvent]);
const handleHoverLeave = useCallback(() => {
hoverTimerRef.current = setTimeout(() => {
setDetailEvent(null);
setDetailAnchorRect(null);
}, 200);
if (hoverTimerRef.current) { clearTimeout(hoverTimerRef.current); hoverTimerRef.current = null; }
setDetailEvent(null);
setDetailAnchorRect(null);
}, []);
const handleEditFromDetail = useCallback(() => {
+18
View File
@@ -19,6 +19,7 @@ export function CalendarSettings() {
showWeekNumbers,
enableCalendarTasks,
showTasksOnCalendar,
calendarHoverPreview,
updateSetting,
} = useSettingsStore();
const { isFeatureEnabled } = usePolicyStore();
@@ -80,6 +81,23 @@ export function CalendarSettings() {
/>
</SettingItem>
<SettingItem
label={t('hover_preview')}
description={t('hover_preview_desc')}
>
<Select
value={calendarHoverPreview}
onChange={(value) => updateSetting('calendarHoverPreview', value as 'off' | 'instant' | 'delay-500ms' | 'delay-1s' | 'delay-2s')}
options={[
{ value: 'instant', label: t('hover_preview_instant') },
{ value: 'delay-500ms', label: t('hover_preview_delay_500ms') },
{ value: 'delay-1s', label: t('hover_preview_delay_1s') },
{ value: 'delay-2s', label: t('hover_preview_delay_2s') },
{ value: 'off', label: t('hover_preview_off') },
]}
/>
</SettingItem>
{isFeatureEnabled('calendarTasksEnabled') && (
<>
<SettingItem
+8 -1
View File
@@ -1981,7 +1981,14 @@
"enable_tasks": "Enable tasks",
"enable_tasks_desc": "Show a tasks view in the calendar for managing to-dos",
"show_tasks_on_calendar": "Show tasks on calendar",
"show_tasks_on_calendar_desc": "Display task chips on the day and week calendar views"
"show_tasks_on_calendar_desc": "Display task chips on the day and week calendar views",
"hover_preview": "Event hover preview",
"hover_preview_desc": "Show a detail popover when hovering over calendar events",
"hover_preview_instant": "Instant",
"hover_preview_delay_500ms": "0.5-second delay",
"hover_preview_delay_1s": "1-second delay",
"hover_preview_delay_2s": "2-second delay",
"hover_preview_off": "Disabled"
},
"days": {
"monday": "Monday",
+4
View File
@@ -34,6 +34,7 @@ export type AttachmentPosition = 'beside-sender' | 'below-header';
export type ToolbarPosition = 'top' | 'below-subject';
export type ArchiveMode = 'single' | 'year' | 'month';
export type MailLayout = 'split' | 'focus';
export type CalendarHoverPreview = 'off' | 'instant' | 'delay-500ms' | 'delay-1s' | 'delay-2s';
export type HoverAction = 'delete' | 'star' | 'markRead' | 'archive' | 'tag' | 'spam';
export type HoverActionsMode = 'inline' | 'floating';
@@ -134,6 +135,7 @@ interface SettingsState {
// Calendar
showTimeInMonthView: boolean;
showWeekNumbers: boolean;
calendarHoverPreview: CalendarHoverPreview;
// Calendar Tasks
enableCalendarTasks: boolean;
@@ -257,6 +259,7 @@ const DEFAULT_SETTINGS = {
// Calendar
showTimeInMonthView: false,
showWeekNumbers: false,
calendarHoverPreview: 'delay-500ms' as CalendarHoverPreview,
// Calendar Tasks
enableCalendarTasks: false,
@@ -370,6 +373,7 @@ export const useSettingsStore = create<SettingsState>()(
expandedFilterView: state.expandedFilterView,
showTimeInMonthView: state.showTimeInMonthView,
showWeekNumbers: state.showWeekNumbers,
calendarHoverPreview: state.calendarHoverPreview,
toolbarPosition: state.toolbarPosition,
hideAccountSwitcher: state.hideAccountSwitcher,
showRailAccountList: state.showRailAccountList,