fix(ui): WCAG light-theme accent, overflow-safe audit page, formal address
Some checks are pending
Security / Security check (push) Waiting to run

Accessibility/responsive audit pass with two new permanent test
gates (test/a11y_test.dart: WCAG text contrast + labeled tap
targets on every page in both themes; test/responsive_test.dart:
no layout overflow at 800/960/1280/1920 px). Findings fixed:

- Light theme primary/tertiary sky-500 → sky-700: white text on
  the lighter accent only reached 2.8:1 (welcome CTA, active
  sidebar label); sky-700 clears WCAG AA at ~5.9:1. Dark theme
  unchanged (already compliant). FABs now follow the same accent
  instead of Material 3's washed-out tonal default.
- Audit page: filter chips collapse into a checkmark popup menu
  below 900 px window width (app bar overflowed); the live-status
  bar's left text is now Expanded with ellipsis so the row can
  shrink, and the disconnected state's copyable error gets the
  full remaining width.
- German strings now use formal address consistently (~20 strings
  still used du-forms next to Sie-forms on welcome/setup), the
  audit event-type chip "Step" is "Schritt", and the doctor
  page's event count pluralises correctly in both languages.

flutter analyze clean, 64 tests green. Screenshot pass light+dark
via the guide-shots harness (verified parity, no overflows).

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-07-15 04:34:19 +02:00
parent efaa089454
commit da58125f20
9 changed files with 339 additions and 95 deletions

View file

@ -195,7 +195,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get errServiceUnavailableForStepHint =>
'Das Modul braucht einen Service (z.B. ollama, playwright), den der Operator nicht deklariert hat. Trage ihn unter `services:` in ~/.chain/config.yaml ein.';
'Das Modul braucht einen Service (z.B. ollama, playwright), den der Operator nicht deklariert hat. Tragen Sie ihn unter `services:` in ~/.chain/config.yaml ein.';
@override
String get errMissingValue => 'Pflichtwert fehlt.';
@ -217,7 +217,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get errCapabilityNotInstalledHint =>
'Im Text-Tab des Flows klickst du auf den Fix-Button — der installiert die Capability, sofern sie im Store ist.';
'Im Text-Tab des Flows klicken Sie auf den Fix-Button — der installiert die Capability, sofern sie im Store ist.';
@override
String get welcomeDocClose => 'Schließen';
@ -527,7 +527,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get systemAiOffBlurb =>
'Aus — Fehlererklärungen auf der Protokoll-Seite sind deaktiviert. Klicke Konfigurieren…, um einen Provider zu wählen (Ollama / OpenAI / LM Studio / vLLM / Eigene). Die Operator-Konfig wird direkt überschrieben; kein Daemon-Neustart nötig.';
'Aus — Fehlererklärungen auf der Protokoll-Seite sind deaktiviert. Klicken Sie auf Konfigurieren…, um einen Provider zu wählen (Ollama / OpenAI / LM Studio / vLLM / Eigene). Die Operator-Konfig wird direkt überschrieben; kein Daemon-Neustart nötig.';
@override
String mcpServersCount(int n) {
@ -715,7 +715,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get storeAskAiUnavailable =>
'Konfiguriere eine System-AI in den Einstellungen, um Fragen in normaler Sprache zu stellen.';
'Konfigurieren Sie eine System-AI in den Einstellungen, um Fragen in normaler Sprache zu stellen.';
@override
String get storeAskNoMatches =>
@ -1054,7 +1054,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get storeDocsErrorAuth =>
'Die Registry erfordert Authentifizierung, um dieses README zu laden. Setze CHAIN_REGISTRY_TOKEN in der Umgebung des Daemons und starte den Hub neu.';
'Die Registry erfordert Authentifizierung, um dieses README zu laden. Setzen Sie CHAIN_REGISTRY_TOKEN in der Umgebung des Daemons und starten Sie den Hub neu.';
@override
String storeDocsErrorNetwork(String detail) {
@ -1130,7 +1130,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String storeProviderAddedZeroToast(String name) {
return '$name ist eingetragen, aber der Server hat noch keine Fähigkeiten geliefert. Öffne Einstellungen → MCP-Clients, um Discovery erneut zu versuchen oder den Server zu prüfen.';
return '$name ist eingetragen, aber der Server hat noch keine Fähigkeiten geliefert. Öffnen Sie Einstellungen → MCP-Clients, um Discovery erneut zu versuchen oder den Server zu prüfen.';
}
@override
@ -1146,7 +1146,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get auditNoEventsHint =>
'Starte einen Flow, um den Audit-Stream zu füllen.\nEreignisse erscheinen innerhalb von Sekunden.';
'Starten Sie einen Flow, um den Audit-Stream zu füllen.\nEreignisse erscheinen innerhalb von Sekunden.';
@override
String get auditFilterAll => 'alle';
@ -1155,11 +1155,14 @@ class AppLocalizationsDe extends AppLocalizations {
String get auditFilterFlow => 'Flow';
@override
String get auditFilterStep => 'Step';
String get auditFilterStep => 'Schritt';
@override
String get auditFilterModule => 'Modul';
@override
String get auditFilterTooltip => 'Ereignisse filtern';
@override
String get auditClearLogTooltip => 'Protokoll löschen (nur local/dev Kanal)';
@ -1616,7 +1619,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String uninstallVersionPickerBody(String module) {
return 'Mehrere Versionen von `$module` sind parallel installiert. Wähle genau die Version aus, die entfernt werden soll — die anderen bleiben bestehen.';
return 'Mehrere Versionen von `$module` sind parallel installiert. Wählen Sie genau die Version aus, die entfernt werden soll — die anderen bleiben bestehen.';
}
@override
@ -1948,7 +1951,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get approvalsNoDataConfirmBody =>
'Dieser Flow hat bewusst keine Prüfdaten hinterlegt (kein \"show:\" am Freigabe-Schritt). Du kannst trotzdem freigeben — entscheidest dann aber, ohne die Daten hinter dieser Entscheidung gesehen zu haben.';
'Dieser Flow hat bewusst keine Prüfdaten hinterlegt (kein \"show:\" am Freigabe-Schritt). Sie können trotzdem freigeben — entscheiden dann aber, ohne die Daten hinter dieser Entscheidung gesehen zu haben.';
@override
String get approvalsNoDataConfirmAction => 'Trotzdem freigeben';
@ -2113,7 +2116,13 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String doctorChainIntactDetail(int n) {
return '$n Ereignisse · prev_event_sha256 lückenlos verifiziert';
String _temp0 = intl.Intl.pluralLogic(
n,
locale: localeName,
other: 'Ereignisse',
one: 'Ereignis',
);
return '$n $_temp0 · prev_event_sha256 lückenlos verifiziert';
}
@override
@ -2553,14 +2562,14 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get flowEditorEmptyBody =>
'Wähle links einen aus oder klicke Neuer Flow um einen neuen anzulegen.';
'Wählen Sie links einen aus oder klicken Sie auf Neuer Flow, um einen neuen anzulegen.';
@override
String get flowEditorListEmptyTitle => 'Keine gespeicherten Flows';
@override
String get flowEditorListEmptyBody =>
'Klicke Neuer Flow um aus einer Vorlage zu starten.';
'Klicken Sie auf Neuer Flow, um aus einer Vorlage zu starten.';
@override
String get flowEditorDiscardTitle => 'Ungespeicherte Änderungen verwerfen?';
@ -2728,14 +2737,14 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get addSourceHint =>
'https://git.flemming.ai/deine-org/dein-modul/releases/download/v0.1.0/foo-0.1.0.chain';
'https://git.flemming.ai/ihre-org/ihr-modul/releases/download/v0.1.0/foo-0.1.0.chain';
@override
String get addSourceHowItWorksTitle => 'Wie private Module funktionieren';
@override
String get addSourceHowItWorksBody =>
'Ein Modul ist ein Verzeichnis mit module.yaml + WASM-Artefakt. Zum Teilen: `chain pack <verzeichnis>` baut ein `.chain`-Bundle, das du beliebig hosten kannst (eigene Forgejo / GitHub / S3). Der Hub installiert per URL und prüft die Signatur gegen seinen Trust-Store.\n\nLokal entwickeln? Nimm das CLI — Studio installiert (noch) nicht aus einem unverpackten Verzeichnis:';
'Ein Modul ist ein Verzeichnis mit module.yaml + WASM-Artefakt. Zum Teilen: `chain pack <verzeichnis>` baut ein `.chain`-Bundle, das Sie beliebig hosten können (eigene Forgejo / GitHub / S3). Der Hub installiert per URL und prüft die Signatur gegen seinen Trust-Store.\n\nLokal entwickeln? Nimm das CLI — Studio installiert (noch) nicht aus einem unverpackten Verzeichnis:';
@override
String get addSourceCliExample => 'chain install --link /pfad/zum/modul';
@ -2756,7 +2765,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get welcomeHubDownBody =>
'Studio spricht mit einem lokalen Hub — der Engine, die Module lädt und Flows ausführt. Sie ist gerade nicht erreichbar. Starte sie, um loszulegen.';
'Studio spricht mit einem lokalen Hub — der Engine, die Module lädt und Flows ausführt. Sie ist gerade nicht erreichbar. Starten Sie die Engine, um loszulegen.';
@override
String get welcomeHubDownStart => 'Hub starten';
@ -2788,7 +2797,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get chainBinaryNotFoundHint =>
'Installiere die Ch∆In-Plattform oder verweise Studio auf eine vorhandene `chain`-Datei.';
'Installieren Sie die Ch∆In-Plattform oder verweisen Sie Studio auf eine vorhandene `chain`-Datei.';
@override
String get chainBinaryLocateButton => '`chain`-Programm suchen …';
@ -2819,7 +2828,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get sysAiFixEnvMissing =>
'Die Umgebungsvariable für den API-Schlüssel ist leer. Setze sie in deiner Shell und starte den Daemon neu.';
'Die Umgebungsvariable für den API-Schlüssel ist leer. Setzen Sie sie in Ihrer Shell und starten Sie den Daemon neu.';
@override
String get sysAiFixNetwork =>
@ -2827,7 +2836,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get sysAiFixHttp =>
'Der Anbieter hat einen Status außerhalb 2xx geliefert. Prüfe Endpunkt, Modellname und API-Schlüssel.';
'Der Anbieter hat einen Status außerhalb 2xx geliefert. Prüfen Sie Endpunkt, Modellnamen und API-Schlüssel.';
@override
String get sysAiFixEmptyResponse =>
@ -2845,15 +2854,15 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get providerDescOllama =>
'Lokales `ollama serve`. Die Modelle bleiben auf deinem Rechner. Kein API-Schlüssel nötig.';
'Lokales `ollama serve`. Die Modelle bleiben auf Ihrem Rechner. Kein API-Schlüssel nötig.';
@override
String get providerDescOpenai =>
'Gehostete OpenAI-API. Erfordert einen API-Schlüssel. Daten verlassen deinen Rechner.';
'Gehostete OpenAI-API. Erfordert einen API-Schlüssel. Daten verlassen Ihren Rechner.';
@override
String get providerDescLmstudio =>
'Lokaler LM-Studio-Server. Die Modelle bleiben auf deinem Rechner. Kein API-Schlüssel nötig.';
'Lokaler LM-Studio-Server. Die Modelle bleiben auf Ihrem Rechner. Kein API-Schlüssel nötig.';
@override
String get providerDescVllm =>
@ -2898,7 +2907,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get federationEmptyHint =>
'Verbinde einen weiteren Hub als Satellit, um Capabilities dort auszuführen. Stelle dazu ein Enrollment-Token aus.';
'Verbinden Sie einen weiteren Hub als Satellit, um Capabilities dort auszuführen. Stellen Sie dazu ein Enrollment-Token aus.';
@override
String get federationPillConnected => 'verbunden';