Der Prototyp war auf Schreibtischbreiten gebaut. Bei 375 px lief die Seite um 306 px seitlich über, und dem Inhalt blieben 135 px, weil die Seitenleiste ihre vollen 240 px behielt. Seitenleiste (an HiveGrid abgeglichen, nicht erfunden): - Unterhalb 768 px faehrt sie als Schublade ueber den Inhalt. Derselbe Breakpoint, den die Software als MOBILE_BREAKPOINT fuehrt. - Hamburger links in der Kopfzeile, FeatherMenu, 32x32, md:hidden, vor dem Breadcrumb — wie SubframeAppShell ihn rendert. - Abdeckung dahinter, Escape schliesst, Fokus wandert beim Oeffnen auf den ersten Eintrag und kehrt beim Schliessen zum Ausloeser zurueck. - Fokusfalle mit Tab und Umschalt+Tab: Der Rahmen traegt role=dialog und aria-modal, ohne Falle waere das gegenueber einem Screenreader unwahr. - Der Einklapp-Knopf ist unterhalb md ausgeblendet. Er ragt bauartbedingt 17 px nach rechts heraus und blieb sonst als angeschnittener, wirkungsloser Rest bei x = -16 am Bildrand stehen — der gemeldete Fehler. Inhalte: Raster einspaltig ab 375 px, Seitenkopf mit Aktionen unter dem Titel und Icon-only, Zeitraum-Segment und Reiterstreifen waagerecht scrollend statt umbrechend (ein Segment ueber zwei Zeilen liest sich als zwei Steuerelemente), Filter-Panel auf volle Zeilenbreite, Tabellen mit eigenem Scrollbereich. Zwei abgeschnittene Fehler mitbehoben, die der Prueferer nicht sieht: - KPI-Label lief bei 1280 px um 5 px aus seinem Kasten; bricht jetzt um. Die Karte wird dadurch eine Zeile hoeher — der Preis fuer eine vollstaendig lesbare Beschriftung. - Randmarken der Auslastungsachse ragten je rund 10 px ueber die Spur. In sehr schmalen Karten entfaellt die Achse ganz; dort bleibt nur rund 40 px Spur, auf der selbst zwei Marken aneinanderstossen. verify-layout deckt jetzt 375-1920 px ab (vorher ab 1024) und meldet zusaetzlich Seitenueberlauf: ein waagerechter Scrollbalken auf Dokumentebene ist immer ein Fehler, nie ein Kompromiss. 7 Seiten x 9 Breiten gruen. Ab 1024 px ist der abgenommene Stand unveraendert — numerisch geprueft ueber die Bounding-Boxen aller Karten, Raster, Tabellen und Kopfelemente. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
86 lines
3.3 KiB
TypeScript
86 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { FeatherDownload, FeatherRefreshCw, FeatherShare2 } from "@subframe/core";
|
|
import { useToast } from "../../context/ToastContext";
|
|
|
|
/**
|
|
* Kopf einer Analyse-Seite: Titel, Einordnung, Seitenaktionen.
|
|
* Die Aktionen sind im Prototyp bewusst folgenlos (Toast statt Export) —
|
|
* siehe HANDOVER.md, Abschnitt "Was noch Logik braucht".
|
|
*/
|
|
export function PageHeader({
|
|
titel,
|
|
beschreibung,
|
|
aktionen,
|
|
/**
|
|
* Aktualisieren, Export und Teilen. Auf Seiten ohne Inhalt gibt es nichts zu
|
|
* aktualisieren oder zu exportieren — dort schaltet man sie ab, statt
|
|
* Schaltflächen anzubieten, die ins Leere greifen.
|
|
*/
|
|
standardAktionen = true,
|
|
}: {
|
|
titel: string;
|
|
beschreibung: string;
|
|
aktionen?: React.ReactNode;
|
|
standardAktionen?: boolean;
|
|
}) {
|
|
const { zeigeToast } = useToast();
|
|
|
|
/**
|
|
* Unter `sm` tragen die beiden beschrifteten Knöpfe nur ihr Icon.
|
|
* Nebeneinander brauchen "Aktualisieren" und "Export" rund 240 px — mehr,
|
|
* als bei 375 px neben dem Titel überhaupt vorhanden ist. Die Beschriftung
|
|
* entfällt, `aria-label` bleibt: Für die Sprachausgabe ändert sich nichts.
|
|
*/
|
|
const knopf =
|
|
"flex h-9 w-9 flex-none items-center justify-center gap-2 rounded-md border border-solid " +
|
|
"border-border-default bg-white text-[13px] font-medium text-text-neutral-secondary " +
|
|
"hover:bg-neutral-50 sm:w-auto sm:px-3";
|
|
|
|
return (
|
|
// Unter `sm` untereinander: Titel und Aktionen nebeneinander lassen für den
|
|
// Titel keine 130 px übrig — er zerfiele in vier Zeilen, während die Knöpfe
|
|
// aus dem Bild laufen.
|
|
<div className="flex flex-col items-stretch gap-4 px-4 pb-6 pt-6 sm:flex-row sm:flex-wrap sm:items-start sm:justify-between sm:px-6">
|
|
<div className="flex min-w-0 flex-col gap-0">
|
|
<h1 className="break-words text-[22px] font-semibold leading-tight tracking-[-0.02em] text-text-neutral-primary">
|
|
{titel}
|
|
</h1>
|
|
<p className="text-[13px] leading-relaxed text-text-neutral-tertiary">{beschreibung}</p>
|
|
</div>
|
|
|
|
<div className="dv-no-print flex flex-none items-center gap-2">
|
|
{aktionen}
|
|
{standardAktionen ? (
|
|
<>
|
|
<button
|
|
onClick={() => zeigeToast("Ansicht aktualisiert", "Demo-Daten, Stichtag 30.07.2026")}
|
|
className={knopf}
|
|
aria-label="Ansicht aktualisieren"
|
|
>
|
|
<FeatherRefreshCw className="text-[15px]" />
|
|
<span className="hidden sm:inline">Aktualisieren</span>
|
|
</button>
|
|
<button
|
|
onClick={() => zeigeToast("Export vorgemerkt", "PDF/CSV folgt in der Umsetzung")}
|
|
className={knopf}
|
|
aria-label="Ansicht exportieren"
|
|
>
|
|
<FeatherDownload className="text-[15px]" />
|
|
<span className="hidden sm:inline">Export</span>
|
|
</button>
|
|
<button
|
|
onClick={() => zeigeToast("Link kopiert", "Teilen wird serverseitig umgesetzt")}
|
|
className="flex h-9 w-9 flex-none items-center justify-center rounded-md border border-solid border-border-default bg-white text-text-neutral-tertiary hover:bg-neutral-50"
|
|
aria-label="Ansicht teilen"
|
|
>
|
|
<FeatherShare2 className="text-[15px]" />
|
|
</button>
|
|
</>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|