185 lines
4.8 KiB
Text
185 lines
4.8 KiB
Text
---
|
|
import AppLayout from '../layouts/AppLayout.astro';
|
|
import { getAllUsersPublic } from '../lib/db';
|
|
import type { UserPublic, Role } from '../lib/db';
|
|
|
|
const user = Astro.locals.user;
|
|
|
|
const allUsers = getAllUsersPublic().filter((u) => u.active);
|
|
|
|
// Group by organisation
|
|
const orgs = new Map<string, UserPublic[]>();
|
|
for (const u of allUsers) {
|
|
if (!orgs.has(u.organisation)) orgs.set(u.organisation, []);
|
|
orgs.get(u.organisation)!.push(u);
|
|
}
|
|
|
|
const roleLabels: Record<Role, string> = {
|
|
pilot: 'Pilot',
|
|
cab: 'CAB',
|
|
fenja: 'Fenja',
|
|
};
|
|
|
|
const roleColors: Record<Role, string> = {
|
|
pilot: 'var(--pigment-copper)',
|
|
cab: 'var(--pigment-indigo)',
|
|
fenja: 'var(--secondary)',
|
|
};
|
|
---
|
|
<AppLayout title="Participants" user={user}>
|
|
<div class="page">
|
|
|
|
<header class="page-header">
|
|
<p class="label-sm eyebrow">Participants</p>
|
|
<h1 class="display-md page-title">The people.</h1>
|
|
<p class="lead subtitle">
|
|
Everyone in the Bifrost pilot — who they are, where they are from,
|
|
and what they bring.
|
|
</p>
|
|
</header>
|
|
|
|
<div class="orgs">
|
|
{[...orgs.entries()].map(([orgName, members]) => (
|
|
<section class="org-section">
|
|
<h2 class="headline-sm org-name">{orgName}</h2>
|
|
<ul class="member-list">
|
|
{members.map((member) => (
|
|
<li class="member-card">
|
|
<div class="member-header">
|
|
<span class="body-md member-name">{member.name}</span>
|
|
<span
|
|
class="role-badge label-sm"
|
|
style={`color: ${roleColors[member.role]}`}
|
|
>
|
|
{roleLabels[member.role]}
|
|
</span>
|
|
</div>
|
|
{member.bio && (
|
|
<p class="body-sm member-bio">{member.bio}</p>
|
|
)}
|
|
{member.id === user.id && (
|
|
<a href="/account" class="edit-bio-link label-sm">
|
|
Edit your bio
|
|
</a>
|
|
)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
))}
|
|
</div>
|
|
|
|
</div>
|
|
</AppLayout>
|
|
|
|
<style>
|
|
.page {
|
|
padding: var(--space-12) var(--space-20) var(--space-16);
|
|
max-width: var(--content-max);
|
|
margin: 0 auto;
|
|
}
|
|
|
|
/* ── Header ──────────────────────────────────────────────────────── */
|
|
.page-header {
|
|
max-width: 44rem;
|
|
margin-bottom: var(--space-12);
|
|
}
|
|
|
|
.eyebrow {
|
|
letter-spacing: var(--tracking-wider);
|
|
text-transform: uppercase;
|
|
color: var(--on-surface-muted);
|
|
margin-bottom: var(--space-3);
|
|
}
|
|
|
|
.page-title { margin-bottom: var(--space-5); }
|
|
|
|
.subtitle {
|
|
color: var(--on-surface-variant);
|
|
max-width: var(--reading-max);
|
|
margin: 0;
|
|
}
|
|
|
|
/* ── Orgs ────────────────────────────────────────────────────────── */
|
|
.orgs {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-12);
|
|
max-width: 52rem;
|
|
}
|
|
|
|
.org-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-5);
|
|
}
|
|
|
|
.org-name {
|
|
font-family: var(--font-serif);
|
|
font-weight: 400;
|
|
letter-spacing: var(--tracking-snug);
|
|
margin: 0;
|
|
padding-bottom: var(--space-4);
|
|
border-bottom: var(--ghost-border);
|
|
color: var(--on-surface);
|
|
}
|
|
|
|
/* ── Member cards ────────────────────────────────────────────────── */
|
|
.member-list {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
|
gap: var(--space-4);
|
|
}
|
|
|
|
.member-card {
|
|
background: var(--surface-container-lowest);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-5);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-3);
|
|
}
|
|
|
|
.member-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
gap: var(--space-3);
|
|
}
|
|
|
|
.member-name {
|
|
font-weight: 600;
|
|
color: var(--on-surface);
|
|
margin: 0;
|
|
}
|
|
|
|
.role-badge {
|
|
letter-spacing: var(--tracking-wide);
|
|
text-transform: uppercase;
|
|
font-weight: 600;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.member-bio {
|
|
color: var(--on-surface-variant);
|
|
margin: 0;
|
|
line-height: var(--leading-relaxed);
|
|
}
|
|
|
|
.edit-bio-link {
|
|
color: var(--on-surface-muted);
|
|
letter-spacing: var(--tracking-wide);
|
|
text-transform: uppercase;
|
|
text-decoration: none;
|
|
border-bottom: none;
|
|
transition: color var(--duration-fast) var(--ease-standard);
|
|
align-self: flex-start;
|
|
}
|
|
.edit-bio-link:hover {
|
|
color: var(--on-surface-variant);
|
|
border-bottom: none;
|
|
}
|
|
</style>
|