/news: wear the shared HubBar (consistent chrome), keep BottomNav + global footer

Per the agreed direction (Codex calls): /news joins the new family without CD.
- NewsFeed gets an explicit chrome="legacy|hub" prop (never inferred from path):
  `/` passes legacy (its own Header, unchanged) and /news passes hub (the shared
  editorial HubBar). Exactly one bar renders — never HubBar + Header.
- HubBar gains a configurable `newsHref`; the /news instance links News → /news
  (active), not the live `/`. Other hub pages keep the default (News → /).
- BottomNav kept (Highlights/Latest/Play/You stay visible); no top-level Back on
  bare /news (HubBar Home returns to the hub); contextual Back on drill-in views
  is unchanged. No new footer — the global footer stays until the shared Footer step.

Known prominence shift (refinable later): Saved/Boundaries move off the top bar on
/news (reachable via account); Feedback stays via the global footer. /news still
noindex. 32 tests green; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-28 15:32:08 -04:00
parent 2fd28fa719
commit e974fc4942
4 changed files with 19 additions and 7 deletions
+6 -4
View File
@@ -2,7 +2,9 @@
// Shared editorial top bar for the hub (/home3) and its detail pages (/word, /quote, // Shared editorial top bar for the hub (/home3) and its detail pages (/word, /quote,
// /onthisday). Full horizontal nav on wide screens; a hamburger + drop panel on phones // /onthisday). Full horizontal nav on wide screens; a hamburger + drop panel on phones
// so the bar stays clean. `active` highlights the current section. // so the bar stays clean. `active` highlights the current section.
let { active = '' } = $props(); // `newsHref` is configurable so the transitional /news instance links News → /news
// (not the current `/`, which is still the live feed until cutover).
let { active = '', newsHref = '/' } = $props();
let open = $state(false); let open = $state(false);
// Close the menu when we cross into desktop width, so it can't linger open and reappear // Close the menu when we cross into desktop width, so it can't linger open and reappear
@@ -14,12 +16,12 @@
return () => mq.removeEventListener('change', sync); return () => mq.removeEventListener('change', sync);
}); });
const LINKS = [ let LINKS = $derived([
{ key: 'home', href: '/home3', label: 'Home' }, { key: 'home', href: '/home3', label: 'Home' },
{ key: 'news', href: '/', label: 'News' }, { key: 'news', href: newsHref, label: 'News' },
{ key: 'games', href: '/play', label: 'Games' }, { key: 'games', href: '/play', label: 'Games' },
{ key: 'art', href: '/art', label: 'Art' }, { key: 'art', href: '/art', label: 'Art' },
]; ]);
</script> </script>
<svelte:window on:keydown={(e) => { if (e.key === 'Escape') open = false; }} /> <svelte:window on:keydown={(e) => { if (e.key === 'Escape') open = false; }} />
+11 -1
View File
@@ -5,6 +5,7 @@
import { getJSON, postJSON } from '$lib/api.js'; import { getJSON, postJSON } from '$lib/api.js';
import * as P from '$lib/prefs.js'; import * as P from '$lib/prefs.js';
import Header from '$lib/components/Header.svelte'; import Header from '$lib/components/Header.svelte';
import HubBar from '$lib/components/HubBar.svelte';
import BottomNav from '$lib/components/BottomNav.svelte'; import BottomNav from '$lib/components/BottomNav.svelte';
import MoodNav from '$lib/components/MoodNav.svelte'; import MoodNav from '$lib/components/MoodNav.svelte';
import LanePicker from '$lib/components/LanePicker.svelte'; import LanePicker from '$lib/components/LanePicker.svelte';
@@ -19,6 +20,11 @@
import { ritualState, markBriefSeen } from '$lib/ritual.js'; import { ritualState, markBriefSeen } from '$lib/ritual.js';
import { feedBase, parseView, viewUrl } from '$lib/feednav.js'; import { feedBase, parseView, viewUrl } from '$lib/feednav.js';
// Which top bar to wear: 'legacy' = the feed's own Header (the interim `/` mount, kept
// unchanged), 'hub' = the shared editorial HubBar (the /news mount, part of the new family).
// Explicit prop, never inferred from the path.
let { chrome = 'legacy' } = $props();
let moods = $state([]); let moods = $state([]);
let topics = $state([]); let topics = $state([]);
let families = $state([]); let families = $state([]);
@@ -626,7 +632,11 @@
}); });
</script> </script>
<Header onSaved={() => (showSaved = true)} onaccount={openAccount} user={auth.user} boundariesActive={filtersOn} /> {#if chrome === 'hub'}
<HubBar active="news" newsHref="/news" />
{:else}
<Header onSaved={() => (showSaved = true)} onaccount={openAccount} user={auth.user} boundariesActive={filtersOn} />
{/if}
{#if showSignIn}<SignIn onclose={() => { showSignIn = false; if (!auth.user) pendingDigestOptIn = false; }} />{/if} {#if showSignIn}<SignIn onclose={() => { showSignIn = false; if (!auth.user) pendingDigestOptIn = false; }} />{/if}
{#if showSaved && auth.user}<SavedFlyout onclose={() => (showSaved = false)} />{/if} {#if showSaved && auth.user}<SavedFlyout onclose={() => (showSaved = false)} />{/if}
+1 -1
View File
@@ -5,4 +5,4 @@
import NewsFeed from '$lib/components/NewsFeed.svelte'; import NewsFeed from '$lib/components/NewsFeed.svelte';
</script> </script>
<NewsFeed /> <NewsFeed chrome="legacy" />
+1 -1
View File
@@ -9,4 +9,4 @@
<meta name="robots" content="noindex, follow" /> <meta name="robots" content="noindex, follow" />
</svelte:head> </svelte:head>
<NewsFeed /> <NewsFeed chrome="hub" />