Einheitliche Team-Porträts einbauen

- Neue Studio-Porträts für Atena, Ahmad, Ali, Younes und Mo (gleicher
  Hintergrund, gleiches Licht, schwarzes Shirt) statt der gemischten
  Originalfotos
- Zusätzlich quadratische Thumbnails (320 px) für Fotoraster und
  Preis-Thumbnails, damit dort keine großen Bilder geladen werden
- Team-Liste: Bildausschnitt auf Kopf und Schultern ausgerichtet,
  neutraler Hintergrund hinter den Porträts
- README: Hinweise zu den Porträts und zum fehlenden Foto von Amin

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KBHsCnWNXAB2Le3gAEsivF
This commit is contained in:
Claude committed 2026-09-29 13:13:49 +00:00
1 parent c89d9e16bd
commit 3413040e8c
15 files changed
+26 -12

No files matched your search

+6 -1
View File
@@ -31,10 +31,15 @@ npm run preview # Build lokal ansehen
| Favicon, App-Icon, Vorschaubild zum Teilen | `public/` | | Favicon, App-Icon, Vorschaubild zum Teilen | `public/` |
| Impressum & Datenschutz | `impressum.html`, `datenschutz.html` | | Impressum & Datenschutz | `impressum.html`, `datenschutz.html` |
**Fotos:** Alle Bilder stammen aus den Team-Fotos der Setmore-Seite (Logo-Wand im Salon). Für den **Fotos:** Hero, „Über uns“ und Menü nutzen die Fotos von der Logo-Wand im Salon (Setmore-Seite). Für den
Hero lohnt sich ein eigenes, hochauflösendes Foto (mind. 2400 px breit), z. B. ein Barber bei der Arbeit. Hero lohnt sich ein eigenes, hochauflösendes Foto (mind. 2400 px breit), z. B. ein Barber bei der Arbeit.
Einfach `salon-wand.webp` bzw. `salon-wand-800.webp` ersetzen. Einfach `salon-wand.webp` bzw. `salon-wand-800.webp` ersetzen.
**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
Preis-Thumbnails). Für Amin fehlt noch ein Foto – bis dahin zeigt die Seite bei ihm das Wandlogo. Neues
Porträt als `amin.webp` / `amin-thumb.webp` ablegen und in `src/data/salon.ts` eintragen.
**Direktbuchung:** Jede Leistung trägt ihre Setmore-ID (`id`). Wird bei Setmore eine Leistung **Direktbuchung:** Jede Leistung trägt ihre Setmore-ID (`id`). Wird bei Setmore eine Leistung
neu angelegt, bekommt sie eine neue ID. Sie steht im Buchungslink der Leistung auf der neu angelegt, bekommt sie eine neue ID. Sie steht im Buchungslink der Leistung auf der
Setmore-Seite hinter `products=`. Setmore-Seite hinter `products=`.
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 43 KiB

+1 -1
View File
@@ -11,7 +11,7 @@ const YEAR = new Date().getFullYear()
// 3 × 2 Fotoraster zwischen den Wörtern: fünf Porträts und das Logo an der Wand // 3 × 2 Fotoraster zwischen den Wörtern: fünf Porträts und das Logo an der Wand
const tiles = [ const tiles = [
...team.filter((m) => m.key !== 'amin').map((m) => ({ src: m.photo, alt: m.name })), ...team.filter((m) => m.key !== 'amin').map((m) => ({ src: m.thumb, alt: m.name })),
{ src: image('photos/emblem-quadrat'), alt: 'Logo an der Salonwand' }, { src: image('photos/emblem-quadrat'), alt: 'Logo an der Salonwand' },
] ]
+1 -1
View File
@@ -15,7 +15,7 @@ function Faces({ keys, className }: { keys: string[]; className?: string }) {
return ( return (
<img <img
key={key} key={key}
src={m.photo} src={m.thumb}
alt={m.name} alt={m.name}
title={m.name} title={m.name}
loading="lazy" loading="lazy"
+2 -2
View File
@@ -43,7 +43,7 @@ export function TeamList() {
))} ))}
</ul> </ul>
<div className="relative order-1 aspect-square overflow-hidden bg-ink md:order-2 md:aspect-auto md:min-h-[32rem]"> <div className="relative order-1 aspect-square overflow-hidden bg-[#cfccc6] md:order-2 md:aspect-auto md:min-h-[32rem]">
{team.map((m, i) => ( {team.map((m, i) => (
<img <img
key={m.key} key={m.key}
@@ -52,7 +52,7 @@ export function TeamList() {
loading="lazy" loading="lazy"
decoding="async" decoding="async"
className={cn( className={cn(
'absolute inset-0 size-full object-cover', 'absolute inset-0 size-full object-cover object-[50%_20%]',
i === active i === active
? 'z-20 [clip-path:inset(0_0_0_0)] transition-[clip-path] duration-700 ease-out-expo' ? 'z-20 [clip-path:inset(0_0_0_0)] transition-[clip-path] duration-700 ease-out-expo'
: i === previous : i === previous
+16 -7
View File
@@ -134,7 +134,16 @@ export const services: ServiceCategory[] = [
}, },
] ]
export type Member = { key: string; name: string; short: string; role: string; photo: string } export type Member = {
key: string
name: string
short: string
role: string
/** großes Porträt für die Team-Liste */
photo: string
/** quadratischer Ausschnitt fürs Fotoraster und die kleinen Porträts bei den Preisen */
thumb: string
}
const images = import.meta.glob<string>(['../assets/team/*.webp', '../assets/photos/*.webp'], { const images = import.meta.glob<string>(['../assets/team/*.webp', '../assets/photos/*.webp'], {
eager: true, eager: true,
@@ -144,12 +153,12 @@ const images = import.meta.glob<string>(['../assets/team/*.webp', '../assets/pho
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[] = [
{ key: 'amin', name: 'Amin B. Ahmadi', short: 'Amin', role: 'Inhaber · Barber', photo: image('photos/emblem-breit-900') }, { key: 'amin', name: 'Amin B. Ahmadi', short: 'Amin', role: 'Inhaber · Barber', photo: image('photos/emblem-breit-900'), thumb: image('photos/emblem-quadrat') },
{ key: 'atena', name: 'Atena', short: 'Atena', role: 'Damen · Farbe · Beauty', photo: image('team/atena') }, { key: 'atena', name: 'Atena', short: 'Atena', role: 'Damen · Farbe · Beauty', photo: image('team/atena'), thumb: image('team/atena-thumb') },
{ key: 'ahmad', name: 'Ahmad', short: 'Ahmad', role: 'Barber', photo: image('team/ahmad') }, { key: 'ahmad', name: 'Ahmad', short: 'Ahmad', role: 'Barber', photo: image('team/ahmad'), thumb: image('team/ahmad-thumb') },
{ key: 'ali', name: 'Ali', short: 'Ali', role: 'Barber', photo: image('team/ali') }, { key: 'ali', name: 'Ali', short: 'Ali', role: 'Barber', photo: image('team/ali'), thumb: image('team/ali-thumb') },
{ key: 'younes', name: 'Younes', short: 'Younes', role: 'Barber', photo: image('team/younes') }, { key: 'younes', name: 'Younes', short: 'Younes', role: 'Barber', photo: image('team/younes'), thumb: image('team/younes-thumb') },
{ key: 'mo', name: 'Mo Bargus', short: 'Mo', role: 'Barber', photo: image('team/mo') }, { key: 'mo', name: 'Mo Bargus', short: 'Mo', role: 'Barber', photo: image('team/mo'), thumb: image('team/mo-thumb') },
] ]
export const member = (key: string) => team.find((m) => m.key === key)! export const member = (key: string) => team.find((m) => m.key === key)!