107 lines
6.3 KiB
Plaintext
107 lines
6.3 KiB
Plaintext
---
|
||
import { getCollection } from 'astro:content';
|
||
import Base from '../layouts/Base.astro';
|
||
|
||
const posts = (await getCollection('news', ({ data }) => !data.draft))
|
||
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
|
||
.slice(0, 3);
|
||
const fmt = (d) => new Intl.DateTimeFormat('en-GB', { dateStyle: 'long' }).format(d);
|
||
const iso = (d) => d.toISOString().slice(0, 10);
|
||
// Reading time from the Markdown body (~220 wpm) — differentiating card metadata;
|
||
// 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. Tiles carry no status chrome — honesty
|
||
// lives at the interaction point (REQUIREMENTS §5): each target page opens with
|
||
// its own whisper badge. Planned services stay in the grid but subdued (muted,
|
||
// no link) with availability folded into the description text.
|
||
// 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.',
|
||
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.',
|
||
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.',
|
||
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.',
|
||
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"/>' },
|
||
// Two subdued planned tiles complete the 2×3 grid (an orphan 4th tile in a
|
||
// 3-col grid reads broken); the remaining TBD services stay on the quiet line.
|
||
{ title: 'Software', planned: true, desc: 'Science analysis tools and pipelines — planned.',
|
||
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', planned: true, desc: 'User guides and technical documentation — planned.',
|
||
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"/>' },
|
||
];
|
||
const planned = ['Scheduling', 'Science alerts'];
|
||
---
|
||
<Base title="CTAO Science Portal" description="News, observation proposals, data and user services of the Cherenkov Telescope Array Observatory" ambient>
|
||
{/* Photographic hero: LST-1 under the La Palma night sky (copied from the
|
||
content library to /brand/hero.jpg) beneath the Galaxy scrim — text
|
||
contrast computed worst-case in DESIGN.md. Three elements only:
|
||
headline, brand subtitle, CTA pair (Apple hero restraint). */}
|
||
<section class="hero-band">
|
||
<div class="band-bg" aria-hidden="true"></div>
|
||
<div class="container hero">
|
||
<div class="eyebrow">Cherenkov Telescope Array Observatory</div>
|
||
<h1>CTAO Science Portal</h1>
|
||
<p>Exploring the Universe at the Highest Energies</p>
|
||
{/* Hero actions = the two REAL things a logged-out visitor can do today:
|
||
news (SPEC §3.1 lists general information/announcements FIRST; §3.3.1
|
||
"displays the main information"; calls for proposals arrive VIA news)
|
||
and the external Data Explorer. Proposals stays in nav + tiles — a
|
||
mock doesn't earn hero billing. Search lives in the header. */}
|
||
<div class="hero-cta">
|
||
<a class="btn" href="/news">Browse news & announcements</a>
|
||
<a class="btn btn--ghost external" href="https://padc-ctao-data-explorer.obspm.fr/" target="_blank" rel="noopener">Explore the data</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* 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={s.planned ? 'card tile tile--planned' : 'card tile'}>
|
||
<svg class="ico" aria-hidden="true" viewBox="0 0 24 24" set:html={s.icon} />
|
||
<h3>{s.planned
|
||
? s.title
|
||
: (s.ext
|
||
? <a class="external" href={s.href} target="_blank" rel="noopener">{s.title}</a>
|
||
: <a href={s.href}>{s.title}</a>)}</h3>
|
||
<p class="desc">{s.desc}</p>
|
||
</article>
|
||
))}
|
||
</div>
|
||
<p class="planned-note">Planned services: {planned.join(' · ')}</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="container page">
|
||
<div class="section-head">
|
||
<h2>Latest news</h2>
|
||
<a class="more" href="/news">All news →</a>
|
||
</div>
|
||
<div class="grid">
|
||
{posts.map((post) => (
|
||
<article class="card">
|
||
{post.data.cover && <img class="cover" src={encodeURI(post.data.cover)} alt="" loading="lazy" />}
|
||
<div class="body">
|
||
<h3><a href={`/news/${post.id}`}>{post.data.title}</a></h3>
|
||
<p class="desc">{post.data.description}</p>
|
||
<div class="meta"><time datetime={iso(post.data.date)}>{fmt(post.data.date)}</time> · {readMin(post)} min read</div>
|
||
</div>
|
||
</article>
|
||
))}
|
||
</div>
|
||
</section>
|
||
</Base>
|