feat(calendar-web): add right-click context menu to events in week view

Use shared ContextMenu component on EventCard for quick actions:
edit, duplicate, and delete. Includes i18n for all 5 languages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-03-23 22:02:46 +01:00
parent 250e0b20af
commit e7bf58c5b6
6 changed files with 105 additions and 5 deletions

View file

@ -28,6 +28,7 @@
} from '$lib/utils/eventFiltering';
import EventCard from './EventCard.svelte';
import TaskBlock from './TaskBlock.svelte';
import { ContextMenu, type ContextMenuItem } from '@manacore/shared-ui';
import { goto } from '$app/navigation';
import {
format,
@ -336,6 +337,63 @@
}
// (Drag/drop/resize/create/keyboard handlers are in composables above)
// Context menu state
let contextMenuVisible = $state(false);
let contextMenuX = $state(0);
let contextMenuY = $state(0);
let contextMenuEvent = $state<CalendarEvent | null>(null);
function handleEventContextMenu(event: CalendarEvent, e: MouseEvent) {
contextMenuX = e.clientX;
contextMenuY = e.clientY;
contextMenuEvent = event;
contextMenuVisible = true;
}
function getContextMenuItems(): ContextMenuItem[] {
if (!contextMenuEvent) return [];
const event = contextMenuEvent;
return [
{
id: 'edit',
label: $_('calendar.contextMenu.edit'),
action: () => {
if (onEventClick) {
onEventClick(event);
} else {
goto(`/?event=${event.id}`);
}
},
},
{
id: 'duplicate',
label: $_('calendar.contextMenu.duplicate'),
action: async () => {
await eventsStore.createEvent({
calendarId: event.calendarId,
title: `${event.title} (${$_('calendar.contextMenu.copy')})`,
description: event.description ?? undefined,
location: event.location ?? undefined,
startTime: event.startTime,
endTime: event.endTime,
isAllDay: event.isAllDay,
timezone: event.timezone ?? undefined,
color: event.color ?? undefined,
status: event.status ?? undefined,
});
},
},
{ id: 'divider-1', label: '', type: 'divider' },
{
id: 'delete',
label: $_('calendar.contextMenu.delete'),
variant: 'danger',
action: () => eventsStore.deleteEvent(event.id),
},
];
}
</script>
<div class="week-view">
@ -490,6 +548,7 @@
? eventDragDrop.getResizePreviewTime()
: formatEventTimeRange(event)}
onClick={handleEventClick}
onContextMenu={handleEventContextMenu}
onPointerDown={eventDragDrop.startDrag}
onResizeStart={eventDragDrop.startResize}
/>
@ -608,6 +667,17 @@
/>
{/if}
<ContextMenu
visible={contextMenuVisible}
x={contextMenuX}
y={contextMenuY}
items={getContextMenuItems()}
onClose={() => {
contextMenuVisible = false;
contextMenuEvent = null;
}}
/>
<style>
.week-view {
display: flex;

View file

@ -37,7 +37,13 @@
"draftEvent": "(Neuer Termin)",
"untitled": "Ohne Titel",
"hideSidebar": "Sidebar ausblenden",
"showSidebar": "Sidebar einblenden"
"showSidebar": "Sidebar einblenden",
"contextMenu": {
"edit": "Bearbeiten",
"duplicate": "Duplizieren",
"copy": "Kopie",
"delete": "Löschen"
}
},
"event": {
"title": "Titel",

View file

@ -37,7 +37,13 @@
"draftEvent": "(New Event)",
"untitled": "Untitled",
"hideSidebar": "Hide sidebar",
"showSidebar": "Show sidebar"
"showSidebar": "Show sidebar",
"contextMenu": {
"edit": "Edit",
"duplicate": "Duplicate",
"copy": "Copy",
"delete": "Delete"
}
},
"event": {
"title": "Title",

View file

@ -32,7 +32,13 @@
"allDay": "Todo el día",
"myCalendars": "Mis calendarios",
"sharedCalendars": "Calendarios compartidos",
"untitled": "Sin título"
"untitled": "Sin título",
"contextMenu": {
"edit": "Editar",
"duplicate": "Duplicar",
"copy": "Copia",
"delete": "Eliminar"
}
},
"event": {
"title": "Título",

View file

@ -32,7 +32,13 @@
"allDay": "Toute la journée",
"myCalendars": "Mes calendriers",
"sharedCalendars": "Calendriers partagés",
"untitled": "Sans titre"
"untitled": "Sans titre",
"contextMenu": {
"edit": "Modifier",
"duplicate": "Dupliquer",
"copy": "Copie",
"delete": "Supprimer"
}
},
"event": {
"title": "Titre",

View file

@ -32,7 +32,13 @@
"allDay": "Tutto il giorno",
"myCalendars": "I miei calendari",
"sharedCalendars": "Calendari condivisi",
"untitled": "Senza titolo"
"untitled": "Senza titolo",
"contextMenu": {
"edit": "Modifica",
"duplicate": "Duplica",
"copy": "Copia",
"delete": "Elimina"
}
},
"event": {
"title": "Titolo",