Fix indexability of case study detail pages#404
Conversation
Render all 34 case-study cards in static HTML (cards beyond the first
page marked hidden via class) instead of slicing to PAGE_SIZE before
SSR. Pagination/filter/search now toggle visibility on existing cards
instead of rebuilding innerHTML, so every detail-page link is present
for crawlers while the visible UX stays unchanged.
Refactor along the way:
- Drop the window.__CS_DATA__ global and its inline script; cards now
carry data-title/data-description/data-categories attributes and JS
reads them once via readCards().
- Combine the two-step filter in search() into a single predicate and
remove duplicate getActiveCategories()/searchInput.value lookups
inside updateDisplay().
- Cache .cs-filter-pill nodes once at init instead of doing a
closest('.cs-filter-pill') walk per update.
- Drop the redundant pages.includes() guards in the page-list builder
(the ranges can't produce duplicates by construction).
- Remove two no-op [hidden] { display: none } CSS rules where the
element has no overriding display: and the UA stylesheet already
honors [hidden].
vvlladd28
left a comment
There was a problem hiding this comment.
Review summary
Reviewed 1 changed file in Fix indexability of case study detail pages. Left 1 comment inline.
The SEO fix is sound: rendering all 34 cards as plain <a href> elements in static HTML — with cards beyond PAGE_SIZE hidden via is-hidden — lets Googlebot discover every detail-page URL while preserving the paginated UX. Toggling visibility instead of rebuilding innerHTML is also a nice simplification, and the _includes-style cleanups (single-pass filter, cached pills, DOM-as-data via data-* attrs, dropping window.__CS_DATA__) all look correct. Verified the removed [hidden] { display: none } rules on .cs-no-results and .cs-filter-clear are truly no-ops — neither element sets an explicit display: value, so the UA default [hidden] rule still applies. Verified the pagination simplification (dropping pages.includes() guards) is safe: start is always ≥ 2 and the inner loop's end is bounded by total - 1, so duplicates can't occur.
This is an auto-generated review. Findings may contain errors — please verify before applying changes.
| > | ||
| <div class="cs-card-content"> | ||
| <div class="cs-card-top"> | ||
| <img |
There was a problem hiding this comment.
Worth adding loading="lazy" here. Before this PR, only 9 cards existed in the DOM so all logos were above the fold; now there are ~25 hidden cards whose <img> tags can still trigger network requests in some browsers (the display: none on the ancestor doesn't reliably suppress <img> fetches the way it does background-image). PartnerCard.astro:45 already does this for the same pattern in #395.
Address review feedback. Before this PR only 9 cards existed in the DOM so all logos were above the fold; now the 25 cards hidden via display: none still have <img> tags whose fetches some browsers don't reliably suppress through the hidden ancestor. Matches the pattern in PartnerCard.astro from #395.
Summary
/case-studies/instead of slicing toPAGE_SIZEbefore SSR. Cards beyond the first page get anis-hiddenclass; pagination/filter/search now toggle that class on existing elements instead of rebuildinginnerHTML. Every detail-page link is now present in the initial HTML for Googlebot to discover.Fix hardware partner indexing). Surfaced by Google Search Console reporting "no referring links" for/case-studies/suessco/and other studies at index ≥9 in the data list.window.__CS_DATA__global (read filter data fromdata-*attrs), combine the two filter passes insearch()into one predicate, cache.cs-filter-pillnodes once at init, drop redundantpages.includes()guards in the pagination renderer, and remove two no-op[hidden] { display: none }CSS rules.