Files
homepage_relaunch/src/pages/_Team.astro
T
2026-09-18 16:04:05 +02:00

100 lines
3.7 KiB
Plaintext

---
import { Picture } from 'astro:assets';
import Base from '../layouts/Base.astro';
import teamPhoto from '../assets/images/team.png';
import { team } from '../data/team';
import { t, type Lang } from '../i18n/ui';
interface Props { lang: Lang }
const { lang } = Astro.props;
const ui = t(lang);
---
<Base lang={lang} title={ui.meta.team.title} description={ui.meta.team.description}>
<section class="section section--intro team-intro">
<div class="container grid">
<h1 class="display team-intro__title">
{ui.team.title.map((line) => <span class="line">{line}</span>)}
</h1>
<p class="team-intro__lead">{ui.team.intro}</p>
</div>
</section>
<div class="team-photo">
<Picture
src={teamPhoto}
alt={ui.team.photoAlt}
formats={['avif']}
fallbackFormat="webp"
widths={[640, 960, 1440]}
sizes="100vw"
loading="eager"
decoding="async"
class="img-cover img-mono team-photo__img"
pictureAttributes={{ class: 'team-photo__picture' }}
/>
<div class="team-photo__overlay" aria-hidden="true"></div>
</div>
<section class="section" aria-label={ui.nav.team}>
<div class="container">
<ul class="people" role="list">
{team.map((p) => (
<li class="person">
<Picture
src={p.portrait}
alt={p.name}
formats={['avif']}
fallbackFormat="webp"
widths={[320, 480, 640]}
sizes="(min-width: 64rem) 22vw, (min-width: 48rem) 45vw, 100vw"
loading="lazy"
decoding="async"
class="img-mono img-print person__img"
/>
<h2 class="h3 person__name">{p.name}</h2>
<p class="muted">{ui.team.roles[p.role]}</p>
<ul class="person__links small" role="list">
{p.github && <li><a href={p.github} rel="noopener">{ui.team.links.github}</a></li>}
{p.linkedin && <li><a href={p.linkedin} rel="noopener">{ui.team.links.linkedin}</a></li>}
<li><a href={`mailto:${p.email}`}>{ui.team.links.email}</a></li>
</ul>
</li>
))}
</ul>
</div>
</section>
</Base>
<style>
.line { display: block; }
.team-intro__title { grid-column: 1 / -1; }
.team-intro__lead { grid-column: 1 / -1; max-width: var(--measure); color: var(--ink-muted); }
@media (min-width: 48rem) {
.team-intro__title { grid-column: 1 / span 7; }
.team-intro__lead { grid-column: 9 / span 4; align-self: end; }
}
.team-photo {
position: relative;
/* Explicit height: an aspect-ratio with max-height would transfer the cap to the width. */
height: min(66.67vw, 80svh);
min-height: 20rem;
overflow: hidden;
}
:global(.team-photo__picture) { position: absolute; inset: 0; }
.team-photo__img, :global(.team-photo__img) { width: 100%; height: 100%; object-fit: cover; object-position: 50% 30%; }
.team-photo__overlay { position: absolute; inset: 0; background: var(--overlay); opacity: 0.6; }
.people {
display: grid;
gap: var(--space-8) var(--gap);
}
.person { display: grid; gap: var(--space-2); align-content: start; }
.person__img, :global(.person__img) { width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; margin-bottom: var(--space-2); }
.person__links { display: flex; gap: var(--space-4); margin-top: var(--space-2); }
.person__links a { text-decoration: underline; text-decoration-thickness: var(--hairline); text-underline-offset: 0.2em; }
@media (min-width: 30rem) { .people { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 64rem) { .people { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
</style>