From affa3262efbb2372c4bc24f99ffd983ef06a74e7 Mon Sep 17 00:00:00 2001 From: ctao Date: Sat, 25 Jul 2026 18:33:06 +0200 Subject: [PATCH] fix: search scroll jump (atomic list swap, no clear-before-await); services grid back to 6 tiles (2 subdued planned) + planned line for the rest --- public/search-client.js | 21 +++++++++++++-------- src/pages/index.astro | 20 +++++++++++++------- src/styles/global.css | 4 +++- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/public/search-client.js b/public/search-client.js index 0c4bfcf..5315bc2 100644 --- a/public/search-client.js +++ b/public/search-client.js @@ -69,29 +69,31 @@ // the newest articles from the same index. async function idle() { if (input.value.trim().length >= 2) return; - list.innerHTML = ''; + // Build off-DOM, swap atomically — clearing before the await shrinks the + // page mid-flight and the browser clamps the scroll position ("jumps up"). + const frag = document.createDocumentFragment(); const r = recents(); if (r.length) { - list.append(label('Recent')); - for (const term of r) list.append(row([term], '/search?q=' + encodeURIComponent(term), term)); + frag.append(label('Recent')); + for (const term of r) frag.append(row([term], '/search?q=' + encodeURIComponent(term), term)); } const fresh = (await ensureIndex()).slice(0, Math.max(1, 5 - r.length)); if (input.value.trim().length >= 2) return; // typed meanwhile — run() owns the list - list.append(label('Latest news')); + frag.append(label('Latest news')); for (const p of fresh) { const li = row([p.title], '/news/' + encodeURIComponent(p.slug)); const small = document.createElement('small'); small.textContent = p.date; li.append(small); - list.append(li); + frag.append(li); } + list.replaceChildren(frag); hint(); status.textContent = opts.hint || (r.length ? 'Showing recent searches and latest news' : 'Showing latest news'); } async function run() { const q = input.value.trim().toLowerCase(); - if (q.length < 2) { list.innerHTML = ''; idle(); return; } - list.innerHTML = ''; + if (q.length < 2) { list.replaceChildren(); idle(); return; } const idx = await ensureIndex(); const hits = idx .filter((p) => (p.title + ' ' + p.description + ' ' + p.category).toLowerCase().includes(q)) @@ -100,13 +102,16 @@ status.textContent = hits.length ? hits.length + ' ' + unit + (hits.length === 1 ? '' : 's') + ' for “' + input.value.trim() + '”' : 'No results for “' + input.value.trim() + '” — try a shorter or different term.'; + // Off-DOM build + atomic swap (no transient page-height collapse) + const frag = document.createDocumentFragment(); for (const p of hits) { const li = row(highlight(p.title, q), '/news/' + encodeURIComponent(p.slug)); const small = document.createElement('small'); small.textContent = p.date; li.append(small); - list.append(li); + frag.append(li); } + list.replaceChildren(frag); hint(); } input.addEventListener('input', () => { clearTimeout(timer); timer = setTimeout(run, 150); }); diff --git a/src/pages/index.astro b/src/pages/index.astro index b815b8a..bde48cd 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -27,10 +27,14 @@ const services = [ icon: '' }, { title: 'User Support', href: '/support', desc: 'Help desk, FAQ, user forum and mailing lists.', icon: '' }, + // 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: '' }, + { title: 'Documentation', planned: true, desc: 'User guides and technical documentation — planned.', + icon: '' }, ]; -// Planned services (SPEC §3.1/§3.3.2, all TBD): one quiet line instead of dead -// tiles — a grid should not ship tiles that do nothing (Apple-lens audit). -const planned = ['Software', 'Documentation', 'Scheduling', 'Science alerts']; +const planned = ['Scheduling', 'Science alerts']; --- {/* Photographic hero: LST-1 under the La Palma night sky (copied from the @@ -66,11 +70,13 @@ const planned = ['Software', 'Documentation', 'Scheduling', 'Science alerts'];

Services

{services.map((s) => ( -
+ ))} diff --git a/src/styles/global.css b/src/styles/global.css index 0a053e7..b26189a 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -468,7 +468,9 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive .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; } -/* Planned services — one quiet line under the grid, never dead tiles */ +/* Planned tiles complete the grid rows but stay subdued (no link, muted) */ +.tile--planned :is(h3, .ico) { color: var(--muted); } +/* Remaining planned services — one quiet line under the grid */ .planned-note { color: var(--muted); font-size: var(--fs-s); margin: var(--space-m) 0 0; } /* Article — 70ch column; on ≥1200px a sticky "On this page" rail sits to the right */