Files
paliad/frontend/src/projects-chart.tsx
mAi e9bcf3a7b6 feat(t-paliad-177): chart reciprocal "Zurück zum Verlauf" link
Slice 3 step 5 (optional). The back-link on the chart page now points
explicitly at /projects/{id}/history (Verlauf sub-path) instead of
the bare /projects/{id}. Today's projects-detail.ts treats both the
same — bare and /history land on the Verlauf tab — but /history is
the explicit form, so the link keeps working if Verlauf ever stops
being the default tab.

Label flips from "Zurück zum Projekt" → "Zurück zum Verlauf" so
users see exactly where they're heading. Pairs naturally with the
Slice 1 "Als Chart anzeigen ↗" affordance: the trip is round.

Design ref: docs/design-project-chart-2026-05-09.md §8.1.
2026-05-13 11:53:46 +02:00

173 lines
8.7 KiB
TypeScript

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";
// t-paliad-177 Slice 1 — Project Timeline / Chart standalone page.
//
// Pure shell: header / controls scaffold (inert chips for the
// vertical-toggle, density and palette pickers, which Slice 3 wires
// live) + a chart host that client/projects-chart.ts mounts the SVG
// renderer into. Project metadata is loaded client-side so the same
// dist/projects-chart.html serves every {id}.
//
// Design ref: docs/design-project-chart-2026-05-09.md §8.2 + §12.
export function renderProjectsChart(): string {
return "<!DOCTYPE html>" + (
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="theme-color" content="#BFF355" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<PWAHead />
<title data-i18n="projects.chart.title">Projekt-Chart &mdash; Paliad</title>
<link rel="stylesheet" href="/assets/global.css" />
</head>
<body className="has-sidebar">
<Sidebar currentPath="/projects" />
<BottomNav currentPath="/projects" />
<main>
<section className="tool-page smart-timeline-chart-page">
<div className="container">
<a
id="projects-chart-back-link"
href="/projects"
className="back-link"
data-i18n="projects.chart.back"
>
&larr; Zur&uuml;ck zum Verlauf
</a>
<div id="projects-chart-loading" className="entity-loading">
<p data-i18n="projects.chart.loading">L&auml;dt&hellip;</p>
</div>
<div id="projects-chart-notfound" className="entity-empty" style="display:none">
<p data-i18n="projects.chart.notfound">Projekt nicht gefunden oder keine Berechtigung.</p>
</div>
<div id="projects-chart-body" style="display:none">
<header className="smart-timeline-chart-header">
<h1 id="projects-chart-title" />
<span id="projects-chart-meta" className="smart-timeline-chart-meta" />
</header>
<div className="smart-timeline-chart-controls" id="projects-chart-controls">
{/* Slice 1: chips render inert. Slice 3 wires them to
density / palette / zoom state. The presence keeps
the surface visually stable when controls light up. */}
<span className="chip-inert" data-i18n="projects.chart.control.layout.horizontal" title="Slice 3">
Layout: Horizontal
</span>
<span className="smart-timeline-chart-picker">
<label htmlFor="projects-chart-range" data-i18n="projects.chart.control.range.label">
Zeitraum:
</label>
<select id="projects-chart-range">
<option value="1y" data-i18n="projects.chart.range.1y">1 Jahr</option>
<option value="2y" data-i18n="projects.chart.range.2y">2 Jahre</option>
<option value="all" data-i18n="projects.chart.range.all">Alles anzeigen</option>
<option value="custom" data-i18n="projects.chart.range.custom">Eigener Bereich</option>
</select>
</span>
<span className="smart-timeline-chart-picker smart-timeline-chart-range-custom" id="projects-chart-range-custom" style="display:none">
<label htmlFor="projects-chart-range-from" data-i18n="projects.chart.range.from">Von:</label>
<input type="date" id="projects-chart-range-from" />
<label htmlFor="projects-chart-range-to" data-i18n="projects.chart.range.to">Bis:</label>
<input type="date" id="projects-chart-range-to" />
</span>
<span className="smart-timeline-chart-picker">
<label htmlFor="projects-chart-density" data-i18n="projects.chart.control.density.label">
Dichte:
</label>
<select id="projects-chart-density">
<option value="compact" data-i18n="projects.chart.density.compact">Kompakt</option>
<option value="standard" data-i18n="projects.chart.density.standard">Standard</option>
<option value="spacious" data-i18n="projects.chart.density.spacious">Großzügig</option>
</select>
</span>
<span className="smart-timeline-chart-picker">
<label htmlFor="projects-chart-palette" data-i18n="projects.chart.control.palette.label">
Palette:
</label>
<select id="projects-chart-palette">
<option value="default" data-i18n="projects.chart.palette.default">Standard</option>
<option value="kind-coded" data-i18n="projects.chart.palette.kind_coded">Nach Ereignistyp</option>
<option value="track-coded" data-i18n="projects.chart.palette.track_coded">Nach Spur</option>
<option value="high-contrast" data-i18n="projects.chart.palette.high_contrast">Hoher Kontrast</option>
<option value="print" data-i18n="projects.chart.palette.print">Druck (S/W)</option>
</select>
</span>
<button
type="button"
id="projects-chart-copylink"
className="smart-timeline-chart-copylink"
data-i18n="projects.chart.permalink.copy"
data-i18n-title="projects.chart.permalink.title"
title="URL mit allen Filtern in die Zwischenablage kopieren"
>
&#128279; Link kopieren
</button>
<details className="smart-timeline-chart-export">
<summary data-i18n="projects.chart.export.menu">
&dArr; Export
</summary>
<menu className="smart-timeline-chart-export-menu">
<li>
<button type="button" id="projects-chart-export-svg" data-i18n="projects.chart.export.svg">
SVG (Vektorgrafik)
</button>
</li>
<li>
<button type="button" id="projects-chart-export-png" data-i18n="projects.chart.export.png">
PNG (Bild, 2&times; HiDPI)
</button>
</li>
<li>
<button type="button" id="projects-chart-export-print" data-i18n="projects.chart.export.print">
PDF (Drucken)
</button>
</li>
<li className="smart-timeline-chart-export-divider" />
<li>
<button type="button" id="projects-chart-export-csv" data-i18n="projects.chart.export.csv">
CSV (Excel-Tabelle)
</button>
</li>
<li>
<button type="button" id="projects-chart-export-json" data-i18n="projects.chart.export.json">
JSON (Rohdaten)
</button>
</li>
<li>
<button type="button" id="projects-chart-export-ics" data-i18n="projects.chart.export.ics">
iCal (.ics Outlook / Apple)
</button>
</li>
</menu>
</details>
</div>
<div id="projects-chart-lanes-filter" className="smart-timeline-chart-lanes-filter" style="display:none" />
<div id="projects-chart-host" className="smart-timeline-chart-host" />
<p id="projects-chart-undated" className="smart-timeline-chart-undated-hint" style="display:none" />
</div>
</div>
</section>
</main>
<Footer />
<PaliadinWidget />
<script src="/assets/projects-chart.js"></script>
</body>
</html>
);
}