feat: Team, Villa-Bilder und bestaetigte Camp-Eckdaten
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m49s
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m49s
- Team-Abschnitt mit neun Personen, Eric Heitz als Head of Modelcamp, Portraets im Rundbogen mit Initialen-Platzhaltern bis Fotos vorliegen - Unterkunftsbilder der Villa La Chiesina lokal in public/images/unterkunft (vom Auftraggeber freigegeben), Hero-Leitbild, Ausstattung, Booking-Link - Migration: Termin 08.05.-15.05.2027, Ort Arcidosso (Toskana), eigenes Bett im geteilten Zimmer, 13 Plaetze; Admin-Werte bleiben erhalten - Reveal: kein Hydration-Fehler mehr bei reduzierter Bewegung - Doku zu offenen Punkten aktualisiert Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
28663cda7a
commit
804bb832ea
28 files changed
+220
-89
No files matched your search
@@ -1,36 +1,69 @@
|
||||
import { site } from "@/content/site";
|
||||
import { site, type Media } from "@/content/site";
|
||||
import { MediaFrame } from "../MediaFrame";
|
||||
import { Reveal } from "../Reveal";
|
||||
import { VideoSlot } from "../VideoSlot";
|
||||
|
||||
export function TeachersSection({ showDrafts }: { showDrafts: boolean }) {
|
||||
const { teachers } = site;
|
||||
type TeamMember = { name: string; role: string; bio: string | null; portrait: Media };
|
||||
|
||||
function Bio({ bio, showDrafts }: { bio: string | null; showDrafts: boolean }) {
|
||||
if (bio) return <p className="mt-3 max-w-md">{bio}</p>;
|
||||
return showDrafts ? <p className="mt-3"><span className="draft-flag">Kurzbeschreibung folgt</span></p> : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Team: Eric Heitz als Head of Modelcamp gross vorangestellt, darunter alle
|
||||
* weiteren gleichwertig im Raster. Portraets im Rundbogen – ein Motiv aus
|
||||
* der Architektur der Villa. Die Spalten sind auf breiten Bildschirmen
|
||||
* leicht versetzt, damit das Raster wie eine Magazinseite wirkt.
|
||||
*/
|
||||
export function TeamSection({ showDrafts }: { showDrafts: boolean }) {
|
||||
const { team } = site;
|
||||
const { head } = team;
|
||||
return (
|
||||
<section id="dozentinnen" aria-labelledby="dozentinnen-title" className="bg-paper py-24 md:py-36">
|
||||
<section id="team" aria-labelledby="team-title" className="bg-paper py-24 md:py-36">
|
||||
<div className="container-edge">
|
||||
<h2 id="dozentinnen-title" className="section-title">{teachers.title}</h2>
|
||||
<div className="mt-14 grid gap-16 md:grid-cols-12 md:gap-10">
|
||||
{teachers.people.map((person, index) => (
|
||||
<article
|
||||
key={index}
|
||||
aria-label={person.name ?? `Dozentin ${index + 1}`}
|
||||
className={index === 0 ? "md:col-span-5" : "md:col-span-5 md:col-start-8 md:mt-40"}
|
||||
>
|
||||
<Reveal>
|
||||
<MediaFrame media={person.portrait} aspect="aspect-[3/4]" sizes="(min-width: 768px) 40vw, 100vw" showLabel={showDrafts} />
|
||||
</Reveal>
|
||||
<h3 className="display mt-6 text-3xl">
|
||||
{person.name ?? (showDrafts ? `Dozentin ${index + 1}: Name folgt` : "Wird in Kürze vorgestellt")}
|
||||
</h3>
|
||||
{person.role && <p className="mt-1 text-stone">{person.role}</p>}
|
||||
{person.bio ? (
|
||||
<p className="mt-4 max-w-md">{person.bio}</p>
|
||||
) : (
|
||||
showDrafts && <p className="mt-4"><span className="draft-flag">Kurzbeschreibung folgt</span></p>
|
||||
)}
|
||||
</article>
|
||||
))}
|
||||
<div className="grid gap-6 md:grid-cols-12 md:gap-10">
|
||||
<h2 id="team-title" className="section-title md:col-span-5">{team.title}</h2>
|
||||
<p className="max-w-xl text-lg text-ink/85 md:col-span-6 md:col-start-7 md:pt-3">{team.lead}</p>
|
||||
</div>
|
||||
|
||||
<article aria-label={head.name} className="mt-14 grid items-end gap-8 md:mt-20 md:grid-cols-12 md:gap-10">
|
||||
<Reveal className="md:col-span-5">
|
||||
<MediaFrame media={head.portrait} aspect="aspect-[4/5]" shape="arch" sizes="(min-width: 768px) 40vw, 100vw" showLabel={showDrafts} />
|
||||
</Reveal>
|
||||
<div className="md:col-span-6 md:col-start-7 md:pb-10">
|
||||
<p className="text-sm font-semibold uppercase tracking-[0.18em] text-rosso">{head.title}</p>
|
||||
<h3 className="display mt-4 text-[3rem] leading-[0.95] md:text-[5.5rem]">{head.name}</h3>
|
||||
<p className="mt-5 border-t border-ink pt-4 text-lg">{head.role}</p>
|
||||
<Bio bio={head.bio} showDrafts={showDrafts} />
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<ul className="mt-20 grid grid-cols-2 gap-x-4 gap-y-12 md:mt-28 md:grid-cols-4 md:gap-x-8 md:gap-y-16">
|
||||
{team.people.map((person: TeamMember, index) => (
|
||||
<li key={person.name} className={index % 2 === 1 ? "md:mt-16" : ""}>
|
||||
<article aria-label={person.name}>
|
||||
<Reveal delay={(index % 4) * 0.06}>
|
||||
<MediaFrame
|
||||
media={person.portrait}
|
||||
aspect="aspect-[3/4]"
|
||||
shape="arch"
|
||||
sizes="(min-width: 768px) 22vw, 50vw"
|
||||
showLabel={false}
|
||||
/>
|
||||
</Reveal>
|
||||
<h3 className="display mt-4 text-[1.375rem] leading-tight md:text-[1.75rem]">{person.name}</h3>
|
||||
<p className="mt-1 text-sm text-stone md:text-[0.9375rem]">{person.role}</p>
|
||||
<Bio bio={person.bio} showDrafts={showDrafts} />
|
||||
</article>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{showDrafts && (
|
||||
<p className="mt-12">
|
||||
<span className="draft-flag">Porträts folgen</span> Platzhalter mit Initialen, bis freigegebene Fotos vorliegen.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user