5601022cf7
- New frontend/ SvelteKit static SPA (Svelte 5), served by FastAPI from frontend/build (falls back to the legacy page if unbuilt). - Calm design system: cream/sage palette, serif headlines, generous space, no urgency colors, gentle motion (respects prefers-reduced-motion). - Home screen: mood-mode nav (Today/Wonder/People Helping/Solutions/Light Only/Grounded), the daily brief as a hero + remaining four, browsable mood lanes, an explicit calm end-state, inline Not today / Less like this / Hide affordances, and device-local Calm Filters mirroring goodnews/filters.py. - Backend: moods.py + GET /api/moods (single source of truth for the modes); FilterPrefs gains max_cortisol/max_ragebait ceilings (for Light Only). - Push categorical filters (include/mute topics+flavors, ceilings) into SQL in queries.feed so low-ranked-but-matching items (e.g. discovery for Wonder) are not truncated by ranking; only avoid-terms stay a Python pass. - PWA manifest + icon (installable; offline deferred per plan). - Multi-stage Dockerfile builds the site then serves it from the API. - Tests: queries.feed categorical filters (63 total). README updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
48 lines
1.2 KiB
Svelte
48 lines
1.2 KiB
Svelte
<script>
|
|
import '../app.css';
|
|
let { children } = $props();
|
|
</script>
|
|
|
|
<header class="site">
|
|
<div class="container">
|
|
<a class="brand" href="/">good<span>News</span></a>
|
|
<p class="tagline">Calm, constructive news worth your attention — and nothing that isn't.</p>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="container">
|
|
{@render children()}
|
|
</main>
|
|
|
|
<footer class="site">
|
|
<div class="container">
|
|
goodNews · metadata & links only, no stored articles · <a href="/docs">API</a>
|
|
</div>
|
|
</footer>
|
|
|
|
<style>
|
|
header.site {
|
|
text-align: center;
|
|
padding: 38px 0 22px;
|
|
background: linear-gradient(180deg, var(--surface), var(--bg));
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
.brand {
|
|
font-family: var(--serif);
|
|
font-size: 2.1rem;
|
|
font-weight: 600;
|
|
letter-spacing: -0.02em;
|
|
}
|
|
.brand span { color: var(--sage); }
|
|
.tagline { margin: 6px 0 0; color: var(--muted); font-size: 0.98rem; }
|
|
main.container { padding-top: 18px; padding-bottom: 40px; min-height: 60vh; }
|
|
footer.site {
|
|
text-align: center;
|
|
color: var(--muted);
|
|
font-size: 0.82rem;
|
|
padding: 26px 0 34px;
|
|
border-top: 1px solid var(--line);
|
|
}
|
|
footer.site a { color: var(--sage-deep); }
|
|
</style>
|