Index the resources in search, and give the landing page a filterable table - #8
Conversation
… table web/resources.json is now the source of truth for the 653 resources. The nine markdown pages stay committed so they read on GitHub, and the build reads the same file for the search index and the table -- one file behind both, so they cannot drift apart. Search. Every resource is now findable by title, taking the index from 79 entries to 732. Entries are deliberately lean: no description field, because 653 of them would treble a file every visitor downloads for a line most people never read. The publisher goes in the short label, where it disambiguates near-identical titles cheaply. That index is 22 KB gzipped, and every page used to block on it whether or not anyone searched. It is fetched on first open of the search dialog instead, with a prefetch hint so the browser can pull it while idle. Verified in a browser: window.SEARCH_INDEX is undefined on load and holds 732 entries a moment after the dialog opens. If the fetch fails there is nothing to search rather than a broken dialog. Because the file is generated rather than checked in, asset() cannot hash it from disk, so the index is built before rendering and its hash seeded from the bytes that will be written. That meant moving the carve helpers and the resource load ahead of it too -- the search index publishes section summaries and has to apply the same sensitivity test the stack table does. The landing page. All 653 in one table: filter by words, narrow by group chips or a topic select, sort any column. mountFilterGrid drove chips only, so it now also drives selects -- fifty topics as a chip row would be longer than the table it filters. Sorting collates numerically so "10 Ways" does not sort ahead of "2 Ways", and an empty publisher sorts last in both directions rather than floating a block of blanks to the top when the direction flips. Three things caught by looking at it rather than by reasoning about it: the filter bar used an invented class with no CSS behind it, so the search icon rendered as a full-width circle; the sort button on the pre-sorted column re-applied the same direction and appeared dead until it adopted the order the markup declares; and the sticky header sat 58px below the top of the table because .table-wrap sets overflow-x, which makes it a scroll container and resolves sticky against the container rather than the page.
|
Warning Review limit reached
Next review available in: 9 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Follows PR #7, which brought the 653 resources onto main. This makes them findable.
Search
All 653 resources are now findable by title — the index goes from 79 entries to 732.
Entries are deliberately lean: no description field, because 653 of them would treble a file every visitor downloads for a line most people never read. The publisher goes in the short label, where it disambiguates near-identical titles cheaply.
That index is 22 KB gzipped, and every page was blocking on it whether or not anyone searched. It is now fetched on first open of the search dialog, with a
prefetchhint so the browser can pull it while idle. Verified in a browser:window.SEARCH_INDEXisundefinedon load, and holds 732 entries a moment after the dialog opens. If the fetch fails there is simply nothing to search rather than a broken dialog.Because the index is generated rather than checked in,
asset()cannot hash it from disk — so it is built before rendering and its hash seeded from the bytes that will be written. That meant moving the carve helpers and the resource load ahead of it too: the search index publishes section summaries and has to apply the same sensitivity test the stack table does.The landing page
All 653 in one table. Filter by words, narrow by group chips or a topic select, sort any column.
mountFilterGriddrove chips only, so it now drives selects as well — fifty topics as a chip row would be longer than the table it filters.One source of truth
web/resources.jsonnow holds the 653 records. The nine markdown pages stay committed so they read on GitHub, and the build reads the same file for the search index and the table — one file behind both, so they cannot drift.Three bugs found by looking, not by reasoning
.fieldstyling is scoped to.toolbar.table-wrapsetsoverflow-x, making it a scroll container, so sticky resolved against the container rather than the page. I then reintroduced the same bug withoverflow: hiddenfor a border radius, and removed it again.Verification
Driven in a real browser rather than assumed:
node web/build.mjsclean: 71 pages, 732 search entries.Generated by Claude Code