diff --git a/frontend/src/agenda.tsx b/frontend/src/agenda.tsx index 1e54356..f1a7824 100644 --- a/frontend/src/agenda.tsx +++ b/frontend/src/agenda.tsx @@ -66,6 +66,12 @@ export function renderAgenda(): string { + +
+ +
+
+ +
+
+
diff --git a/frontend/src/deadlines.tsx b/frontend/src/deadlines.tsx index a9b0dd2..deb92fb 100644 --- a/frontend/src/deadlines.tsx +++ b/frontend/src/deadlines.tsx @@ -82,6 +82,10 @@ export function renderDeadlines(): string { + + +
@@ -100,6 +104,7 @@ export function renderDeadlines(): string { Titel Projekt Regel + Typ Status diff --git a/frontend/src/i18n-keys.ts b/frontend/src/i18n-keys.ts index d274b82..7f903f2 100644 --- a/frontend/src/i18n-keys.ts +++ b/frontend/src/i18n-keys.ts @@ -190,6 +190,7 @@ export type I18nKey = | "agenda.filter.appointments" | "agenda.filter.both" | "agenda.filter.deadlines" + | "agenda.filter.event_type" | "agenda.filter.range" | "agenda.filter.type" | "agenda.heading" @@ -399,6 +400,7 @@ export type I18nKey = | "checklisten.reset.error" | "checklisten.subtitle" | "checklisten.title" + | "common.cancel" | "dashboard.action.short.akte_archived" | "dashboard.action.short.akte_created" | "dashboard.action.short.appointment_created" @@ -477,6 +479,7 @@ export type I18nKey = | "deadlines.calculate" | "deadlines.col.akte" | "deadlines.col.due" + | "deadlines.col.event_type" | "deadlines.col.rule" | "deadlines.col.status" | "deadlines.col.title" @@ -547,6 +550,7 @@ export type I18nKey = | "deadlines.field.akte.empty" | "deadlines.field.akte.empty.link" | "deadlines.field.due" + | "deadlines.field.event_type" | "deadlines.field.notes" | "deadlines.field.notes.placeholder" | "deadlines.field.rule" @@ -557,6 +561,7 @@ export type I18nKey = | "deadlines.filter.akte.all" | "deadlines.filter.all" | "deadlines.filter.completed" + | "deadlines.filter.event_type" | "deadlines.filter.overdue" | "deadlines.filter.pending" | "deadlines.filter.status" @@ -713,6 +718,37 @@ export type I18nKey = | "event.title.project_reparented" | "event.title.project_type_changed" | "event.title.status_changed" + | "event_types.add.category" + | "event_types.add.duplicate_warn" + | "event_types.add.error.generic" + | "event_types.add.error.required" + | "event_types.add.error.slug_taken" + | "event_types.add.firm_wide" + | "event_types.add.firm_wide.hint" + | "event_types.add.jurisdiction" + | "event_types.add.jurisdiction.any" + | "event_types.add.jurisdiction.none" + | "event_types.add.label_de" + | "event_types.add.label_en" + | "event_types.add.submit" + | "event_types.add.title" + | "event_types.cat.decision" + | "event_types.cat.fee" + | "event_types.cat.hearing" + | "event_types.cat.order" + | "event_types.cat.other" + | "event_types.cat.service" + | "event_types.cat.submission" + | "event_types.filter.all" + | "event_types.filter.apply" + | "event_types.filter.n_selected" + | "event_types.filter.reset" + | "event_types.filter.search" + | "event_types.filter.untyped" + | "event_types.picker.add" + | "event_types.picker.no_match" + | "event_types.picker.remove" + | "event_types.picker.search" | "footer.text" | "gebuehren.col.courtfee" | "gebuehren.col.fee" diff --git a/frontend/src/styles/global.css b/frontend/src/styles/global.css index 7b59df4..20d1342 100644 --- a/frontend/src/styles/global.css +++ b/frontend/src/styles/global.css @@ -8166,3 +8166,251 @@ dialog.quick-add-sheet::backdrop { mode, the browser-default scrollbar is dark via color-scheme, so no per-element override is needed here. */ +/* ============================================================================ + t-paliad-088 — Event Types: picker, multi-select filter, add modal + ============================================================================ */ + +/* Picker host — chip cluster + search + suggest dropdown */ +.event-type-picker { + display: flex; + flex-direction: column; + gap: 0.5rem; + border: 1px solid var(--color-border); + border-radius: 0.5rem; + padding: 0.5rem; + background: var(--color-bg-subtle); +} + +.event-type-chips { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; +} + +.event-type-chip { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.15rem 0.35rem 0.15rem 0.55rem; + background: var(--color-bg-lime-tint); + border: 1px solid var(--color-border); + border-radius: 999px; + font-size: 0.875rem; + line-height: 1.2; +} +.event-type-chip-label { white-space: nowrap; } +.event-type-chip-remove { + background: transparent; + border: 0; + padding: 0 0.25rem; + cursor: pointer; + font-size: 1.05rem; + line-height: 1; + color: var(--color-text-muted); +} +.event-type-chip-remove:hover { color: var(--color-text); } + +.event-type-search-row { + display: flex; + gap: 0.5rem; + align-items: center; +} +.event-type-search { + flex: 1; + padding: 0.4rem 0.5rem; + border: 1px solid var(--color-border); + border-radius: 0.375rem; + background: var(--color-bg); + font-size: 0.875rem; +} +.event-type-add-btn { + padding: 0.4rem 0.75rem; + border: 1px dashed var(--color-border); + border-radius: 0.375rem; + background: transparent; + cursor: pointer; + font-size: 0.875rem; + color: var(--color-text); + white-space: nowrap; +} +.event-type-add-btn:hover { background: var(--color-bg-subtle); } + +.event-type-suggest { + display: flex; + flex-direction: column; + border: 1px solid var(--color-border); + border-radius: 0.375rem; + background: var(--color-bg); + max-height: 14rem; + overflow-y: auto; +} +.event-type-suggest-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.4rem 0.6rem; + background: transparent; + border: 0; + border-bottom: 1px solid var(--color-border); + cursor: pointer; + text-align: left; + font-size: 0.875rem; + color: var(--color-text); +} +.event-type-suggest-row:last-child { border-bottom: 0; } +.event-type-suggest-row:hover { background: var(--color-bg-lime-tint); } +.event-type-suggest-cat { + font-size: 0.75rem; + color: var(--color-text-muted); + margin-left: 0.5rem; +} +.event-type-suggest-empty { + padding: 0.5rem 0.6rem; + font-size: 0.875rem; + color: var(--color-text-muted); +} + +/* Multi-select filter — trigger button + popover panel */ +.akten-multi-trigger { + display: inline-flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + cursor: pointer; + text-align: left; + min-width: 12rem; +} +.akten-multi-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.akten-multi-chevron { + color: var(--color-text-muted); + flex-shrink: 0; +} + +.akten-multi-panel { + position: absolute; + z-index: 50; + margin-top: 0.25rem; + width: 22rem; + max-width: calc(100vw - 1rem); + background: var(--color-bg); + border: 1px solid var(--color-border); + border-radius: 0.5rem; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); + padding: 0.5rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + max-height: 28rem; +} +.akten-multi-panel[hidden] { display: none; } +.akten-multi-search-row { display: flex; } +.akten-multi-search { + flex: 1; + padding: 0.4rem 0.5rem; + border: 1px solid var(--color-border); + border-radius: 0.375rem; + background: var(--color-bg-subtle); + font-size: 0.875rem; +} +.akten-multi-specials { + display: flex; + flex-direction: column; + gap: 0.15rem; + padding-bottom: 0.4rem; + border-bottom: 1px solid var(--color-border); +} +.akten-multi-list { + overflow-y: auto; + flex: 1; + min-height: 4rem; +} +.akten-multi-group { padding: 0.25rem 0; } +.akten-multi-group-label { + font-size: 0.75rem; + font-weight: 600; + color: var(--color-text-muted); + text-transform: uppercase; + letter-spacing: 0.04em; + padding: 0.25rem 0.4rem; +} +.akten-multi-option { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.3rem 0.5rem; + border-radius: 0.25rem; + cursor: pointer; + font-size: 0.875rem; +} +.akten-multi-option:hover { background: var(--color-bg-lime-tint); } +.akten-multi-option input[type="checkbox"] { margin: 0; } +.akten-multi-special { font-weight: 500; } +.akten-multi-actions { + display: flex; + justify-content: flex-end; + gap: 0.5rem; + border-top: 1px solid var(--color-border); + padding-top: 0.5rem; +} + +/* Typ pill in the deadlines table — compact, neutral. */ +.akten-event-type-pill { + display: inline-block; + padding: 0.05rem 0.4rem; + margin-right: 0.2rem; + background: var(--color-bg-subtle); + border: 1px solid var(--color-border); + border-radius: 999px; + font-size: 0.75rem; + color: var(--color-text); + white-space: nowrap; +} + +/* Hide-on-uniform: when no row has any event_type, hide the column. */ +.akten-table--hide-event-type .akten-col-event-type { display: none; } + +/* Add-modal styling — extends the existing .modal-overlay/.modal pattern. */ +.event-type-add-modal { + width: 28rem; + max-width: calc(100vw - 2rem); +} +.event-type-add-modal .form-field-row { display: flex; gap: 0.75rem; } +.event-type-add-modal .form-field-row > .form-field { flex: 1; } +.event-type-suggest-warn { + padding: 0.5rem 0.6rem; + background: var(--status-amber-soft-bg); + color: var(--status-amber-soft-fg); + border-radius: 0.375rem; + font-size: 0.875rem; +} +.event-type-suggest-pill { + display: inline-block; + margin: 0 0.2rem; + padding: 0.05rem 0.4rem; + background: var(--color-bg); + border: 1px solid var(--color-border); + border-radius: 999px; + font-size: 0.75rem; +} + +/* Mobile: filter row already wraps; the multi-panel becomes a bottom-anchored + sheet on narrow viewports. */ +@media (max-width: 640px) { + .akten-multi-panel { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: auto; + width: 100%; + max-width: 100%; + max-height: 70vh; + border-radius: 0.75rem 0.75rem 0 0; + margin: 0; + } +} +