100 lines
3.7 KiB
Plaintext
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>
|