diff --git a/src/components/ReadingMap.astro b/src/components/ReadingMap.astro index 0346c6d..4ea1710 100644 --- a/src/components/ReadingMap.astro +++ b/src/components/ReadingMap.astro @@ -57,12 +57,21 @@ const { try { const { mount } = await import('../lib/reading-map.js'); for (const el of containers) { - mount(el, { + const map = await mount(el, { src: el.dataset.src!, // Fail closed, like the garden's other widgets: a missing payload or a dead GPU // leaves a plain page rather than an empty bordered box. onError: (err: unknown) => console.warn('reading map unavailable:', err), }); + if (!map) continue; + + // Ring the node the header's quote came from. The two are independent fetches on + // every page view and either can land first, so handle both orders: read the hash if + // it is already there, and listen in case it is not. `garden:quote` is dispatched by + // the header script in Base.astro. + const ring = (hash?: string) => hash && map.markQuoted(hash); + ring(window.__gardenQuoteHash); + addEventListener('garden:quote', (e) => ring((e as CustomEvent).detail?.text_hash)); } } catch (err) { /* chunk failed to load: the figure stays hidden */ diff --git a/src/components/ReadingNow.astro b/src/components/ReadingNow.astro new file mode 100644 index 0000000..58ad106 --- /dev/null +++ b/src/components/ReadingNow.astro @@ -0,0 +1,117 @@ +--- +/** + * "Currently reading" — the book Wes most recently made progress in. + * + * import ReadingNow from '../components/ReadingNow.astro'; + * + * + * Data: api.c0smere.net/reading/current, which is kobo_archive on phlegethon by way of + * api.reading_current(). Date-only by design — the timestamp would publish when he is awake. + * + * ⚠️ **It says how long ago on purpose.** Six of the ten books on the currently-reading shelf + * have not been opened in months, so this widget will sit on one entry indefinitely the moment + * the Kobo goes down for a while. Without the relative date that reads as a broken widget + * rather than an honest one; past DORMANT_DAYS it also mutes itself and says "paused". + * + * No cover image: there is no source for one. `kobo.books.isbn` is a sideloader's UUID for most + * of the shelf and `kobo.storygraph_links` carries no cover URL. The remaining route is pulling + * it out of the epub at intake time, which is a library-rag change, not a garden one. + */ +--- + + + + + + diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..ad6b6c8 --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,18 @@ +/// + +declare global { + interface Window { + /** + * `text_hash` of the reading highlight in the page header, set by Base.astro once + * api.c0smere.net/highlights/random answers. The reading map reads it to ring the node + * that passage came from. + * + * A global as well as a `garden:quote` event because the two fetches race: whichever + * lands second needs the other's result, and only one of the two mechanisms works in + * each order. + */ + __gardenQuoteHash?: string; + } +} + +export {}; diff --git a/src/layouts/Base.astro b/src/layouts/Base.astro index ae6b62b..b24e9b0 100644 --- a/src/layouts/Base.astro +++ b/src/layouts/Base.astro @@ -5,6 +5,7 @@ import { buildNavTree } from '../lib/nav.mjs'; import { COMMIT, BUILT_AT } from '../lib/build-info.mjs'; import NavTree from '../components/NavTree.astro'; import Toc from '../components/Toc.astro'; +import ReadingNow from '../components/ReadingNow.astro'; import { loadNotebooks, notebookUrl } from '../lib/notebooks.mjs'; interface Props { @@ -198,13 +199,13 @@ const pageUrl = new URL(Astro.url.pathname, Astro.site); - { - showToc && ( - - ) - } + {/* The rail exists whenever EITHER thing wants it. It used to be rendered only when + there was a table of contents, which would have left the reading widget with no home + on any page of fewer than two headings — including the homepage. */} +