Improve Lazy Loading, Refactor Filtering via `data-tags` in Toolkit Layout
Summary
Optimized toolkit rendering by switching from tag-based URL filtering to in-page
data-tags
filtering, improving responsiveness and removing full page reloads. Also enabled lazy loading and async decoding for tool images to reduce initial load time.Why Care
Previously, selecting a tag triggered a URL reload with query parameters (
?tag=...
). This caused the entire page to re-render, resetting scroll position, reloading all cards, and introducing latency. Switching to in-page data-tags
filtering enables instant feedback and seamless UX. Lazy loading image assets further improves toolkit performance and lowers bandwidth use.Implementation
Changes Made
π’ Refactored Toolkit Filtering
- Replaced tag-based URL filtering with in-place DOM filtering using
data-tags
on each.tool-card
- Updated
CardGrid.astro
to ensuredata-tags
is passed in bothToolCard
andBareToolCard
renderings - Updated
TagColumn.astro
to:- Dispatch custom
tagsUpdated
event - Filter visible
.tool-card
elements by comparingdata-tags
with selected tags
π’ Optimized Image Performance
- Enabled
loading="lazy"
anddecoding="async"
on all<img>
tags inToolCard.astro
- Preserved existing fallback logic for missing or broken images, with graceful degradation to:
- Screenshot URLs
- Placeholder fallback:
https://i0.wp.com/port2flavors.com/wp-content/uploads/2022/07/placeholder-614.png
Affected Files
text
src/components/tool-components/
βββ ToolCard.astro # + lazy loading, data-tag logic
βββ TagColumn.astro # + client-side filtering & search
βββ BareToolCard.astro # (minor updates, if used)
src/layouts/
βββ ToolkitLayout.astro # removed filterTag prop, now passes all tools
Technical Details
data-tags
Example from ToolCard.astro
astro
<ToolCard
{...tool}
filePath={tool.filePath}
class="tool-card"
data-tags={JSON.stringify(tool.tags || [])}
/>
Filtering Logic in TagColumn.astro
(JS)
js
function filterCards() {
allCards.forEach(card => {
const tags = JSON.parse(card.dataset.tags || '[]');
const match = selectedTags.every(tag => tags.includes(tag));
card.style.display = match || selectedTags.length === 0 ? '' : 'none';
});
}
Removed Prop Logic in ToolkitLayout.astro
astro
// Removed this:
const {
...
filterTag
} = Astro.props;
const filteredEntries = filterTag
? toolEntries.filter(entry => entry.data.tags?.includes(filterTag))
: toolEntries;
Now
CardGrid
is rendered unfiltered with all entries, and the filtering happens entirely client-side using JavaScript.Integration Points
- Ensures tag filters persist visually and functionally across paginated or dynamically styled content
- Tag filtering now plays well with other layout JS (like mouse tracking and image fallbacks)
- Removed dependency on server-rendered tag filters β no need to sync Astro route logic with query param state
Documentation
No external libraries added or removed. No breaking API changes introduced.