feat: Onepage nach Filmcamp-Gliederung umgebaut
- Figtree als einzige Schrift, Logo mittig in fester Kopfzeile - Headerbild ueber volle Breite und Hoehe, ohne Preis, mit Terminleiste - "Was dich erwartet" stellt die Villa mit animierter Bilderfolge vor, darunter Tagesablauf als Karussell (Programm folgt als PDF) - Preis: regulaerer Preis durchgestrichen, kein Verkaufsstartdatum, Ueberschrift "Jetzt Platz sichern mit Early Bird" - Team als "Mit dabei", danach drei Reels im Hochformat - Logo, Headerbild, Portraets und Reels ueber feste Dateinamen im Medienverzeichnis (docs/MEDIEN.md), ohne Neustart austauschbar - Widerrufsbelehrung im Admin pflegbar, Seite /widerruf, Live-Verkauf ohne Freigabe gesperrt - Anreise: Abholung am Bahnhof Firenze Santa Maria Novella - Booking-Link entfernt, Gedankenstriche aus Kundentexten entfernt Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
3cba3e2341
commit
7203cd1e6e
37 files changed
+962
-517
No files matched your search
+82
-62
@@ -8,14 +8,16 @@
|
||||
* und Staging sichtbar als solche markiert und werden im Produktivbetrieb
|
||||
* (APP_ENV=production) ausgeblendet oder durch einen neutralen Hinweis
|
||||
* ersetzt.
|
||||
* - Termin, Ort, Zimmer-/Bettbeschreibung, Veranstalter, Steuerhinweis und
|
||||
* Bedingungen pflegt der Adminbereich (Datenbank), weil sie den
|
||||
* Live-Verkauf freischalten. Hier steht alles Uebrige.
|
||||
* - Termin, Ort, Zimmer-/Bettbeschreibung, Veranstalter, Steuerhinweis,
|
||||
* Bedingungen und Widerrufsbelehrung pflegt der Adminbereich (Datenbank),
|
||||
* weil sie den Live-Verkauf freischalten. Hier steht alles Uebrige.
|
||||
* - Bilder: nur mit bestaetigter Nutzungsberechtigung und immer als lokale
|
||||
* Datei, nie per Hotlinking. Feste Bilder liegen in public/images/,
|
||||
* austauschbare Medien im Medienverzeichnis (MEDIA_DIR, /media/…).
|
||||
* Datei, nie per Hotlinking. Feste Bilder liegen in public/images/.
|
||||
* Logo, Headerbild, Portraets und Reels kommen ueber feste Dateinamen aus
|
||||
* dem Medienverzeichnis (src/lib/site-media.ts, docs/MEDIEN.md).
|
||||
* Die Unterkunftsbilder stammen aus dem Booking.com-Eintrag der Villa
|
||||
* und wurden vom Auftraggeber am 01.10.2026 zur Nutzung freigegeben.
|
||||
* - Keine Gedankenstriche in Texten (Wunsch des Auftraggebers).
|
||||
*
|
||||
* Offene Punkte: docs/OFFENE-PUNKTE.md
|
||||
*/
|
||||
@@ -28,49 +30,75 @@ export type Media =
|
||||
|
||||
export type Confirmable<T> = T & { confirmed: boolean };
|
||||
|
||||
export type ScheduleDay = { title: string | null; items: string[] };
|
||||
|
||||
const portrait = (name: string, initials: string): Media => ({ kind: "placeholder", label: `Porträt ${name}`, tone: "portrait", glyph: initials });
|
||||
/** Lokales Bild aus public/images/unterkunft (1280 x 853 px). */
|
||||
const villa = (file: string, alt: string): Media => ({ kind: "image", src: `/images/unterkunft/${file}.jpg`, alt, width: 1280, height: 853 });
|
||||
|
||||
export const site = {
|
||||
hero: {
|
||||
title: "Modelcamp Toskana 2027",
|
||||
// Entwurf zur Freigabe: bewusst ohne Versprechen zu Shootings,
|
||||
// Vermittlung oder Ergebnissen.
|
||||
headline: "Gemeinsam wachsen. In Italien.",
|
||||
subline:
|
||||
"Das ARTISTA Modelcamp 2027 bringt Models an einem Ort in Italien zusammen – zum Lernen, Arbeiten und Wohnen unter einem Dach.",
|
||||
"Eine Woche in einer Villa in der Toskana. Lernen vor und hinter der Kamera, mit einem Team aus Fotografen, Models und Content Creators, und Abende, an denen alle zusammen am Tisch sitzen.",
|
||||
cta: "Jetzt Platz sichern",
|
||||
// Standardbild, solange kein header.jpg im Medienverzeichnis liegt.
|
||||
media: villa("villa-luftbild", "Luftaufnahme der Villa La Chiesina zwischen Zypressen und Wiesen in der Toskana"),
|
||||
},
|
||||
|
||||
camp: {
|
||||
title: "Das Camp",
|
||||
lead: "Ein paar Tage, an denen sich alles um deine Arbeit als Model dreht – in Ruhe, in einer kleinen Gruppe und mit Zeit füreinander.",
|
||||
expect: {
|
||||
title: "Was dich erwartet",
|
||||
lead: "Eine Woche in der Villa La Chiesina, mitten in der Toskana.",
|
||||
paragraphs: [
|
||||
"Das Modelcamp verbindet gemeinsames Arbeiten mit dem Leben unter einem Dach. Du wohnst mit den anderen Teilnehmerinnen in einer Unterkunft in Italien, lernst von zwei Dozentinnen und tauschst dich mit Menschen aus, die dieselbe Leidenschaft teilen.",
|
||||
"Das Programm wird gerade zusammengestellt. Was bereits feststeht, findest du unten unter Leistungen – alles andere ergänzen wir, sobald es verbindlich ist.",
|
||||
"Die Villa liegt zwischen Zypressen oberhalb von Arcidosso, mit Blick über die Hügel am Monte Amiata. Hier wohnen, arbeiten und essen wir eine Woche lang zusammen.",
|
||||
"Garten, Pool, alte Steintreppen und Räume mit Holzbalkendecken: Die Villa bietet viele Orte zum Fotografieren und zum Durchatmen.",
|
||||
],
|
||||
audience: {
|
||||
title: "Für wen das Camp gedacht ist",
|
||||
items: [
|
||||
"Models, die bereits mit ARTISTA arbeiten",
|
||||
"Models, die ARTISTA und die Arbeit vor der Kamera näher kennenlernen möchten",
|
||||
"Alle, die Lust auf eine konzentrierte Zeit in einer kleinen Gruppe haben",
|
||||
],
|
||||
confirmed: false,
|
||||
},
|
||||
// Ausdruecklich KEINE Aussagen zu Agenturvermittlung, Auftraegen,
|
||||
// Verdienst oder Karriereerfolg (Briefing Abschnitt 4).
|
||||
highlights: ["Eigenes Bett im geteilten Zimmer", "Abholung am Bahnhof in Florenz", "Kleine Gruppe, ein ganzes Team"],
|
||||
slides: [
|
||||
villa("villa-eingang", "Die Villa La Chiesina mit Steintreppe und Rasen im Frühling"),
|
||||
villa("pool-zypressen", "Pool zwischen hohen Zypressen, im Hintergrund die Hügel der Toskana"),
|
||||
villa("wohnzimmer-kamin", "Wohnzimmer mit Holzbalkendecke, Natursteinwand und Kamin"),
|
||||
villa("terrasse", "Sitzplatz auf der Gartenterrasse"),
|
||||
villa("anwesen-luftbild", "Luftaufnahme des Anwesens mit Zypressenallee, Pool und Tennisplatz"),
|
||||
] as Media[],
|
||||
},
|
||||
|
||||
schedule: {
|
||||
title: "Tagesablauf",
|
||||
note: "Programmentwurf. Das finale Programm kann sich noch ändern.",
|
||||
// Ein Eintrag pro Tag ab Anreisetag; das Datum kommt aus dem
|
||||
// Adminbereich. Das Programm liefert der Auftraggeber als PDF nach.
|
||||
// Leere Tage zeigen "Programm folgt". Nichts erfinden.
|
||||
days: [
|
||||
{
|
||||
title: "Anreise",
|
||||
items: [
|
||||
"Eigene Anreise nach Florenz",
|
||||
"Abholung am Bahnhof Firenze Santa Maria Novella und gemeinsame Fahrt zur Villa",
|
||||
"Mit dem Auto? Dann fährst du direkt zur Villa",
|
||||
],
|
||||
},
|
||||
{ title: null, items: [] },
|
||||
{ title: null, items: [] },
|
||||
{ title: null, items: [] },
|
||||
{ title: null, items: [] },
|
||||
{ title: null, items: [] },
|
||||
{ title: null, items: [] },
|
||||
{ title: "Abreise", items: [] },
|
||||
] as ScheduleDay[],
|
||||
},
|
||||
|
||||
services: {
|
||||
title: "Erlebnisse und Leistungen",
|
||||
included: [
|
||||
// Bestaetigt durch das Buchungsprodukt selbst:
|
||||
// Bestaetigt durch das Buchungsprodukt bzw. den Auftraggeber:
|
||||
{ text: "Teilnahme am Modelcamp 2027", confirmed: true },
|
||||
{ text: "Unterbringung in einer geteilten Unterkunft in Italien", confirmed: true },
|
||||
{ text: "Sieben Nächte in der Villa La Chiesina, eigenes Bett im geteilten Zimmer", confirmed: true },
|
||||
{ text: "Abholung am Anreisetag vom Bahnhof Firenze Santa Maria Novella", confirmed: true },
|
||||
// Entwuerfe: erst nach Bestaetigung (Admin: "Leistungen bestaetigt")
|
||||
// auf confirmed: true setzen.
|
||||
{ text: "Workshops mit den beiden Dozentinnen", confirmed: false },
|
||||
{ text: "Workshops und Coachings mit dem ARTISTA-Team", confirmed: false },
|
||||
{ text: "Verpflegung vor Ort (Umfang folgt)", confirmed: false },
|
||||
] satisfies Confirmable<{ text: string }>[],
|
||||
excluded: [
|
||||
@@ -79,26 +107,15 @@ export const site = {
|
||||
"Persönliche Ausgaben vor Ort",
|
||||
"Reiserücktrittsversicherung",
|
||||
],
|
||||
exampleSchedule: {
|
||||
// Beispiel, KEIN verbindliches Programm.
|
||||
note: "Beispielhafter Ablauf – das verbindliche Programm veröffentlichen wir, sobald alle Punkte bestätigt sind.",
|
||||
steps: [
|
||||
{ title: "Ankommen", text: "Anreise, Zimmer beziehen, erstes Kennenlernen der Gruppe." },
|
||||
{ title: "Arbeiten", text: "Gemeinsame Einheiten mit den Dozentinnen und Zeit für Fragen." },
|
||||
{ title: "Abschied", text: "Rückblick, Austausch und individuelle Abreise." },
|
||||
],
|
||||
confirmed: false,
|
||||
},
|
||||
},
|
||||
|
||||
accommodation: {
|
||||
title: "Die Unterkunft",
|
||||
lead: "Eine Villa zwischen Zypressen, mit Blick über die Hügel am Monte Amiata. Wohnen, arbeiten und abends zusammensitzen – alles an einem Ort.",
|
||||
lead: "Eine Villa zwischen Zypressen, mit Blick über die Hügel am Monte Amiata. Wohnen, arbeiten und abends zusammensitzen, alles an einem Ort.",
|
||||
name: "Villa La Chiesina",
|
||||
place: "Arcidosso, Toskana",
|
||||
// Ohne Tracking-Parameter; Termin und Personenzahl waehlt man dort selbst.
|
||||
bookingUrl: "https://www.booking.com/hotel/it/villa-la-chiesina-arcidosso.de.html" as string | null,
|
||||
// Ausstattung laut Unterkunftsbeschreibung (Booking.com, Stand 01.10.2026).
|
||||
// Die Booking-Seite selbst wird bewusst nicht verlinkt.
|
||||
features: [
|
||||
"Eigener Außenpool (saisonal)",
|
||||
"Großer Garten mit Terrasse",
|
||||
@@ -122,13 +139,13 @@ export const site = {
|
||||
},
|
||||
|
||||
team: {
|
||||
title: "Das Team",
|
||||
title: "Mit dabei",
|
||||
lead: "Fotografie, Modelcoaching, Content und eine Küche, die alle zusammenbringt: Diese Menschen sind beim Modelcamp 2027 dabei.",
|
||||
// Namen und Rollen vom Auftraggeber (01.10.2026). Porträts folgen:
|
||||
// Datei in public/images/team/ legen und "portrait" ersetzen, z. B.
|
||||
// { kind: "image", src: "/images/team/eric-heitz.jpg", alt: "Porträt Eric Heitz", width: 1200, height: 1500 }.
|
||||
// Namen und Rollen vom Auftraggeber (01.10.2026). Portraets kommen ueber
|
||||
// das Medienverzeichnis als team/<slug>.jpg (docs/MEDIEN.md).
|
||||
// Kurzbeschreibungen nur aus freigegebenen Angaben, keine erfundenen Referenzen.
|
||||
head: {
|
||||
slug: "eric-heitz",
|
||||
name: "Eric Heitz",
|
||||
title: "Head of Modelcamp",
|
||||
role: "Fotograf · Content Creator · Modelcoach",
|
||||
@@ -136,14 +153,14 @@ export const site = {
|
||||
portrait: portrait("Eric Heitz", "EH"),
|
||||
},
|
||||
people: [
|
||||
{ name: "Michele Ietro", role: "Editorial- und Casual-Fotograf", bio: null as string | null, portrait: portrait("Michele Ietro", "MI") },
|
||||
{ name: "Lola Stoll", role: "Editorial Model · UGC · GNTM 2026", bio: null as string | null, portrait: portrait("Lola Stoll", "LS") },
|
||||
{ name: "Eileen Kaupp", role: "Editorial Model · Fashion · GNTM 2026", bio: null as string | null, portrait: portrait("Eileen Kaupp", "EK") },
|
||||
{ name: "Gabriela Pronkin", role: "Commercial · Casual Model · UGC", bio: null as string | null, portrait: portrait("Gabriela Pronkin", "GP") },
|
||||
{ name: "Stefan Höchtl", role: "Social Media Content Creator", bio: null as string | null, portrait: portrait("Stefan Höchtl", "SH") },
|
||||
{ name: "Saskia Sirowatka", role: "Social Media Managerin", bio: null as string | null, portrait: portrait("Saskia Sirowatka", "SS") },
|
||||
{ name: "André Hartshauser", role: "Workshop-Organisation · Assistenz Küche", bio: null as string | null, portrait: portrait("André Hartshauser", "AH") },
|
||||
{ name: "Ante Rejo", role: "Chefkoch", bio: null as string | null, portrait: portrait("Ante Rejo", "AR") },
|
||||
{ slug: "michele-ietro", name: "Michele Ietro", role: "Editorial- und Casual-Fotograf", bio: null as string | null, portrait: portrait("Michele Ietro", "MI") },
|
||||
{ slug: "lola-stoll", name: "Lola Stoll", role: "Editorial Model · UGC · GNTM 2026", bio: null as string | null, portrait: portrait("Lola Stoll", "LS") },
|
||||
{ slug: "eileen-kaupp", name: "Eileen Kaupp", role: "Editorial Model · Fashion · GNTM 2026", bio: null as string | null, portrait: portrait("Eileen Kaupp", "EK") },
|
||||
{ slug: "gabriela-pronkin", name: "Gabriela Pronkin", role: "Commercial · Casual Model · UGC", bio: null as string | null, portrait: portrait("Gabriela Pronkin", "GP") },
|
||||
{ slug: "stefan-hoechtl", name: "Stefan Höchtl", role: "Social Media Content Creator", bio: null as string | null, portrait: portrait("Stefan Höchtl", "SH") },
|
||||
{ slug: "saskia-sirowatka", name: "Saskia Sirowatka", role: "Social Media Managerin", bio: null as string | null, portrait: portrait("Saskia Sirowatka", "SS") },
|
||||
{ slug: "andre-hartshauser", name: "André Hartshauser", role: "Workshop-Organisation · Assistenz Küche", bio: null as string | null, portrait: portrait("André Hartshauser", "AH") },
|
||||
{ slug: "ante-rejo", name: "Ante Rejo", role: "Chefkoch", bio: null as string | null, portrait: portrait("Ante Rejo", "AR") },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -155,13 +172,16 @@ export const site = {
|
||||
paragraphs: [] as string[],
|
||||
},
|
||||
|
||||
videos: {
|
||||
title: "Stimmen",
|
||||
// Genau drei Slots. Nur echte, freigegebene Videos eintragen.
|
||||
reels: {
|
||||
title: "Reels",
|
||||
lead: "Eindrücke und Stimmen in drei kurzen Clips.",
|
||||
// Genau drei Slots. Video und Vorschaubild kommen ueber das
|
||||
// Medienverzeichnis (reels/reel-1.mp4 und reels/reel-1.jpg usw.).
|
||||
// Name und Begleittext nur mit Freigabe der gezeigten Person.
|
||||
slots: [
|
||||
{ name: null as string | null, caption: null as string | null, poster: null as Media | null, src: null as string | null, externalId: null as string | null },
|
||||
{ name: null as string | null, caption: null as string | null, poster: null as Media | null, src: null as string | null, externalId: null as string | null },
|
||||
{ name: null as string | null, caption: null as string | null, poster: null as Media | null, src: null as string | null, externalId: null as string | null },
|
||||
{ name: null as string | null, caption: null as string | null },
|
||||
{ name: null as string | null, caption: null as string | null },
|
||||
{ name: null as string | null, caption: null as string | null },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -170,12 +190,12 @@ export const site = {
|
||||
},
|
||||
} as const;
|
||||
|
||||
/** Links in der Kopfzeile: die ersten drei links vom Logo, der Rest rechts. */
|
||||
export const NAV_ITEMS = [
|
||||
{ id: "camp", label: "Das Camp" },
|
||||
{ id: "leistungen", label: "Leistungen" },
|
||||
{ id: "erwartet", label: "Was dich erwartet" },
|
||||
{ id: "ablauf", label: "Tagesablauf" },
|
||||
{ id: "unterkunft", label: "Unterkunft" },
|
||||
{ id: "team", label: "Team" },
|
||||
{ id: "artista", label: "Über ARTISTA" },
|
||||
{ id: "preis", label: "Preis" },
|
||||
{ id: "team", label: "Team" },
|
||||
{ id: "fragen", label: "Fragen" },
|
||||
] as const;
|
||||
Reference in new issue
Block a user