Conversation
## The Issue Blog post listings used prev/next pagination links requiring full page navigations to browse content. Tables in blog posts also lacked full-width rendering and horizontal scroll on mobile. Search results were capped at 10 with no way to see more, and did not restore when navigating back. ## How This PR Solves The Issue **Infinite scroll for blog listings** Replaces pagination with a fetch-HTML-fragment approach. Each listing page (index, category, author) renders its first 12 posts normally. A `data-next-url` attribute on the grid container points to the next pre-built static page. An `IntersectionObserver` fires when the user scrolls near the bottom, fetches that URL, extracts the post cards via `DOMParser`, and appends them to the current grid. The next `data-next-url` is then read from the fetched page to continue the chain. This keeps every page's initial payload at 12 posts regardless of total post count, preserves full Astro image optimization on all cards (no client-side re-rendering), and leaves all paginated static routes intact as valid URLs and noscript fallbacks. All logic is centralised in a new `BlogPostGrid` component. `Paging.astro` is removed as it is no longer referenced anywhere. **Infinite scroll for search** Search results now load progressively in batches of 10 as the user scrolls, with all matches held in memory after each query. Previously results were hard-capped at 10. The input value is also checked on page initialisation so results are restored correctly after browser back navigation. **Full-width tables with mobile scroll** `overflow-x: auto` on a `<table>` element has no effect because tables are not block containers. The previous workaround (`display: block`) broke the table's natural full-width behaviour. A new rehype plugin (`rehype-wrap-tables.mjs`) wraps each `<table>` in a `<div class="table-wrapper">` at build time, keeping the table as `display: table` (full width via Tailwind Typography) while the block-level wrapper provides the scroll container. ## Manual Testing Instructions - Visit /blog/ and scroll down to verify posts load without page navigation - Visit /blog/category/<category>/ and /blog/author/<author>/ and scroll - Check Network tab: each scroll fetch returns 200, not 301 - Disable JS and confirm the noscript fallback link is visible - Search for a term with many results and scroll to load beyond the first 10 - Navigate to a result, press back, confirm results are restored - Open a blog post with a wide table and verify it is full width on desktop and scrolls horizontally on mobile ## Automated Testing Overview No automated tests added; all changes are client-side JS and build-time HTML transforms. ## Release/Deployment Notes All paginated static routes (/blog/2/, /blog/category/x/2/, etc.) remain valid URLs. No redirects or deployment config changes needed. 🤖 Developed with assistance from [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
🌐 Fork Preview for PR #557 https://pr-557.ddev-com-fork-previews.pages.dev This preview updates automatically when you push changes to your fork. |
|
Works well. Thank you. The only "issue "with infinity scroll is you lose access to the page footer as you have to scroll increasing further to reach it. With this is mind, are there any links that would be better in the header? |
It might be better to use a "Load More" button that fetches and appends items instead of loading them automatically. Edit: I added a "Load More" button. |
## Blog listing - Replace infinite scroll with a "Load More" button, fixing the inaccessible footer problem - Button is hidden by default, shown only when JS is available - Button matches the site's hollow button style with dark mode support ## AnimatedTerminal - Add noscript fallback: pre-render ddev describe output at build time - Use CSS (data-theme attribute set by inline head script) to toggle between animated and static pre elements with zero flash - Deduplicate describeOutput — defined once in frontmatter, passed via data attribute, read by the animation script ## get-started page - Replace noscript message with CSS :has() rules so platform picker works without JS (clicking labels shows the correct platform section) ## global.css - Hide copy buttons for noscript users (html:not([data-theme])) - Add noscript notice for unrendered Mermaid diagrams - Remove noscript dark mode CSS (not supported without JS) 🤖 Developed with assistance from [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Actually, I can add support for both "Load More" and infinite scroll, with "Load More" as the default. Edit: done. |
Adds a persistent "Auto-load on scroll" checkbox to all blog listing pages. Preference is saved to localStorage so it applies across visits. Defaults to "Load More" button mode. Toggle is always visible regardless of whether a next page exists, allowing preference to be set on short category pages. 🤖 Developed with assistance from [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
The Issue
Blog post listings used prev/next pagination links requiring full page navigations to browse content. Search results were capped at 10 with no way to see more, and did not restore when navigating back. Several site features (terminal animation, platform picker, code copy buttons) had no meaningful fallback without JavaScript.
How This PR Solves The Issue
"Load More" button and optional auto-scroll for blog listings
Replaces prev/next pagination with a fetch-HTML-fragment approach. Each listing page (index, category, author) renders its first 15 posts normally. A
data-next-urlattribute on the grid container points to the next pre-built static page. Clicking "Load More" fetches that URL, extracts the post cards viaDOMParser, and appends them to the current grid. The nextdata-next-urlis then read from the fetched page to continue the chain.An "Auto-load on scroll" checkbox lets users switch to infinite scroll mode. The preference is saved to
localStorageand applied on every blog listing page. It defaults to "Load More" button mode, keeping the footer accessible. The toggle is visible on all listing pages (including short ones) so the preference can always be changed.This keeps every page's initial payload at 15 posts regardless of total post count, preserves full Astro image optimization on all cards (no client-side re-rendering), and leaves all paginated static routes intact as valid URLs and noscript fallbacks.
All logic is centralised in a new
BlogPostGridcomponent.Paging.astrois removed as it is no longer referenced anywhere.Progressive search results
Search results now load in batches of 10 as the user scrolls, with all matches held in memory after each query. Previously results were hard-capped at 10. The input value is also checked on page initialisation so results are restored correctly after browser back navigation.
Noscript fallbacks
BlogPostGrid: prev/next pagination links are rendered inside<noscript>tags; the "Load More" button is hidden by default and only revealed by JSAnimatedTerminal: a staticddev describeoutput is shown via a second<pre>element; toggled byhtml[data-theme](set by an inline head script before body renders) so there is no flash when JS is enabledget-started.astroPlatformPicker: CSS:has()rules make radio-based platform selection work without JShtml:not([data-theme])selector when JS is absentTable wrapping
A new rehype plugin (
rehype-wrap-tables.mjs) wraps markdown tables in adiv.table-wrapperfor horizontal scroll on mobile.Manual Testing Instructions
ddev describeoutput with no flash on re-enableAutomated Testing Overview
No automated tests added; all changes are client-side JS and build-time HTML transforms.
Release/Deployment Notes
All paginated static routes (
/blog/2/,/blog/category/x/2/, etc.) remain valid URLs. No redirects or deployment config changes needed.🤖 Developed with assistance from Claude Code