Skip to content

Commit 1002b51

Browse files
committed
Add shared and TDA component gallery
1 parent afc7193 commit 1002b51

10 files changed

Lines changed: 936 additions & 10 deletions

File tree

content/meta/code-architecture.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ order: 1
77
status: revised
88
created: 2026-08-08
99
revised: 2026-08-08
10-
revision: 2
10+
revision: 3
1111
tags:
1212
- meta
1313
---
@@ -135,6 +135,14 @@ properties the kit names but does not ship), and the domain components in `src/c
135135
stylesheet also has to point Tailwind at the package, because source detection does not look inside
136136
`node_modules`, and the built-output test is what checks it did.
137137

138+
`site/src/pages/gallery/` is the visual acceptance surface for that boundary. It imports every case
139+
from `@galaxy-foundry/site-kit/specimens` and renders the shared components through this instance's
140+
theme; package-declared `isolated` and `document` surfaces receive generated standalone routes.
141+
Local specimen groups place the filtration hero, persistence divider, point-cloud fingerprint,
142+
topology breadcrumb, and every declared reference kind beside the shared cases without moving
143+
their domain vocabulary into the package. Built-output tests require complete shared and local
144+
coverage, every standalone route, the gallery's design-index link, and the intended search policy.
145+
138146
The site is a pure reader. It validates and renders source; it does not mutate content, author
139147
notes, or cast artifacts. The only client-side code is progressive enhancement — the homepage
140148
filtration control — and there is no UI framework.
@@ -179,6 +187,7 @@ aspirational or the checkout is broken.
179187
| companion measurement | `site/src/lib/companions.ts` |
180188
| presentation registries | `site/src/lib/tags.ts`, `design-records.ts`, `detail-routes.ts` |
181189
| shell composition and identity | `site/src/layouts/Base.astro`, `site/src/lib/site-identity.ts` |
190+
| shared and local visual acceptance | `site/src/pages/gallery/`, `site/src/lib/gallery.ts` |
182191
| domain furniture | `site/src/components/`, `site/src/lib/motifs.ts` |
183192
| routes | `site/src/pages/` |
184193
| corpus and contract tests | `site/tests/` |
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
---
2+
import { specimenPath, type Specimen, type SpecimenGroup } from '@galaxy-foundry/site-kit/specimens';
3+
4+
interface Props {
5+
group: SpecimenGroup;
6+
specimen: Specimen;
7+
origin: 'shared' | 'tda';
8+
}
9+
10+
const { group, specimen, origin } = Astro.props;
11+
const anchor = specimenPath(group, specimen).replace('/', '--');
12+
---
13+
14+
<article
15+
id={anchor}
16+
class="gallery-specimen"
17+
data-gallery-component={group.component}
18+
data-gallery-origin={origin}
19+
>
20+
<header class="gallery-specimen-copy">
21+
<span>{origin === 'shared' ? 'Shared case' : 'TDA case'}</span>
22+
<h3><a href={`#${anchor}`}>{specimen.name}</a></h3>
23+
<p>{specimen.why}</p>
24+
<code>{specimenPath(group, specimen)}</code>
25+
</header>
26+
<div class="gallery-specimen-stage bg-grid">
27+
<slot />
28+
</div>
29+
</article>
30+
31+
<style>
32+
.gallery-specimen {
33+
display: grid;
34+
grid-template-columns: minmax(12rem, 0.34fr) minmax(0, 1fr);
35+
gap: clamp(1.25rem, 4vw, 3.5rem);
36+
padding: clamp(1.5rem, 4vw, 3rem) 0;
37+
border-top: 1px solid var(--color-border-subtle);
38+
scroll-margin-top: 6rem;
39+
}
40+
41+
.gallery-specimen-copy {
42+
align-self: start;
43+
position: sticky;
44+
top: 5.5rem;
45+
}
46+
47+
.gallery-specimen-copy > span {
48+
color: var(--color-brand);
49+
font-family: var(--font-mono);
50+
font-size: 0.66rem;
51+
font-weight: 600;
52+
letter-spacing: 0.12em;
53+
text-transform: uppercase;
54+
}
55+
56+
.gallery-specimen-copy h3 {
57+
margin: 0.45rem 0 0.7rem;
58+
font-family: var(--font-serif);
59+
font-size: clamp(1.35rem, 2.5vw, 1.9rem);
60+
font-variation-settings: 'opsz' 28;
61+
font-weight: 580;
62+
letter-spacing: -0.035em;
63+
line-height: 1.08;
64+
}
65+
66+
.gallery-specimen-copy h3 a {
67+
color: var(--color-text-primary);
68+
text-decoration: none;
69+
}
70+
71+
.gallery-specimen-copy h3 a:hover {
72+
color: var(--color-link);
73+
}
74+
75+
.gallery-specimen-copy p {
76+
margin: 0;
77+
color: var(--color-text-secondary);
78+
font-size: 0.9rem;
79+
line-height: 1.6;
80+
text-wrap: pretty;
81+
}
82+
83+
.gallery-specimen-copy code {
84+
display: inline-block;
85+
margin-top: 1rem;
86+
color: var(--color-text-muted);
87+
font-family: var(--font-mono);
88+
font-size: 0.67rem;
89+
}
90+
91+
.gallery-specimen-stage {
92+
min-width: 0;
93+
overflow: hidden;
94+
border: 1px solid var(--color-border-subtle);
95+
border-radius: 0.8rem 0.8rem 2rem 0.8rem;
96+
background-color: var(--color-surface-raised);
97+
box-shadow: 0 1.2rem 3.5rem color-mix(in srgb, var(--color-chrome) 8%, transparent);
98+
padding: clamp(1rem, 2.5vw, 1.75rem);
99+
}
100+
101+
[data-gallery-component='SiteFooter'] .gallery-specimen-stage,
102+
[data-gallery-component='SiteHeader'] .gallery-specimen-stage,
103+
[data-gallery-component='SiteShell'] .gallery-specimen-stage,
104+
[data-gallery-component='FiltrationHero'] .gallery-specimen-stage {
105+
padding: 0;
106+
}
107+
108+
[data-gallery-component='PersistenceDivider'] .gallery-specimen-stage,
109+
[data-gallery-component='PointCloudFingerprint'] .gallery-specimen-stage,
110+
[data-gallery-component='TopologyBreadcrumb'] .gallery-specimen-stage {
111+
display: grid;
112+
min-height: 9rem;
113+
align-items: center;
114+
}
115+
116+
@media (max-width: 760px) {
117+
.gallery-specimen {
118+
grid-template-columns: 1fr;
119+
gap: 1rem;
120+
}
121+
122+
.gallery-specimen-copy {
123+
position: static;
124+
}
125+
}
126+
</style>

site/src/layouts/Base.astro

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
---
2-
import '@fontsource-variable/ibm-plex-sans/wght.css';
3-
import '@fontsource-variable/ibm-plex-sans/wght-italic.css';
4-
import '@fontsource-variable/source-serif-4/opsz.css';
5-
import '@fontsource-variable/source-serif-4/opsz-italic.css';
6-
import '@fontsource/ibm-plex-mono/latin-400.css';
7-
import '@fontsource/ibm-plex-mono/latin-500.css';
8-
import '@fontsource/ibm-plex-mono/latin-600.css';
9-
import '@fontsource/ibm-plex-mono/latin-700.css';
10-
import '../styles/global.css';
2+
import '../styles/site-theme';
113
import SiteShell from '@galaxy-foundry/site-kit/SiteShell.astro';
124
135
import { base } from '../lib/site-base';

site/src/lib/gallery-renderers.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import ContentNote from '@galaxy-foundry/site-kit/ContentNote.astro';
2+
import LicenseBadge from '@galaxy-foundry/site-kit/LicenseBadge.astro';
3+
import LicenseFileBody from '@galaxy-foundry/site-kit/LicenseFileBody.astro';
4+
import ReferenceContract from '@galaxy-foundry/site-kit/ReferenceContract.astro';
5+
import SiteFooter from '@galaxy-foundry/site-kit/SiteFooter.astro';
6+
import SiteHeader from '@galaxy-foundry/site-kit/SiteHeader.astro';
7+
import SiteShell from '@galaxy-foundry/site-kit/SiteShell.astro';
8+
import TagChips from '@galaxy-foundry/site-kit/TagChips.astro';
9+
import type { AstroComponentFactory } from 'astro/runtime/server/index.js';
10+
11+
import FiltrationHero from '../components/FiltrationHero.astro';
12+
import PersistenceDivider from '../components/PersistenceDivider.astro';
13+
import PointCloudFingerprint from '../components/PointCloudFingerprint.astro';
14+
import TopologyBreadcrumb from '../components/TopologyBreadcrumb.astro';
15+
import { ALL_SPECIMENS } from './gallery';
16+
17+
export const GALLERY_RENDERERS: Record<string, AstroComponentFactory> = {
18+
ContentNote,
19+
LicenseBadge,
20+
LicenseFileBody,
21+
ReferenceContract,
22+
SiteFooter,
23+
SiteHeader,
24+
SiteShell,
25+
TagChips,
26+
FiltrationHero,
27+
PersistenceDivider,
28+
PointCloudFingerprint,
29+
TopologyBreadcrumb,
30+
};
31+
32+
const unrenderable = ALL_SPECIMENS.filter((group) => !GALLERY_RENDERERS[group.component]);
33+
if (unrenderable.length > 0) {
34+
throw new Error(
35+
`gallery has no renderer for: ${unrenderable.map((group) => group.component).join(', ')}`,
36+
);
37+
}

site/src/lib/gallery.ts

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import { contractKeys } from '@galaxy-foundry/reference-contract';
2+
import type { ReferenceContractProps } from '@galaxy-foundry/site-kit';
3+
import {
4+
SPECIMENS,
5+
type Specimen,
6+
type SpecimenGroup,
7+
} from '@galaxy-foundry/site-kit/specimens';
8+
9+
import { contentReader } from './content-reader';
10+
import { referenceContract as loadReferenceContract } from './reference-contract';
11+
import { base } from './site-base';
12+
13+
const referenceContract = loadReferenceContract();
14+
15+
const kindSpecimen = (kind: string): Specimen<ReferenceContractProps> => {
16+
const term = referenceContract.kinds[kind];
17+
return {
18+
id: kind,
19+
name: term?.label ?? kind,
20+
why:
21+
term?.description ??
22+
`The ${kind} reference kind under this Foundry's palette and fallback accent.`,
23+
props: {
24+
contract: referenceContract,
25+
references: [
26+
{
27+
kind,
28+
ref: `[[gallery-${kind}]]`,
29+
used_at: 'runtime',
30+
load: 'upfront',
31+
mode: 'verbatim',
32+
evidence: 'corpus-observed',
33+
},
34+
],
35+
},
36+
};
37+
};
38+
39+
export const TDA_KIND_SPECIMENS: SpecimenGroup<ReferenceContractProps> = {
40+
id: 'tda-reference-kinds',
41+
component: 'ReferenceContract',
42+
importPath: '@galaxy-foundry/site-kit/ReferenceContract.astro',
43+
summary:
44+
'Every reference kind this Foundry declares, derived from its contract so a new kind cannot arrive unseen.',
45+
surface: 'inline',
46+
specimens: contractKeys(referenceContract, 'kinds').map(kindSpecimen),
47+
};
48+
49+
export const FILTRATION_HERO_SPECIMENS: SpecimenGroup<{ noteCount: number }> = {
50+
id: 'tda-filtration-hero',
51+
component: 'FiltrationHero',
52+
importPath: '../components/FiltrationHero.astro',
53+
summary:
54+
'The interactive frontispiece: a point cloud becomes a complex and leaves one persistent loop.',
55+
surface: 'isolated',
56+
specimens: [
57+
{
58+
id: 'stable-loop',
59+
name: 'Structure across scale',
60+
why:
61+
'The range control makes filtration tangible while the copy connects multiscale structure to the Foundry workflow.',
62+
props: { noteCount: contentReader.noteTargets().length },
63+
},
64+
],
65+
};
66+
67+
export const PERSISTENCE_DIVIDER_SPECIMENS: SpecimenGroup<{ seed: string }> = {
68+
id: 'tda-persistence-divider',
69+
component: 'PersistenceDivider',
70+
importPath: '../components/PersistenceDivider.astro',
71+
summary:
72+
'A deterministic barcode used as punctuation between conceptual sections.',
73+
surface: 'inline',
74+
specimens: [
75+
{
76+
id: 'section-punctuation',
77+
name: 'Persistent section break',
78+
why:
79+
'One interval receives the persistent accent, turning a divider into domain-specific hierarchy without adding prose.',
80+
props: { seed: 'gallery:persistence-divider' },
81+
},
82+
],
83+
};
84+
85+
export const POINT_CLOUD_SPECIMENS: SpecimenGroup<{ seed: string }> = {
86+
id: 'tda-point-cloud-fingerprint',
87+
component: 'PointCloudFingerprint',
88+
importPath: '../components/PointCloudFingerprint.astro',
89+
summary:
90+
'Seeded geometric marginalia that gives each surface a stable visual fingerprint.',
91+
surface: 'inline',
92+
specimens: [
93+
{
94+
id: 'stable-fingerprint',
95+
name: 'Seeded point cloud',
96+
why:
97+
'The same semantic seed always yields the same points, neighborhood edges, and highlighted loop.',
98+
props: { seed: 'gallery:point-cloud-fingerprint' },
99+
},
100+
],
101+
};
102+
103+
export const TOPOLOGY_BREADCRUMB_SPECIMENS: SpecimenGroup<{
104+
href: string;
105+
label: string;
106+
current: string;
107+
seed: string;
108+
}> = {
109+
id: 'tda-topology-breadcrumb',
110+
component: 'TopologyBreadcrumb',
111+
importPath: '../components/TopologyBreadcrumb.astro',
112+
summary:
113+
'Back navigation drawn as connected nodes, paired with a deterministic point-cloud signature.',
114+
surface: 'inline',
115+
specimens: [
116+
{
117+
id: 'method-detail',
118+
name: 'Connected reading path',
119+
why:
120+
'The ordinary collection-to-note relationship is expressed as a tiny graph without weakening breadcrumb semantics.',
121+
props: {
122+
href: `${base}/methods/`,
123+
label: 'Methods',
124+
current: 'Persistent homology',
125+
seed: 'gallery:topology-breadcrumb',
126+
},
127+
},
128+
],
129+
};
130+
131+
export const TDA_SPECIMENS: readonly SpecimenGroup[] = [
132+
TDA_KIND_SPECIMENS,
133+
FILTRATION_HERO_SPECIMENS,
134+
PERSISTENCE_DIVIDER_SPECIMENS,
135+
POINT_CLOUD_SPECIMENS,
136+
TOPOLOGY_BREADCRUMB_SPECIMENS,
137+
];
138+
139+
export const ALL_SPECIMENS: readonly SpecimenGroup[] = [...SPECIMENS, ...TDA_SPECIMENS];
140+
141+
const groupIds = ALL_SPECIMENS.map((group) => group.id);
142+
if (new Set(groupIds).size !== groupIds.length) {
143+
throw new Error('gallery specimen group ids must be unique across shared and TDA groups');
144+
}
145+
146+
export const specimenOrigin = (group: SpecimenGroup): 'shared' | 'tda' =>
147+
TDA_SPECIMENS.some((candidate) => candidate.id === group.id) ? 'tda' : 'shared';

0 commit comments

Comments
 (0)