feat(card): Marken-Logos entfernt, Community-Logo unten rechts im Renderer
- card/config.ts: network und das Apple-Logo entfallen. CardConfig.logo ist die ID eines Community-Logos (Muster ID_PATTERN,
sonst null), DEFAULT_CONFIG.logo = null, serializeConfig schreibt {v, template, logo, details, brand, crop}. Ein altes network
wird ignoriert, brand 'apple' fällt auf den Standard. ID_PATTERN steht jetzt hier (die reine Konfiguration prüft die Logo-ID,
ohne Appwrite zu laden), account/cards.ts reicht sie weiter; single-sources.test.ts sorgt für genau eine Definition.
- card/geometry.ts: fitLogo und LOGO_MAX_H (125) ersetzen fitNetwork, Layout.network heißt Layout.logo.
- card/marks.ts: nur noch die AirCard-IOS-Marken (BRAND_MARKS, getBrandMark, svgAspect, tintSvg, loadMarkImage). Die 19 SVGs
der Netzwerke und von Apple sind per git rm gelöscht, ein Test hält assets/marks auf die zwei AirCard-Dateien.
- card/render.ts: LogoAsset, CardAssets.logo statt network, LoadedAssets.logoMissing. loadCardAssets(config, image, loadLogo =
loadLogoAsset): ohne Logo kein Aufruf, null vom Lader ergibt logoMissing, ein Ladefehler wirft. Der Renderer zeichnet das
Logo mit fitLogo(w / h) unten rechts, wenn Vorlage und Bilder eines haben.
- logos/logo-asset.ts (neu): loadLogoAsset(id, tone) holt Zeile (getLogo) und PNG (loadLogoBlob) und dekodiert mit
createImageBitmap, sonst über ein Image. Einfarbige Logos werden in einem eigenen Canvas mit source-in in der Details-Farbe
gefüllt, mehrfarbige bleiben. Fehlende Zeile, ausgeblendetes Logo (auch für Hochlader und Admins), Datei 404, unlesbare
Datei und mehr als 1 000 000 Pixel ergeben null. Je (id, tone) ein Ladevorgang, ein Fehler bleibt nicht im Cache.
rememberLogo, forgetLogo und LOGO_MISSING nach der Schnittstelle des Plans.
- editor/options-panel.ts: keine Netzwerk-Kacheln mehr, Überschrift „Logo oben links“ mit Symbol, Text und Kein Logo (ohne
Apple), dazu logoSlot als leerer Platz oben für Task 8 (editor.css: Details rückt bei leerem Platz wie bisher nach oben).
- editor/editor-page.ts: logoKey aus Logo, Details und Marke, der Logo-Zustand hält missing. Fehlt das Logo, wird die Karte
ohne es gezeichnet und der Hinweis LOGO_MISSING gezeigt, solange das so bleibt; ein Wechsel auf ein vorhandenes Logo oder
auf kein Logo nimmt nur diesen Hinweis weg (PNG-Größe und „Bild fehlt“ stehen getrennt und bleiben). Kein LOGO_ERROR bei
fehlendem Logo, nur bei echtem Ladefehler, auch beim Download.
- community/publish.ts: LOGO_MISSING_PUBLISH, renderForGallery (jetzt exportiert) bricht bei logoMissing vor dem Rendern ab,
es wird nichts hochgeladen. publish-dialog.ts lässt den Text im Wortlaut durch.
- i18n/en.ts: englische Texte zu LOGO_MISSING, LOGO_MISSING_PUBLISH und „Logo oben links“.
- Tests: config, geometry, marks, render und die Fixtures von cards, theme, cards-page auf das neue Modell; neu
logo-asset.test.ts (28) und options-panel.test.ts (10); editor-page (14 neue), publish und publish-dialog erweitert.
Vitest 45 Dateien, 1319 Tests grün, tsc und Build sauber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3051b3b3f9
commit
0be5abd954
44 files changed
+1401
-366
No files matched your search
@@ -350,7 +350,7 @@ describe('save: bestehende Karte', () => {
|
||||
|
||||
it('ohne Bildwechsel: nur neue Vorschau, Update, dann alte Vorschau löschen', async () => {
|
||||
const fake = fakeApi([existing()]);
|
||||
const c = config({ network: 'jcb' });
|
||||
const c = config({ logo: 'abc123' });
|
||||
const saved = await service(fake).save(
|
||||
newInput({ name: 'Neu', config: c, imageChanged: false, previous: previous() }),
|
||||
);
|
||||
@@ -370,7 +370,7 @@ describe('save: bestehende Karte', () => {
|
||||
expect(saved.id).toBe('row1');
|
||||
expect(saved.imageFileId).toBe('oldImage');
|
||||
expect(saved.previewFileId).toBe('file1');
|
||||
expect(saved.config.network).toBe('jcb');
|
||||
expect(saved.config.logo).toBe('abc123');
|
||||
});
|
||||
|
||||
it('veralteter Schnappschuss (Bild in anderem Tab ersetzt): das Update schickt kein altes imageFileId, die Zeile behält das neue Bild', async () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Gespeicherte Karten: Dienst (Regeln fürs Speichern, Aufräumen, Laden) und Anschluss an Appwrite.
|
||||
// Der Dienst kennt nur das schmale `CardsApi`-Interface und lässt sich dadurch ohne Netzwerk testen.
|
||||
import { AppwriteException, ID, Permission, Query, Role, type Models } from 'appwrite';
|
||||
import { parseConfig, serializeConfig, type CardConfig } from '../card/config';
|
||||
import { ID_PATTERN, parseConfig, serializeConfig, type CardConfig } from '../card/config';
|
||||
import type { SavedCardRef } from '../editor/state';
|
||||
import { APPWRITE_ENDPOINT, IDS, client, storage, tables } from './appwrite';
|
||||
import { currentUserId } from './auth';
|
||||
@@ -46,8 +46,8 @@ export interface SaveInput {
|
||||
|
||||
export const DEFAULT_CARD_NAME = 'Meine Karte';
|
||||
const NAME_MAX = 80;
|
||||
/** Zeilen- und Datei-IDs von Appwrite: höchstens 36 Zeichen, kein Sonderzeichen am Anfang. */
|
||||
export const ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$/;
|
||||
/** Zeilen- und Datei-IDs von Appwrite (definiert in card/config.ts, dort braucht sie auch die Logo-ID der Konfiguration). */
|
||||
export { ID_PATTERN };
|
||||
|
||||
/** Trimmt, fasst Leerraum zusammen und kürzt auf 80 Zeichen (Codepoints); leer ergibt „Meine Karte“. */
|
||||
export function normalizeName(name: string): string {
|
||||
|
||||
Reference in new issue
Block a user