diff --git a/data/wotd_audio/renewal.mp3 b/data/wotd_audio/renewal.mp3 new file mode 100644 index 0000000..008789d Binary files /dev/null and b/data/wotd_audio/renewal.mp3 differ diff --git a/frontend/src/lib/components/NewsFeed.svelte b/frontend/src/lib/components/NewsFeed.svelte new file mode 100644 index 0000000..363632f --- /dev/null +++ b/frontend/src/lib/components/NewsFeed.svelte @@ -0,0 +1,1070 @@ + + +
(showSaved = true)} onaccount={openAccount} user={auth.user} boundariesActive={filtersOn} /> + +{#if showSignIn} { showSignIn = false; if (!auth.user) pendingDigestOptIn = false; }} />{/if} +{#if showSaved && auth.user} (showSaved = false)} />{/if} +{#if showLanes && lanePool} + (showLanes = false)} /> +{/if} + +
+ {#if navLanes.length} + (showLanes = true)} /> + {/if} + + {#if notice}

{notice}

{/if} + + {#if loading} +

Gathering the good news…

+ {:else if error} +

{error}

+ {:else} + {#key selected} +
+
+

{viewLabel}

+ {#if viewSubtitle}

{viewSubtitle}

{/if} +
+
+ + {#if auth.user && followTarget} + + {/if} + {#if selected !== 'today'} + + {/if} +
+
+ + {#if searchOpen || selected === 'search'} + + {/if} + + {#if selected === 'today'} + {#if sinceCount > 0 && !sinceDismissed} +
+

+ Since you were last here, {sinceCount} new calm read{sinceCount === 1 ? '' : 's'} came in. + {#if !sinceOpen}{/if} +

+ +
+ {#if sinceOpen && sinceItems.length} +
+

New since your last visit

+
+ {#each sinceItems as a (a.id)} + drill('tag:' + t)} onsource={(id, name) => drill('source:' + id, { id, name })} onview={record} /> + {/each} +
+
+ {/if} + {/if} + {#if brief?.items?.length} + {#if homeEditing || (!homeValue && !homePromptDismissed)} +
+ {#if !homeValue}

Want your good news closer to home?

{/if} +
+ + {#if pickCountry === 'US'} + + {/if} + + {#if homeValue} + {:else}{/if} +
+
+ {:else if homeValue} +
+ Good news closest first +
+ {#each scopeStops as [s, label] (s)} + + {/each} +
+ + + + +
+ {/if} +
+ drill('tag:' + t)} onsource={(id, name) => drill('source:' + id, { id, name })} onview={record} onimageerror={heroImageFailed} /> + {#if restArticles.length} +
+ {#each restArticles as a, i (a.id)} + {#if a.section && a.section !== restArticles[i - 1]?.section && a.section !== heroArticle?.section} +

{sectionLabel(a.section)}

+ {/if} + drill('tag:' + t)} onsource={(id, name) => drill('source:' + id, { id, name })} onview={record} /> + {/each} +
+ {/if} +
+
+

✦ that's the good news for today ✦

+

You're caught up for now.

+ {#if ritual.total} +
+

Today's calm set

+
    + {#each ritual.items as it (it.key)} +
  • + {#if it.done || it.key === 'brief'}{it.label}{:else}{it.label}{/if} +
  • + {/each} +
+

+ {ritual.count === ritual.total ? `All ${ritual.total} enjoyed today` : `${ritual.count} of ${ritual.total} enjoyed today`} · fresh set tomorrow · make it yours +

+
+ {/if} + {#if auth.user?.digest_enabled} +

Tomorrow's brief is headed to your inbox ☕

+ {:else} + + {/if} +
+ {:else} +

No highlights yet today — try a calmer filter, or check back soon.

+ {/if} + {:else if feed.length} + {#if selected === 'latest'} + {#if homeEditing || (!homeValue && !homePromptDismissed)} +
+

Want good news closer to home?

+
+ + {#if pickCountry === 'US'} + + {/if} + + {#if homeValue} + + {:else} + + {/if} +
+
+ {:else if homeValue} +
📍 Showing local first · ·
+ {/if} + {/if} +
+ {#each feed as a, i (a.id)} + {#if a.section && a.section !== feed[i - 1]?.section} +

{sectionLabel(a.section)}

+ {/if} + drill('tag:' + t)} onsource={(id, name) => drill('source:' + id, { id, name })} onview={record} /> + {/each} +
+ {#if !feedDone} +
+ +
+ {:else} +

✦ you're all caught up ✦

+ {/if} + {:else if selected === 'search'} +

No articles found for “{searchQuery}”. Try a different word, or a source name like “Nature”.

+ {:else if selected === 'following'} +

+ {#if auth.user}Nothing here yet — open a source or a grouping and tap Follow to fill this lane with what you care about. + {:else}Sign in and follow a few sources or topics, and this becomes your own calm lane.{/if} +

+ {:else} +

Nothing here right now — try another, or ease a boundary.

+ {/if} + {/key} + + {#if families.length} +
+

Explore Upbeat Bytes

+
+ {#each families as f (f.name)} + {@const tags = f.tags.filter((t) => t.count > 0)} + {#if tags.length} +
+

{f.name}

+

{f.description}

+
+ {#each tags as t (t.key)} + + {/each} +
+
+ {/if} + {/each} +
+
+ {/if} + + {#if !pwa.isStandalone && !pwa.dismissed && (pwa.canInstall || pwa.isIOS)} + + {/if} + {/if} +
+ + navigate('today')} onLatest={() => navigate('latest')} onPlay={() => goto('/play')} onYou={openAccount} user={auth.user} /> + + diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index ecfedb3..4a63172 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -1,1065 +1,8 @@ -
(showSaved = true)} onaccount={openAccount} user={auth.user} boundariesActive={filtersOn} /> - -{#if showSignIn} { showSignIn = false; if (!auth.user) pendingDigestOptIn = false; }} />{/if} -{#if showSaved && auth.user} (showSaved = false)} />{/if} -{#if showLanes && lanePool} - (showLanes = false)} /> -{/if} - -
- {#if navLanes.length} - (showLanes = true)} /> - {/if} - - {#if notice}

{notice}

{/if} - - {#if loading} -

Gathering the good news…

- {:else if error} -

{error}

- {:else} - {#key selected} -
-
-

{viewLabel}

- {#if viewSubtitle}

{viewSubtitle}

{/if} -
-
- - {#if auth.user && followTarget} - - {/if} - {#if selected !== 'today'} - - {/if} -
-
- - {#if searchOpen || selected === 'search'} - - {/if} - - {#if selected === 'today'} - {#if sinceCount > 0 && !sinceDismissed} -
-

- Since you were last here, {sinceCount} new calm read{sinceCount === 1 ? '' : 's'} came in. - {#if !sinceOpen}{/if} -

- -
- {#if sinceOpen && sinceItems.length} -
-

New since your last visit

-
- {#each sinceItems as a (a.id)} - drill('tag:' + t)} onsource={(id, name) => drill('source:' + id, { id, name })} onview={record} /> - {/each} -
-
- {/if} - {/if} - {#if brief?.items?.length} - {#if homeEditing || (!homeValue && !homePromptDismissed)} -
- {#if !homeValue}

Want your good news closer to home?

{/if} -
- - {#if pickCountry === 'US'} - - {/if} - - {#if homeValue} - {:else}{/if} -
-
- {:else if homeValue} -
- Good news closest first -
- {#each scopeStops as [s, label] (s)} - - {/each} -
- - - - -
- {/if} -
- drill('tag:' + t)} onsource={(id, name) => drill('source:' + id, { id, name })} onview={record} onimageerror={heroImageFailed} /> - {#if restArticles.length} -
- {#each restArticles as a, i (a.id)} - {#if a.section && a.section !== restArticles[i - 1]?.section && a.section !== heroArticle?.section} -

{sectionLabel(a.section)}

- {/if} - drill('tag:' + t)} onsource={(id, name) => drill('source:' + id, { id, name })} onview={record} /> - {/each} -
- {/if} -
-
-

✦ that's the good news for today ✦

-

You're caught up for now.

- {#if ritual.total} -
-

Today's calm set

-
    - {#each ritual.items as it (it.key)} -
  • - {#if it.done || it.key === 'brief'}{it.label}{:else}{it.label}{/if} -
  • - {/each} -
-

- {ritual.count === ritual.total ? `All ${ritual.total} enjoyed today` : `${ritual.count} of ${ritual.total} enjoyed today`} · fresh set tomorrow · make it yours -

-
- {/if} - {#if auth.user?.digest_enabled} -

Tomorrow's brief is headed to your inbox ☕

- {:else} - - {/if} -
- {:else} -

No highlights yet today — try a calmer filter, or check back soon.

- {/if} - {:else if feed.length} - {#if selected === 'latest'} - {#if homeEditing || (!homeValue && !homePromptDismissed)} -
-

Want good news closer to home?

-
- - {#if pickCountry === 'US'} - - {/if} - - {#if homeValue} - - {:else} - - {/if} -
-
- {:else if homeValue} -
📍 Showing local first · ·
- {/if} - {/if} -
- {#each feed as a, i (a.id)} - {#if a.section && a.section !== feed[i - 1]?.section} -

{sectionLabel(a.section)}

- {/if} - drill('tag:' + t)} onsource={(id, name) => drill('source:' + id, { id, name })} onview={record} /> - {/each} -
- {#if !feedDone} -
- -
- {:else} -

✦ you're all caught up ✦

- {/if} - {:else if selected === 'search'} -

No articles found for “{searchQuery}”. Try a different word, or a source name like “Nature”.

- {:else if selected === 'following'} -

- {#if auth.user}Nothing here yet — open a source or a grouping and tap Follow to fill this lane with what you care about. - {:else}Sign in and follow a few sources or topics, and this becomes your own calm lane.{/if} -

- {:else} -

Nothing here right now — try another, or ease a boundary.

- {/if} - {/key} - - {#if families.length} -
-

Explore Upbeat Bytes

-
- {#each families as f (f.name)} - {@const tags = f.tags.filter((t) => t.count > 0)} - {#if tags.length} -
-

{f.name}

-

{f.description}

-
- {#each tags as t (t.key)} - - {/each} -
-
- {/if} - {/each} -
-
- {/if} - - {#if !pwa.isStandalone && !pwa.dismissed && (pwa.canInstall || pwa.isIOS)} - - {/if} - {/if} -
- - navigate('today')} onLatest={() => navigate('latest')} onPlay={() => goto('/play')} onYou={openAccount} user={auth.user} /> - - + diff --git a/frontend/src/routes/news/+page.svelte b/frontend/src/routes/news/+page.svelte new file mode 100644 index 0000000..556224b --- /dev/null +++ b/frontend/src/routes/news/+page.svelte @@ -0,0 +1,12 @@ + + + + + + +