Match the site to the approved designs

Denser star field, the page nebula, a favicon package, the filament banner
without its box, the About portrait, Kashi and tea photos and Scorpius, the
Store's own header, a header logo glow, a resume PDF that fills its page,
one divider on the Library and Shelf, star-chart art for coverless
favorites, Shelf Players, Play time and blog filters with a Show all fold,
make kind pills on craft pages, and full-width closing bands.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
This commit is contained in:
Claude
2026-10-12 03:33:15 +00:00
parent 3f6167455d
commit 151bed230a
45 changed files with 671 additions and 166 deletions
@@ -1,9 +1,10 @@
---
/**
* Greg's portrait in a gold frame. No portrait file exists yet, so the
* star-chart art stands in; pass `src` once there is one.
* Greg's portrait in a gold frame, from the Page text note's `portrait`.
* Without one, or if it fails to load, the star-chart art stands in.
*/
import GiltCorners from "@gk/ui/components/GiltCorners.astro";
import Star from "@gk/ui/components/Star.astro";
import StarChartArt from "@gk/ui/components/StarChartArt.astro";
import type { SealName } from "@gk/ui/components/seals.ts";
@@ -20,6 +21,8 @@ const { variant = "hero", src, alt = "Greg Kilmer", seal = "transmutation", clas
<figure class:list={["portrait", variant, className]}>
<StarChartArt seal={seal} ratio={variant === "hero" ? "188 / 228" : "auto"} src={src} alt={alt} class="art" />
{variant === "panel" && <GiltCorners inset={4} size={30} />}
{variant === "hero" && <Star size={34} class="spark tl" />}
{variant === "hero" && <Star size={24} class="spark br" />}
{!src && <figcaption class="gk-visually-hidden">Portrait coming soon</figcaption>}
</figure>
@@ -38,6 +41,20 @@ const { variant = "hero", src, alt = "Greg Kilmer", seal = "transmutation", clas
.hero :global(.art) {
border-radius: var(--gk-radius);
}
.hero :global(.photo) {
object-position: 50% 20%;
}
.hero :global(.spark) {
position: absolute;
}
.hero :global(.tl) {
left: -17px;
top: -17px;
}
.hero :global(.br) {
right: -12px;
bottom: -12px;
}
.panel {
width: 100%;
padding: 10px;
@@ -50,4 +67,7 @@ const { variant = "hero", src, alt = "Greg Kilmer", seal = "transmutation", clas
width: 100%;
height: 320px;
}
.panel :global(.photo) {
object-position: 50% 25%;
}
</style>
@@ -1,9 +1,11 @@
---
/**
* The favorites constellation: round covers strung on a dotted gold line,
* each linking to its row in the list.
* each linking to its row in the list. A favorite without a cover gets
* star-chart art in its circle.
*/
import Star from "@gk/ui/components/Star.astro";
import StarChartArt from "@gk/ui/components/StarChartArt.astro";
import TickScale from "@gk/ui/components/TickScale.astro";
import { mediaSrc } from "../../lib/site.ts";
import type { Item } from "../../lib/library.ts";
@@ -35,7 +37,7 @@ const points = items.map((_, i) => `${(((i + 0.5) / n) * 1000).toFixed(1)},${lif
items.map((item, i) => (
<li style={`--lift:${lift[i % lift.length]}px`}>
<a href={`#${item.slug}`}>
<img src={mediaSrc(item.data.cover)} alt="" width="80" height="80" decoding="async" />
<StarChartArt class="orb" ratio="1 / 1" seal="zodiac" src={mediaSrc(item.data.cover)} />
<span>{item.title}</span>
</a>
</li>
@@ -104,18 +106,32 @@ const points = items.map((_, i) => `${(((i + 0.5) / n) * 1000).toFixed(1)},${lif
color: var(--gk-text);
text-decoration: none;
}
img {
a :global(.orb) {
flex: none;
width: 80px;
height: 80px;
border-radius: 50%;
object-fit: cover;
background: var(--gk-midnight);
box-shadow:
0 0 0 2px var(--gk-gold),
0 0 22px rgba(201, 162, 74, 0.45);
transition: box-shadow 0.2s;
}
a:hover img {
a :global(.orb .mat) {
display: none;
}
a :global(.orb .seal) {
width: 54px;
height: 54px;
opacity: 0.8;
}
a :global(.orb .photo) {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
a:hover :global(.orb) {
box-shadow:
0 0 0 2px var(--gk-gold-bright),
0 0 30px rgba(201, 162, 74, 0.7);
@@ -137,7 +153,7 @@ const points = items.map((_, i) => `${(((i + 0.5) / n) * 1000).toFixed(1)},${lif
li {
padding-top: 0;
}
img {
a :global(.orb) {
width: 64px;
height: 64px;
}
@@ -11,7 +11,7 @@ import StarChartArt from "@gk/ui/components/StarChartArt.astro";
import StatusPill from "@gk/ui/components/StatusPill.astro";
import StatusChip from "../StatusChip.astro";
import { formatDate, mediaSrc, type SiteIndex } from "../../lib/site.ts";
import { gamePlayers, gamePlayTime, type Game } from "../../lib/library.ts";
import { gamePlayers, gamePlayTime, minutesOf, playersOf, type Game } from "../../lib/library.ts";
interface Props {
game: Game;
@@ -24,6 +24,8 @@ const plays = d.howItPlays ?? [];
const status = site.statusFor(game);
// Players and play time sync from BoardGameGeek; nothing shows until they have.
const facts = [gamePlayers(game), gamePlayTime(game)].filter(Boolean);
const seats = playersOf(game);
const hasPost = site.backlinks(game, { type: "post" }).length > 0;
---
<li
id={game.slug}
@@ -34,6 +36,9 @@ const facts = [gamePlayers(game), gamePlayTime(game)].filter(Boolean);
data-f={d.favorite ? "1" : undefined}
data-lp={d.lastPlayed}
data-c={d.created}
data-pl={seats?.join("-")}
data-t={minutesOf(game)}
data-b={hasPost ? "1" : undefined}
hidden={hidden}
>
<Card as="div" class="game-card">
@@ -1,5 +1,8 @@
---
/** The closing band on a world page: a line, a note and one or two buttons. */
/**
* The closing band on a world page: a full-width strip with a line, a note and
* one or two buttons, like the one on Work.
*/
interface Props {
title: string;
note?: string;
@@ -7,25 +10,32 @@ interface Props {
const { title, note } = Astro.props;
---
<aside class="cta" aria-label={title}>
<div class="words">
<p class="t">{title}</p>
{note && <p class="n">{note}</p>}
<div class="inner">
<div class="words">
<p class="t">{title}</p>
{note && <p class="n">{note}</p>}
</div>
<div class="btns"><slot /></div>
</div>
<div class="btns"><slot /></div>
</aside>
<style>
.cta {
margin-inline: calc(50% - 50vw);
margin-top: 48px;
padding: 32px 36px;
background: var(--gk-midnight);
border-top: 1px solid var(--gk-lines);
border-bottom: 1px solid var(--gk-lines);
}
.inner {
max-width: var(--gk-page-max);
margin: 0 auto;
padding: 36px var(--gk-gutter);
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 20px;
background: var(--gk-midnight);
border: 1px solid var(--gk-lines);
border-radius: var(--gk-radius);
}
.words {
display: flex;
@@ -50,8 +60,8 @@ const { title, note } = Astro.props;
gap: 12px;
}
@media (max-width: 640px) {
.cta {
padding: 24px 20px;
.inner {
padding-block: 28px;
}
}
</style>