feat(fristenrechner): Slice S3 — Mode A direct search (m/paliad#146)
Some checks failed
Paliad CI gate / build (push) Has been cancelled
Paliad CI gate / test-go (push) Has been cancelled
Paliad CI gate / deploy (push) Has been cancelled

Mode A " Direkt suchen" — the power-user entry path defined in
docs/design-fristenrechner-overhaul-2026-05-26.md §3.1. Renders
above the §4 result view; clicking a result row locks the trigger
event and transitions to the shared result surface from S2.

Frontend:
  * `fristenrechner-mode-a.ts` — filter strip (Forum / Verfahren /
    Was passierte / Partei) + free-text search input + result list.
    Section-split visual hierarchy per m §11.Q3: filter chips in a
    bordered "Filter (eingrenzen)" strip on top, result list below.
    Inbox channel chip lives behind an "Erweitert" details summary
    per §3.3; picking CMS / beA auto-nudges the Forum chip. Party
    chip retains a "Beide" option (Mode A is filter mode per §11.Q8;
    Mode B drops it in S4).
  * `fristenrechner-result.ts` — new `mountModeShell(activeTab)`
    renders the two mode tabs per §11.Q2 and lazy-imports Mode A.
    Mode B tab is a placeholder until S4 lands.
  * `fristenrechner.ts` boot — when `?overhaul=1` is set and `?event`
    is empty, mountModeShell takes over (default tab = search; `?mode=
    wizard` opens the wizard tab when S4 ships). With `?event=` the
    flow still jumps straight to the result view. URL state syncs
    forum / pt / kind / party / q on every chip click.
  * 28 i18n keys added (DE + EN parity), 310-line CSS block for the
    mode tabs + Mode A surface.

Backend:
  * New `ProceedingListOptions { Jurisdiction, Kind }` + service
    method `ListProceedings(ctx, opts)`. Legacy
    `ListFristenrechnerTypes` keeps the no-filter signature for
    existing callers. Handler `/api/tools/proceeding-types` accepts
    `?jurisdiction=` and `?kind=` query params.
  * `kind=proceeding` filter targets the taxonomy column landed in
    mig 153 (parallel branch t-paliad-325, m/paliad#147). Sequenced
    per the taxonomy doc §7 option (c): mig 153 merges before S3
    ships to main, so the filter is never false-positive (no phase
    / side_action / meta rows leak into the chip strip).

Verified — bun build clean (2955 i18n keys, data-i18n attributes
clean), 249 frontend tests pass, go build + vet clean. New
TestListProceedings — 4 PASS (no-filter, jurisdiction=UPC,
jurisdiction=DE, ListFristenrechnerTypes alias) + 1 SKIP for the
kind=proceeding case that probes the column and skips when mig 153
hasn't landed yet. S1 + S2 live tests still green.
This commit is contained in:
mAi
2026-05-27 10:07:27 +02:00
parent 058a36976b
commit 2a2c5b8033
9 changed files with 1160 additions and 13 deletions

View File

@@ -19226,3 +19226,313 @@ a.fristen-overhaul-rule-source {
min-width: 0;
}
}
/* === Fristenrechner overhaul Mode A + mode tabs (t-paliad-323 S3) ===
*
* Mode tab pair + filter strip + search box + result list per
* docs/design-fristenrechner-overhaul-2026-05-26.md §3.1.
* Section-split visual hierarchy per m §11.Q3: filter strip on top
* ("Filter (eingrenzen)" header), result list below (clicking a row
* IS the qualifier commit).
* ==================================================================== */
.fristen-mode-tabs {
display: flex;
gap: 0.4rem;
margin: 0 0 1rem 0;
border-bottom: 2px solid #e3e3da;
}
.fristen-mode-tab {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.55rem 1.1rem;
background: transparent;
border: 0;
border-bottom: 3px solid transparent;
margin-bottom: -2px;
color: #555;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
border-radius: 0.4rem 0.4rem 0 0;
}
.fristen-mode-tab:hover {
background: #f5f5ef;
color: #1f1f1f;
}
.fristen-mode-tab.is-active {
color: #2a2a2a;
border-bottom-color: #c6f41c;
background: #fbfdf3;
}
.fristen-mode-tab-icon {
font-size: 1.1rem;
}
.fristen-mode-tab-label {
font-weight: 500;
}
.fristen-mode-a-root {
display: flex;
flex-direction: column;
gap: 1rem;
}
.fristen-mode-a-filters {
background: #f7f8f2;
border: 1px solid #e2e3d7;
border-radius: 0.7rem;
padding: 0.8rem 1rem;
}
.fristen-mode-a-filters-header {
font-size: 0.8rem;
letter-spacing: 0.05em;
color: #6e7256;
text-transform: uppercase;
margin-bottom: 0.6rem;
font-weight: 600;
}
.fristen-mode-a-chip-row {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
margin-bottom: 0.4rem;
}
.fristen-mode-a-axis-label {
font-size: 0.85rem;
color: #555;
min-width: 7rem;
font-weight: 500;
}
.fristen-mode-a-chips {
display: flex;
flex-wrap: wrap;
gap: 0.3rem;
}
.fristen-mode-a-chip {
display: inline-flex;
align-items: center;
gap: 0.3rem;
padding: 0.25rem 0.65rem;
border: 1px solid #d4d4c9;
background: #fff;
color: #2a2a2a;
border-radius: 1rem;
font-size: 0.85rem;
cursor: pointer;
font-family: inherit;
}
.fristen-mode-a-chip:hover {
border-color: #b9c98f;
background: #f6fae5;
}
.fristen-mode-a-chip.is-active {
background: #d8ed90;
border-color: #98b545;
color: #2c3d10;
font-weight: 600;
}
.fristen-mode-a-chip-icon {
font-size: 0.95rem;
}
.fristen-mode-a-chip-loading,
.fristen-mode-a-chip-empty {
color: #888;
font-size: 0.85rem;
font-style: italic;
}
.fristen-mode-a-inbox {
margin-top: 0.5rem;
padding-top: 0.4rem;
border-top: 1px dashed #d8d8cd;
}
.fristen-mode-a-inbox-summary {
cursor: pointer;
color: #5f664a;
font-size: 0.85rem;
margin-bottom: 0.3rem;
user-select: none;
}
.fristen-mode-a-inbox-summary:hover {
color: #2a2a2a;
}
.fristen-mode-a-search {
background: #fff;
border: 1px solid #d8d8ce;
border-radius: 0.7rem;
padding: 0.6rem 0.9rem;
}
.fristen-mode-a-search-input-wrap {
display: flex;
align-items: center;
gap: 0.6rem;
}
.fristen-mode-a-search-icon {
color: #888;
}
.fristen-mode-a-search-input {
flex: 1 1 auto;
border: 0;
outline: none;
font-size: 1rem;
background: transparent;
padding: 0.3rem 0;
color: #1f1f1f;
}
.fristen-mode-a-results {
background: #fff;
border: 1px solid #e0e0d4;
border-radius: 0.7rem;
padding: 0.7rem 0.9rem;
}
.fristen-mode-a-results-header {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 0.5rem;
}
.fristen-mode-a-results-title {
font-weight: 600;
color: #2a2a2a;
}
.fristen-mode-a-results-count {
font-size: 0.85rem;
color: #777;
}
.fristen-mode-a-result-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.4rem;
max-height: 60vh;
overflow-y: auto;
}
.fristen-mode-a-result {
display: grid;
grid-template-columns: auto 1fr auto;
gap: 0.7rem;
align-items: center;
padding: 0.55rem 0.7rem;
background: #fafaf6;
border: 1px solid #ececde;
border-radius: 0.5rem;
cursor: pointer;
}
.fristen-mode-a-result:hover,
.fristen-mode-a-result:focus {
background: #f1f7d8;
border-color: #c2d182;
outline: none;
}
.fristen-mode-a-result-icon {
font-size: 1.3rem;
}
.fristen-mode-a-result-body {
min-width: 0;
}
.fristen-mode-a-result-title {
font-weight: 600;
color: #1f1f1f;
}
.fristen-mode-a-result-meta {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
align-items: center;
font-size: 0.8rem;
color: #555;
margin-top: 0.2rem;
}
.fristen-mode-a-result-pt {
font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
padding: 0.05rem 0.45rem;
background: #efefe6;
border-radius: 0.3rem;
}
.fristen-mode-a-result-pt-name {
color: #555;
}
.fristen-mode-a-result-juris {
padding: 0.05rem 0.45rem;
background: #d3edb7;
color: #38531a;
border-radius: 0.3rem;
font-weight: 600;
}
.fristen-mode-a-result-followups {
color: #4a6f1f;
font-weight: 500;
}
.fristen-mode-a-result-cta {
color: #88a554;
font-size: 1.2rem;
}
.fristen-mode-a-result-loading,
.fristen-mode-a-result-empty,
.fristen-mode-a-result-error {
list-style: none;
padding: 0.7rem 0.5rem;
color: #888;
font-style: italic;
font-size: 0.9rem;
}
.fristen-mode-a-result-error {
color: #732f25;
}
@media (max-width: 600px) {
.fristen-mode-a-axis-label {
min-width: 0;
width: 100%;
}
.fristen-mode-a-result {
grid-template-columns: auto 1fr;
}
.fristen-mode-a-result-cta {
grid-column: 1 / -1;
text-align: right;
}
}