diff --git a/frontend/build.ts b/frontend/build.ts index a3e4e82..adb013a 100644 --- a/frontend/build.ts +++ b/frontend/build.ts @@ -5,6 +5,7 @@ import { renderLogin } from "./src/login"; import { renderKostenrechner } from "./src/kostenrechner"; import { renderFristenrechner } from "./src/fristenrechner"; import { renderVerfahrensablauf } from "./src/verfahrensablauf"; +import { renderProcedures } from "./src/procedures"; import { renderDownloads } from "./src/downloads"; import { renderLinks } from "./src/links"; import { renderGlossary } from "./src/glossary"; @@ -243,6 +244,7 @@ async function build() { join(import.meta.dir, "src/client/kostenrechner.ts"), join(import.meta.dir, "src/client/fristenrechner.ts"), join(import.meta.dir, "src/client/verfahrensablauf.ts"), + join(import.meta.dir, "src/client/procedures.ts"), join(import.meta.dir, "src/client/downloads.ts"), join(import.meta.dir, "src/client/links.ts"), join(import.meta.dir, "src/client/glossary.ts"), @@ -371,6 +373,7 @@ async function build() { await Bun.write(join(DIST, "kostenrechner.html"), renderKostenrechner()); await Bun.write(join(DIST, "fristenrechner.html"), renderFristenrechner()); await Bun.write(join(DIST, "verfahrensablauf.html"), renderVerfahrensablauf()); + await Bun.write(join(DIST, "procedures.html"), renderProcedures()); await Bun.write(join(DIST, "downloads.html"), renderDownloads()); await Bun.write(join(DIST, "links.html"), renderLinks()); await Bun.write(join(DIST, "glossary.html"), renderGlossary()); diff --git a/frontend/src/client/i18n.ts b/frontend/src/client/i18n.ts index cba9ccb..167ec99 100644 --- a/frontend/src/client/i18n.ts +++ b/frontend/src/client/i18n.ts @@ -205,6 +205,25 @@ const translations: Record> = { "tools.verfahrensablauf.heading": "Verfahrensablauf", "tools.verfahrensablauf.subtitle": "Typischen Verfahrensablauf einsehen \u2014 Verfahrensart w\u00e4hlen, Datum optional setzen.", + // Unified procedural-events tool (m/paliad#151, U0 skeleton) + "procedures.title": "Verfahren & Fristen \u2014 Paliad", + "procedures.heading": "Verfahren & Fristen", + "procedures.subtitle": "Verfahrensablauf, Fristenrechner und gef\u00fchrte Suche in einem Tool.", + "procedures.filter.search.placeholder": "Klageerhebung, Hinweisbeschluss, oral hearing\u2026", + "procedures.filter.axis.forum": "Forum:", + "procedures.filter.axis.proc": "Verfahren:", + "procedures.filter.axis.kind": "Ereignisart:", + "procedures.filter.axis.party": "Partei:", + "procedures.tab.proceeding": "Verfahren w\u00e4hlen", + "procedures.tab.search": "Direkt suchen", + "procedures.tab.wizard": "Gef\u00fchrt", + "procedures.tab.akte": "Aus Akte", + "procedures.panel.proceeding.placeholder": "Verfahrenswahl folgt in U3 \u2014 das \u00dcbersichts-Baumdiagramm wird hier eingebettet.", + "procedures.panel.search.placeholder": "Direktsuche folgt in U1.", + "procedures.panel.wizard.placeholder": "Gef\u00fchrter Einstieg folgt in U2.", + "procedures.panel.akte.placeholder": "Akten-Einstieg folgt in einem sp\u00e4teren Slice.", + "nav.procedures": "Verfahren & Fristen", + "deadlines.step1": "Verfahrensart w\u00e4hlen", "deadlines.step2": "Ausgangsdatum eingeben", "deadlines.step2.perspective": "Perspektive und Datum", @@ -3399,6 +3418,25 @@ const translations: Record> = { "tools.verfahrensablauf.heading": "Procedure Roadmap", "tools.verfahrensablauf.subtitle": "Browse the typical proceeding shape \u2014 pick a proceeding type, optionally set a trigger date.", + // Unified procedural-events tool (m/paliad#151, U0 skeleton) + "procedures.title": "Procedures & Deadlines \u2014 Paliad", + "procedures.heading": "Procedures & Deadlines", + "procedures.subtitle": "Procedure roadmap, deadline calculator, and guided search in one tool.", + "procedures.filter.search.placeholder": "Statement of claim, hearing notice, m\u00fcndliche Verhandlung\u2026", + "procedures.filter.axis.forum": "Forum:", + "procedures.filter.axis.proc": "Proceeding:", + "procedures.filter.axis.kind": "Event kind:", + "procedures.filter.axis.party": "Party:", + "procedures.tab.proceeding": "Pick proceeding", + "procedures.tab.search": "Direct search", + "procedures.tab.wizard": "Guided", + "procedures.tab.akte": "From matter", + "procedures.panel.proceeding.placeholder": "Pick-proceeding view ships in U3 \u2014 the overview tree mounts here.", + "procedures.panel.search.placeholder": "Direct search ships in U1.", + "procedures.panel.wizard.placeholder": "Guided entry ships in U2.", + "procedures.panel.akte.placeholder": "Matter entry ships in a later slice.", + "nav.procedures": "Procedures & Deadlines", + "deadlines.step1": "Select Proceeding Type", "deadlines.step2": "Enter Trigger Date", "deadlines.step2.perspective": "Perspective and Date", diff --git a/frontend/src/client/procedures.ts b/frontend/src/client/procedures.ts new file mode 100644 index 0000000..1595bde --- /dev/null +++ b/frontend/src/client/procedures.ts @@ -0,0 +1,72 @@ +// /tools/procedures client — U0 skeleton boot +// (m/paliad#151, docs/design-unified-procedural-events-tool-2026-05-27.md). +// +// U0 owns: +// - Tab switching across the four entry modes (proceeding / search / +// wizard / akte). URL-driven via ?mode=; cold open lands on +// "proceeding" per design §11.5.Q3. +// - Showing exactly one panel at a time. +// +// Later slices wire data: +// U1 mounts Mode A into #procedures-panel-search. +// U2 mounts Mode B into #procedures-panel-wizard. +// U3 mounts Verfahrensablauf into #procedures-panel-proceeding + +// #procedures-output-tree. +// The search box in the top filter strip and the chip filters in +// #procedures-filter-chips-* are also wired in U1+ as each slice +// adds its dimension-aware behaviour. + +import { initI18n } from "./i18n"; +import { initSidebar } from "./sidebar"; + +type ProceduresTab = "proceeding" | "search" | "wizard" | "akte"; + +const TABS: ProceduresTab[] = ["proceeding", "search", "wizard", "akte"]; + +function readTabFromUrl(): ProceduresTab { + const params = new URLSearchParams(window.location.search); + const raw = params.get("mode"); + if (raw && (TABS as string[]).includes(raw)) return raw as ProceduresTab; + return "proceeding"; +} + +function writeTabToUrl(tab: ProceduresTab): void { + const url = new URL(window.location.href); + if (tab === "proceeding") { + url.searchParams.delete("mode"); + } else { + url.searchParams.set("mode", tab); + } + history.replaceState(null, "", url.pathname + url.search + url.hash); +} + +function showTab(tab: ProceduresTab): void { + for (const t of TABS) { + const btn = document.getElementById(`procedures-tab-${t}`); + const panel = document.getElementById(`procedures-panel-${t}`); + const active = t === tab; + if (btn) { + btn.classList.toggle("is-active", active); + btn.setAttribute("aria-selected", active ? "true" : "false"); + } + if (panel) panel.hidden = !active; + } +} + +function wireTabs(): void { + for (const t of TABS) { + const btn = document.getElementById(`procedures-tab-${t}`); + if (!btn) continue; + btn.addEventListener("click", () => { + showTab(t); + writeTabToUrl(t); + }); + } +} + +document.addEventListener("DOMContentLoaded", () => { + initI18n(); + initSidebar(); + showTab(readTabFromUrl()); + wireTabs(); +}); diff --git a/frontend/src/i18n-keys.ts b/frontend/src/i18n-keys.ts index 4706209..01e21c8 100644 --- a/frontend/src/i18n-keys.ts +++ b/frontend/src/i18n-keys.ts @@ -2088,6 +2088,7 @@ export type I18nKey = | "nav.logout" | "nav.neuigkeiten" | "nav.paliadin" + | "nav.procedures" | "nav.projekte" | "nav.soon.tooltip" | "nav.submissions" @@ -2204,6 +2205,22 @@ export type I18nKey = | "partner_unit.members_label" | "partner_unit.none" | "partner_unit.subtitle" + | "procedures.filter.axis.forum" + | "procedures.filter.axis.kind" + | "procedures.filter.axis.party" + | "procedures.filter.axis.proc" + | "procedures.filter.search.placeholder" + | "procedures.heading" + | "procedures.panel.akte.placeholder" + | "procedures.panel.proceeding.placeholder" + | "procedures.panel.search.placeholder" + | "procedures.panel.wizard.placeholder" + | "procedures.subtitle" + | "procedures.tab.akte" + | "procedures.tab.proceeding" + | "procedures.tab.search" + | "procedures.tab.wizard" + | "procedures.title" | "project.instance_level.appeal" | "project.instance_level.cassation" | "project.instance_level.first" diff --git a/frontend/src/procedures.tsx b/frontend/src/procedures.tsx new file mode 100644 index 0000000..93bd5b8 --- /dev/null +++ b/frontend/src/procedures.tsx @@ -0,0 +1,193 @@ +import { h } from "./jsx"; +import { Sidebar } from "./components/Sidebar"; +import { PaliadinWidget } from "./components/PaliadinWidget"; +import { BottomNav } from "./components/BottomNav"; +import { Footer } from "./components/Footer"; +import { PWAHead } from "./components/PWAHead"; + +// U0 — Skeleton for the unified procedural-events tool +// (m/paliad#151, design docs/design-unified-procedural-events-tool-2026-05-27.md). +// +// Folds /tools/fristenrechner (Mode A + Mode B + result) and +// /tools/verfahrensablauf into a single page at /tools/procedures. Each +// later slice fills one of the four entry tabs: +// +// U1 — Direkt suchen (Mode A search) +// U2 — Geführt (Mode B wizard) +// U3 — Verfahren (Verfahrensablauf tree + 3-way detail filter) +// U4 — Hard-cut 301 (drop legacy pages, redirect URLs) +// +// This file ships only the page chrome — sidebar, header, filter strip +// with search box, four entry-mode tabs, and the host containers the +// later slices mount their UI into. No data wiring. + +export function renderProcedures(): string { + return "" + ( + + + + + + + + + Verfahren & Fristen — Paliad + + + + + + +
+
+
+
+

Verfahren & Fristen

+

+ Verfahrensablauf, Fristenrechner und gerührte Suche in einem Tool. +

+
+ + {/* Shared filter strip — search box + four chip groups + (forum / proceeding / event_kind / party). Lives at the + top of the page so every entry tab and output mode reads + the same active filter set (design §4 + m's Q3 + divergence: search composes with chip filters). U0 + ships the markup only; chip hydration + search wiring + arrive with U1-U3. */} +
+
+ + +
+
+
+ Forum: +
+
+
+ Verfahren: +
+
+
+ Ereignisart: +
+
+
+ Partei: +
+
+
+
+ + {/* Entry-mode tab strip — all four tabs visible from boot + (m's Q3 divergence). The active tab is URL-driven + (?mode=proceeding|search|wizard|akte); cold open lands + on "proceeding" per design §11.5.Q3. */} + + + {/* Per-tab content hosts. Only one is visible at a time — + procedures.ts toggles `hidden` on the inactive ones. + Each later slice fills the corresponding host. */} +
+
+ Verfahrenswahl folgt in U3 — das Übersichts-Baumdiagramm wird hier eingebettet. +
+
+ + + + + + + + {/* Tree output host. Slice U3 mounts the Verfahrensablauf + tree here; U0 leaves it empty + hidden so the + tab placeholders are the only thing visible. */} + + + {/* Linear-drawer host. Inline drawer expanding beneath a + tree card (design §8 — desktop) AND the standalone + linear follow-up view that Mode A / Mode B land on + after locking a trigger event (design §3.2). U1 + switches it on. */} + +
+
+
+ +