Adapt + improve all public pages to the atom design system

Extended the same design-system treatment to the public site, faithful
to AtomCMS's "atom" theme. New src/components/public/ui.tsx provides the
signature atom building blocks + a scoped CSS layer:
- ContentCard: surface card with a primary-tinted header (icon circle +
  title + subtitle) and padded body — the atom content-card, used as
  every page's header and section wrapper.
- StatBlock / stat-grid, EmptyState, OnlineBadge (online/offline pill),
  RankBadge (medals for the top 3), and responsive .card-grid helpers.

Swept ~45 public pages (home/community/rankings hand-built as the
reference; the rest via parallel agents that read the schema and
preserved every query, server action, auth gate and field name):
heroes → ContentCard headers, lists → card-grids in ContentCards,
"no X" → EmptyState, status → OnlineBadge/RankBadge. The leaderboard
gained Credits/Diamonds/Duckets tabs (usersCurrency).

Behaviour unchanged. Verified on the prod server against amx_test: 15+
public pages render the content-cards/grids with real data, no errors;
computed styles confirm the tinted header, icon circle, medal + online
pills. Fixed an undefined --color-golden ref. tsc 0, vitest 49/49,
next build 0.
This commit is contained in:
2026-06-28 19:28:36 +02:00
parent 0de0ac6a3c
commit e9ea19795a
47 changed files with 2264 additions and 1714 deletions
+92 -90
View File
@@ -1,4 +1,5 @@
import { redirect } from "next/navigation";
import { ContentCard } from "@/components/public/ui";
import { auth } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { applyDj } from "@/actions/radio-apply";
@@ -26,18 +27,17 @@ export default async function RadioApplyPage() {
: null;
return (
<main>
<div className="hero">
<h1 style={{ margin: "0 0 0.25rem" }}>Apply to be a Radio DJ</h1>
<p className="muted" style={{ margin: 0 }}>
Tell us about yourself and why you&apos;d be a great fit for the airwaves.
</p>
</div>
<main style={{ display: "grid", gap: "1.5rem" }}>
<ContentCard
icon="🎤"
title="Apply to be a Radio DJ"
subtitle="Tell us about yourself and why you'd be a great fit for the airwaves"
/>
{existing ? (
<div className="card" style={{ marginBottom: "1.25rem" }}>
<ContentCard icon="📋" title="Your latest application">
<p style={{ margin: 0 }}>
<strong>Your latest application:</strong> {existing.status}
<strong>Status:</strong> {existing.status}
{submittedDate ? (
<span className="muted"> · submitted {submittedDate}</span>
) : null}
@@ -45,101 +45,103 @@ export default async function RadioApplyPage() {
<p className="muted" style={{ margin: "0.4rem 0 0" }}>
You can submit again below if your details have changed.
</p>
</div>
</ContentCard>
) : null}
<form action={applyDj} className="card">
<div className="grid cols-2">
<div>
<label htmlFor="realName" className="muted">
Real name
<ContentCard icon="📝" title="Application form" subtitle="All fields marked required must be filled in">
<form action={applyDj}>
<div className="card-grid sm-2">
<div>
<label htmlFor="realName" className="muted">
Real name
</label>
<input
id="realName"
name="realName"
type="text"
required
maxLength={255}
placeholder="Your full name"
style={{ width: "100%", marginTop: "0.3rem" }}
/>
</div>
<div>
<label htmlFor="age" className="muted">
Age
</label>
<input
id="age"
name="age"
type="number"
required
min={13}
max={120}
placeholder="18"
style={{ width: "100%", marginTop: "0.3rem" }}
/>
</div>
</div>
<div style={{ marginTop: "1rem" }}>
<label htmlFor="availability" className="muted">
Availability
</label>
<textarea
id="availability"
name="availability"
required
rows={3}
placeholder="Which days and times can you broadcast?"
style={{ width: "100%", marginTop: "0.3rem", resize: "vertical" }}
/>
</div>
<div style={{ marginTop: "1rem" }}>
<label htmlFor="musicStyle" className="muted">
Music style
</label>
<input
id="realName"
name="realName"
id="musicStyle"
name="musicStyle"
type="text"
required
maxLength={255}
placeholder="Your full name"
placeholder="e.g. House, Pop, Hip-Hop"
style={{ width: "100%", marginTop: "0.3rem" }}
/>
</div>
<div>
<label htmlFor="age" className="muted">
Age
<div style={{ marginTop: "1rem" }}>
<label htmlFor="experience" className="muted">
Experience <span className="muted">(optional)</span>
</label>
<input
id="age"
name="age"
type="number"
required
min={13}
max={120}
placeholder="18"
style={{ width: "100%", marginTop: "0.3rem" }}
<textarea
id="experience"
name="experience"
rows={3}
placeholder="Any prior DJ or hosting experience?"
style={{ width: "100%", marginTop: "0.3rem", resize: "vertical" }}
/>
</div>
</div>
<div style={{ marginTop: "1rem" }}>
<label htmlFor="availability" className="muted">
Availability
</label>
<textarea
id="availability"
name="availability"
required
rows={3}
placeholder="Which days and times can you broadcast?"
style={{ width: "100%", marginTop: "0.3rem", resize: "vertical" }}
/>
</div>
<div style={{ marginTop: "1rem" }}>
<label htmlFor="motivation" className="muted">
Motivation
</label>
<textarea
id="motivation"
name="motivation"
required
rows={4}
placeholder="Why do you want to join the radio team?"
style={{ width: "100%", marginTop: "0.3rem", resize: "vertical" }}
/>
</div>
<div style={{ marginTop: "1rem" }}>
<label htmlFor="musicStyle" className="muted">
Music style
</label>
<input
id="musicStyle"
name="musicStyle"
type="text"
maxLength={255}
placeholder="e.g. House, Pop, Hip-Hop"
style={{ width: "100%", marginTop: "0.3rem" }}
/>
</div>
<div style={{ marginTop: "1rem" }}>
<label htmlFor="experience" className="muted">
Experience <span className="muted">(optional)</span>
</label>
<textarea
id="experience"
name="experience"
rows={3}
placeholder="Any prior DJ or hosting experience?"
style={{ width: "100%", marginTop: "0.3rem", resize: "vertical" }}
/>
</div>
<div style={{ marginTop: "1rem" }}>
<label htmlFor="motivation" className="muted">
Motivation
</label>
<textarea
id="motivation"
name="motivation"
required
rows={4}
placeholder="Why do you want to join the radio team?"
style={{ width: "100%", marginTop: "0.3rem", resize: "vertical" }}
/>
</div>
<button type="submit" className="btn btn-primary" style={{ marginTop: "1.25rem" }}>
Submit application
</button>
</form>
<button type="submit" className="btn btn-primary" style={{ marginTop: "1.25rem" }}>
Submit application
</button>
</form>
</ContentCard>
</main>
);
}