From 1c4486ceba6ca6ceca9fad7828842fecc4bce50c Mon Sep 17 00:00:00 2001 From: Till JS Date: Sun, 26 Apr 2026 19:48:20 +0200 Subject: [PATCH] =?UTF-8?q?fix(comic):=20inline=20face-upload=20banner=20?= =?UTF-8?q?=E2=80=94=20Parit=C3=A4t=20mit=20Wardrobe-UX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-Feedback: in Wardrobe konnte man das Gesichtsbild direkt aus der Workbench-Card hochladen, in Comic verwies der Hint nur auf /profile/me-images. Asymmetrie geheilt — beide Module nutzen jetzt das gleiche Banner-Pattern. Comic-ListView (Modul-Root, oberhalb der Tabs): - Wardrobe-Banner verbatim übernommen (MeImageUploadZone + 3-Phasen-State-Machine idle/uploading/success + 2.5s success-card mit fade-out + dismissable + spinner-overlay während upload + error-card auf Fehler). - Sitzt oberhalb der Tabs, damit es für BEIDE Sub-Views (Stories | Characters) sichtbar ist — Comic-Panel UND Charakter-Generierung brauchen das Face-Ref. Banner blendet sich automatisch aus sobald face$ via liveQuery flippt + die 2.5s success-Window vorbei ist. - Copy angepasst: "Wir brauchen dich auf Bild, damit Comic-Panels und Charakter-Varianten von dir gerendert werden können" statt Wardrobe's "Try-On Kleidung an dir visualisieren". Success-CTA: "als nächstes baust du deinen ersten Comic- Character oder legst direkt eine Story an". Sub-Views aufgeräumt: - views/ListView.svelte (StoriesView): hat den redundanten "Lade erst dein Gesichtsbild"-Hint inkl. UserCircle-Import + useImageByPrimary-Hook gehabt → entfernt. Modul-Root liefert das jetzt. - views/CharactersView.svelte: gleicher Cleanup. Imports von UserCircle und useImageByPrimary raus. Repair-Hook (`repairSilentTwinAvatarRows`) bewusst NICHT kopiert — das war eine Wardrobe-spezifische Migration für die M2.5-silent-twin-Bug; Comic ist nach v40 entstanden, hat das Problem nie gehabt. Comic-Files type-checken sauber. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../web/src/lib/modules/comic/ListView.svelte | 172 ++++++++++++++++++ .../modules/comic/views/CharactersView.svelte | 25 +-- .../lib/modules/comic/views/ListView.svelte | 27 +-- 3 files changed, 180 insertions(+), 44 deletions(-) diff --git a/apps/mana/apps/web/src/lib/modules/comic/ListView.svelte b/apps/mana/apps/web/src/lib/modules/comic/ListView.svelte index d9c0828be..ed149b6f1 100644 --- a/apps/mana/apps/web/src/lib/modules/comic/ListView.svelte +++ b/apps/mana/apps/web/src/lib/modules/comic/ListView.svelte @@ -4,8 +4,20 @@ wiederverwendbaren Identity-Anchors. Tab-State ist lokal und bleibt erhalten solange ListView gemountet ist (SvelteKit hält uns gemountet bei Navigation innerhalb /comic). + + Face-Ref-Banner (oben, oberhalb der Tabs) übernimmt das Wardrobe- + Pattern 1:1 — wenn der aktive Space kein face-ref hat, kann der + User das Bild direkt hier inline droppen statt in Profil → Bilder + navigieren zu müssen. Banner zeigt sich für beide Tabs (Stories + UND Characters brauchen ein Face-Ref) und blendet sich nach + erfolgreichem Upload mit einem 2.5s Success-Card aus. -->
@@ -41,6 +107,88 @@ {/each} + {#if showBanner} +
+ {#if uploadPhase === 'success'} +
+ {#if uploadedPreviewUrl} + + {:else} + + + + {/if} +
+

+ + Gesichtsbild gespeichert +

+

+ Perfekt — als nächstes baust du deinen ersten Comic-Character oder legst direkt eine + Story an. +

+
+ +
+ {:else} +
+ +
+

Lade ein Gesichtsbild hoch

+

+ Wir brauchen dich auf Bild, damit Comic-Panels und Charakter-Varianten von dir + gerendert werden können. Das Bild bleibt lokal und wird nur für deine eigenen + Generierungen genutzt. +

+
+
+
+ + {#if uploadPhase === 'uploading'} + + + Lade… + + {/if} +
+ {#if faceUploadError} + + {/if} + {/if} +
+ {/if} +
{#if activeTab === 'stories'} @@ -109,6 +257,30 @@ min-height: 0; overflow-y: auto; } + .face-banner { + border-color: hsl(var(--color-border)); + background: hsl(var(--color-background) / 0.5); + transition: + background-color 0.25s, + border-color 0.25s; + } + .face-banner-success { + border-style: solid; + border-color: hsl(var(--color-primary) / 0.4); + background: hsl(var(--color-primary) / 0.06); + } + /* Spinner reaches into Phosphor's child SVG via :global(). */ + .face-banner :global(.spinner) { + animation: comic-spin 0.9s linear infinite; + } + @keyframes comic-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } @container (min-width: 640px) { .comic-root { padding: 0.75rem 1rem 1rem; diff --git a/apps/mana/apps/web/src/lib/modules/comic/views/CharactersView.svelte b/apps/mana/apps/web/src/lib/modules/comic/views/CharactersView.svelte index b0564314d..480eeccd5 100644 --- a/apps/mana/apps/web/src/lib/modules/comic/views/CharactersView.svelte +++ b/apps/mana/apps/web/src/lib/modules/comic/views/CharactersView.svelte @@ -1,12 +1,12 @@
@@ -37,21 +35,6 @@ - {#if !hasFace && !face$.loading} -
-
- -
-

Lade erst dein Gesichtsbild hoch

-

- Charakter-Generierung braucht ein Face-Bild als Source. Hochladen in - Profil → Bilder. -

-
-
-
- {/if} - {#if characters.length > 0}
{#each characters as character (character.id)} diff --git a/apps/mana/apps/web/src/lib/modules/comic/views/ListView.svelte b/apps/mana/apps/web/src/lib/modules/comic/views/ListView.svelte index 64f445e53..d09759474 100644 --- a/apps/mana/apps/web/src/lib/modules/comic/views/ListView.svelte +++ b/apps/mana/apps/web/src/lib/modules/comic/views/ListView.svelte @@ -1,13 +1,11 @@
@@ -38,21 +34,6 @@ - {#if !hasFace && !face$.loading} -
-
- -
-

Lade erst dein Gesichtsbild hoch

-

- Ohne Face-Ref im aktiven Space kann kein Comic-Panel generiert werden. Hochladen in - Profil → Bilder. -

-
-
-
- {/if} - {#if stories.length > 0}
{#each stories as story (story.id)}