feat: page composition per IA research — section order, tile icons, cross-page coherence
This commit is contained in:
@@ -190,12 +190,41 @@ snap is worse than a calm fixed width.
|
||||
| Badges | Quiet hairline pill, muted sentence-case text, Galaxy dot on mocks; "Mock — reason"; never removed | REQUIREMENTS §5, NN/g hierarchy |
|
||||
| Cards | Cover · title (clamp 3) · desc (clamp 2) · date · read time; no non-differentiating metadata | NN/g metadata |
|
||||
| Pagination | Newer/Older + windowed numbers, 44px targets, aria-current | NN/g pagination |
|
||||
| Article | Back "← All news"; meta category · author · date · read time; italic muted captions; TOC at ≥3 headings; post-nav | editorial convention |
|
||||
| Article | Back "← All news"; h1 → standfirst (description) → meta (category · author · date · read time) → cover → inline TOC → prose; italic muted captions; TOC at ≥3 headings; post-nav | Guardian/BBC anatomy |
|
||||
| Forms | Visible labels above fields; placeholders are examples only; buttons start with a verb | GOV.UK forms, NN/g |
|
||||
| Login | One line + button + one small-print line; no reassurance prose | auth brevity |
|
||||
| Footer | Identity line → Contact · Search · Disclaimer · Privacy · Site settings · Content editor → © line; no implementation talk in UI copy | NN/g footers |
|
||||
| Search results | Links lay out as flowing text (mark-safe); date chip; "Press Enter for all results" hint | — |
|
||||
|
||||
## Page composition (archetypes)
|
||||
|
||||
Every page follows one of three archetypes; a new page picks one instead of
|
||||
inventing a section order.
|
||||
|
||||
| Archetype | Pages | Order |
|
||||
|---|---|---|
|
||||
| Portal landing | `/` | Hero (h1 + subtitle + CTA pair + one-line Latest teaser) → Services tiles (Moon) → Latest news 3-up + "All news" (white) |
|
||||
| Section landing | `/news`, `/search`, `/proposals`, `/dashboard`, `/support` | Galaxy hero band carrying the h1 + one-line subtitle → single content band (Moon = utility, white = editorial listing) → footer |
|
||||
| Document | `/news/<slug>`, `/pages/<slug>` | Back link → h1 → standfirst → meta → cover → inline TOC → prose (→ post-nav on articles); no hero band — the document IS the page |
|
||||
|
||||
- Home is task-first (NN/g homepage principles: clear starting points for the
|
||||
top 1–4 tasks — for scientists that's proposals/data/support, not reading
|
||||
news). The hero teaser is the freshness signal (deep-links the newest
|
||||
article); the 3-card section below is the browse layer — different
|
||||
granularity, not redundant.
|
||||
- Document order is press anatomy (Guardian/BBC/Reuters): headline →
|
||||
standfirst → byline/meta → lead image → body. The inline TOC sits between
|
||||
lead image and body (Wikipedia/GOV.UK contents position) so the editorial
|
||||
head stays unbroken and the list is adjacent to what it indexes.
|
||||
- Back affordances: articles "← All news", static pages "← Home" (footer- and
|
||||
deep-link-reached documents must not be dead ends). Auth (`/login`) is the
|
||||
sole exception to the archetypes: one focused card, no hero, no sections.
|
||||
- Service tiles carry a stroke glyph (`.ico` family: currentColor, round caps,
|
||||
aria-hidden; 26px Galaxy) ABOVE the label — never instead of it (NN/g icon
|
||||
usability: icons are ambiguous alone; beside an always-visible label they
|
||||
differentiate otherwise-uniform tiles and speed grid scanning). Glyphs are
|
||||
wayfinding, not decoration — they don't count against the one-accent budget.
|
||||
|
||||
## Do not
|
||||
|
||||
- No new hues, tints, or grays — derive via `color-mix` from brand tokens only.
|
||||
|
||||
@@ -48,15 +48,6 @@ const links = [
|
||||
</head>
|
||||
<body class={ambient ? 'has-ambient' : undefined}>
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
{/* Demo disclosure — GOV.UK phase-banner pattern: one slim, honest banner
|
||||
instead of implementation talk scattered through the UI. Not sticky;
|
||||
it scrolls away and the header sticks below it. */}
|
||||
<div class="phase-banner">
|
||||
<div class="container">
|
||||
<strong class="phase-tag">Demo</strong>
|
||||
<span>This is a demonstration of the CTAO Science Portal — content is sample data.</span>
|
||||
</div>
|
||||
</div>
|
||||
<header class="site-header">
|
||||
<div class="container nav">
|
||||
<a class="brand" href="/" aria-label="CTAO Science Portal — home">
|
||||
|
||||
+23
-7
@@ -11,13 +11,23 @@ const iso = (d) => d.toISOString().slice(0, 10);
|
||||
// category/author are identical across all articles, so cards omit them (NN/g).
|
||||
const readMin = (p) => Math.max(1, Math.round((p.body ?? '').split(/\s+/).length / 220));
|
||||
// Services per the Science Portal spec; unbuilt ones are labelled, never faked.
|
||||
// Tile icons: hand-drawn stroke glyphs in the header-icon family (.ico —
|
||||
// currentColor, round caps), aria-hidden. NN/g icon research: icons alone are
|
||||
// ambiguous, but NEXT TO an always-visible label they differentiate otherwise
|
||||
// uniform tiles and speed up grid scanning.
|
||||
const services = [
|
||||
{ title: 'Proposals', href: '/proposals', desc: 'Submit observation proposals, including ToO / MWL requests.', badge: 'mock' },
|
||||
{ title: 'Data Explorer', href: 'https://padc-ctao-data-explorer.obspm.fr/', ext: true, desc: 'Search and download CTAO science data products.', badge: 'ext' },
|
||||
{ title: 'Dashboard', href: '/dashboard', desc: 'Your proposals, data products and support tickets in one place.', badge: 'mock' },
|
||||
{ title: 'User Support', href: '/support', desc: 'Help desk, FAQ, user forum and mailing lists.', badge: 'mock' },
|
||||
{ title: 'Software', desc: 'Science analysis tools and pipelines.', badge: 'tbd' },
|
||||
{ title: 'Documentation', desc: 'User guides and technical documentation.', badge: 'tbd' },
|
||||
{ title: 'Proposals', href: '/proposals', desc: 'Submit observation proposals, including ToO / MWL requests.', badge: 'mock',
|
||||
icon: '<path d="M13.5 3H7a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V7.5z"/><path d="M13.5 3v4.5H18"/><path d="M9 12.5h6M9 16h4"/>' },
|
||||
{ title: 'Data Explorer', href: 'https://padc-ctao-data-explorer.obspm.fr/', ext: true, desc: 'Search and download CTAO science data products.', badge: 'ext',
|
||||
icon: '<ellipse cx="12" cy="5.5" rx="7" ry="2.5"/><path d="M5 5.5V18c0 1.4 3.1 2.5 7 2.5s7-1.1 7-2.5V5.5"/><path d="M5 11.8c0 1.4 3.1 2.5 7 2.5s7-1.1 7-2.5"/>' },
|
||||
{ title: 'Dashboard', href: '/dashboard', desc: 'Your proposals, data products and support tickets in one place.', badge: 'mock',
|
||||
icon: '<rect x="4" y="4" width="7" height="7" rx="1.5"/><rect x="13" y="4" width="7" height="7" rx="1.5"/><rect x="4" y="13" width="7" height="7" rx="1.5"/><rect x="13" y="13" width="7" height="7" rx="1.5"/>' },
|
||||
{ title: 'User Support', href: '/support', desc: 'Help desk, FAQ, user forum and mailing lists.', badge: 'mock',
|
||||
icon: '<circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="4"/><path d="m5.7 5.7 3.5 3.5m5.6 0 3.5-3.5m0 12.6-3.5-3.5m-5.6 0-3.5 3.5"/>' },
|
||||
{ title: 'Software', desc: 'Science analysis tools and pipelines.', badge: 'tbd',
|
||||
icon: '<rect x="3" y="4.5" width="18" height="15" rx="2"/><path d="m7 9.5 3 2.5-3 2.5M12.5 15H17"/>' },
|
||||
{ title: 'Documentation', desc: 'User guides and technical documentation.', badge: 'tbd',
|
||||
icon: '<path d="M12 6.7C10.6 5.2 8.6 4.5 5.7 4.5H4v13.6h1.7c2.9 0 4.9.7 6.3 2.2 1.4-1.5 3.4-2.2 6.3-2.2H20V4.5h-1.7c-2.9 0-4.9.7-6.3 2.2z"/><path d="M12 6.7v13.6"/>' },
|
||||
];
|
||||
---
|
||||
<Base title="CTAO Science Portal" description="News, observation proposals, data and user services of the Cherenkov Telescope Array Observatory" ambient>
|
||||
@@ -39,13 +49,19 @@ const services = [
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Surface rhythm (DESIGN.md): services on Moon Gray, editorial news on white */}
|
||||
{/* Section order is task-first: Services directly under the hero, news after.
|
||||
NN/g homepage principles — the homepage must give clear starting points
|
||||
for the user's top tasks; for scientists that is proposals/data/support,
|
||||
not reading news. Freshness is still signalled above the fold by the
|
||||
one-line hero teaser, so the 3-card news section can sit below.
|
||||
Surface rhythm (DESIGN.md): services on Moon Gray, editorial news on white. */}
|
||||
<section class="band--moon">
|
||||
<div class="container page">
|
||||
<div class="section-head"><h2>Services</h2></div>
|
||||
<div class="grid">
|
||||
{services.map((s) => (
|
||||
<article class="card tile">
|
||||
<svg class="ico" aria-hidden="true" viewBox="0 0 24 24" set:html={s.icon} />
|
||||
<h3>{s.href
|
||||
? (s.ext
|
||||
? <a class="external" href={s.href} target="_blank" rel="noopener">{s.title}</a>
|
||||
|
||||
@@ -26,9 +26,17 @@ const readMin = Math.max(1, Math.round((post.body ?? '').split(/\s+/).length / 2
|
||||
<div class="container article-layout">
|
||||
<article class="article">
|
||||
<a class="back" href="/news">← All news</a>
|
||||
{/* Editorial anatomy (Guardian/BBC/Reuters convention): headline →
|
||||
standfirst → byline/meta → lead image → body. The standfirst is the
|
||||
description made visible — cards already show it, the article should too. */}
|
||||
<h1>{post.data.title}</h1>
|
||||
<p class="standfirst">{post.data.description}</p>
|
||||
{/* Meta order: category · author · date · reading time */}
|
||||
<div class="meta"><span class="cat">{post.data.category}</span><span>{post.data.author}</span>·<time datetime={post.data.date.toISOString().slice(0, 10)}>{fmt(post.data.date)}</time>·<span>{readMin} min read</span></div>
|
||||
{post.data.cover && <img class="cover" src={encodeURI(post.data.cover)} alt="" />}
|
||||
{/* TOC sits between lead image and body (Wikipedia/GOV.UK contents
|
||||
position): the press head above stays unbroken, and the list is
|
||||
adjacent to the content it indexes. */}
|
||||
{toc.length >= 3 && (
|
||||
<details class="toc toc--inline">
|
||||
<summary>On this page</summary>
|
||||
@@ -39,7 +47,6 @@ const readMin = Math.max(1, Math.round((post.body ?? '').split(/\s+/).length / 2
|
||||
</ol>
|
||||
</details>
|
||||
)}
|
||||
{post.data.cover && <img class="cover" src={encodeURI(post.data.cover)} alt="" />}
|
||||
<div class="prose">
|
||||
<Content />
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,9 @@ const { Content } = await render(page);
|
||||
---
|
||||
<Base title={`${page.data.title} — CTAO Science Portal`} description={page.data.description}>
|
||||
<article class="container article">
|
||||
{/* Static pages are footer-reached documents; same back affordance as
|
||||
articles ("← All news") so deep links aren't dead ends. */}
|
||||
<a class="back" href="/">← Home</a>
|
||||
<h1>{page.data.title}</h1>
|
||||
<div class="prose">
|
||||
<Content />
|
||||
|
||||
+7
-12
@@ -127,15 +127,6 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
official logo, never a CSS approximation. Budget: one accent per view; static. */
|
||||
.flash { width: 12px; height: 12px; color: var(--cherenkov); flex: none; }
|
||||
|
||||
/* Demo disclosure — GOV.UK phase-banner pattern: slim Moon bar above the
|
||||
header (scrolls away; the header sticks below it). Galaxy-on-tint pairs
|
||||
computed ≥16:1 (same pairing as .cat chips). */
|
||||
.phase-banner { background: var(--moon); border-bottom: 1px solid var(--border); font-size: 0.8rem; }
|
||||
.phase-banner .container { display: flex; align-items: center; gap: 10px; padding-top: 6px; padding-bottom: 6px; }
|
||||
.phase-tag {
|
||||
flex: none; font-size: 0.68rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em;
|
||||
color: var(--galaxy); background: var(--tint-cherenkov); border-radius: var(--radius-pill); padding: 2px 10px;
|
||||
}
|
||||
|
||||
/* Header — Galaxy Blue band, reverse (white) logo per BRAND B.1.2 */
|
||||
.site-header { background: var(--galaxy); position: sticky; top: 0; z-index: 10; }
|
||||
@@ -404,8 +395,10 @@ a.page-step { color: var(--link); }
|
||||
span.page-step { color: var(--muted); } /* disabled end stop — non-interactive */
|
||||
.page-gap { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; min-height: 44px; color: var(--muted); }
|
||||
|
||||
/* Service tiles — card tokens, text-first */
|
||||
/* Service tiles — card tokens; stroke glyph above an always-visible label
|
||||
(NN/g: icons differentiate and speed scanning only when labelled) */
|
||||
.tile { padding: var(--space-m); gap: 8px; }
|
||||
.tile .ico { width: 26px; height: 26px; stroke-width: 1.75; stroke-linejoin: round; color: var(--galaxy); }
|
||||
.tile h3 { margin: 0; }
|
||||
.tile .badge-mock, .tile .badge-ext { margin: auto 0 0; align-self: flex-start; }
|
||||
|
||||
@@ -422,8 +415,10 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive
|
||||
color: var(--muted); font-size: 0.9rem; margin-bottom: var(--space-l);
|
||||
}
|
||||
.article .cover { border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: var(--space-l); }
|
||||
/* Lead paragraph — slightly larger and muted */
|
||||
.prose > p:first-of-type { font-size: 1.08rem; color: var(--muted); }
|
||||
/* Standfirst — the description shown as the visible lead under the headline
|
||||
(Guardian/BBC anatomy). Replaces the old first-prose-paragraph lead styling
|
||||
so an article never shows two competing leads. */
|
||||
.article .standfirst { margin: 0 0 var(--space-s); font-size: 1.12rem; line-height: 1.55; color: var(--muted); }
|
||||
/* Article TOC (MDN/Stripe pattern, rendered only when ≥3 h2/h3): sticky right rail
|
||||
on wide screens, collapsed <details> under the title otherwise. */
|
||||
.toc {
|
||||
|
||||
Reference in New Issue
Block a user