feat(logos): Dialog „Logo hochladen“ und gemerkter Anzeigename

Task 7: der Dialog zum Hochladen eines Community-Logos (Spec § 4) und der zuletzt benutzte Anzeigename, den er mit dem
Veröffentlichen-Dialog teilt.

- logos/logo-dialog.ts (neu): logoUploadDialog öffnet ein eigenes <dialog> nach dem Muster von publish-dialog.ts (showModal, Fokus
  zurück an den Auslöser, Texte nur als Text; beim Hochladen sind Abbrechen, Esc und Hintergrund wirkungslos, nur das Signal schließt
  immer; ein zweites Absenden wird ignoriert). Die gewählte Datei geht erst durch validateLogoFile, dann durch prepare (Standard
  prepareLogo); währenddessen ist „Hochladen“ gesperrt, eine neue Wahl macht die laufende Verarbeitung hinfällig. Das fertige PNG
  erscheint als Object-URL zweimal, auf dunklem und hellem Grund; „Einfarbig“ (nur wählbar mit transparenten Bereichen, bei jeder
  neuen Datei zurückgesetzt) zeigt stattdessen eine Maske auf dieselbe URL, gefüllt mit TONE_COLOR (Weiß bzw. #111111). Die URL wird
  beim Schließen und beim Ersetzen freigegeben. Der Name wird aus dem Dateinamen ohne Endung vorbelegt (höchstens 40 Zeichen, nie
  mitten in einem Emoji), ein selbst getippter Name bleibt. Hochladen über uploadPreparedLogo mit withLogin (abgelaufene Sitzung →
  Anmeldung); Fehler erscheinen als „Hochladen fehlgeschlagen – <Grund>“ (ApiError über apiErrorText, Texte von prepareLogo im
  Wortlaut, sonst errorMessage), eine abgebrochene Anmeldung als „Bitte melde dich an“. validateLogoForm prüft Datei, Name (leer,
  Steuerzeichen, 40), Anzeigename (Steuerzeichen, 30) und Pflicht-Häkchen mit den Texten aus Spec § 4 und § 11.
- logos/logos.css (neu): Breite des Dialogs, Datei-Feld, die zwei Vorschauflächen und die Maske; Hülle, Felder und Knöpfe kommen aus
  community.css und account.css.
- account/display-name.ts (neu): DISPLAY_NAME_KEY (aircard.displayName), rememberedDisplayName und rememberDisplayName; jeder Zugriff
  in try/catch, ein leerer Name entfernt den Schlüssel.
- community/publish-dialog.ts: der Anzeigename ist aus dem gemerkten Namen vorbelegt und wird nach erfolgreichem Veröffentlichen
  gemerkt; CONTROL_CHARACTERS und DISPLAY_NAME_MAX werden exportiert (der Logo-Dialog prüft mit denselben Regeln).
- i18n/en.ts: englische Texte zu allen neuen Beschriftungen, Hinweisen und Meldungen („Einfarbig“ heißt „Single color“).
- Tests: logo-dialog.test.ts (validateLogoForm, Aufbau, Dateiwahl mit Vorschau, Namensvorschlag, Maske, Object-URLs, veraltete
  Verarbeitung, Prüfung, Senden mit Doppelklick und Sperren, Fehlertexte in beiden Sprachen, Standardwerte, Schließen),
  display-name.test.ts, publish-dialog.test.ts (Vorbelegung und Speichern). Vitest 49 Dateien, 1566 Tests grün, tsc und Build sauber.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-04 22:00:12 +00:00
1 parent 56d841b8e2
commit e22919f4dc
8 files changed
+1665 -2

No files matched your search

+29
View File
@@ -45,6 +45,35 @@ export const EN: Readonly<Record<string, string>> = {
'Das Logo ist leer.': 'The logo is empty.',
'Das Logo ist zu klein (mindestens 8 × 8 Pixel).': 'The logo is too small (at least 8 × 8 pixels).',
// Dialog „Logo hochladen“ (logos/logo-dialog.ts). „Bitte gib einen Namen an.“ steht unter den API-Fehlertexten.
'Logo hochladen': 'Upload logo',
'Datei (Pflicht)': 'File (required)',
'PNG, JPG, WebP oder SVG, höchstens 5 MB und 40 Megapixel.': 'PNG, JPG, WebP or SVG, up to 5 MB and 40 megapixels.',
'Vorschau': 'Preview',
'Dunkel': 'Dark',
'Hell': 'Light',
'Logo-Vorschau auf dunklem Grund': 'Logo preview on a dark background',
'Logo-Vorschau auf hellem Grund': 'Logo preview on a light background',
'Einfarbig – passt sich Hell/Dunkel an': 'Single color – adapts to light/dark mode',
'Nur wählbar, wenn das Logo transparente Bereiche hat.': 'Only available if the logo has transparent areas.',
'Name (Pflicht)': 'Name (required)',
'Anzeigename (optional)': 'Display name (optional)',
'Anonym': 'Anonymous',
'Leer = „Anonym“. Deine E-Mail-Adresse wird nie angezeigt.': 'Leave empty for “Anonymous”. Your email address is never shown.',
'Ich habe die Rechte an diesem Logo oder die Erlaubnis des Inhabers, und es darf öffentlich geteilt werden.':
'I own the rights to this logo or have permission from the owner, and it may be shared publicly.',
'Abbrechen': 'Cancel',
'Hochladen': 'Upload',
'Logo wird verarbeitet …': 'Processing logo …',
'Wird hochgeladen …': 'Uploading …',
'Hochladen fehlgeschlagen – {reason}': 'Upload failed – {reason}',
'Bitte wähle eine Datei.': 'Please choose a file.',
'Der Name enthält ungültige Zeichen.': 'The name contains invalid characters.',
'Der Name ist zu lang (höchstens {max} Zeichen).': 'The name is too long (at most {max} characters).',
'Der Anzeigename enthält ungültige Zeichen.': 'The display name contains invalid characters.',
'Der Anzeigename ist zu lang (höchstens {max} Zeichen).': 'The display name is too long (at most {max} characters).',
'Bitte bestätige, dass du das Logo teilen darfst.': 'Please confirm that you’re allowed to share the logo.',
// API-Fehlertexte (i18n/api-messages.ts). Schlüssel und deutsche Texte stammen aus MSG (deploy/api/common.js); api-messages.test.ts hält sie gleich.
'Bitte melde dich an.': 'Please sign in.',
'Nicht gefunden.': 'Not found.',