mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:01:09 +02:00
refactor(calendar): improve agenda and event components
- Replace native select with FilterDropdown in AgendaFilters - Add view options to DateStripContextMenu - Improve EventForm layout and styling - Enhance QuickEventOverlay with better time handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
cc28cc739e
commit
48edd85591
4 changed files with 76 additions and 57 deletions
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { Calendar, CheckSquare, Filter } from 'lucide-svelte';
|
||||
import { FilterDropdown, type FilterDropdownOption } from '@manacore/shared-ui';
|
||||
|
||||
interface Props {
|
||||
showEvents: boolean;
|
||||
|
|
@ -19,10 +20,10 @@
|
|||
onRangeChange,
|
||||
}: Props = $props();
|
||||
|
||||
const rangeOptions = [
|
||||
{ value: '7' as const, label: '7 Tage' },
|
||||
{ value: '30' as const, label: '30 Tage' },
|
||||
{ value: 'all' as const, label: 'Alle' },
|
||||
const rangeOptions: FilterDropdownOption[] = [
|
||||
{ value: '7', label: '7 Tage' },
|
||||
{ value: '30', label: '30 Tage' },
|
||||
{ value: 'all', label: 'Alle' },
|
||||
];
|
||||
</script>
|
||||
|
||||
|
|
@ -53,15 +54,13 @@
|
|||
<div class="filter-group">
|
||||
<div class="range-selector">
|
||||
<Filter size={14} />
|
||||
<select
|
||||
<FilterDropdown
|
||||
options={rangeOptions}
|
||||
value={timeRange}
|
||||
onchange={(e) =>
|
||||
onRangeChange?.((e.target as HTMLSelectElement).value as '7' | '30' | 'all')}
|
||||
>
|
||||
{#each rangeOptions as option}
|
||||
<option value={option.value}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
onChange={(v) => onRangeChange?.(v as '7' | '30' | 'all')}
|
||||
placeholder="Zeitraum"
|
||||
embedded={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -122,21 +121,6 @@
|
|||
color: hsl(var(--color-muted-foreground));
|
||||
}
|
||||
|
||||
.range-selector select {
|
||||
padding: 0.375rem 0.75rem;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid hsl(var(--color-border));
|
||||
background: hsl(var(--color-surface));
|
||||
color: hsl(var(--color-foreground));
|
||||
font-size: 0.8125rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.range-selector select:focus {
|
||||
outline: none;
|
||||
border-color: hsl(var(--color-primary));
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.agenda-filters {
|
||||
flex-direction: column;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { ContextMenu, type ContextMenuItem } from '@manacore/shared-ui';
|
||||
import { Moon, Calendar, Eye, Columns, ArrowsIn } from '@manacore/shared-icons';
|
||||
import { Moon, Calendar, Eye, Columns, ArrowsIn, ArrowsOut } from '@manacore/shared-icons';
|
||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||
|
||||
// Context menu state
|
||||
|
|
@ -77,6 +77,17 @@
|
|||
checked: settingsStore.dateStripCompact,
|
||||
action: () => toggleSetting('dateStripCompact'),
|
||||
},
|
||||
{
|
||||
id: 'divider-3',
|
||||
label: '',
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
id: 'minimize',
|
||||
label: settingsStore.dateStripCollapsed ? 'Erweitern' : 'Minimieren',
|
||||
icon: settingsStore.dateStripCollapsed ? ArrowsOut : ArrowsIn,
|
||||
action: () => toggleSetting('dateStripCollapsed'),
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@
|
|||
import { calendarsStore } from '$lib/stores/calendars.svelte';
|
||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
||||
import { eventTagsStore } from '$lib/stores/event-tags.svelte';
|
||||
import { TagSelector, type Tag } from '@manacore/shared-ui';
|
||||
import {
|
||||
TagSelector,
|
||||
FilterDropdown,
|
||||
type Tag,
|
||||
type FilterDropdownOption,
|
||||
} from '@manacore/shared-ui';
|
||||
import AttendeeSelector from './AttendeeSelector.svelte';
|
||||
import ResponsiblePersonSelector from './ResponsiblePersonSelector.svelte';
|
||||
import type {
|
||||
|
|
@ -79,6 +84,18 @@
|
|||
// Derived available tags for TagSelector
|
||||
let availableTags = $derived(eventTagsStore.tags.map(eventTagToTag));
|
||||
|
||||
// Calendar options for FilterDropdown
|
||||
let calendarOptions = $derived<FilterDropdownOption[]>(
|
||||
calendarsStore.calendars.map((cal) => ({ value: cal.id, label: cal.name }))
|
||||
);
|
||||
|
||||
// All-day display mode options
|
||||
const displayModeOptions: FilterDropdownOption[] = [
|
||||
{ value: 'default', label: 'Standard (aus Einstellungen)' },
|
||||
{ value: 'header', label: 'In Kopfzeile' },
|
||||
{ value: 'block', label: 'Als Tagesblock' },
|
||||
];
|
||||
|
||||
// Auto-expand location details if any field is filled
|
||||
$effect(() => {
|
||||
if (event?.metadata?.locationDetails) {
|
||||
|
|
@ -228,17 +245,14 @@
|
|||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="calendar" class="text-sm font-medium text-foreground">Kalender</label>
|
||||
<span class="text-sm font-medium text-foreground">Kalender</span>
|
||||
{#if calendarsStore.calendars.length > 0}
|
||||
<select
|
||||
id="calendar"
|
||||
class="w-full px-3 py-2 border-2 border-border rounded-lg bg-background text-foreground focus:outline-none focus:border-primary transition-colors"
|
||||
bind:value={calendarId}
|
||||
>
|
||||
{#each calendarsStore.calendars as cal}
|
||||
<option value={cal.id}>{cal.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<FilterDropdown
|
||||
options={calendarOptions}
|
||||
value={calendarId}
|
||||
onChange={(v) => (calendarId = typeof v === 'string' ? v : '')}
|
||||
placeholder="Kalender wählen"
|
||||
/>
|
||||
{:else}
|
||||
<p class="text-sm text-muted-foreground italic">Standardkalender wird automatisch erstellt</p>
|
||||
{/if}
|
||||
|
|
@ -253,16 +267,13 @@
|
|||
|
||||
{#if isAllDay}
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="displayMode" class="text-sm font-medium text-foreground">Anzeigeart</label>
|
||||
<select
|
||||
id="displayMode"
|
||||
class="w-full px-3 py-2 border-2 border-border rounded-lg bg-background text-foreground focus:outline-none focus:border-primary transition-colors"
|
||||
bind:value={allDayDisplayMode}
|
||||
>
|
||||
<option value="default">Standard (aus Einstellungen)</option>
|
||||
<option value="header">In Kopfzeile</option>
|
||||
<option value="block">Als Tagesblock</option>
|
||||
</select>
|
||||
<span class="text-sm font-medium text-foreground">Anzeigeart</span>
|
||||
<FilterDropdown
|
||||
options={displayModeOptions}
|
||||
value={allDayDisplayMode}
|
||||
onChange={(v) => (allDayDisplayMode = (v as 'default' | 'header' | 'block') || 'default')}
|
||||
placeholder="Anzeigeart wählen"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,13 @@
|
|||
EventAttendee,
|
||||
} from '@calendar/shared';
|
||||
import type { ContactSummary, ContactOrManual, ManualContactEntry } from '@manacore/shared-types';
|
||||
import { ContactSelector, ContactAvatar, ConfirmationPopover } from '@manacore/shared-ui';
|
||||
import {
|
||||
ContactSelector,
|
||||
ContactAvatar,
|
||||
ConfirmationPopover,
|
||||
FilterDropdown,
|
||||
type FilterDropdownOption,
|
||||
} from '@manacore/shared-ui';
|
||||
import { Users } from 'lucide-svelte';
|
||||
import { format, addMinutes } from 'date-fns';
|
||||
import { de } from 'date-fns/locale';
|
||||
|
|
@ -208,6 +214,13 @@
|
|||
let showPeopleSelector = $state(false);
|
||||
let contactsAvailable = $state<boolean | null>(null);
|
||||
|
||||
// All-day display mode options
|
||||
const displayModeOptions: FilterDropdownOption[] = [
|
||||
{ value: 'default', label: 'Standard (aus Einstellungen)' },
|
||||
{ value: 'header', label: 'In Kopfzeile' },
|
||||
{ value: 'block', label: 'Als Tagesblock' },
|
||||
];
|
||||
|
||||
// Check contacts availability
|
||||
$effect(() => {
|
||||
contactsStore.checkAvailability().then((available) => {
|
||||
|
|
@ -849,11 +862,13 @@
|
|||
<div class="row-icon"></div>
|
||||
<div class="row-content">
|
||||
<span class="field-label">Anzeigeart</span>
|
||||
<select class="field-select" bind:value={allDayDisplayMode}>
|
||||
<option value="default">Standard (aus Einstellungen)</option>
|
||||
<option value="header">In Kopfzeile</option>
|
||||
<option value="block">Als Tagesblock</option>
|
||||
</select>
|
||||
<FilterDropdown
|
||||
options={displayModeOptions}
|
||||
value={allDayDisplayMode}
|
||||
onChange={(v) =>
|
||||
(allDayDisplayMode = (v as 'default' | 'header' | 'block') || 'default')}
|
||||
placeholder="Anzeigeart wählen"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -1306,7 +1321,6 @@
|
|||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.field-select,
|
||||
.field-input {
|
||||
width: 100%;
|
||||
padding: 0.5rem 0.625rem;
|
||||
|
|
@ -1317,7 +1331,6 @@
|
|||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.field-select:focus,
|
||||
.field-input:focus {
|
||||
outline: none;
|
||||
border-color: hsl(var(--color-primary));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue