Reskin auf Pinterest-Desktop-Optik, Funktionen unveraendert
Vorlage ist die Pinterest-Web-App. Geaendert wurde ausschliesslich die Gestaltung: state, Tastaturkuerzel, deck/flash/commit/undo, die Drag-Handler und die Beispieldaten sind Byte-fuer-Byte identisch. - Hell statt dunkel: weisser Grund, Text #111, roter Akzent #e60023 statt Mint auf Tannen-/Weinrot-Verlauf - Sidebar (236px, beschriftet) wird zur 80px-Icon-Rail, Einstellungen sitzt unten; Zustaende ueber .rail/.rail.active statt inline, weil die dc-Laufzeit style-hover mit !important setzt und den aktiven Button sonst beim Hover aufhellt - Kopfzeile bekommt das Pinterest-Suchfeld (Pille, 48px) plus Konto; Tabs wandern in eine eigene Leiste mit 3px-Unterstrich - Karten randlos mit 16px-Radius; Merken-Pille erscheint beim Hover oben rechts, dazu ein Scrim - beides an :hover/:focus-within der Karte - Profil-Galerie wird Masonry (columns:5, gestaffelte Hoehen) - Nur noch Manrope, JetBrains Mono und backdrop-filter entfallen Der Tageszaehler "Karten gesichtet" hat mit der schmalen Rail seinen Platz verloren und sitzt jetzt in der Tab-Leiste. Offen: das Suchfeld ist eine Attrappe - die App hat keine Suche. Im README unter "Offene Punkte" vermerkt. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,9 @@ Setze das Design aus diesem Ordner in unserem Stack um.
|
|||||||
in unserer bestehenden Umgebung mit unseren Patterns und Komponenten nachbauen.
|
in unserer bestehenden Umgebung mit unseren Patterns und Komponenten nachbauen.
|
||||||
3. Fidelity ist high — pixelgenau umsetzen: Farben, Radien, Übergänge, Hover-/Focus-States,
|
3. Fidelity ist high — pixelgenau umsetzen: Farben, Radien, Übergänge, Hover-/Focus-States,
|
||||||
Drag-Schwellen und Animationsdauern wie im README angegeben.
|
Drag-Schwellen und Animationsdauern wie im README angegeben.
|
||||||
|
Die visuelle Sprache ist Pinterest Desktop: weißer Hintergrund, 80px-Icon-Rail ohne
|
||||||
|
Beschriftung, Suchfeld als Pille, rote Primäraktion `#e60023`, randlose 16px-Karten,
|
||||||
|
Masonry im Profil. Hover-Elemente (Merken-Pille, Scrim) hängen am Hover der Karte.
|
||||||
4. Umfang: App-Shell (Sidebar + Kopfzeile mit Tabs) und die vier Screens
|
4. Umfang: App-Shell (Sidebar + Kopfzeile mit Tabs) und die vier Screens
|
||||||
Feed, Profil, Erstellen, Einstellungen.
|
Feed, Profil, Erstellen, Einstellungen.
|
||||||
5. Icons als Lucide-Icons umsetzen (im Prototyp stehen Unicode-Glyphen als Platzhalter).
|
5. Icons als Lucide-Icons umsetzen (im Prototyp stehen Unicode-Glyphen als Platzhalter).
|
||||||
|
|||||||
@@ -2,8 +2,17 @@
|
|||||||
|
|
||||||
## Überblick
|
## Überblick
|
||||||
Die bestehende Mobile-App („videogen", Swipe-Feed für Creator-/Produkt-Posts) als Desktop-Web-App.
|
Die bestehende Mobile-App („videogen", Swipe-Feed für Creator-/Produkt-Posts) als Desktop-Web-App.
|
||||||
Statt einer schmalen Handy-Spalte im Browser: dreispaltiges App-Layout mit permanenter Navigation,
|
Statt einer schmalen Handy-Spalte im Browser: Icon-Rail links, breite Kopfzeile mit Suche,
|
||||||
zentralem Kartenstapel und Detailspalte. Swipen wird durch Maus-Drag, Buttons und Tastatur ersetzt.
|
zentraler Kartenstapel und Detailspalte. Swipen wird durch Maus-Drag, Buttons und Tastatur ersetzt.
|
||||||
|
|
||||||
|
**Visuelle Sprache: Pinterest Desktop.** Heller Hintergrund, schmale Icon-Leiste ohne Beschriftung,
|
||||||
|
Suchfeld als breite Pille, rote Primäraktion („Merken"), randlose Karten mit 16px-Radius,
|
||||||
|
Masonry-Raster im Profil. Referenz ist die Pinterest-Web-App (`de.pinterest.com`); der Screenshot
|
||||||
|
dafür liegt bisher nicht im Repo, siehe [Offene Punkte](#offene-punkte).
|
||||||
|
|
||||||
|
**Die Funktionen sind gegenüber dem ersten Entwurf unverändert** — Kartenstapel, Merken/Ablehnen,
|
||||||
|
Undo, Tabs, die vier Screens und das State-Modell bleiben, wie sie waren. Geändert hat sich
|
||||||
|
ausschließlich die Gestaltung.
|
||||||
|
|
||||||
## Zu den Design-Dateien
|
## Zu den Design-Dateien
|
||||||
Die Dateien in diesem Bundle sind **Design-Referenzen in HTML** — Prototypen, die Aussehen und
|
Die Dateien in diesem Bundle sind **Design-Referenzen in HTML** — Prototypen, die Aussehen und
|
||||||
@@ -27,40 +36,40 @@ und sollen pixelgenau nachgebaut werden — mit den Komponenten/Utilities des Zi
|
|||||||
|
|
||||||
- Wurzel: `display:flex`, `min-height:100vh`, **`min-width:1180px`** (darunter horizontales Scrollen,
|
- Wurzel: `display:flex`, `min-height:100vh`, **`min-width:1180px`** (darunter horizontales Scrollen,
|
||||||
die App ist Desktop-only gedacht).
|
die App ist Desktop-only gedacht).
|
||||||
- Hintergrund (fix, nicht mitscrollend):
|
- Hintergrund durchgehend `#ffffff`, Grundschrift `#111111`. Keine Verläufe, kein `backdrop-filter`.
|
||||||
`radial-gradient(120% 80% at 50% 0%, #0d4c3d 0%, #0a3a30 34%, #24121a 68%, #40161b 100%)`,
|
|
||||||
`background-attachment: fixed`. Oben Tannengrün, unten Weinrot — direkt aus der App übernommen.
|
|
||||||
- Grundschrift `#f2efe9` auf diesem Verlauf.
|
|
||||||
|
|
||||||
### 1. Sidebar (links)
|
### 1. Icon-Rail (links)
|
||||||
- Breite `236px`, `flex:none`, `position:sticky; top:0; height:100vh`.
|
- Breite `80px`, `flex:none`, `position:sticky; top:0; height:100vh`, `background:#ffffff`,
|
||||||
- `background: rgba(8,26,22,.42)`, `backdrop-filter: blur(14px)`, rechte Kante `1px solid rgba(255,255,255,.08)`.
|
rechte Kante `1px solid #efefef`. Padding `12px 0 16px`, Inhalt zentrierte Flex-Spalte, `gap:8px`.
|
||||||
- Padding `26px 20px`, Inhalt als Flex-Spalte, `gap:28px`.
|
- **Brand**: 32×32 Kreis `#e60023` in einem 48px-Slot, weißes „V" 17px/700.
|
||||||
- **Brand**: 30×30 Kachel, `border-radius:9px`, `linear-gradient(150deg,#2fa87f,#0e5442)`, Buchstabe „V" 15px/700;
|
- **Nav-Buttons**: 48×48, `border-radius:50%`, Icon 20px, **ohne Textlabel** — der Name steht im
|
||||||
daneben Wortmarke „videogen" 16px/600, `letter-spacing:-.01em`.
|
`title`-Attribut und wird als Tooltip gezeigt.
|
||||||
- **Nav** (Flex-Spalte, `gap:4px`), Einträge: Feed, Profil, Erstellen, Einstellungen.
|
- Inaktiv: transparent, Icon `#111111`. Hover: `background:#e9e9e9`.
|
||||||
- Item: `display:flex; gap:11px; padding:11px 13px; border-radius:11px; font:500 14px Manrope; text-align:left; cursor:pointer`.
|
- Aktiv: `background:#111111`, Icon `#ffffff`. Aktiv + Hover: `background:#000000`.
|
||||||
- Inaktiv: transparent, Text `rgba(242,239,233,.7)`, Border transparent.
|
- Transition `.12s ease`.
|
||||||
- Aktiv: `background: rgba(126,226,184,.12)`, `border:1px solid rgba(126,226,184,.4)`, Text `#d6fbec`.
|
- **Umsetzungshinweis:** Die Zustände gehören in Klassen (`.rail`, `.rail.active`), nicht in
|
||||||
- Hover: `background: rgba(255,255,255,.09)`, Text `#ffffff`. Transition `.18s ease`.
|
Inline-Styles. Im Prototyp setzt die `.dc`-Laufzeit `style-hover` mit `!important`; ein inline
|
||||||
- Icon-Slot 20px breit (im Prototyp Glyphen ◧ ◍ + ⚙ — **in der Implementierung durch Lucide-Icons ersetzen**:
|
gesetztes Aktiv-Schwarz würde beim Hover überschrieben und der aktive Button hellte auf.
|
||||||
`layout-grid`, `user`, `plus`, `settings`).
|
- Reihenfolge oben: **Feed, Profil, Erstellen**. Unten (`margin-top:auto`): **Einstellungen**.
|
||||||
- **Fußbereich** (`margin-top:auto`):
|
- Icons (im Prototyp Unicode-Glyphen als Platzhalter) — **Lucide**: `home`, `user`, `plus`, `settings`.
|
||||||
- Statistik-Karte: `1px solid rgba(255,255,255,.12)`, `radius:14px`, `padding:14px`, `background: rgba(255,255,255,.03)`.
|
|
||||||
Kicker „HEUTE" 11px, `letter-spacing:.14em`, uppercase, `rgba(242,239,233,.5)`; Zahl 22px JetBrains Mono,
|
|
||||||
`font-variant-numeric: tabular-nums`, zweistellig mit führender Null; Label „Karten gesichtet" 12px `rgba(242,239,233,.55)`.
|
|
||||||
- Konto-Zeile: 32px Kreis `linear-gradient(140deg,#b2323c,#5d1620)`, Name 13px/600, Rolle 11px `rgba(242,239,233,.5)`.
|
|
||||||
|
|
||||||
### 2. Kopfzeile (über dem Inhalt)
|
### 2. Kopfzeile
|
||||||
- Höhe `72px`, `padding: 0 34px`, Unterkante `1px solid rgba(255,255,255,.07)`, Inhalt `space-between`.
|
- `padding:12px 16px 4px`, Flex-Zeile, `gap:8px`.
|
||||||
- **Tabs** links (`gap:6px`): „Videos", „Folge ich", „Posts". Jeder Tab wechselt den Kartenstapel und
|
- **Suchfeld**: `flex:1`, Höhe `48px`, `border-radius:24px`, `background:#efefef`, `padding:0 16px`,
|
||||||
springt zurück auf den Feed-Screen (Index/History zurücksetzen).
|
Platzhaltertext „Suchen" 16px `#767676`; links Lupe, rechts Objektiv-Symbol
|
||||||
- `padding:9px 18px; border-radius:999px; font:500 16px Manrope`.
|
(Lucide `search` und `camera`).
|
||||||
- Aktiv: `background: rgba(255,255,255,.08)`, `border:1px solid rgba(255,255,255,.22)`, Text `#fff`, 600.
|
- **Konto**: 40px Kreis `linear-gradient(140deg,#b2323c,#5d1620)` mit weißer Initiale 15px/700,
|
||||||
- Inaktiv: transparent, Text `rgba(242,239,233,.58)`; Hover → `#fff`.
|
daneben 28px Chevron-Button (`▾`, Hover `#e9e9e9`).
|
||||||
- **Rechts**: Zähler „3 / 5" (12px JetBrains Mono, tabular-nums, `rgba(242,239,233,.5)`) und runder
|
|
||||||
Info-Button 36px (`border:1px solid rgba(255,255,255,.18)`, `background: rgba(255,255,255,.04)`;
|
### 3. Tab-Leiste
|
||||||
Hover `rgba(255,255,255,.12)` + `translateY(-1px)`), toggelt das Kürzel-Panel.
|
- `padding:0 24px`, Unterkante `1px solid #efefef`, Tabs mit `gap:24px`, an der Grundlinie ausgerichtet.
|
||||||
|
- **Tabs**: „Videos", „Folge ich", „Posts". Jeder Tab wechselt den Kartenstapel und springt zurück
|
||||||
|
auf den Feed-Screen (Index/History zurücksetzen).
|
||||||
|
- `padding:0 2px 12px`, Unterkante `3px solid` — aktiv `#111111`, inaktiv `transparent`.
|
||||||
|
- Aktiv: `#111111`, 700. Inaktiv: `#767676`, 500; Hover → `#111111`. Schriftgröße 16px.
|
||||||
|
- **Rechts**: Tageszähler „**NN** heute gesichtet" (Zahl 700 `#111111` mit `tabular-nums`,
|
||||||
|
Rest 13px `#767676`), Stapelzähler „3 / 5" (13px `#767676`, `tabular-nums`) und runder
|
||||||
|
Info-Button 36px (transparent, Hover `#e9e9e9`), der das Kürzel-Panel toggelt.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -77,108 +86,122 @@ und sollen pixelgenau nachgebaut werden — mit den Komponenten/Utilities des Zi
|
|||||||
- Es werden **bis zu 3 Karten** gestapelt gerendert (konfigurierbar 1–5).
|
- Es werden **bis zu 3 Karten** gestapelt gerendert (konfigurierbar 1–5).
|
||||||
- Karte k (0 = oben): `transform: translate3d(0, -12px·k, 0) scale(1 - 0.045·k)`, `z-index: 10-k`,
|
- Karte k (0 = oben): `transform: translate3d(0, -12px·k, 0) scale(1 - 0.045·k)`, `z-index: 10-k`,
|
||||||
`pointer-events` nur auf der obersten.
|
`pointer-events` nur auf der obersten.
|
||||||
- Karte: `position:absolute; inset:0; border-radius:26px; overflow:hidden;
|
- Karte: `position:absolute; inset:0; border-radius:26px` → **`16px`**, `overflow:hidden`,
|
||||||
border:1px solid rgba(255,255,255,.14); box-shadow: 0 26px 60px rgba(0,0,0,.45);
|
**kein Rahmen**, `box-shadow: 0 1px 20px rgba(0,0,0,.18)`,
|
||||||
touch-action:none; user-select:none; cursor:grab` (beim Ziehen `grabbing`).
|
`touch-action:none; user-select:none; cursor:grab` (beim Ziehen `grabbing`).
|
||||||
- Transition: `transform .34s cubic-bezier(.22,.9,.3,1), opacity .3s ease` — während des aktiven Drags `none`.
|
- Transition: `transform .34s cubic-bezier(.22,.9,.3,1), opacity .3s ease` — während des aktiven Drags `none`.
|
||||||
- **Karteninhalt (von unten nach oben gestapelt):**
|
- **Karteninhalt (von unten nach oben gestapelt):**
|
||||||
1. Grundfläche: `linear-gradient(155deg, <hue0> 0%, <hue1> 100%)` (pro Karte, siehe Daten unten).
|
1. Grundfläche: `linear-gradient(155deg, <hue0> 0%, <hue1> 100%)` (pro Karte, siehe Daten unten).
|
||||||
2. Streifen-Overlay: `repeating-linear-gradient(<40+9·i>deg, rgba(255,255,255,.08) 0 2px, transparent 2px 16px)`, `opacity:.5`.
|
2. Streifen-Overlay: `repeating-linear-gradient(<40+9·i>deg, rgba(255,255,255,.08) 0 2px, transparent 2px 16px)`, `opacity:.5`.
|
||||||
(Im Prototyp Platzhalter für das Video-/Bild-Asset — im Produkt liegt hier das Medium.)
|
(Im Prototyp Platzhalter für das Video-/Bild-Asset — im Produkt liegt hier das Medium.)
|
||||||
3. Lesbarkeits-Verlauf: `linear-gradient(180deg, rgba(0,0,0,.32) 0%, transparent 26%, transparent 52%, rgba(0,0,0,.66) 100%)`.
|
3. **Hover-Scrim**: `rgba(0,0,0,.24)`, `opacity` 0 → 1 in `.12s`, nur wenn die Karte gehovert wird.
|
||||||
4. **Pills** oben links (`padding:18px`, `gap:9px`): Art („Produkt"/„Video") und Assets („3 Bilder").
|
4. Lesbarkeits-Verlauf: `linear-gradient(180deg, transparent 46%, rgba(0,0,0,.62) 100%)`.
|
||||||
`padding:7px 15px; border-radius:999px; border:1px solid rgba(255,255,255,.34);
|
5. **Pills** oben links (`padding:16px`, `gap:8px`): Art („Produkt"/„Video") und Assets („3 Bilder").
|
||||||
background: rgba(0,0,0,.22); backdrop-filter: blur(6px); font:600 13px`.
|
`padding:6px 12px; border-radius:16px; background: rgba(255,255,255,.94); color:#111111; font:600 13px`.
|
||||||
5. **Caption** mittig, 118px über der Unterkante: JetBrains Mono 15px, `padding:9px 16px`,
|
6. **Merken-Pille** oben rechts, **nur auf der obersten Karte und erst beim Hover**
|
||||||
`border-radius:9px`, `background: rgba(0,0,0,.5)`, `backdrop-filter: blur(4px)`.
|
(`opacity` 0 → 1 in `.12s`): `padding:11px 16px; border-radius:22px; background:#e60023;
|
||||||
6. **Creator-Zeile** unten (`padding:20px`, `gap:13px`): 46px Avatar-Kreis (Farbverlauf, `border:2px solid rgba(255,255,255,.3)`),
|
color:#ffffff; font:700 15px`, Hover `#ad081b`. Klick = dieselbe Aktion wie „Merken"/→.
|
||||||
Name 19px/700 `letter-spacing:-.01em`, Untertitel 14px `rgba(255,255,255,.72)`.
|
7. **Caption** mittig, 104px über der Unterkante: `font:600 15px`, `padding:8px 14px`,
|
||||||
7. **Entscheidungs-Badge** (nur oberste Karte, erscheint ab 40px Drag oder beim Exit):
|
`border-radius:16px`, `background: rgba(255,255,255,.94)`, `color:#111111`.
|
||||||
`top:86px`, links bei „GEMERKT" / rechts bei „SKIP", `padding:8px 16px; border-radius:10px;
|
8. **Creator-Zeile** unten (`padding:18px`, `gap:12px`, Text weiß): 44px Avatar-Kreis (Farbverlauf,
|
||||||
font:800 15px; letter-spacing:.12em`, `border:2px solid` und Text in
|
ohne Rand), Name 18px/700 `letter-spacing:-.01em`, Untertitel 14px `rgba(255,255,255,.82)`.
|
||||||
Grün `rgba(126,226,184,.9)` / `#a9f0d0` bzw. Rot `rgba(232,120,120,.9)` / `#f0a8a8`,
|
9. **Entscheidungs-Badge** (nur oberste Karte, erscheint ab 40px Drag oder beim Exit):
|
||||||
`rotate(-10deg)` bzw. `rotate(10deg)`, Opacity `min(1, |dx|/110)`, Transition `.16s`.
|
`top:86px`, links bei „GEMERKT" / rechts bei „SKIP", `padding:10px 18px; border-radius:22px;
|
||||||
- **Leerzustand** (Stapel durch): gestrichelter Rahmen `1px dashed rgba(255,255,255,.2)`, `radius:26px`,
|
font:700 15px; letter-spacing:.08em`, Text immer `#ffffff`, Fläche
|
||||||
Titel „Alles gesichtet" 20px/600, Text „Für heute sind keine neuen Karten mehr in dieser Ansicht.",
|
`#e60023` (GEMERKT) bzw. `#111111` (SKIP), `rotate(-10deg)` bzw. `rotate(10deg)`,
|
||||||
Outline-Button „Stapel neu laden" (`border:1px solid rgba(126,226,184,.6)`, Text `#8fe3c1`,
|
Opacity `min(1, |dx|/110)`, Transition `.16s`.
|
||||||
Hover `background: rgba(126,226,184,.14)`), Einblendung `fadeIn .3s`.
|
- **Leerzustand** (Stapel durch): Fläche `#f5f5f5`, `radius:16px`, Titel „Alles gesichtet" 20px/700,
|
||||||
- **Aktions-Buttons** unter der Bühne (`gap:18px`), alle `border-radius:50%`,
|
Text „Für heute sind keine neuen Karten mehr in dieser Ansicht." 15px `#5f5f5f`,
|
||||||
`background: rgba(14,10,12,.72)`, `border:1px solid rgba(255,255,255,.16)`,
|
roter Pill-Button „Stapel neu laden" (`#e60023`, Hover `#ad081b`, weiß 15px/700,
|
||||||
Transition `.18s`, Hover `translateY(-3px) scale(1.05)`, Active `scale(.95)`:
|
`padding:12px 20px; radius:24px`), Einblendung `fadeIn .3s`.
|
||||||
- ✕ Ablehnen — 62px, Hover-Border `rgba(230,120,120,.75)`, Hover-BG `rgba(120,32,38,.5)`.
|
- **Aktions-Buttons** unter der Bühne (`gap:16px`), Hover `scale(1.04)`, Active `scale(.96)`,
|
||||||
- ↺ Zurück — 52px, Hover-Border `rgba(255,255,255,.4)`.
|
Transition `.12s`:
|
||||||
- ♥ Merken — 70px, Text `#8fe3c1`, Border `rgba(126,226,184,.45)`, Hover-BG `rgba(20,88,68,.6)`, Hover `scale(1.06)`.
|
- ✕ Ablehnen — 56px Kreis, `background:#efefef`, Icon `#111111`, Hover `#e2e2e2`.
|
||||||
(Icons in der Implementierung: Lucide `x`, `rotate-ccw`, `heart`.)
|
- ↺ Zurück — 48px Kreis, gleiche Flächen.
|
||||||
- **Kürzel-Panel** (Info-Button): absolut `right:26px; top:26px`, 250px, `radius:14px`,
|
- **Merken** — roter Pill statt Kreis: Höhe 56px, `padding:0 30px`, `border-radius:28px`,
|
||||||
`background: rgba(10,26,22,.9)`, `blur(12px)`, `border:1px solid rgba(255,255,255,.14)`,
|
`background:#e60023`, `color:#ffffff`, `font:700 17px`, Hover `#ad081b`.
|
||||||
|
(Icons in der Implementierung: Lucide `x`, `rotate-ccw`; „Merken" trägt Text, kein Icon.)
|
||||||
|
- **Kürzel-Panel** (Info-Button): absolut `right:26px; top:26px`, 250px, `radius:16px`,
|
||||||
|
`background:#ffffff`, `box-shadow: 0 1px 20px rgba(0,0,0,.16)`, `padding:16px`,
|
||||||
Einblendung `riseIn .22s`. Inhalt: ← Ablehnen, → Merken, ↑ Zurücknehmen, Maus Karte ziehen.
|
Einblendung `riseIn .22s`. Inhalt: ← Ablehnen, → Merken, ↑ Zurücknehmen, Maus Karte ziehen.
|
||||||
|
|
||||||
#### A2 Detailspalte (rechts, 372px)
|
#### A2 Detailspalte (rechts, 372px)
|
||||||
- `border-left:1px solid rgba(255,255,255,.07)`, `background: rgba(8,22,19,.34)`, `padding:30px 28px`,
|
- `border-left:1px solid #efefef`, `background:#ffffff`, `padding:28px`,
|
||||||
Flex-Spalte `gap:24px`, `overflow:auto`.
|
Flex-Spalte `gap:22px`, `overflow:auto`.
|
||||||
- Kicker „AKTUELLE KARTE" (11px, `letter-spacing:.16em`, uppercase, `rgba(242,239,233,.45)`),
|
- Kicker „Aktuelle Karte" 12px/600 `#767676`, Titel = Caption der obersten Karte 28px/700
|
||||||
Titel = Caption der obersten Karte 26px/600 `letter-spacing:-.02em`, darunter „Name · Untertitel" 14px `rgba(242,239,233,.62)`.
|
`letter-spacing:-.02em`, darunter „Name · Untertitel" 15px `#5f5f5f`.
|
||||||
- Hairline `1px rgba(255,255,255,.09)`.
|
- Hairline `1px #efefef`.
|
||||||
- **Statistik-Raster** 3 Spalten, `gap:12px`: Kachel `border:1px solid rgba(255,255,255,.1)`, `radius:12px`,
|
- **Statistik-Raster** 3 Spalten, `gap:10px`: Kachel `background:#f5f5f5`, `radius:16px`,
|
||||||
`padding:12px`; Wert 17px JetBrains Mono tabular-nums, Label 11px `rgba(242,239,233,.5)`.
|
`padding:14px`; Wert 18px/700 `tabular-nums`, Label 12px `#767676`.
|
||||||
- **Beschreibung**: Kicker + Fließtext 14px, `line-height:1.75`, `rgba(242,239,233,.78)`, `text-wrap:pretty`.
|
- **Beschreibung**: Kicker + Fließtext 15px, `line-height:1.7`, `#333333`, `text-wrap:pretty`.
|
||||||
- **Tags**: Pills `padding:6px 12px`, `radius:999px`, `border:1px solid rgba(255,255,255,.18)`, 12px.
|
- **Tags**: Pills `padding:8px 14px`, `radius:18px`, `background:#efefef`, 13px/600 `#111111`.
|
||||||
- **Aktionen unten** (`margin-top:auto`, `gap:10px`), beide `padding:13px; radius:12px`:
|
- **Aktionen unten** (`margin-top:auto`, `gap:8px`), beide `padding:14px; radius:24px; font:700 15px`:
|
||||||
„Zur Sammlung hinzufügen" (Akzent-Outline `rgba(126,226,184,.55)`, Text `#8fe3c1`, Hover `rgba(126,226,184,.14)`) =
|
„Zur Sammlung hinzufügen" (rot `#e60023`, weiß, Hover `#ad081b`) = gleiche Aktion wie „Merken";
|
||||||
gleiche Aktion wie ♥; „Überspringen" (neutrale Outline) = gleiche Aktion wie ✕.
|
„Überspringen" (`#efefef`, `#111111`, Hover `#e2e2e2`) = gleiche Aktion wie ✕.
|
||||||
|
|
||||||
### B. Profil
|
### B. Profil
|
||||||
- `padding:38px 44px`, `overflow:auto`, Einblendung `riseIn .26s`.
|
- `padding:32px 24px 40px`, `overflow:auto`, Einblendung `riseIn .26s`.
|
||||||
- Kopf: 96px Avatar-Kreis (`linear-gradient(140deg,#b2323c,#5d1620)`, `border:2px solid rgba(255,255,255,.2)`),
|
- Kopf **zentriert** als Spalte, `gap:10px`, `padding-bottom:28px`: 120px Avatar-Kreis
|
||||||
Name 32px/600 `letter-spacing:-.02em`, Meta „Studio-Konto · seit März 2026" 14px `rgba(242,239,233,.6)`;
|
(`linear-gradient(140deg,#b2323c,#5d1620)`, ohne Rand), Name 36px/700 `letter-spacing:-.02em`,
|
||||||
rechts drei Kennzahlen (`gap:34px`): Posts 38, Gemerkt (live aus dem Feed), Follower 1.204 —
|
Meta „Studio-Konto · seit März 2026" 15px `#5f5f5f`; darunter drei Kennzahlen nebeneinander
|
||||||
Werte 22px JetBrains Mono tabular-nums, Labels 12px. Unterkante Hairline `rgba(255,255,255,.09)`, `padding-bottom:26px`.
|
(`gap:28px`, zentriert): Posts 38, Gemerkt (live aus dem Feed), Follower 1.204 —
|
||||||
- Galerie: `grid-template-columns: repeat(4,1fr)`, `gap:18px`, `margin-top:28px`.
|
Werte 18px/700 `tabular-nums`, Labels 13px `#767676`.
|
||||||
Kachel: Höhe 230px, `radius:16px`, `border:1px solid rgba(255,255,255,.12)`, Kartenverlauf + Streifen (`opacity:.45`),
|
- **Masonry-Raster** statt Gitter: `columns:5; column-gap:16px`.
|
||||||
Titel unten auf `linear-gradient(0deg, rgba(0,0,0,.7), transparent)`, 13px/600, `padding:14px`.
|
Kachel: `break-inside:avoid; margin-bottom:16px`, **unterschiedliche Höhen**
|
||||||
Hover: `translateY(-4px)`, Border `rgba(126,226,184,.5)`, Transition `.2s`.
|
(Zyklus 320 / 240 / 400 / 280 / 360 / 220 / 300 / 260 px), `radius:16px`, **kein Rahmen**,
|
||||||
|
Kartenverlauf + Streifen (`opacity:.45`), `cursor:zoom-in`.
|
||||||
|
Titel unten auf `linear-gradient(0deg, rgba(0,0,0,.62), transparent)`, 14px/600 weiß, `padding:14px`.
|
||||||
|
**Hover:** Scrim `rgba(0,0,0,.24)` und rote Merken-Pille oben rechts (`right:12px; top:12px`,
|
||||||
|
`padding:11px 16px; radius:22px`) blenden mit `.12s` ein.
|
||||||
|
|
||||||
### C. Erstellen
|
### C. Erstellen
|
||||||
- `padding:38px 44px`; Inhalt `max-width:920px`, `grid-template-columns: 1fr 320px`, `gap:34px`.
|
- `padding:32px 24px 40px`; Inhalt in einer weißen Karte: `max-width:920px`, zentriert,
|
||||||
- Titel „Neuen Post erstellen" 30px/600, Untertitel 14px `rgba(242,239,233,.6)`.
|
`radius:24px`, `box-shadow: 0 1px 20px rgba(0,0,0,.12)`, `padding:32px`,
|
||||||
- **Dropzone**: Höhe 220px, `border:1px dashed rgba(255,255,255,.24)`, `radius:18px`,
|
`grid-template-columns: 1fr 320px`, `gap:32px`.
|
||||||
`background: rgba(255,255,255,.03)`; Hover Border `rgba(126,226,184,.6)`, BG `rgba(126,226,184,.06)`.
|
- Titel „Neuen Post erstellen" 30px/700, Untertitel 15px `#5f5f5f`.
|
||||||
Text „Dateien hierher ziehen" 15px/600 + „MP4, MOV oder bis zu 10 Bilder" 13px.
|
- **Dropzone**: Höhe 220px, `border:2px dashed #cdcdcd`, `radius:16px`, `background:#f5f5f5`;
|
||||||
- **Felder** Titel und Untertitel: Label 12px uppercase `letter-spacing:.14em` `rgba(242,239,233,.5)`;
|
Hover Border `#e60023`, BG `#fafafa`.
|
||||||
Input `padding:13px 15px`, `radius:11px`, `border:1px solid rgba(255,255,255,.16)`,
|
Text „Dateien hierher ziehen" 16px/700 + „MP4, MOV oder bis zu 10 Bilder" 14px `#767676`.
|
||||||
`background: rgba(0,0,0,.24)`, Text `#f2efe9`, 15px. Beide sind an die Live-Vorschau gebunden.
|
- **Felder** Titel und Untertitel: Label 13px/700 `#111111` (keine Versalien, kein `letter-spacing`);
|
||||||
- **Art**: Segmented Pills „Produkt / Video / Serie", `padding:10px 18px`, `radius:999px`;
|
Input `padding:14px 16px`, `radius:16px`, `border:2px solid #cdcdcd`, `background:#ffffff`,
|
||||||
aktiv `border rgba(126,226,184,.6)`, `background rgba(126,226,184,.12)`, Text `#a9f0d0`.
|
Text `#111111`, 15px. Beide sind an die Live-Vorschau gebunden.
|
||||||
- **Aktionen**: „Veröffentlichen" (Akzent-Outline, löst Toast „Post veröffentlicht" aus),
|
- **Art**: Pills „Produkt / Video / Serie", `padding:11px 18px`, `radius:22px`, `font:700 15px`;
|
||||||
„Als Entwurf sichern" (neutrale Outline), beide `padding:13px 24px`, `radius:12px`.
|
aktiv `background:#111111`, Text `#ffffff`; inaktiv `background:#efefef`, Text `#111111`.
|
||||||
- **Vorschau** (rechte Spalte): Kicker + Karte 420px hoch, `radius:22px`,
|
- **Aktionen**: „Veröffentlichen" (rot `#e60023`, weiß, löst Toast „Post veröffentlicht" aus),
|
||||||
|
„Als Entwurf sichern" (`#efefef`), beide `padding:14px 24px`, `radius:24px`, `font:700 15px`.
|
||||||
|
- **Vorschau** (rechte Spalte): Kicker 12px/600 `#767676` + Karte 420px hoch, `radius:16px`,
|
||||||
`linear-gradient(155deg,#1f8163,#0d4034)` + `repeating-linear-gradient(48deg, rgba(255,255,255,.07) 0 2px, transparent 2px 15px)`,
|
`linear-gradient(155deg,#1f8163,#0d4034)` + `repeating-linear-gradient(48deg, rgba(255,255,255,.07) 0 2px, transparent 2px 15px)`,
|
||||||
unten Titel 18px/700 und Untertitel 13px auf schwarzem Verlauf — spiegelt die Eingaben live.
|
unten Titel 18px/700 und Untertitel 14px auf schwarzem Verlauf — spiegelt die Eingaben live.
|
||||||
|
|
||||||
### D. Einstellungen
|
### D. Einstellungen
|
||||||
- `padding:38px 44px`, Inhalt `max-width:660px`. Titel „Einstellungen" 30px/600.
|
- `padding:32px 24px 40px`, Inhalt `max-width:660px`, zentriert. Titel „Einstellungen" 30px/700.
|
||||||
- Liste: Container `border:1px solid rgba(255,255,255,.1)`, `radius:16px`, `overflow:hidden`.
|
- Liste: Container `radius:16px`, `overflow:hidden`, `box-shadow: 0 1px 20px rgba(0,0,0,.12)`,
|
||||||
Zeile `padding:18px 20px`, `background: rgba(255,255,255,.02)`, Trenner `1px solid rgba(255,255,255,.07)`;
|
**kein Rahmen**. Zeile `padding:20px`, `background:#ffffff`, Trenner `1px solid #efefef`;
|
||||||
Label 15px/600, Hinweis 13px `rgba(242,239,233,.55)`.
|
Label 16px/700, Hinweis 14px `#767676`.
|
||||||
- Toggle: Track 52×30, `radius:999px`; aus → `background rgba(255,255,255,.05)`, `border rgba(255,255,255,.2)`,
|
- Toggle: Track 52×30, `radius:999px`, kein Rahmen; aus → `background:#cdcdcd`,
|
||||||
Knopf links 3px, `rgba(242,239,233,.55)`; an → `background rgba(126,226,184,.18)`,
|
an → `background:#e60023`. Knopf 24px, immer `#ffffff` mit `box-shadow: 0 1px 3px rgba(0,0,0,.25)`,
|
||||||
`border rgba(126,226,184,.6)`, Knopf links 25px, `#8fe3c1`. Knopf 22px, Transition
|
links 3px → 25px, Transition `left .2s cubic-bezier(.22,.9,.3,1)`.
|
||||||
`left .2s cubic-bezier(.22,.9,.3,1), background .2s`.
|
|
||||||
- Einträge: Videos automatisch abspielen (an), Ton beim Öffnen (aus), Wochenrückblick (an), Bewegte Übergänge (an).
|
- Einträge: Videos automatisch abspielen (an), Ton beim Öffnen (aus), Wochenrückblick (an), Bewegte Übergänge (an).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Interaktion & Verhalten
|
## Interaktion & Verhalten
|
||||||
|
|
||||||
**Karte entscheiden — drei gleichwertige Wege:**
|
**Karte entscheiden — vier gleichwertige Wege:**
|
||||||
1. **Maus-Drag**: Pointer Events auf der obersten Karte (`pointerdown` → `setPointerCapture`,
|
1. **Maus-Drag**: Pointer Events auf der obersten Karte (`pointerdown` → `setPointerCapture`,
|
||||||
`pointermove` → Delta, `pointerup`/`pointercancel` → Auswertung).
|
`pointermove` → Delta, `pointerup`/`pointercancel` → Auswertung).
|
||||||
Live-Transform: `translate3d(dx, dy, 0) rotate(dx/22 deg)`, Transition währenddessen aus.
|
Live-Transform: `translate3d(dx, dy, 0) rotate(dx/22 deg)`, Transition währenddessen aus.
|
||||||
Schwelle **±120px**: `dx > 120` = merken, `dx < -120` = ablehnen, sonst Rücksprung (Transition wieder an).
|
Schwelle **±120px**: `dx > 120` = merken, `dx < -120` = ablehnen, sonst Rücksprung (Transition wieder an).
|
||||||
2. **Buttons** ✕ / ↺ / ♥ unter der Bühne (und die beiden Buttons in der Detailspalte).
|
2. **Buttons** ✕ / ↺ / „Merken" unter der Bühne (und die beiden Buttons in der Detailspalte).
|
||||||
3. **Tastatur** (global, nur auf dem Feed-Screen, mit `preventDefault`):
|
3. **Merken-Pille auf der Karte** (erscheint beim Hover, oben rechts) — identisch mit „merken".
|
||||||
|
4. **Tastatur** (global, nur auf dem Feed-Screen, mit `preventDefault`):
|
||||||
`ArrowLeft` = ablehnen, `ArrowRight` = merken, `ArrowUp` = zurücknehmen.
|
`ArrowLeft` = ablehnen, `ArrowRight` = merken, `ArrowUp` = zurücknehmen.
|
||||||
|
|
||||||
|
**Hover-Zustände:** Scrim und Merken-Pille hängen am Hover der *Karte*, nicht am eigenen Element
|
||||||
|
(im Prototyp `.pin:hover .pin-save` / `.pin:hover .pin-scrim`, zusätzlich `:focus-within` für
|
||||||
|
Tastaturbedienung). Im Ziel-Framework als Hover-State der Kartenkomponente umsetzen —
|
||||||
|
und den Fokusfall nicht vergessen, sonst ist die Pille per Tastatur nicht erreichbar.
|
||||||
|
|
||||||
**Exit-Animation:** `transform: translate3d(±620px, -40px, 0) rotate(±22deg)`, `opacity: 0`,
|
**Exit-Animation:** `transform: translate3d(±620px, -40px, 0) rotate(±22deg)`, `opacity: 0`,
|
||||||
Dauer **320ms**, danach Index +1 und `exiting` zurücksetzen. Während `exiting` sind weitere
|
Dauer **320ms**, danach Index +1 und `exiting` zurücksetzen. Während `exiting` sind weitere
|
||||||
Entscheidungen gesperrt.
|
Entscheidungen gesperrt.
|
||||||
@@ -186,15 +209,15 @@ Entscheidungen gesperrt.
|
|||||||
**Undo:** letzte Entscheidung aus der History, Index zurück, „Gemerkt"-Zähler ggf. −1.
|
**Undo:** letzte Entscheidung aus der History, Index zurück, „Gemerkt"-Zähler ggf. −1.
|
||||||
Leere History → Toast „Nichts zurückzunehmen".
|
Leere History → Toast „Nichts zurückzunehmen".
|
||||||
|
|
||||||
**Toast:** fixiert `bottom:34px`, horizontal zentriert, `padding:12px 22px`, `radius:999px`,
|
**Toast:** fixiert `bottom:28px`, horizontal zentriert, `padding:16px 22px`, `radius:16px`,
|
||||||
`background: rgba(10,24,20,.92)`, `blur(10px)`, `border:1px solid rgba(255,255,255,.16)`, 14px,
|
`background:#ffffff`, `box-shadow: 0 1px 20px rgba(0,0,0,.22)`, `color:#111111`, 15px/600,
|
||||||
Einblendung `riseIn .2s`, verschwindet nach **1700ms**. Texte: „Zu ‚<Name>' gemerkt",
|
Einblendung `riseIn .2s`, verschwindet nach **1700ms**. Texte: „Zu ‚<Name>' gemerkt",
|
||||||
„Übersprungen", „Nichts zurückzunehmen", „Post veröffentlicht".
|
„Übersprungen", „Nichts zurückzunehmen", „Post veröffentlicht".
|
||||||
|
|
||||||
**Keyframes:**
|
**Keyframes:**
|
||||||
- `riseIn`: `opacity:0; translateY(14px)` → `opacity:1; none` (.2–.26s ease)
|
- `riseIn`: `opacity:0; translateY(14px)` → `opacity:1; none` (.2–.26s ease)
|
||||||
- `fadeIn`: `opacity:0` → `1`
|
- `fadeIn`: `opacity:0` → `1`
|
||||||
- Fokus: `:focus-visible { outline: 2px solid #7ee2b8; outline-offset: 2px; }` — nie der Browser-Default.
|
- Fokus: `:focus-visible { outline: 2px solid #0074e8; outline-offset: 2px; }` — nie der Browser-Default.
|
||||||
|
|
||||||
**Responsive:** Desktop-only, `min-width:1180px`; darunter horizontal scrollen.
|
**Responsive:** Desktop-only, `min-width:1180px`; darunter horizontal scrollen.
|
||||||
Der Feed-Bereich scrollt bei geringer Fensterhöhe (`min-height:0; overflow:auto`).
|
Der Feed-Bereich scrollt bei geringer Fensterhöhe (`min-height:0; overflow:auto`).
|
||||||
@@ -205,13 +228,13 @@ Der Feed-Bereich scrollt bei geringer Fensterhöhe (`min-height:0; overflow:auto
|
|||||||
|
|
||||||
| State | Typ | Zweck |
|
| State | Typ | Zweck |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `screen` | `'feed' \| 'profile' \| 'create' \| 'settings'` | aktive Ansicht (Sidebar) |
|
| `screen` | `'feed' \| 'profile' \| 'create' \| 'settings'` | aktive Ansicht (Icon-Rail) |
|
||||||
| `tab` | `'videos' \| 'following' \| 'posts'` | aktiver Stapel; Wechsel setzt `idx`/`history` zurück und springt auf `feed` |
|
| `tab` | `'videos' \| 'following' \| 'posts'` | aktiver Stapel; Wechsel setzt `idx`/`history` zurück und springt auf `feed` |
|
||||||
| `idx` | number | Index der obersten Karte im aktuellen Stapel |
|
| `idx` | number | Index der obersten Karte im aktuellen Stapel |
|
||||||
| `drag` | `{x, y, active} \| null` | laufende Drag-Geste |
|
| `drag` | `{x, y, active} \| null` | laufende Drag-Geste |
|
||||||
| `exiting` | `'left' \| 'right' \| null` | laufende Exit-Animation (sperrt Eingaben) |
|
| `exiting` | `'left' \| 'right' \| null` | laufende Exit-Animation (sperrt Eingaben) |
|
||||||
| `history` | `{idx, dir}[]` | für Undo |
|
| `history` | `{idx, dir}[]` | für Undo |
|
||||||
| `seen`, `saved` | number | Zähler Sidebar / Profil |
|
| `seen`, `saved` | number | Zähler Tab-Leiste / Profil |
|
||||||
| `showInfo` | boolean | Kürzel-Panel |
|
| `showInfo` | boolean | Kürzel-Panel |
|
||||||
| `toast` | string | Toast-Text (leer = versteckt) |
|
| `toast` | string | Toast-Text (leer = versteckt) |
|
||||||
| `draftTitle`, `draftSub`, `draftKind` | string | Formular „Erstellen", live in der Vorschau |
|
| `draftTitle`, `draftSub`, `draftKind` | string | Formular „Erstellen", live in der Vorschau |
|
||||||
@@ -229,33 +252,45 @@ Die drei Tabs liefern drei Stapel (Videos, Folge ich, Posts).
|
|||||||
**Farben**
|
**Farben**
|
||||||
| Rolle | Wert |
|
| Rolle | Wert |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Seitenverlauf | `#0d4c3d` → `#0a3a30` → `#24121a` → `#40161b` |
|
| Seite | `#ffffff` |
|
||||||
| Text | `#f2efe9` |
|
| Text | `#111111` |
|
||||||
| Text gedämpft | `rgba(242,239,233,.62)` / `.55` / `.5` / `.45` |
|
| Text gedämpft | `#5f5f5f` (Fließtext sekundär), `#767676` (Labels, inaktive Tabs), `#333333` (Beschreibung) |
|
||||||
| Akzent (Mint) | `#8fe3c1`, hell `#a9f0d0` / `#d6fbec`, Fokus `#7ee2b8` |
|
| Akzent (Rot) | `#e60023`, Hover `#ad081b` |
|
||||||
| Akzent-Tint | `rgba(126,226,184,.12)` Fläche, `.4–.6` Rahmen, `.14` Hover |
|
| Dunkel | `#111111` (aktiver Rail-Button, aktive Art-Pille, SKIP-Badge), Hover `#000000` |
|
||||||
| Ablehnen | `rgba(232,120,120,.9)` Rahmen, `#f0a8a8` Text, `rgba(120,32,38,.5)` Hover |
|
| Neutrale Flächen | `#efefef` (Suchfeld, Buttons, Tags), Hover `#e2e2e2`; `#e9e9e9` (Rail-Hover); `#f5f5f5` (Kacheln, Dropzone, Leerzustand) |
|
||||||
| Flächen | `rgba(8,26,22,.42)` Sidebar, `rgba(8,22,19,.34)` Detailspalte, `rgba(255,255,255,.02–.09)` |
|
| Linien | `#efefef` (Trenner, Kanten), `#cdcdcd` (Eingabe-Rahmen, Toggle aus) |
|
||||||
| Rahmen | `rgba(255,255,255,.07)` / `.1` / `.12` / `.16` / `.18` / `.22` |
|
| Auf Medien | `rgba(255,255,255,.94)` Pills, `rgba(255,255,255,.82)` Untertitel, `rgba(0,0,0,.24)` Hover-Scrim, `rgba(0,0,0,.62)` Lesbarkeitsverlauf |
|
||||||
|
| Fokus | `#0074e8` |
|
||||||
| Karten-Verläufe | grün `#1f8163→#0d4034`, blau `#256f8b→#0c2f3f`, ocker `#8a6a2f→#3a2a11`, rot `#7a2f38→#2c1014`, tannen `#2f6f5a→#0e332b`, türkis `#1c6f7f→#0a2c33`, violett `#6a2f7a→#26102c`, gold `#7a5a2a→#2f2110` |
|
| Karten-Verläufe | grün `#1f8163→#0d4034`, blau `#256f8b→#0c2f3f`, ocker `#8a6a2f→#3a2a11`, rot `#7a2f38→#2c1014`, tannen `#2f6f5a→#0e332b`, türkis `#1c6f7f→#0a2c33`, violett `#6a2f7a→#26102c`, gold `#7a5a2a→#2f2110` |
|
||||||
|
|
||||||
**Typografie** — Manrope 400/500/600/700 (UI), JetBrains Mono 400/500 (Zahlen, Captions).
|
**Typografie** — **nur Manrope** 400/500/600/700. JetBrains Mono entfällt; Zahlen laufen in Manrope
|
||||||
Skala: 32 / 30 / 26 / 22 / 19 / 17 / 16 / 15 / 14 / 13 / 12 / 11 px.
|
mit `font-variant-numeric: tabular-nums`.
|
||||||
Große Überschriften `letter-spacing:-.02em`, Kicker `+.14em`/`.16em` uppercase.
|
Skala: 36 / 30 / 28 / 20 / 18 / 17 / 16 / 15 / 14 / 13 / 12 px.
|
||||||
Alle Zahlen mit `font-variant-numeric: tabular-nums`.
|
Große Überschriften `letter-spacing:-.02em`. Keine Versalien-Kicker mehr — Kicker sind
|
||||||
|
12px/600 in `#767676`, normal geschrieben.
|
||||||
|
|
||||||
**Abstände** 3 / 4 / 6 / 8 / 9 / 10 / 12 / 13 / 14 / 18 / 20 / 22 / 26 / 28 / 34 / 38 / 44 px.
|
**Abstände** 2 / 4 / 6 / 8 / 10 / 12 / 14 / 16 / 18 / 20 / 22 / 24 / 26 / 28 / 30 / 32 / 40 px.
|
||||||
**Radien** 9 / 11 / 12 / 14 / 16 / 18 / 22 / 26 px, Pills `999px`, Kreise `50%`.
|
**Radien** 16px (Karten, Kacheln, Eingaben, Pills auf Medien, Toast, Panel),
|
||||||
**Schatten** nur an der Karte: `0 26px 60px rgba(0,0,0,.45)`.
|
18 / 22 / 24 / 28px (Tag-, Art-, Button-Pillen), `50%` Kreise, `999px` Toggle-Track.
|
||||||
**Blur** 4 / 6 / 10 / 12 / 14 px (`backdrop-filter`).
|
**Schatten** `0 1px 20px rgba(0,0,0,.12)` Flächen/Listen · `.16` Kürzel-Panel · `.18` Karte ·
|
||||||
**Transitions** `.16s` / `.18s` / `.2s` / `.3s` ease, Karten-Bewegung `.34s cubic-bezier(.22,.9,.3,1)`, Exit `320ms`.
|
`.22` Toast · `0 1px 3px rgba(0,0,0,.25)` Toggle-Knopf.
|
||||||
|
**Kein `backdrop-filter`** — die Pinterest-Oberfläche ist deckend.
|
||||||
|
**Transitions** `.12s ease` (Hover, Farbwechsel, Ein-/Ausblenden), `.16s` (Badge),
|
||||||
|
`.2s` (Toggle), Karten-Bewegung `.34s cubic-bezier(.22,.9,.3,1)`, Exit `320ms`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Assets
|
## Assets
|
||||||
Keine Binärdateien. Alle Medien sind Platzhalter aus CSS-Verläufen und Streifenmustern —
|
Keine Binärdateien im Prototyp. Alle Medien sind Platzhalter aus CSS-Verläufen und Streifenmustern —
|
||||||
im Produkt durch echte Bilder/Videos ersetzen. Icons: **Lucide** (im Prototyp Unicode-Glyphen als Platzhalter).
|
im Produkt durch echte Bilder/Videos ersetzen. Icons: **Lucide** (im Prototyp Unicode-Glyphen als
|
||||||
Fonts: Google Fonts — Manrope, JetBrains Mono.
|
Platzhalter). Fonts: Google Fonts — **nur Manrope**.
|
||||||
|
|
||||||
|
## Offene Punkte
|
||||||
|
- **Suchfeld ohne Funktion.** Die Pinterest-Kopfzeile lebt von der Suche, im Prototyp ist sie eine
|
||||||
|
reine Attrappe — es gibt bisher keine Suchfunktion in der App. Vor der Umsetzung klären, ob Suche
|
||||||
|
gebaut wird; wenn nicht, gehört das Feld raus, statt eine Funktion vorzutäuschen.
|
||||||
|
- **Pinterest-Referenz liegt nicht im Repo.** Die Vorlage kam als Screenshot im Chat. Wer sie
|
||||||
|
dauerhaft braucht, legt sie als `referenz/pinterest-desktop.png` daneben.
|
||||||
|
|
||||||
## Dateien in diesem Bundle
|
## Dateien in diesem Bundle
|
||||||
- `PROMPT.md` — fertiger Auftrag zum Einfügen in Claude Code.
|
- `PROMPT.md` — fertiger Auftrag zum Einfügen in Claude Code.
|
||||||
|
|||||||
@@ -10,66 +10,70 @@
|
|||||||
<helmet>
|
<helmet>
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
html, body { margin:0; padding:0; background:#120b0d; }
|
html, body { margin:0; padding:0; background:#ffffff; }
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
a { color:#8fe3c1; text-decoration:none; }
|
a { color:#111111; text-decoration:none; }
|
||||||
a:hover { color:#b9f2da; }
|
::selection { background:rgba(230,0,35,.16); }
|
||||||
::selection { background:rgba(126,226,184,.28); }
|
button:focus-visible, [tabindex]:focus-visible, input:focus-visible { outline:2px solid #0074e8; outline-offset:2px; }
|
||||||
button:focus-visible, [tabindex]:focus-visible { outline:2px solid #7ee2b8; outline-offset:2px; }
|
|
||||||
@keyframes riseIn { from { opacity:0; transform:translateY(14px);} to { opacity:1; transform:none;} }
|
@keyframes riseIn { from { opacity:0; transform:translateY(14px);} to { opacity:1; transform:none;} }
|
||||||
@keyframes fadeIn { from { opacity:0 } to { opacity:1 } }
|
@keyframes fadeIn { from { opacity:0 } to { opacity:1 } }
|
||||||
@keyframes pulseRing { 0%{ box-shadow:0 0 0 0 rgba(126,226,184,.35)} 70%{ box-shadow:0 0 0 18px rgba(126,226,184,0)} 100%{ box-shadow:0 0 0 0 rgba(126,226,184,0)} }
|
.pin-save { opacity:0; transition:opacity .12s ease; }
|
||||||
|
.pin:hover .pin-save, .pin:focus-within .pin-save { opacity:1; }
|
||||||
|
.pin-scrim { opacity:0; transition:opacity .12s ease; }
|
||||||
|
.pin:hover .pin-scrim { opacity:1; }
|
||||||
|
.rail { background:transparent; color:#111111; }
|
||||||
|
.rail:hover { background:#e9e9e9; }
|
||||||
|
.rail.active { background:#111111; color:#ffffff; }
|
||||||
|
.rail.active:hover { background:#000000; }
|
||||||
</style>
|
</style>
|
||||||
</helmet>
|
</helmet>
|
||||||
|
|
||||||
<div style="min-height:100vh; width:100%; min-width:1180px; display:flex; font-family:'Manrope',system-ui,sans-serif; color:#f2efe9; background:radial-gradient(120% 80% at 50% 0%, #0d4c3d 0%, #0a3a30 34%, #24121a 68%, #40161b 100%); background-attachment:fixed;">
|
<div style="min-height:100vh; width:100%; min-width:1180px; display:flex; font-family:'Manrope',system-ui,sans-serif; color:#111111; background:#ffffff;">
|
||||||
|
|
||||||
<aside style="width:236px; flex:none; display:flex; flex-direction:column; gap:28px; padding:26px 20px; border-right:1px solid rgba(255,255,255,.08); background:rgba(8,26,22,.42); backdrop-filter:blur(14px); position:sticky; top:0; height:100vh;">
|
<aside style="width:80px; flex:none; display:flex; flex-direction:column; align-items:center; gap:8px; padding:12px 0 16px; border-right:1px solid #efefef; background:#ffffff; position:sticky; top:0; height:100vh;">
|
||||||
<div style="display:flex; align-items:center; gap:10px;">
|
<div style="width:48px; height:48px; display:grid; place-items:center; margin-bottom:4px;">
|
||||||
<div style="width:30px; height:30px; border-radius:9px; background:linear-gradient(150deg,#2fa87f,#0e5442); display:grid; place-items:center; font-size:15px; font-weight:700;">V</div>
|
<div style="width:32px; height:32px; border-radius:50%; background:#e60023; display:grid; place-items:center; color:#ffffff; font-size:17px; font-weight:700;">V</div>
|
||||||
<div style="font-size:16px; font-weight:600; letter-spacing:-.01em;">videogen</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav style="display:flex; flex-direction:column; gap:4px;">
|
<nav style="display:flex; flex-direction:column; align-items:center; gap:8px;">
|
||||||
<sc-for list="{{ navItems }}" as="item" hint-placeholder-count="4">
|
<sc-for list="{{ navTop }}" as="item" hint-placeholder-count="3">
|
||||||
<button onClick="{{ item.go }}" style="{{ item.style }}" style-hover="background:rgba(255,255,255,.09); color:#ffffff;">
|
<button onClick="{{ item.go }}" title="{{ item.label }}" class="{{ item.cls }}" style="{{ item.style }}">{{ item.glyph }}</button>
|
||||||
<span style="width:20px; display:grid; place-items:center; opacity:.9;">{{ item.glyph }}</span>
|
|
||||||
<span>{{ item.label }}</span>
|
|
||||||
</button>
|
|
||||||
</sc-for>
|
</sc-for>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div style="margin-top:auto; display:flex; flex-direction:column; gap:14px;">
|
<div style="margin-top:auto; display:flex; flex-direction:column; align-items:center; gap:10px;">
|
||||||
<div style="border:1px solid rgba(255,255,255,.12); border-radius:14px; padding:14px; background:rgba(255,255,255,.03);">
|
<sc-for list="{{ navBottom }}" as="item" hint-placeholder-count="1">
|
||||||
<div style="font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:rgba(242,239,233,.5); margin-bottom:8px;">Heute</div>
|
<button onClick="{{ item.go }}" title="{{ item.label }}" class="{{ item.cls }}" style="{{ item.style }}">{{ item.glyph }}</button>
|
||||||
<div style="font-family:'JetBrains Mono',monospace; font-size:22px; font-variant-numeric:tabular-nums;">{{ swipesToday }}</div>
|
</sc-for>
|
||||||
<div style="font-size:12px; color:rgba(242,239,233,.55);">Karten gesichtet</div>
|
|
||||||
</div>
|
|
||||||
<div style="display:flex; align-items:center; gap:10px; padding:8px 6px;">
|
|
||||||
<div style="width:32px; height:32px; border-radius:50%; background:linear-gradient(140deg,#b2323c,#5d1620); flex:none;"></div>
|
|
||||||
<div style="min-width:0;">
|
|
||||||
<div style="font-size:13px; font-weight:600;">Jonas K.</div>
|
|
||||||
<div style="font-size:11px; color:rgba(242,239,233,.5);">Studio-Konto</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<main style="flex:1; min-width:0; display:flex; flex-direction:column;">
|
<main style="flex:1; min-width:0; display:flex; flex-direction:column;">
|
||||||
|
|
||||||
<header style="height:72px; flex:none; display:flex; align-items:center; justify-content:space-between; padding:0 34px; border-bottom:1px solid rgba(255,255,255,.07);">
|
<header style="flex:none; display:flex; align-items:center; gap:8px; padding:12px 16px 4px;">
|
||||||
<div style="display:flex; gap:6px; align-items:center;">
|
<div style="flex:1; min-width:0; display:flex; align-items:center; gap:12px; height:48px; padding:0 16px; border-radius:24px; background:#efefef; color:#767676; font-size:16px;">
|
||||||
|
<span style="font-size:15px;">⌕</span>
|
||||||
|
<span style="flex:1; min-width:0;">Suchen</span>
|
||||||
|
<span style="font-size:15px;">◎</span>
|
||||||
|
</div>
|
||||||
|
<button title="Konto" style="width:40px; height:40px; flex:none; border:none; border-radius:50%; background:linear-gradient(140deg,#b2323c,#5d1620); color:#ffffff; font-size:15px; font-weight:700; cursor:pointer; display:grid; place-items:center;">J</button>
|
||||||
|
<button title="Konto-Menü" style="width:28px; height:28px; flex:none; border:none; border-radius:50%; background:transparent; color:#5f5f5f; font-size:12px; cursor:pointer;" style-hover="background:#e9e9e9;">▾</button>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div style="flex:none; display:flex; align-items:flex-end; justify-content:space-between; gap:20px; padding:0 24px; border-bottom:1px solid #efefef;">
|
||||||
|
<div style="display:flex; gap:24px; align-items:flex-end;">
|
||||||
<sc-for list="{{ tabs }}" as="t" hint-placeholder-count="3">
|
<sc-for list="{{ tabs }}" as="t" hint-placeholder-count="3">
|
||||||
<button onClick="{{ t.go }}" style="{{ t.style }}" style-hover="color:#ffffff;">{{ t.label }}</button>
|
<button onClick="{{ t.go }}" style="{{ t.style }}" style-hover="color:#111111;">{{ t.label }}</button>
|
||||||
</sc-for>
|
</sc-for>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex; align-items:center; gap:12px;">
|
<div style="display:flex; align-items:center; gap:14px; padding-bottom:10px;">
|
||||||
<div style="font-size:12px; color:rgba(242,239,233,.5); font-family:'JetBrains Mono',monospace; font-variant-numeric:tabular-nums;">{{ counter }}</div>
|
<div style="font-size:13px; color:#767676;"><span style="font-weight:700; color:#111111; font-variant-numeric:tabular-nums;">{{ swipesToday }}</span> heute gesichtet</div>
|
||||||
<button onClick="{{ toggleInfo }}" title="Kürzel anzeigen" style="width:36px; height:36px; border-radius:50%; border:1px solid rgba(255,255,255,.18); background:rgba(255,255,255,.04); color:#f2efe9; font-size:14px; cursor:pointer; transition:background .18s ease, transform .18s ease;" style-hover="background:rgba(255,255,255,.12); transform:translateY(-1px);">i</button>
|
<div style="font-size:13px; color:#767676; font-variant-numeric:tabular-nums;">{{ counter }}</div>
|
||||||
|
<button onClick="{{ toggleInfo }}" title="Kürzel anzeigen" style="width:36px; height:36px; border:none; border-radius:50%; background:transparent; color:#111111; font-size:14px; font-weight:700; cursor:pointer; transition:background .12s ease;" style-hover="background:#e9e9e9;">i</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</div>
|
||||||
|
|
||||||
<sc-if value="{{ isFeed }}" hint-placeholder-val="{{ true }}">
|
<sc-if value="{{ isFeed }}" hint-placeholder-val="{{ true }}">
|
||||||
<section style="flex:1; min-height:0; overflow:auto; display:grid; grid-template-columns:minmax(0,1fr) 372px; gap:0;">
|
<section style="flex:1; min-height:0; overflow:auto; display:grid; grid-template-columns:minmax(0,1fr) 372px; gap:0;">
|
||||||
@@ -77,25 +81,29 @@
|
|||||||
<div style="position:relative; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:26px 20px 30px; gap:22px; min-width:0; min-height:min-content;">
|
<div style="position:relative; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:26px 20px 30px; gap:22px; min-width:0; min-height:min-content;">
|
||||||
<div style="position:relative; width:min(404px,100%); height:560px; flex:none;">
|
<div style="position:relative; width:min(404px,100%); height:560px; flex:none;">
|
||||||
<sc-for list="{{ stack }}" as="c" hint-placeholder-count="3">
|
<sc-for list="{{ stack }}" as="c" hint-placeholder-count="3">
|
||||||
<div style="{{ c.shell }}" onPointerDown="{{ c.down }}" onPointerMove="{{ c.move }}" onPointerUp="{{ c.up }}" onPointerCancel="{{ c.up }}">
|
<div class="pin" style="{{ c.shell }}" onPointerDown="{{ c.down }}" onPointerMove="{{ c.move }}" onPointerUp="{{ c.up }}" onPointerCancel="{{ c.up }}">
|
||||||
<div style="{{ c.media }}">
|
<div style="{{ c.media }}">
|
||||||
<div style="position:absolute; inset:0; background:{{ c.stripes }}; opacity:.5;"></div>
|
<div style="position:absolute; inset:0; background:{{ c.stripes }}; opacity:.5;"></div>
|
||||||
<div style="position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,.32) 0%, rgba(0,0,0,0) 26%, rgba(0,0,0,0) 52%, rgba(0,0,0,.66) 100%);"></div>
|
<div class="pin-scrim" style="position:absolute; inset:0; background:rgba(0,0,0,.24);"></div>
|
||||||
|
<div style="position:absolute; inset:0; background:linear-gradient(180deg, rgba(0,0,0,0) 46%, rgba(0,0,0,.62) 100%);"></div>
|
||||||
|
|
||||||
<div style="position:relative; display:flex; gap:9px; padding:18px;">
|
<div style="position:relative; display:flex; align-items:flex-start; justify-content:space-between; gap:9px; padding:16px;">
|
||||||
<span style="padding:7px 15px; border-radius:999px; border:1px solid rgba(255,255,255,.34); background:rgba(0,0,0,.22); backdrop-filter:blur(6px); font-size:13px; font-weight:600;">{{ c.kind }}</span>
|
<div style="display:flex; gap:8px;">
|
||||||
<span style="padding:7px 15px; border-radius:999px; border:1px solid rgba(255,255,255,.34); background:rgba(0,0,0,.22); backdrop-filter:blur(6px); font-size:13px; font-weight:600;">{{ c.assets }}</span>
|
<span style="padding:6px 12px; border-radius:16px; background:rgba(255,255,255,.94); color:#111111; font-size:13px; font-weight:600;">{{ c.kind }}</span>
|
||||||
|
<span style="padding:6px 12px; border-radius:16px; background:rgba(255,255,255,.94); color:#111111; font-size:13px; font-weight:600;">{{ c.assets }}</span>
|
||||||
|
</div>
|
||||||
|
<button class="pin-save" onClick="{{ onLike }}" style="{{ c.save }}" style-hover="background:#ad081b;">Merken</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="position:absolute; inset:auto 0 118px 0; display:flex; justify-content:center; padding:0 22px;">
|
<div style="position:absolute; inset:auto 0 104px 0; display:flex; justify-content:center; padding:0 22px;">
|
||||||
<div style="font-family:'JetBrains Mono',monospace; font-size:15px; padding:9px 16px; border-radius:9px; background:rgba(0,0,0,.5); backdrop-filter:blur(4px); text-align:center; text-wrap:pretty;">{{ c.caption }}</div>
|
<div style="font-size:15px; font-weight:600; padding:8px 14px; border-radius:16px; background:rgba(255,255,255,.94); color:#111111; text-align:center; text-wrap:pretty;">{{ c.caption }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="position:absolute; inset:auto 0 0 0; display:flex; align-items:center; gap:13px; padding:20px;">
|
<div style="position:absolute; inset:auto 0 0 0; display:flex; align-items:center; gap:12px; padding:18px; color:#ffffff;">
|
||||||
<div style="width:46px; height:46px; border-radius:50%; flex:none; background:{{ c.avatar }}; border:2px solid rgba(255,255,255,.3);"></div>
|
<div style="width:44px; height:44px; border-radius:50%; flex:none; background:{{ c.avatar }};"></div>
|
||||||
<div style="min-width:0;">
|
<div style="min-width:0;">
|
||||||
<div style="font-size:19px; font-weight:700; letter-spacing:-.01em;">{{ c.name }}</div>
|
<div style="font-size:18px; font-weight:700; letter-spacing:-.01em;">{{ c.name }}</div>
|
||||||
<div style="font-size:14px; color:rgba(255,255,255,.72);">{{ c.sub }}</div>
|
<div style="font-size:14px; color:rgba(255,255,255,.82);">{{ c.sub }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -105,95 +113,97 @@
|
|||||||
</sc-for>
|
</sc-for>
|
||||||
|
|
||||||
<sc-if value="{{ stackEmpty }}" hint-placeholder-val="{{ false }}">
|
<sc-if value="{{ stackEmpty }}" hint-placeholder-val="{{ false }}">
|
||||||
<div style="position:absolute; inset:0; border:1px dashed rgba(255,255,255,.2); border-radius:26px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px; text-align:center; padding:40px; animation:fadeIn .3s ease;">
|
<div style="position:absolute; inset:0; border-radius:16px; background:#f5f5f5; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; text-align:center; padding:40px; animation:fadeIn .3s ease;">
|
||||||
<div style="font-size:20px; font-weight:600;">Alles gesichtet</div>
|
<div style="font-size:20px; font-weight:700;">Alles gesichtet</div>
|
||||||
<div style="font-size:14px; color:rgba(242,239,233,.6); max-width:230px; text-wrap:pretty;">Für heute sind keine neuen Karten mehr in dieser Ansicht.</div>
|
<div style="font-size:15px; color:#5f5f5f; max-width:240px; text-wrap:pretty;">Für heute sind keine neuen Karten mehr in dieser Ansicht.</div>
|
||||||
<button onClick="{{ reset }}" style="padding:11px 20px; border-radius:999px; border:1px solid rgba(126,226,184,.6); background:transparent; color:#8fe3c1; font-family:inherit; font-size:14px; font-weight:600; cursor:pointer; transition:background .18s ease;" style-hover="background:rgba(126,226,184,.14);">Stapel neu laden</button>
|
<button onClick="{{ reset }}" style="padding:12px 20px; border:none; border-radius:24px; background:#e60023; color:#ffffff; font-family:inherit; font-size:15px; font-weight:700; cursor:pointer; transition:background .12s ease;" style-hover="background:#ad081b;">Stapel neu laden</button>
|
||||||
</div>
|
</div>
|
||||||
</sc-if>
|
</sc-if>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display:flex; align-items:center; gap:18px;">
|
<div style="display:flex; align-items:center; gap:16px;">
|
||||||
<button onClick="{{ onNope }}" title="Ablehnen — Pfeil links" style="width:62px; height:62px; border-radius:50%; border:1px solid rgba(255,255,255,.16); background:rgba(14,10,12,.72); color:#f2efe9; font-size:22px; cursor:pointer; display:grid; place-items:center; transition:transform .18s ease, border-color .18s ease, background .18s ease;" style-hover="transform:translateY(-3px) scale(1.05); border-color:rgba(230,120,120,.75); background:rgba(120,32,38,.5);" style-active="transform:scale(.95);">✕</button>
|
<button onClick="{{ onNope }}" title="Ablehnen — Pfeil links" style="width:56px; height:56px; border:none; border-radius:50%; background:#efefef; color:#111111; font-size:20px; cursor:pointer; display:grid; place-items:center; transition:background .12s ease, transform .12s ease;" style-hover="background:#e2e2e2; transform:scale(1.04);" style-active="transform:scale(.96);">✕</button>
|
||||||
<button onClick="{{ onUndo }}" title="Zurück — Pfeil hoch" style="width:52px; height:52px; border-radius:50%; border:1px solid rgba(255,255,255,.16); background:rgba(14,10,12,.72); color:#f2efe9; font-size:17px; cursor:pointer; display:grid; place-items:center; transition:transform .18s ease, border-color .18s ease;" style-hover="transform:translateY(-3px) scale(1.05); border-color:rgba(255,255,255,.4);" style-active="transform:scale(.95);">↺</button>
|
<button onClick="{{ onUndo }}" title="Zurück — Pfeil hoch" style="width:48px; height:48px; border:none; border-radius:50%; background:#efefef; color:#111111; font-size:17px; cursor:pointer; display:grid; place-items:center; transition:background .12s ease, transform .12s ease;" style-hover="background:#e2e2e2; transform:scale(1.04);" style-active="transform:scale(.96);">↺</button>
|
||||||
<button onClick="{{ onLike }}" title="Merken — Pfeil rechts" style="width:70px; height:70px; border-radius:50%; border:1px solid rgba(126,226,184,.45); background:rgba(14,10,12,.72); color:#8fe3c1; font-size:26px; cursor:pointer; display:grid; place-items:center; transition:transform .18s ease, background .18s ease;" style-hover="transform:translateY(-3px) scale(1.06); background:rgba(20,88,68,.6);" style-active="transform:scale(.95);">♥</button>
|
<button onClick="{{ onLike }}" title="Merken — Pfeil rechts" style="height:56px; padding:0 30px; border:none; border-radius:28px; background:#e60023; color:#ffffff; font-family:inherit; font-size:17px; font-weight:700; cursor:pointer; display:grid; place-items:center; transition:background .12s ease, transform .12s ease;" style-hover="background:#ad081b; transform:scale(1.04);" style-active="transform:scale(.96);">Merken</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<sc-if value="{{ showInfo }}" hint-placeholder-val="{{ false }}">
|
<sc-if value="{{ showInfo }}" hint-placeholder-val="{{ false }}">
|
||||||
<div style="position:absolute; right:26px; top:26px; width:250px; border:1px solid rgba(255,255,255,.14); border-radius:14px; background:rgba(10,26,22,.9); backdrop-filter:blur(12px); padding:16px; font-size:13px; line-height:1.8; animation:riseIn .22s ease;">
|
<div style="position:absolute; right:26px; top:26px; width:250px; border-radius:16px; background:#ffffff; box-shadow:0 1px 20px rgba(0,0,0,.16); padding:16px; font-size:14px; line-height:1.7; animation:riseIn .22s ease;">
|
||||||
<div style="font-weight:700; margin-bottom:8px;">Bedienung</div>
|
<div style="font-weight:700; margin-bottom:8px;">Bedienung</div>
|
||||||
<div style="display:grid; grid-template-columns:auto 1fr; gap:6px 12px; color:rgba(242,239,233,.72);">
|
<div style="display:grid; grid-template-columns:auto 1fr; gap:6px 12px; color:#5f5f5f;">
|
||||||
<span style="font-family:'JetBrains Mono',monospace;">←</span><span>Ablehnen</span>
|
<span style="font-weight:600; color:#111111;">←</span><span>Ablehnen</span>
|
||||||
<span style="font-family:'JetBrains Mono',monospace;">→</span><span>Merken</span>
|
<span style="font-weight:600; color:#111111;">→</span><span>Merken</span>
|
||||||
<span style="font-family:'JetBrains Mono',monospace;">↑</span><span>Zurücknehmen</span>
|
<span style="font-weight:600; color:#111111;">↑</span><span>Zurücknehmen</span>
|
||||||
<span style="font-family:'JetBrains Mono',monospace;">Maus</span><span>Karte ziehen</span>
|
<span style="font-weight:600; color:#111111;">Maus</span><span>Karte ziehen</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</sc-if>
|
</sc-if>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside style="border-left:1px solid rgba(255,255,255,.07); background:rgba(8,22,19,.34); padding:30px 28px; display:flex; flex-direction:column; gap:24px; overflow:auto;">
|
<aside style="border-left:1px solid #efefef; background:#ffffff; padding:28px; display:flex; flex-direction:column; gap:22px; overflow:auto;">
|
||||||
<div>
|
<div>
|
||||||
<div style="font-size:11px; letter-spacing:.16em; text-transform:uppercase; color:rgba(242,239,233,.45);">Aktuelle Karte</div>
|
<div style="font-size:12px; font-weight:600; color:#767676;">Aktuelle Karte</div>
|
||||||
<div style="font-size:26px; font-weight:600; letter-spacing:-.02em; margin-top:10px; text-wrap:pretty;">{{ detailTitle }}</div>
|
<div style="font-size:28px; font-weight:700; letter-spacing:-.02em; margin-top:8px; text-wrap:pretty;">{{ detailTitle }}</div>
|
||||||
<div style="font-size:14px; color:rgba(242,239,233,.62); margin-top:6px;">{{ detailSub }}</div>
|
<div style="font-size:15px; color:#5f5f5f; margin-top:6px;">{{ detailSub }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="height:1px; background:rgba(255,255,255,.09);"></div>
|
<div style="height:1px; background:#efefef;"></div>
|
||||||
|
|
||||||
<div style="display:grid; grid-template-columns:repeat(3,1fr); gap:12px;">
|
<div style="display:grid; grid-template-columns:repeat(3,1fr); gap:10px;">
|
||||||
<sc-for list="{{ detailStats }}" as="s" hint-placeholder-count="3">
|
<sc-for list="{{ detailStats }}" as="s" hint-placeholder-count="3">
|
||||||
<div style="border:1px solid rgba(255,255,255,.1); border-radius:12px; padding:12px;">
|
<div style="border-radius:16px; background:#f5f5f5; padding:14px;">
|
||||||
<div style="font-family:'JetBrains Mono',monospace; font-size:17px; font-variant-numeric:tabular-nums;">{{ s.value }}</div>
|
<div style="font-size:18px; font-weight:700; font-variant-numeric:tabular-nums;">{{ s.value }}</div>
|
||||||
<div style="font-size:11px; color:rgba(242,239,233,.5); margin-top:3px;">{{ s.label }}</div>
|
<div style="font-size:12px; color:#767676; margin-top:3px;">{{ s.label }}</div>
|
||||||
</div>
|
</div>
|
||||||
</sc-for>
|
</sc-for>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div style="font-size:11px; letter-spacing:.16em; text-transform:uppercase; color:rgba(242,239,233,.45); margin-bottom:10px;">Beschreibung</div>
|
<div style="font-size:12px; font-weight:600; color:#767676; margin-bottom:8px;">Beschreibung</div>
|
||||||
<p style="margin:0; font-size:14px; line-height:1.75; color:rgba(242,239,233,.78); text-wrap:pretty;">{{ detailBody }}</p>
|
<p style="margin:0; font-size:15px; line-height:1.7; color:#333333; text-wrap:pretty;">{{ detailBody }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div style="font-size:11px; letter-spacing:.16em; text-transform:uppercase; color:rgba(242,239,233,.45); margin-bottom:10px;">Tags</div>
|
<div style="font-size:12px; font-weight:600; color:#767676; margin-bottom:10px;">Tags</div>
|
||||||
<div style="display:flex; flex-wrap:wrap; gap:8px;">
|
<div style="display:flex; flex-wrap:wrap; gap:8px;">
|
||||||
<sc-for list="{{ detailTags }}" as="tag" hint-placeholder-count="4">
|
<sc-for list="{{ detailTags }}" as="tag" hint-placeholder-count="4">
|
||||||
<span style="padding:6px 12px; border-radius:999px; border:1px solid rgba(255,255,255,.18); font-size:12px; color:rgba(242,239,233,.8);">{{ tag }}</span>
|
<span style="padding:8px 14px; border-radius:18px; background:#efefef; font-size:13px; font-weight:600; color:#111111;">{{ tag }}</span>
|
||||||
</sc-for>
|
</sc-for>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top:auto; display:flex; flex-direction:column; gap:10px;">
|
<div style="margin-top:auto; display:flex; flex-direction:column; gap:8px;">
|
||||||
<button onClick="{{ onLike }}" style="padding:13px; border-radius:12px; border:1px solid rgba(126,226,184,.55); background:transparent; color:#8fe3c1; font-family:inherit; font-size:14px; font-weight:600; cursor:pointer; transition:background .18s ease;" style-hover="background:rgba(126,226,184,.14);">Zur Sammlung hinzufügen</button>
|
<button onClick="{{ onLike }}" style="padding:14px; border:none; border-radius:24px; background:#e60023; color:#ffffff; font-family:inherit; font-size:15px; font-weight:700; cursor:pointer; transition:background .12s ease;" style-hover="background:#ad081b;">Zur Sammlung hinzufügen</button>
|
||||||
<button onClick="{{ onNope }}" style="padding:13px; border-radius:12px; border:1px solid rgba(255,255,255,.16); background:transparent; color:rgba(242,239,233,.8); font-family:inherit; font-size:14px; cursor:pointer; transition:background .18s ease;" style-hover="background:rgba(255,255,255,.07);">Überspringen</button>
|
<button onClick="{{ onNope }}" style="padding:14px; border:none; border-radius:24px; background:#efefef; color:#111111; font-family:inherit; font-size:15px; font-weight:700; cursor:pointer; transition:background .12s ease;" style-hover="background:#e2e2e2;">Überspringen</button>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
</section>
|
</section>
|
||||||
</sc-if>
|
</sc-if>
|
||||||
|
|
||||||
<sc-if value="{{ isProfile }}" hint-placeholder-val="{{ false }}">
|
<sc-if value="{{ isProfile }}" hint-placeholder-val="{{ false }}">
|
||||||
<section style="flex:1; padding:38px 44px; overflow:auto; animation:riseIn .26s ease;">
|
<section style="flex:1; padding:32px 24px 40px; overflow:auto; animation:riseIn .26s ease;">
|
||||||
<div style="display:flex; align-items:flex-end; gap:22px; padding-bottom:26px; border-bottom:1px solid rgba(255,255,255,.09);">
|
<div style="display:flex; flex-direction:column; align-items:center; gap:10px; padding-bottom:28px;">
|
||||||
<div style="width:96px; height:96px; border-radius:50%; background:linear-gradient(140deg,#b2323c,#5d1620); flex:none; border:2px solid rgba(255,255,255,.2);"></div>
|
<div style="width:120px; height:120px; border-radius:50%; background:linear-gradient(140deg,#b2323c,#5d1620); flex:none;"></div>
|
||||||
<div style="flex:1;">
|
<div style="font-size:36px; font-weight:700; letter-spacing:-.02em; text-align:center;">Jonas K.</div>
|
||||||
<div style="font-size:32px; font-weight:600; letter-spacing:-.02em;">Jonas K.</div>
|
<div style="font-size:15px; color:#5f5f5f;">Studio-Konto · seit März 2026</div>
|
||||||
<div style="font-size:14px; color:rgba(242,239,233,.6); margin-top:4px;">Studio-Konto · seit März 2026</div>
|
<div style="display:flex; gap:28px; margin-top:6px;">
|
||||||
</div>
|
|
||||||
<div style="display:flex; gap:34px; padding-bottom:6px;">
|
|
||||||
<sc-for list="{{ profileStats }}" as="s" hint-placeholder-count="3">
|
<sc-for list="{{ profileStats }}" as="s" hint-placeholder-count="3">
|
||||||
<div>
|
<div style="text-align:center;">
|
||||||
<div style="font-family:'JetBrains Mono',monospace; font-size:22px; font-variant-numeric:tabular-nums;">{{ s.value }}</div>
|
<div style="font-size:18px; font-weight:700; font-variant-numeric:tabular-nums;">{{ s.value }}</div>
|
||||||
<div style="font-size:12px; color:rgba(242,239,233,.5);">{{ s.label }}</div>
|
<div style="font-size:13px; color:#767676;">{{ s.label }}</div>
|
||||||
</div>
|
</div>
|
||||||
</sc-for>
|
</sc-for>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:grid; grid-template-columns:repeat(4,1fr); gap:18px; margin-top:28px;">
|
<div style="columns:5; column-gap:16px;">
|
||||||
<sc-for list="{{ gallery }}" as="g" hint-placeholder-count="8">
|
<sc-for list="{{ gallery }}" as="g" hint-placeholder-count="8">
|
||||||
<div style="{{ g.tile }}" style-hover="transform:translateY(-4px); border-color:rgba(126,226,184,.5);">
|
<div class="pin" style="{{ g.tile }}">
|
||||||
<div style="position:absolute; inset:0; background:{{ g.stripes }}; opacity:.45;"></div>
|
<div style="position:absolute; inset:0; background:{{ g.stripes }}; opacity:.45;"></div>
|
||||||
<div style="position:absolute; inset:auto 0 0 0; padding:14px; background:linear-gradient(0deg, rgba(0,0,0,.7), transparent); font-size:13px; font-weight:600;">{{ g.title }}</div>
|
<div class="pin-scrim" style="position:absolute; inset:0; background:rgba(0,0,0,.24);"></div>
|
||||||
|
<div style="position:absolute; right:12px; top:12px;">
|
||||||
|
<button class="pin-save" onClick="{{ onLike }}" style="padding:11px 16px; border:none; border-radius:22px; background:#e60023; color:#ffffff; font-family:inherit; font-size:15px; font-weight:700; cursor:pointer;" style-hover="background:#ad081b;">Merken</button>
|
||||||
|
</div>
|
||||||
|
<div style="position:absolute; inset:auto 0 0 0; padding:14px; background:linear-gradient(0deg, rgba(0,0,0,.62), transparent); color:#ffffff; font-size:14px; font-weight:600;">{{ g.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
</sc-for>
|
</sc-for>
|
||||||
</div>
|
</div>
|
||||||
@@ -201,47 +211,47 @@
|
|||||||
</sc-if>
|
</sc-if>
|
||||||
|
|
||||||
<sc-if value="{{ isCreate }}" hint-placeholder-val="{{ false }}">
|
<sc-if value="{{ isCreate }}" hint-placeholder-val="{{ false }}">
|
||||||
<section style="flex:1; overflow:auto; padding:38px 44px; animation:riseIn .26s ease;">
|
<section style="flex:1; overflow:auto; padding:32px 24px 40px; animation:riseIn .26s ease;">
|
||||||
<div style="max-width:920px; display:grid; grid-template-columns:1fr 320px; gap:34px;">
|
<div style="max-width:920px; margin:0 auto; border-radius:24px; box-shadow:0 1px 20px rgba(0,0,0,.12); padding:32px; display:grid; grid-template-columns:1fr 320px; gap:32px;">
|
||||||
<div style="display:flex; flex-direction:column; gap:22px;">
|
<div style="display:flex; flex-direction:column; gap:20px;">
|
||||||
<div>
|
<div>
|
||||||
<div style="font-size:30px; font-weight:600; letter-spacing:-.02em;">Neuen Post erstellen</div>
|
<div style="font-size:30px; font-weight:700; letter-spacing:-.02em;">Neuen Post erstellen</div>
|
||||||
<div style="font-size:14px; color:rgba(242,239,233,.6); margin-top:6px;">Material hochladen, beschriften, in den Feed geben.</div>
|
<div style="font-size:15px; color:#5f5f5f; margin-top:6px;">Material hochladen, beschriften, in den Feed geben.</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="border:1px dashed rgba(255,255,255,.24); border-radius:18px; height:220px; display:grid; place-items:center; text-align:center; gap:8px; background:rgba(255,255,255,.03); cursor:pointer; transition:border-color .18s ease, background .18s ease;" style-hover="border-color:rgba(126,226,184,.6); background:rgba(126,226,184,.06);">
|
<div style="border:2px dashed #cdcdcd; border-radius:16px; height:220px; display:grid; place-items:center; text-align:center; background:#f5f5f5; cursor:pointer; transition:border-color .12s ease, background .12s ease;" style-hover="border-color:#e60023; background:#fafafa;">
|
||||||
<div>
|
<div>
|
||||||
<div style="font-size:15px; font-weight:600;">Dateien hierher ziehen</div>
|
<div style="font-size:16px; font-weight:700;">Dateien hierher ziehen</div>
|
||||||
<div style="font-size:13px; color:rgba(242,239,233,.55); margin-top:6px;">MP4, MOV oder bis zu 10 Bilder</div>
|
<div style="font-size:14px; color:#767676; margin-top:6px;">MP4, MOV oder bis zu 10 Bilder</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex; flex-direction:column; gap:16px;">
|
<div style="display:flex; flex-direction:column; gap:16px;">
|
||||||
<label style="display:flex; flex-direction:column; gap:8px; font-size:12px; letter-spacing:.14em; text-transform:uppercase; color:rgba(242,239,233,.5);">Titel
|
<label style="display:flex; flex-direction:column; gap:8px; font-size:13px; font-weight:600; color:#111111;">Titel
|
||||||
<input value="{{ draftTitle }}" onChange="{{ setTitle }}" style="padding:13px 15px; border-radius:11px; border:1px solid rgba(255,255,255,.16); background:rgba(0,0,0,.24); color:#f2efe9; font-family:inherit; font-size:15px; letter-spacing:normal; text-transform:none;">
|
<input value="{{ draftTitle }}" onChange="{{ setTitle }}" style="padding:14px 16px; border-radius:16px; border:2px solid #cdcdcd; background:#ffffff; color:#111111; font-family:inherit; font-size:15px; font-weight:400;">
|
||||||
</label>
|
</label>
|
||||||
<label style="display:flex; flex-direction:column; gap:8px; font-size:12px; letter-spacing:.14em; text-transform:uppercase; color:rgba(242,239,233,.5);">Untertitel
|
<label style="display:flex; flex-direction:column; gap:8px; font-size:13px; font-weight:600; color:#111111;">Untertitel
|
||||||
<input value="{{ draftSub }}" onChange="{{ setSub }}" style="padding:13px 15px; border-radius:11px; border:1px solid rgba(255,255,255,.16); background:rgba(0,0,0,.24); color:#f2efe9; font-family:inherit; font-size:15px; letter-spacing:normal; text-transform:none;">
|
<input value="{{ draftSub }}" onChange="{{ setSub }}" style="padding:14px 16px; border-radius:16px; border:2px solid #cdcdcd; background:#ffffff; color:#111111; font-family:inherit; font-size:15px; font-weight:400;">
|
||||||
</label>
|
</label>
|
||||||
<div style="display:flex; flex-direction:column; gap:10px; font-size:12px; letter-spacing:.14em; text-transform:uppercase; color:rgba(242,239,233,.5);">Art
|
<div style="display:flex; flex-direction:column; gap:10px; font-size:13px; font-weight:600; color:#111111;">Art
|
||||||
<div style="display:flex; gap:8px;">
|
<div style="display:flex; gap:8px;">
|
||||||
<sc-for list="{{ kindOptions }}" as="k" hint-placeholder-count="3">
|
<sc-for list="{{ kindOptions }}" as="k" hint-placeholder-count="3">
|
||||||
<button onClick="{{ k.go }}" style="{{ k.style }}" style-hover="border-color:rgba(126,226,184,.6);">{{ k.label }}</button>
|
<button onClick="{{ k.go }}" style="{{ k.style }}">{{ k.label }}</button>
|
||||||
</sc-for>
|
</sc-for>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex; gap:12px;">
|
<div style="display:flex; gap:8px;">
|
||||||
<button onClick="{{ publish }}" style="padding:13px 24px; border-radius:12px; border:1px solid rgba(126,226,184,.6); background:transparent; color:#8fe3c1; font-family:inherit; font-size:14px; font-weight:600; cursor:pointer; transition:background .18s ease;" style-hover="background:rgba(126,226,184,.14);">Veröffentlichen</button>
|
<button onClick="{{ publish }}" style="padding:14px 24px; border:none; border-radius:24px; background:#e60023; color:#ffffff; font-family:inherit; font-size:15px; font-weight:700; cursor:pointer; transition:background .12s ease;" style-hover="background:#ad081b;">Veröffentlichen</button>
|
||||||
<button style="padding:13px 24px; border-radius:12px; border:1px solid rgba(255,255,255,.16); background:transparent; color:rgba(242,239,233,.8); font-family:inherit; font-size:14px; cursor:pointer; transition:background .18s ease;" style-hover="background:rgba(255,255,255,.07);">Als Entwurf sichern</button>
|
<button style="padding:14px 24px; border:none; border-radius:24px; background:#efefef; color:#111111; font-family:inherit; font-size:15px; font-weight:700; cursor:pointer; transition:background .12s ease;" style-hover="background:#e2e2e2;">Als Entwurf sichern</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div style="font-size:11px; letter-spacing:.16em; text-transform:uppercase; color:rgba(242,239,233,.45); margin-bottom:12px;">Vorschau</div>
|
<div style="font-size:12px; font-weight:600; color:#767676; margin-bottom:12px;">Vorschau</div>
|
||||||
<div style="position:relative; height:420px; border-radius:22px; overflow:hidden; border:1px solid rgba(255,255,255,.12); background:linear-gradient(155deg,#1f8163 0%,#0d4034 100%);">
|
<div style="position:relative; height:420px; border-radius:16px; overflow:hidden; background:linear-gradient(155deg,#1f8163 0%,#0d4034 100%);">
|
||||||
<div style="position:absolute; inset:0; background:repeating-linear-gradient(48deg, rgba(255,255,255,.07) 0 2px, transparent 2px 15px); opacity:.5;"></div>
|
<div style="position:absolute; inset:0; background:repeating-linear-gradient(48deg, rgba(255,255,255,.07) 0 2px, transparent 2px 15px); opacity:.5;"></div>
|
||||||
<div style="position:absolute; inset:auto 0 0 0; padding:18px; background:linear-gradient(0deg, rgba(0,0,0,.72), transparent);">
|
<div style="position:absolute; inset:auto 0 0 0; padding:18px; background:linear-gradient(0deg, rgba(0,0,0,.68), transparent); color:#ffffff;">
|
||||||
<div style="font-size:18px; font-weight:700;">{{ draftTitle }}</div>
|
<div style="font-size:18px; font-weight:700;">{{ draftTitle }}</div>
|
||||||
<div style="font-size:13px; color:rgba(255,255,255,.7);">{{ draftSub }}</div>
|
<div style="font-size:14px; color:rgba(255,255,255,.8);">{{ draftSub }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -250,15 +260,15 @@
|
|||||||
</sc-if>
|
</sc-if>
|
||||||
|
|
||||||
<sc-if value="{{ isSettings }}" hint-placeholder-val="{{ false }}">
|
<sc-if value="{{ isSettings }}" hint-placeholder-val="{{ false }}">
|
||||||
<section style="flex:1; overflow:auto; padding:38px 44px; animation:riseIn .26s ease;">
|
<section style="flex:1; overflow:auto; padding:32px 24px 40px; animation:riseIn .26s ease;">
|
||||||
<div style="max-width:660px;">
|
<div style="max-width:660px; margin:0 auto;">
|
||||||
<div style="font-size:30px; font-weight:600; letter-spacing:-.02em;">Einstellungen</div>
|
<div style="font-size:30px; font-weight:700; letter-spacing:-.02em;">Einstellungen</div>
|
||||||
<div style="margin-top:26px; border:1px solid rgba(255,255,255,.1); border-radius:16px; overflow:hidden;">
|
<div style="margin-top:24px; border-radius:16px; overflow:hidden; box-shadow:0 1px 20px rgba(0,0,0,.12);">
|
||||||
<sc-for list="{{ settings }}" as="s" hint-placeholder-count="4">
|
<sc-for list="{{ settings }}" as="s" hint-placeholder-count="4">
|
||||||
<div style="display:flex; align-items:center; justify-content:space-between; gap:20px; padding:18px 20px; border-bottom:1px solid rgba(255,255,255,.07); background:rgba(255,255,255,.02);">
|
<div style="display:flex; align-items:center; justify-content:space-between; gap:20px; padding:20px; border-bottom:1px solid #efefef; background:#ffffff;">
|
||||||
<div>
|
<div>
|
||||||
<div style="font-size:15px; font-weight:600;">{{ s.label }}</div>
|
<div style="font-size:16px; font-weight:700;">{{ s.label }}</div>
|
||||||
<div style="font-size:13px; color:rgba(242,239,233,.55); margin-top:3px; text-wrap:pretty;">{{ s.hint }}</div>
|
<div style="font-size:14px; color:#767676; margin-top:3px; text-wrap:pretty;">{{ s.hint }}</div>
|
||||||
</div>
|
</div>
|
||||||
<button onClick="{{ s.toggle }}" style="{{ s.track }}">
|
<button onClick="{{ s.toggle }}" style="{{ s.track }}">
|
||||||
<span style="{{ s.knob }}"></span>
|
<span style="{{ s.knob }}"></span>
|
||||||
@@ -271,7 +281,7 @@
|
|||||||
</sc-if>
|
</sc-if>
|
||||||
|
|
||||||
<sc-if value="{{ toast }}" hint-placeholder-val="{{ false }}">
|
<sc-if value="{{ toast }}" hint-placeholder-val="{{ false }}">
|
||||||
<div style="position:fixed; left:50%; bottom:34px; transform:translateX(-50%); padding:12px 22px; border-radius:999px; border:1px solid rgba(255,255,255,.16); background:rgba(10,24,20,.92); backdrop-filter:blur(10px); font-size:14px; animation:riseIn .2s ease; z-index:40;">{{ toast }}</div>
|
<div style="position:fixed; left:50%; bottom:28px; transform:translateX(-50%); padding:16px 22px; border-radius:16px; background:#ffffff; box-shadow:0 1px 20px rgba(0,0,0,.22); color:#111111; font-size:15px; font-weight:600; animation:riseIn .2s ease; z-index:40;">{{ toast }}</div>
|
||||||
</sc-if>
|
</sc-if>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
@@ -386,8 +396,8 @@ class Component extends DCLogic {
|
|||||||
}
|
}
|
||||||
const shell = {
|
const shell = {
|
||||||
position: 'absolute', inset: 0, zIndex: 10 - k, opacity, transform, transition,
|
position: 'absolute', inset: 0, zIndex: 10 - k, opacity, transform, transition,
|
||||||
borderRadius: '26px', overflow: 'hidden', boxShadow: '0 26px 60px rgba(0,0,0,.45)',
|
borderRadius: '16px', overflow: 'hidden', boxShadow: '0 1px 20px rgba(0,0,0,.18)',
|
||||||
border: '1px solid rgba(255,255,255,.14)', touchAction: 'none',
|
touchAction: 'none',
|
||||||
cursor: top ? (s.drag && s.drag.active ? 'grabbing' : 'grab') : 'default',
|
cursor: top ? (s.drag && s.drag.active ? 'grabbing' : 'grab') : 'default',
|
||||||
pointerEvents: top ? 'auto' : 'none', userSelect: 'none'
|
pointerEvents: top ? 'auto' : 'none', userSelect: 'none'
|
||||||
};
|
};
|
||||||
@@ -402,12 +412,16 @@ class Component extends DCLogic {
|
|||||||
stripes: this.stripes(s.idx + k),
|
stripes: this.stripes(s.idx + k),
|
||||||
kind: card.kind, assets: card.assets, caption: card.caption, avatar: card.avatar,
|
kind: card.kind, assets: card.assets, caption: card.caption, avatar: card.avatar,
|
||||||
name: card.name, sub: card.sub,
|
name: card.name, sub: card.sub,
|
||||||
|
save: {
|
||||||
|
display: top ? 'block' : 'none', padding: '11px 16px', border: 'none', borderRadius: '22px',
|
||||||
|
background: '#e60023', color: '#ffffff', font: '700 15px/1 Manrope, system-ui, sans-serif',
|
||||||
|
cursor: 'pointer', transition: 'background .12s ease'
|
||||||
|
},
|
||||||
badgeText: liked ? 'GEMERKT' : 'SKIP',
|
badgeText: liked ? 'GEMERKT' : 'SKIP',
|
||||||
badge: {
|
badge: {
|
||||||
position: 'absolute', top: '86px', left: liked ? '24px' : 'auto', right: liked ? 'auto' : '24px',
|
position: 'absolute', top: '86px', left: liked ? '24px' : 'auto', right: liked ? 'auto' : '24px',
|
||||||
padding: '8px 16px', borderRadius: '10px', fontWeight: 800, fontSize: '15px', letterSpacing: '.12em',
|
padding: '10px 18px', borderRadius: '22px', fontWeight: 700, fontSize: '15px', letterSpacing: '.08em',
|
||||||
border: '2px solid ' + (liked ? 'rgba(126,226,184,.9)' : 'rgba(232,120,120,.9)'),
|
background: liked ? '#e60023' : '#111111', color: '#ffffff',
|
||||||
color: liked ? '#a9f0d0' : '#f0a8a8',
|
|
||||||
transform: 'rotate(' + (liked ? -10 : 10) + 'deg)',
|
transform: 'rotate(' + (liked ? -10 : 10) + 'deg)',
|
||||||
opacity: showBadge ? Math.min(1, Math.abs(dx) / 110 || 1) : 0,
|
opacity: showBadge ? Math.min(1, Math.abs(dx) / 110 || 1) : 0,
|
||||||
transition: 'opacity .16s ease', pointerEvents: 'none'
|
transition: 'opacity .16s ease', pointerEvents: 'none'
|
||||||
@@ -415,40 +429,41 @@ class Component extends DCLogic {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const navDef = [['feed','Feed','◧'],['profile','Profil','◍'],['create','Erstellen','+'],['settings','Einstellungen','⚙']];
|
// Rail-Zustaende liegen in .rail/.rail.active (helmet), nicht inline: das Runtime setzt
|
||||||
const navItems = navDef.map(([id, label, glyph]) => ({
|
// style-hover mit !important und wuerde den aktiven Button sonst beim Hover aufhellen.
|
||||||
|
const railStyle = {
|
||||||
|
width: '48px', height: '48px', display: 'grid', placeItems: 'center', border: 'none',
|
||||||
|
borderRadius: '50%', cursor: 'pointer', fontSize: '20px',
|
||||||
|
transition: 'background .12s ease, color .12s ease'
|
||||||
|
};
|
||||||
|
const navDef = [['feed','Feed','⌂'],['profile','Profil','◍'],['create','Erstellen','+'],['settings','Einstellungen','⚙']];
|
||||||
|
const navAll = navDef.map(([id, label, glyph]) => ({
|
||||||
label, glyph, go: () => this.setState({ screen: id }),
|
label, glyph, go: () => this.setState({ screen: id }),
|
||||||
style: {
|
cls: s.screen === id ? 'rail active' : 'rail', style: railStyle
|
||||||
display: 'flex', alignItems: 'center', gap: '11px', padding: '11px 13px', borderRadius: '11px',
|
|
||||||
border: '1px solid ' + (s.screen === id ? 'rgba(126,226,184,.4)' : 'transparent'),
|
|
||||||
background: s.screen === id ? 'rgba(126,226,184,.12)' : 'transparent',
|
|
||||||
color: s.screen === id ? '#d6fbec' : 'rgba(242,239,233,.7)',
|
|
||||||
font: '500 14px/1 Manrope, system-ui, sans-serif', cursor: 'pointer',
|
|
||||||
transition: 'background .18s ease, color .18s ease', textAlign: 'left'
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
const navTop = navAll.slice(0, 3);
|
||||||
|
const navBottom = navAll.slice(3);
|
||||||
|
|
||||||
const tabDef = [['videos','Videos'],['following','Folge ich'],['posts','Posts']];
|
const tabDef = [['videos','Videos'],['following','Folge ich'],['posts','Posts']];
|
||||||
const tabs = tabDef.map(([id, label]) => ({
|
const tabs = tabDef.map(([id, label]) => ({
|
||||||
label, go: () => this.setState({ tab: id, idx: 0, history: [], drag: null, exiting: null, screen: 'feed' }),
|
label, go: () => this.setState({ tab: id, idx: 0, history: [], drag: null, exiting: null, screen: 'feed' }),
|
||||||
style: {
|
style: {
|
||||||
padding: '9px 18px', borderRadius: '999px', border: '1px solid ' + (s.tab === id ? 'rgba(255,255,255,.22)' : 'transparent'),
|
padding: '0 2px 12px', border: 'none', background: 'transparent',
|
||||||
background: s.tab === id ? 'rgba(255,255,255,.08)' : 'transparent',
|
borderBottom: '3px solid ' + (s.tab === id ? '#111111' : 'transparent'),
|
||||||
color: s.tab === id ? '#ffffff' : 'rgba(242,239,233,.58)',
|
color: s.tab === id ? '#111111' : '#767676',
|
||||||
font: (s.tab === id ? '600' : '500') + ' 16px/1 Manrope, system-ui, sans-serif',
|
font: (s.tab === id ? '700' : '500') + ' 16px/1 Manrope, system-ui, sans-serif',
|
||||||
cursor: 'pointer', transition: 'background .18s ease, color .18s ease'
|
cursor: 'pointer', transition: 'color .12s ease, border-color .12s ease'
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const kindOptions = ['Produkt','Video','Serie'].map(k => ({
|
const kindOptions = ['Produkt','Video','Serie'].map(k => ({
|
||||||
label: k, go: () => this.setState({ draftKind: k }),
|
label: k, go: () => this.setState({ draftKind: k }),
|
||||||
style: {
|
style: {
|
||||||
padding: '10px 18px', borderRadius: '999px', cursor: 'pointer',
|
padding: '11px 18px', borderRadius: '22px', cursor: 'pointer', border: 'none',
|
||||||
border: '1px solid ' + (s.draftKind === k ? 'rgba(126,226,184,.6)' : 'rgba(255,255,255,.16)'),
|
background: s.draftKind === k ? '#111111' : '#efefef',
|
||||||
background: s.draftKind === k ? 'rgba(126,226,184,.12)' : 'transparent',
|
color: s.draftKind === k ? '#ffffff' : '#111111',
|
||||||
color: s.draftKind === k ? '#a9f0d0' : 'rgba(242,239,233,.75)',
|
font: '700 15px/1 Manrope, system-ui, sans-serif',
|
||||||
font: '500 14px/1 Manrope, system-ui, sans-serif', letterSpacing: 'normal', textTransform: 'none',
|
transition: 'background .12s ease, color .12s ease'
|
||||||
transition: 'border-color .18s ease, background .18s ease'
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -462,22 +477,22 @@ class Component extends DCLogic {
|
|||||||
label, hint,
|
label, hint,
|
||||||
toggle: () => this.setState(st => ({ settings: { ...st.settings, [id]: !st.settings[id] } })),
|
toggle: () => this.setState(st => ({ settings: { ...st.settings, [id]: !st.settings[id] } })),
|
||||||
track: { position: 'relative', width: '52px', height: '30px', flex: 'none', borderRadius: '999px', cursor: 'pointer',
|
track: { position: 'relative', width: '52px', height: '30px', flex: 'none', borderRadius: '999px', cursor: 'pointer',
|
||||||
border: '1px solid ' + (on ? 'rgba(126,226,184,.6)' : 'rgba(255,255,255,.2)'),
|
border: 'none', background: on ? '#e60023' : '#cdcdcd', transition: 'background .2s ease' },
|
||||||
background: on ? 'rgba(126,226,184,.18)' : 'rgba(255,255,255,.05)', transition: 'background .2s ease, border-color .2s ease' },
|
knob: { position: 'absolute', top: '3px', left: on ? '25px' : '3px', width: '24px', height: '24px', borderRadius: '50%',
|
||||||
knob: { position: 'absolute', top: '3px', left: on ? '25px' : '3px', width: '22px', height: '22px', borderRadius: '50%',
|
background: '#ffffff', boxShadow: '0 1px 3px rgba(0,0,0,.25)', transition: 'left .2s cubic-bezier(.22,.9,.3,1)' }
|
||||||
background: on ? '#8fe3c1' : 'rgba(242,239,233,.55)', transition: 'left .2s cubic-bezier(.22,.9,.3,1), background .2s ease' }
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tileHeights = [320, 240, 400, 280, 360, 220, 300, 260];
|
||||||
const gallery = DATA.posts.concat(DATA.videos).map((c, i) => ({
|
const gallery = DATA.posts.concat(DATA.videos).map((c, i) => ({
|
||||||
title: c.caption, stripes: this.stripes(i),
|
title: c.caption, stripes: this.stripes(i),
|
||||||
tile: { position: 'relative', height: '230px', borderRadius: '16px', overflow: 'hidden', cursor: 'pointer',
|
tile: { position: 'relative', height: tileHeights[i % tileHeights.length] + 'px', borderRadius: '16px',
|
||||||
border: '1px solid rgba(255,255,255,.12)', transition: 'transform .2s ease, border-color .2s ease',
|
overflow: 'hidden', cursor: 'zoom-in', breakInside: 'avoid', marginBottom: '16px',
|
||||||
background: 'linear-gradient(155deg,' + c.hue[0] + ' 0%,' + c.hue[1] + ' 100%)' }
|
background: 'linear-gradient(155deg,' + c.hue[0] + ' 0%,' + c.hue[1] + ' 100%)' }
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
navItems, tabs, stack, kindOptions, settings, gallery,
|
navTop, navBottom, tabs, stack, kindOptions, settings, gallery,
|
||||||
isFeed: s.screen === 'feed', isProfile: s.screen === 'profile', isCreate: s.screen === 'create', isSettings: s.screen === 'settings',
|
isFeed: s.screen === 'feed', isProfile: s.screen === 'profile', isCreate: s.screen === 'create', isSettings: s.screen === 'settings',
|
||||||
stackEmpty: stack.length === 0,
|
stackEmpty: stack.length === 0,
|
||||||
showInfo: s.showInfo, toggleInfo: () => this.setState(st => ({ showInfo: !st.showInfo })),
|
showInfo: s.showInfo, toggleInfo: () => this.setState(st => ({ showInfo: !st.showInfo })),
|
||||||
|
|||||||
Reference in New Issue
Block a user