Logo aus dem Instagram-Profilbild als SVG, in "Über uns" eingebaut
- Profilbild mit potrace vektorisiert: src/assets/logo/emblem.svg (nur Emblem, currentColor) und public/logo-profilbild.svg (quadratisch, weiß auf dunklem Grund wie das Profilbild) - "Sechs Profis. Ein Salon.": Foto der Logo-Wand durch das Logo ersetzt; die Linien zeichnen sich beim Scrollen, danach folgt ein Lichtreflex dem Mauszeiger (ohne Maus der Scroll-Position) - Originalbild nach src/assets/logo verschoben, ungenutztes Foto und ImageReveal entfernt, README ergänzt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KBHsCnWNXAB2Le3gAEsivF
This commit is contained in:
10 files changed
+160
-45
No files matched your search
@@ -25,7 +25,8 @@ npm run preview # Build lokal ansehen
|
|||||||
| Was | Wo |
|
| Was | Wo |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Preise, Dauer, Leistungen, Öffnungszeiten, Team, Kontakt | `src/data/salon.ts` |
|
| Preise, Dauer, Leistungen, Öffnungszeiten, Team, Kontakt | `src/data/salon.ts` |
|
||||||
| Fotos (Hero, Über uns, Menü) | `src/assets/photos/*.webp` |
|
| Fotos (Hero, Menü) | `src/assets/photos/*.webp` |
|
||||||
|
| Logo | `src/assets/logo/emblem.svg` |
|
||||||
| Team-Porträts | `src/assets/team/*.webp` |
|
| Team-Porträts | `src/assets/team/*.webp` |
|
||||||
| Schriftzug oben in der Mitte | `src/components/Nav.tsx` |
|
| Schriftzug oben in der Mitte | `src/components/Nav.tsx` |
|
||||||
| Favicon, App-Icon, Vorschaubild zum Teilen | `public/` |
|
| Favicon, App-Icon, Vorschaubild zum Teilen | `public/` |
|
||||||
@@ -36,8 +37,16 @@ und `hero-mobile.webp` (Hochformat-Ausschnitt fürs Handy). Die Headline steht u
|
|||||||
Schere und Kamm frei bleiben. Beim Austauschen alle drei Dateien ersetzen, den Handy-Ausschnitt so wählen,
|
Schere und Kamm frei bleiben. Beim Austauschen alle drei Dateien ersetzen, den Handy-Ausschnitt so wählen,
|
||||||
dass Gesicht und Hände darin liegen. `hero-detail.webp` (Hände mit Schere und Kamm) erscheint im Menü.
|
dass Gesicht und Hände darin liegen. `hero-detail.webp` (Hände mit Schere und Kamm) erscheint im Menü.
|
||||||
|
|
||||||
**Salon-Fotos:** „Über uns“ und der Menüpunkt „Kontakt“ zeigen das Logo an der Wand im Salon
|
**Logo:** Das Instagram-Profilbild (`src/assets/logo/instagram-profilbild.jpg`) wurde mit potrace
|
||||||
(`emblem.webp`, `emblem-breit-900.webp`, aus den Fotos der Setmore-Seite).
|
vektorisiert:
|
||||||
|
- `src/assets/logo/emblem.svg` – nur das Emblem, Farbe über `currentColor` (standardmäßig schwarz), für Druck & Co.
|
||||||
|
- `public/logo-profilbild.svg` – wie das Profilbild: quadratisch, weißes Emblem auf dunklem Grund.
|
||||||
|
|
||||||
|
Auf der Website steht es in „Über uns“: Die Linien zeichnen sich beim Scrollen, danach folgt ein Lichtreflex
|
||||||
|
dem Mauszeiger (`src/components/Emblem.tsx`). Liegt irgendwann die Original-Vektordatei vom Designer vor,
|
||||||
|
einfach `emblem.svg` ersetzen (ein `<path>` pro Form, `fill="currentColor"`).
|
||||||
|
|
||||||
|
**Salon-Foto:** Der Menüpunkt „Kontakt“ zeigt das Logo an der Wand im Salon (`emblem-breit-900.webp`).
|
||||||
|
|
||||||
**Team-Porträts:** Einheitliche Studio-Porträts (per Bild-KI aus den Originalfotos erstellt), je zweimal
|
**Team-Porträts:** Einheitliche Studio-Porträts (per Bild-KI aus den Originalfotos erstellt), je zweimal
|
||||||
abgelegt: `name.webp` (1000 px breit, Team-Liste) und `name-thumb.webp` (320 × 320, Fotoraster und
|
abgelegt: `name.webp` (1000 px breit, Team-Liste) und `name-thumb.webp` (320 × 320, Fotoraster und
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 583 583"><title>Amin B. Ahmadi – Logo</title><rect width="583" height="583" fill="#02000d"/><g transform="translate(-2.2 107.8) scale(0.5)" fill="#fff"><path d="M359 7c-11 1-20 8-21 16c-1 10 10 24 23 26c8 2 16-5 14-12c-1-5-4-6-10-4c-1 0-2 1-3 1c-2 1-4-1-4-4c0-8 16-9 24-1c10 10 3 30-12 36c-5 2-15 2-26 0c-5-1-6-1-14-1c-4 0-10-1-12-1c-7-1-30-1-38 0c-13 0-27 1-32 2c-2 0-6 1-8 1c-2 0-5 1-7 1c-2 0-4 1-5 1c-2 0-4 0-6 1c-2 0-5 1-7 1c-2 1-4 1-5 2c-2 0-3 0-5 1c-23 5-47 15-64 26c-12 8-20 14-29 24c-9 10-18 24-22 34c-3 11-5 16-6 27c-3 14-2 36 2 53c2 8 1 8-3 4c-8-8-19-9-28-3c-10 8-11 19-1 27c3 2 6 0 5-4c0-2 0-7 1-9c3-7 19 2 23 14c2 5 1 5-3 11c-5 7-7 10-10 13c-4 6-6 11-4 19c1 9 0 11-9 19c-5 4-9 9-12 14c-3 6-4 8-13 17c-17 17-24 25-26 30c0 1-1 2-1 2c-1 1-1 14 0 14c0 1 1 2 2 3c3 4 8 9 15 12c5 3 6 4 8 7c4 6 4 7 7 10c3 5 4 5 8 12c4 6 8 10 12 12c2 0 3 1 4 2c2 1 3 3 4 5c1 5 4 13 7 20c1 1 1 2 1 2c0 1 1 2 2 4c9 13 19 18 32 15c2-1 3-1 3-1c1 0 9-4 11-5c6-4 9-7 11-8c1-1 3-3 4-4c1-1 3-2 4-3c0-1 2-2 2-2c1-1 6-5 11-11c15-13 22-19 32-25c9-4 13-6 14-5c1 0 3 4 3 5c1 2 5 10 7 12c3 5 11 10 18 12c8 2 8 2 5 8c0 2-1 4-2 5c0 1-1 4-2 5c-2 4-3 8-3 12c-2 13-7 20-16 20c-10 0-18-10-12-18c2-3 5-3 5 1c-1 5 4 9 10 7c5-2 7-9 4-15c-4-9-15-12-26-7c-10 5-16 21-11 32c5 12 18 19 31 17c9-1 8-2 9 11c0 10 0 14 1 20c0 2 1 5 1 5c0 1 0 4 0 6c1 2 1 4 2 5c0 3 4 14 7 20c3 9 9 20 12 23c0 1 1 3 2 3c1 2 7 9 10 12c16 14 38 19 53 13c18-9 28-26 24-40c-3-7-10-16-16-19c-1 0-2-1-2-1c-6-4-18-5-25-1c-11 5-14 14-8 23c1 2 8 8 9 9c3 1 5-1 4-5c-2-6-2-10-1-12c7-9 23 3 20 15c-3 9-12 14-24 12c-5 0-5-1-14-5c-11-6-12-7-21-17c-4-5-10-15-12-21c-6-16-8-28-9-45c0-13 1-19 5-28c2-3 8-15 8-17c1-2 2-3 2-2c1 0 1 1 3 6c3 12 7 19 13 28c2 5 4 7 9 13c2 3 12 13 16 17c9 7 13 11 16 13c1 1 4 3 6 5c1 1 4 3 5 4c1 1 3 3 4 4c4 2 6 5 8 6c2 1 3 3 4 4c2 1 5 4 8 6c2 2 6 5 7 6c1 1 2 2 4 3c1 1 3 3 4 4c3 2 10 7 12 8c2 2 5 4 8 6c1 2 2 3 3 3c1 1 4 4 8 7c3 4 8 8 10 10c1 1 4 4 7 6c5 4 22 21 25 25c1 2 3 4 4 5c1 1 6 8 9 13c5 9 10 21 13 33c1 6 1 26-1 33c-7 29-49 37-64 13c-4-8-5-15-1-22c3-7 10-9 15-5c3 4 2 7-4 10c-6 3-7 7-2 12c4 3 5 3 9 3c13 1 20-10 16-23c-5-12-14-17-27-16c-13 2-21 14-21 30c1 11 4 18 11 25c7 6 9 8 17 10c7 1 7 2 6 5c-2 5 1 8 7 6c4-1 4 0 1 4c-4 5-4 11-1 13c4 3 7 2 10-4c2-4 3-4 3 0c0 5 2 11 4 13c1 1 2 2 2 3c5 6 16 8 22 5c3-1 7-5 8-7c2-4 9-7 14-6c2 1 5 3 5 4c0 1-2 2-3 2c-3-1-4-1-5-1c-10 4-9 17 2 18c8 1 14-5 14-13c-1-4-1-6-4-10c-2-4 0-3 6 3c6 7 9 8 13 8c5-1 9-6 7-10c-1 0-1-1-1-2c0-1-1-2-2-4c-4-4-3-4 1-4c10 0 10-11-1-17c-7-5-19-4-27 1c-2 1-3 2-3 2c-2 1-9 11-10 13c0 1 1 2 1 2c1 2 1 2-1 3c-2 0-2-1-3-4c-2-12-15-15-22-5c-2 2-2 2-2 5c-1 6 6 11 13 9c1 0 2 0 2 0c1 1-1 5-5 6c-8 5-20-5-18-15c2-13 11-21 28-23c5 0 23-1 24 0c1 0 1 0 2 0c1 0 9 0 18 0c20 0 20 0 17 4c-5 11 2 25 14 24c6-1 17 4 20 9c0 1 1 2 2 3c1 2 1 7-1 9c-4 8-13 10-18 5c-3-3-2-4 1-3c10 5 18-5 13-13c-7-10-22-7-25 5c-2 9 5 19 15 21c4 1 9-1 15-6c4-4 4-4 3 0c-2 3-3 8-3 11c1 4 2 7 7 12c3 3 5 6 5 6c1 2 3 8 3 9c0 2 2 3 4 3c1-1 2-2 2-5c1-6 2-8 5-11c8-6 11-15 8-22c-1-2-2-5-1-5c0 0 2 1 4 3c8 7 16 7 23 0c6-6 7-12 4-19c-2-5-5-7-9-8c-5-1-8 0-13 4c-4 4-4 10 0 14c3 3 6 3 11 1c4-1 5 0 2 3c-9 9-25-4-19-15c3-7 12-11 22-11c4 0 4 0 6-1c8-3 12-15 8-22c-3-5-3-5 11-5c43-1 52 0 60 2c18 7 24 28 9 37c-5 2-15-1-15-6c0 0 0 0 5 0c8-1 13-6 10-13c-5-11-22-10-23 2c-1 3-2 4-4 4c-1 0-2 0-1-2c1-1 1-2 1-3c-1 0-1-1-2-2c-4-9-13-15-23-16c-12-1-22 5-23 13c0 5 3 7 8 7c4 0 4 0 1 3c-7 10-1 20 9 15c2-1 3-2 7-5c4-5 6-6 7-6c0 0-1 4-2 4c0 1-1 2-1 3c-3 10 1 18 11 18c6 0 11-4 10-10c0-5-4-8-10-8c-5 0-6-2-1-4c5-3 12 0 16 5c5 9 17 11 25 5c7-5 10-10 10-19c0-3 0-5 0-5c1 0 2 2 3 5c3 5 6 7 10 5c4-3 3-8-1-15c-3-5-3-5 2-3c4 1 5 1 7-1c1-3 1-3 0-6c-1-3-1-3 3-4c8-3 13-6 19-12c13-15 11-43-5-51c-4-2-13-3-16-2c0 1-2 1-3 1c-10 2-19 18-15 29c3 9 16 13 24 6c6-5 5-8-2-12c-5-3-6-5-4-8c0-2 4-4 6-4c8-1 14 11 12 21c-8 29-51 30-65 1c-5-10-6-34 0-49c2-8 7-18 10-22c0-1 1-3 3-5c7-11 16-22 29-34c3-3 7-6 9-8c2-1 5-5 8-7c3-2 8-7 11-10c10-9 10-9 15-12c1-1 3-2 5-4c7-5 13-10 18-14c2-3 3-3 8-7c2-1 4-4 6-5c2-2 4-4 5-5c1 0 3-2 5-4c2-1 5-4 7-5c4-4 11-9 17-14c14-12 27-27 32-35c0-1 0-2 1-2c2-3 7-14 10-25c4-10 4-10 7-2c1 3 3 7 4 9c5 10 7 15 7 19c1 6 0 26-1 32c0 1 0 3-1 4c0 1 0 4-1 5c0 2-1 6-2 9c-2 8-7 18-11 24c-7 10-13 17-18 19c-2 1-5 3-8 4c-15 9-32 6-36-6c-4-9 3-18 12-18c7-1 9 4 6 12c-1 5-1 5 0 6c2 2 4 2 10-5c3-4 4-4 5-7c5-16-16-28-34-19c-23 12-26 35-8 52c6 6 14 10 21 11c9 2 24-1 33-7c0 0 2-1 3-1c6-4 20-17 22-23c1-1 2-2 2-3c2-3 8-15 11-22c0-2 1-4 2-6c1-4 4-12 4-16c0-1 1-3 1-3c0 0 0-2 0-4c1-8 2-14 2-23c1-14 0-13 7-12c19 3 38-13 35-29c-3-13-9-19-21-22c-11-2-22 7-19 18c2 9 16 8 15-1c0-5 6-2 7 3c2 9-10 17-20 13c-5-3-8-7-10-20c-1-4-2-7-3-9c0-1-1-4-2-6c-1-2-2-5-3-7c-2-4-2-5 3-6c15-5 23-11 28-26c2-5 3-6 11-2c10 5 17 10 23 15c8 7 8 7 18 16c8 8 13 13 16 15c2 1 4 3 5 4c7 6 16 10 25 12c9 3 21-3 27-13c1-1 1-2 2-3c2-2 7-14 8-19c3-11 3-10 7-12c8-4 10-6 16-16c3-3 6-8 7-9c1-1 2-3 3-4c0-2 1-2 4-7c2-3 3-3 7-5c23-13 25-25 9-42c-1-2-3-5-5-7c-2-2-8-8-13-13c-9-9-9-10-11-13c-1-2-3-5-3-5c-1-1-2-3-2-3c-1-2-6-7-13-14Line truncated
|
||||||
|
After Width: | Height: | Size: 53 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1157 913" fill="currentColor"><path d="M359 7c-11 1-20 8-21 16c-1 10 10 24 23 26c8 2 16-5 14-12c-1-5-4-6-10-4c-1 0-2 1-3 1c-2 1-4-1-4-4c0-8 16-9 24-1c10 10 3 30-12 36c-5 2-15 2-26 0c-5-1-6-1-14-1c-4 0-10-1-12-1c-7-1-30-1-38 0c-13 0-27 1-32 2c-2 0-6 1-8 1c-2 0-5 1-7 1c-2 0-4 1-5 1c-2 0-4 0-6 1c-2 0-5 1-7 1c-2 1-4 1-5 2c-2 0-3 0-5 1c-23 5-47 15-64 26c-12 8-20 14-29 24c-9 10-18 24-22 34c-3 11-5 16-6 27c-3 14-2 36 2 53c2 8 1 8-3 4c-8-8-19-9-28-3c-10 8-11 19-1 27c3 2 6 0 5-4c0-2 0-7 1-9c3-7 19 2 23 14c2 5 1 5-3 11c-5 7-7 10-10 13c-4 6-6 11-4 19c1 9 0 11-9 19c-5 4-9 9-12 14c-3 6-4 8-13 17c-17 17-24 25-26 30c0 1-1 2-1 2c-1 1-1 14 0 14c0 1 1 2 2 3c3 4 8 9 15 12c5 3 6 4 8 7c4 6 4 7 7 10c3 5 4 5 8 12c4 6 8 10 12 12c2 0 3 1 4 2c2 1 3 3 4 5c1 5 4 13 7 20c1 1 1 2 1 2c0 1 1 2 2 4c9 13 19 18 32 15c2-1 3-1 3-1c1 0 9-4 11-5c6-4 9-7 11-8c1-1 3-3 4-4c1-1 3-2 4-3c0-1 2-2 2-2c1-1 6-5 11-11c15-13 22-19 32-25c9-4 13-6 14-5c1 0 3 4 3 5c1 2 5 10 7 12c3 5 11 10 18 12c8 2 8 2 5 8c0 2-1 4-2 5c0 1-1 4-2 5c-2 4-3 8-3 12c-2 13-7 20-16 20c-10 0-18-10-12-18c2-3 5-3 5 1c-1 5 4 9 10 7c5-2 7-9 4-15c-4-9-15-12-26-7c-10 5-16 21-11 32c5 12 18 19 31 17c9-1 8-2 9 11c0 10 0 14 1 20c0 2 1 5 1 5c0 1 0 4 0 6c1 2 1 4 2 5c0 3 4 14 7 20c3 9 9 20 12 23c0 1 1 3 2 3c1 2 7 9 10 12c16 14 38 19 53 13c18-9 28-26 24-40c-3-7-10-16-16-19c-1 0-2-1-2-1c-6-4-18-5-25-1c-11 5-14 14-8 23c1 2 8 8 9 9c3 1 5-1 4-5c-2-6-2-10-1-12c7-9 23 3 20 15c-3 9-12 14-24 12c-5 0-5-1-14-5c-11-6-12-7-21-17c-4-5-10-15-12-21c-6-16-8-28-9-45c0-13 1-19 5-28c2-3 8-15 8-17c1-2 2-3 2-2c1 0 1 1 3 6c3 12 7 19 13 28c2 5 4 7 9 13c2 3 12 13 16 17c9 7 13 11 16 13c1 1 4 3 6 5c1 1 4 3 5 4c1 1 3 3 4 4c4 2 6 5 8 6c2 1 3 3 4 4c2 1 5 4 8 6c2 2 6 5 7 6c1 1 2 2 4 3c1 1 3 3 4 4c3 2 10 7 12 8c2 2 5 4 8 6c1 2 2 3 3 3c1 1 4 4 8 7c3 4 8 8 10 10c1 1 4 4 7 6c5 4 22 21 25 25c1 2 3 4 4 5c1 1 6 8 9 13c5 9 10 21 13 33c1 6 1 26-1 33c-7 29-49 37-64 13c-4-8-5-15-1-22c3-7 10-9 15-5c3 4 2 7-4 10c-6 3-7 7-2 12c4 3 5 3 9 3c13 1 20-10 16-23c-5-12-14-17-27-16c-13 2-21 14-21 30c1 11 4 18 11 25c7 6 9 8 17 10c7 1 7 2 6 5c-2 5 1 8 7 6c4-1 4 0 1 4c-4 5-4 11-1 13c4 3 7 2 10-4c2-4 3-4 3 0c0 5 2 11 4 13c1 1 2 2 2 3c5 6 16 8 22 5c3-1 7-5 8-7c2-4 9-7 14-6c2 1 5 3 5 4c0 1-2 2-3 2c-3-1-4-1-5-1c-10 4-9 17 2 18c8 1 14-5 14-13c-1-4-1-6-4-10c-2-4 0-3 6 3c6 7 9 8 13 8c5-1 9-6 7-10c-1 0-1-1-1-2c0-1-1-2-2-4c-4-4-3-4 1-4c10 0 10-11-1-17c-7-5-19-4-27 1c-2 1-3 2-3 2c-2 1-9 11-10 13c0 1 1 2 1 2c1 2 1 2-1 3c-2 0-2-1-3-4c-2-12-15-15-22-5c-2 2-2 2-2 5c-1 6 6 11 13 9c1 0 2 0 2 0c1 1-1 5-5 6c-8 5-20-5-18-15c2-13 11-21 28-23c5 0 23-1 24 0c1 0 1 0 2 0c1 0 9 0 18 0c20 0 20 0 17 4c-5 11 2 25 14 24c6-1 17 4 20 9c0 1 1 2 2 3c1 2 1 7-1 9c-4 8-13 10-18 5c-3-3-2-4 1-3c10 5 18-5 13-13c-7-10-22-7-25 5c-2 9 5 19 15 21c4 1 9-1 15-6c4-4 4-4 3 0c-2 3-3 8-3 11c1 4 2 7 7 12c3 3 5 6 5 6c1 2 3 8 3 9c0 2 2 3 4 3c1-1 2-2 2-5c1-6 2-8 5-11c8-6 11-15 8-22c-1-2-2-5-1-5c0 0 2 1 4 3c8 7 16 7 23 0c6-6 7-12 4-19c-2-5-5-7-9-8c-5-1-8 0-13 4c-4 4-4 10 0 14c3 3 6 3 11 1c4-1 5 0 2 3c-9 9-25-4-19-15c3-7 12-11 22-11c4 0 4 0 6-1c8-3 12-15 8-22c-3-5-3-5 11-5c43-1 52 0 60 2c18 7 24 28 9 37c-5 2-15-1-15-6c0 0 0 0 5 0c8-1 13-6 10-13c-5-11-22-10-23 2c-1 3-2 4-4 4c-1 0-2 0-1-2c1-1 1-2 1-3c-1 0-1-1-2-2c-4-9-13-15-23-16c-12-1-22 5-23 13c0 5 3 7 8 7c4 0 4 0 1 3c-7 10-1 20 9 15c2-1 3-2 7-5c4-5 6-6 7-6c0 0-1 4-2 4c0 1-1 2-1 3c-3 10 1 18 11 18c6 0 11-4 10-10c0-5-4-8-10-8c-5 0-6-2-1-4c5-3 12 0 16 5c5 9 17 11 25 5c7-5 10-10 10-19c0-3 0-5 0-5c1 0 2 2 3 5c3 5 6 7 10 5c4-3 3-8-1-15c-3-5-3-5 2-3c4 1 5 1 7-1c1-3 1-3 0-6c-1-3-1-3 3-4c8-3 13-6 19-12c13-15 11-43-5-51c-4-2-13-3-16-2c0 1-2 1-3 1c-10 2-19 18-15 29c3 9 16 13 24 6c6-5 5-8-2-12c-5-3-6-5-4-8c0-2 4-4 6-4c8-1 14 11 12 21c-8 29-51 30-65 1c-5-10-6-34 0-49c2-8 7-18 10-22c0-1 1-3 3-5c7-11 16-22 29-34c3-3 7-6 9-8c2-1 5-5 8-7c3-2 8-7 11-10c10-9 10-9 15-12c1-1 3-2 5-4c7-5 13-10 18-14c2-3 3-3 8-7c2-1 4-4 6-5c2-2 4-4 5-5c1 0 3-2 5-4c2-1 5-4 7-5c4-4 11-9 17-14c14-12 27-27 32-35c0-1 0-2 1-2c2-3 7-14 10-25c4-10 4-10 7-2c1 3 3 7 4 9c5 10 7 15 7 19c1 6 0 26-1 32c0 1 0 3-1 4c0 1 0 4-1 5c0 2-1 6-2 9c-2 8-7 18-11 24c-7 10-13 17-18 19c-2 1-5 3-8 4c-15 9-32 6-36-6c-4-9 3-18 12-18c7-1 9 4 6 12c-1 5-1 5 0 6c2 2 4 2 10-5c3-4 4-4 5-7c5-16-16-28-34-19c-23 12-26 35-8 52c6 6 14 10 21 11c9 2 24-1 33-7c0 0 2-1 3-1c6-4 20-17 22-23c1-1 2-2 2-3c2-3 8-15 11-22c0-2 1-4 2-6c1-4 4-12 4-16c0-1 1-3 1-3c0 0 0-2 0-4c1-8 2-14 2-23c1-14 0-13 7-12c19 3 38-13 35-29c-3-13-9-19-21-22c-11-2-22 7-19 18c2 9 16 8 15-1c0-5 6-2 7 3c2 9-10 17-20 13c-5-3-8-7-10-20c-1-4-2-7-3-9c0-1-1-4-2-6c-1-2-2-5-3-7c-2-4-2-5 3-6c15-5 23-11 28-26c2-5 3-6 11-2c10 5 17 10 23 15c8 7 8 7 18 16c8 8 13 13 16 15c2 1 4 3 5 4c7 6 16 10 25 12c9 3 21-3 27-13c1-1 1-2 2-3c2-2 7-14 8-19c3-11 3-10 7-12c8-4 10-6 16-16c3-3 6-8 7-9c1-1 2-3 3-4c0-2 1-2 4-7c2-3 3-3 7-5c23-13 25-25 9-42c-1-2-3-5-5-7c-2-2-8-8-13-13c-9-9-9-10-11-13c-1-2-3-5-3-5c-1-1-2-3-2-3c-1-2-6-7-13-14c-6-6-6-4-5-18c0-5 0-6 0-8c-1-4-1-3-10-16c-1-1-2-3-3-3c0 0-1-2-2-3c-3-4-4-6-2-10c3-10 16-19 22-15c2 1 2 6 1 10c-1 8 7 5 11-3Line truncated
|
||||||
|
After Width: | Height: | Size: 53 KiB |
File renamed without changes.
Binary file not shown.
|
Before Width: | Height: | Size: 65 KiB |
@@ -0,0 +1,99 @@
|
|||||||
|
import { useInView, useMotionValueEvent, useReducedMotion, useScroll } from 'motion/react'
|
||||||
|
import { useEffect, useId, useRef } from 'react'
|
||||||
|
import raw from '../assets/logo/emblem.svg?raw'
|
||||||
|
import { cn } from '../lib/cn'
|
||||||
|
|
||||||
|
// Das Logo (Instagram-Profilbild, vektorisiert) liegt als SVG-Datei vor und wird hier inline gezeichnet,
|
||||||
|
// damit die Linien animiert und vom Licht angestrahlt werden können.
|
||||||
|
const viewBox = raw.match(/viewBox="([^"]+)"/)![1]
|
||||||
|
const [, , VB_W, VB_H] = viewBox.split(' ').map(Number)
|
||||||
|
const paths = [...raw.matchAll(/<path d="([^"]+)"/g)].map((m) => m[1])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logo-Emblem:
|
||||||
|
* - zeichnet sich beim ersten Erscheinen Linie für Linie, danach füllen sich die Linien
|
||||||
|
* - ein Lichtreflex wie auf Metall folgt dem Mauszeiger (ohne Maus: der Scroll-Position)
|
||||||
|
*/
|
||||||
|
export function Emblem({ className }: { className?: string }) {
|
||||||
|
const wrap = useRef<HTMLDivElement>(null)
|
||||||
|
const gradient = useRef<SVGRadialGradientElement>(null)
|
||||||
|
const id = `emblem-light-${useId().replace(/[^\w-]/g, '')}`
|
||||||
|
const reduce = useReducedMotion()
|
||||||
|
const drawn = useInView(wrap, { once: true, amount: 0.4 })
|
||||||
|
|
||||||
|
// Lichtposition (0–1 relativ zum Logo): Ziel und aktueller, weich nachgezogener Wert
|
||||||
|
const light = useRef({ x: 0.3, y: 0.25, tx: 0.3, ty: 0.25, hover: false, raf: 0 })
|
||||||
|
|
||||||
|
const render = () => {
|
||||||
|
const l = light.current
|
||||||
|
l.x += (l.tx - l.x) * 0.12
|
||||||
|
l.y += (l.ty - l.y) * 0.12
|
||||||
|
gradient.current?.setAttribute('cx', String(l.x * VB_W))
|
||||||
|
gradient.current?.setAttribute('cy', String(l.y * VB_H))
|
||||||
|
const settled = Math.abs(l.tx - l.x) < 0.001 && Math.abs(l.ty - l.y) < 0.001
|
||||||
|
l.raf = settled ? 0 : requestAnimationFrame(render)
|
||||||
|
}
|
||||||
|
const moveLight = (x: number, y: number) => {
|
||||||
|
const l = light.current
|
||||||
|
l.tx = x
|
||||||
|
l.ty = y
|
||||||
|
if (reduce) {
|
||||||
|
l.x = x
|
||||||
|
l.y = y
|
||||||
|
render()
|
||||||
|
} else if (!l.raf) l.raf = requestAnimationFrame(render)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { scrollYProgress } = useScroll({ target: wrap, offset: ['start end', 'end start'] })
|
||||||
|
useMotionValueEvent(scrollYProgress, 'change', (p) => {
|
||||||
|
if (!light.current.hover) moveLight(0.1 + 0.8 * p, 0.15 + 0.5 * p)
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const l = light.current
|
||||||
|
return () => cancelAnimationFrame(l.raf)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const onPointerMove = (e: React.PointerEvent) => {
|
||||||
|
const r = wrap.current!.getBoundingClientRect()
|
||||||
|
light.current.hover = true
|
||||||
|
moveLight((e.clientX - r.left) / r.width, (e.clientY - r.top) / r.height)
|
||||||
|
}
|
||||||
|
const onPointerLeave = () => {
|
||||||
|
light.current.hover = false
|
||||||
|
const p = scrollYProgress.get()
|
||||||
|
moveLight(0.1 + 0.8 * p, 0.15 + 0.5 * p)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={wrap}
|
||||||
|
onPointerMove={onPointerMove}
|
||||||
|
onPointerLeave={onPointerLeave}
|
||||||
|
data-drawn={drawn || reduce ? '' : undefined}
|
||||||
|
className={cn('emblem', className)}
|
||||||
|
>
|
||||||
|
<svg viewBox={viewBox} role="img" aria-label="Logo von Amin B. Ahmadi" className="block h-auto w-full overflow-visible">
|
||||||
|
<defs>
|
||||||
|
<radialGradient ref={gradient} id={id} gradientUnits="userSpaceOnUse" cx={0.3 * VB_W} cy={0.25 * VB_H} r={VB_W * 0.55}>
|
||||||
|
<stop offset="0" stopColor="#ffffff" />
|
||||||
|
<stop offset="0.35" stopColor="#ece9e4" />
|
||||||
|
<stop offset="1" stopColor="#8d8a85" />
|
||||||
|
</radialGradient>
|
||||||
|
</defs>
|
||||||
|
{/* Konturen für die Zeichen-Animation */}
|
||||||
|
<g className="emblem-lines" aria-hidden="true">
|
||||||
|
{paths.map((d, i) => (
|
||||||
|
<path key={i} d={d} pathLength={1} style={{ '--i': i } as React.CSSProperties} />
|
||||||
|
))}
|
||||||
|
</g>
|
||||||
|
{/* Gefüllte Linien mit Lichtreflex */}
|
||||||
|
<g className="emblem-fill" fill={`url(#${id})`}>
|
||||||
|
{paths.map((d, i) => (
|
||||||
|
<path key={i} d={d} />
|
||||||
|
))}
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import { image, salon } from '../data/salon'
|
import { salon } from '../data/salon'
|
||||||
import { FadeIn, ImageReveal, RevealLines } from './Reveal'
|
import { Emblem } from './Emblem'
|
||||||
|
import { FadeIn, RevealLines } from './Reveal'
|
||||||
|
|
||||||
export function Intro() {
|
export function Intro() {
|
||||||
return (
|
return (
|
||||||
<section id="salon" className="px-4 py-24 md:px-8 md:py-36">
|
<section id="salon" className="px-4 py-24 md:px-8 md:py-36">
|
||||||
<div className="grid gap-10 md:grid-cols-12 md:gap-8">
|
<div className="grid gap-10 md:grid-cols-12 md:gap-8">
|
||||||
<ImageReveal
|
{/* Logo wie auf Instagram: helle Linien auf dunklem Grund */}
|
||||||
src={image('photos/emblem')}
|
<div className="grid aspect-square place-items-center bg-ink md:col-span-4">
|
||||||
alt={`Das Logo von ${salon.name} aus Edelstahl an der Schieferwand im Salon`}
|
<Emblem className="w-[84%]" />
|
||||||
className="aspect-[4/5] md:col-span-4"
|
</div>
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="flex flex-col justify-between gap-12 md:col-span-8">
|
<div className="flex flex-col justify-between gap-12 md:col-span-8">
|
||||||
<div className="mini flex justify-between">
|
<div className="mini flex justify-between">
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { motion, type Variants } from 'motion/react'
|
import { motion, type Variants } from 'motion/react'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
import { cn } from '../lib/cn'
|
|
||||||
import { EASE_OUT_EXPO } from '../lib/motion'
|
import { EASE_OUT_EXPO } from '../lib/motion'
|
||||||
|
|
||||||
const tags = { h1: motion.h1, h2: motion.h2, h3: motion.h3, p: motion.p, div: motion.div }
|
const tags = { h1: motion.h1, h2: motion.h2, h3: motion.h3, p: motion.p, div: motion.div }
|
||||||
@@ -62,36 +61,3 @@ export function FadeIn({ children, className, delay = 0 }: { children: ReactNode
|
|||||||
</motion.div>
|
</motion.div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Bild, das sich von unten aufdeckt und dabei leicht herauszoomt. */
|
|
||||||
export function ImageReveal({
|
|
||||||
src,
|
|
||||||
alt,
|
|
||||||
className,
|
|
||||||
imgClassName,
|
|
||||||
}: {
|
|
||||||
src: string
|
|
||||||
alt: string
|
|
||||||
className?: string
|
|
||||||
imgClassName?: string
|
|
||||||
}) {
|
|
||||||
const transition = { duration: 1.3, ease: EASE_OUT_EXPO }
|
|
||||||
// Beobachtet wird der ungeclippte Rahmen: ein komplett weggeclipptes Element gilt nie als sichtbar
|
|
||||||
return (
|
|
||||||
<motion.div className={className} initial="hidden" whileInView="show" viewport={{ once: true, amount: 0.25 }}>
|
|
||||||
<motion.div
|
|
||||||
className="size-full overflow-hidden"
|
|
||||||
variants={{ hidden: { clipPath: 'inset(100% 0% 0% 0%)' }, show: { clipPath: 'inset(0% 0% 0% 0%)', transition } }}
|
|
||||||
>
|
|
||||||
<motion.img
|
|
||||||
src={src}
|
|
||||||
alt={alt}
|
|
||||||
loading="lazy"
|
|
||||||
decoding="async"
|
|
||||||
className={cn('size-full object-cover', imgClassName)}
|
|
||||||
variants={{ hidden: { scale: 1.2 }, show: { scale: 1, transition: { ...transition, duration: 1.7 } } }}
|
|
||||||
/>
|
|
||||||
</motion.div>
|
|
||||||
</motion.div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
+1
-1
@@ -149,7 +149,7 @@ const images = import.meta.glob<string>(['../assets/team/*.webp', '../assets/pho
|
|||||||
eager: true,
|
eager: true,
|
||||||
import: 'default',
|
import: 'default',
|
||||||
})
|
})
|
||||||
/** Bild-URL aus `src/assets`, z. B. `image('photos/emblem')` */
|
/** Bild-URL aus `src/assets`, z. B. `image('photos/hero')` */
|
||||||
export const image = (path: string) => images[`../assets/${path}.webp`]
|
export const image = (path: string) => images[`../assets/${path}.webp`]
|
||||||
|
|
||||||
export const team: Member[] = [
|
export const team: Member[] = [
|
||||||
|
|||||||
@@ -72,6 +72,45 @@
|
|||||||
box-shadow: inset -1px 0 0 var(--grid-line, rgb(10 9 12 / 0.07));
|
box-shadow: inset -1px 0 0 var(--grid-line, rgb(10 9 12 / 0.07));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Logo-Emblem: Linien zeichnen sich, danach füllen sie sich (siehe Emblem.tsx) */
|
||||||
|
.emblem .emblem-lines path {
|
||||||
|
fill: none;
|
||||||
|
stroke: var(--color-paper);
|
||||||
|
stroke-width: 2;
|
||||||
|
stroke-dasharray: 1 1;
|
||||||
|
stroke-dashoffset: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emblem .emblem-fill {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emblem[data-drawn] .emblem-lines path {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
transition: stroke-dashoffset 2.6s var(--ease-out-expo) calc(var(--i) * 30ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
.emblem[data-drawn] .emblem-lines {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 1s ease 2.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emblem[data-drawn] .emblem-fill {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 1.4s ease 1.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.emblem .emblem-lines {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emblem .emblem-fill {
|
||||||
|
opacity: 1;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Rechtstexte (Impressum / Datenschutz) */
|
/* Rechtstexte (Impressum / Datenschutz) */
|
||||||
@layer components {
|
@layer components {
|
||||||
.legal h2 {
|
.legal h2 {
|
||||||
|
|||||||
Reference in new issue
Block a user