Add stateful ImageLoader component to eliminate layout shifts - #60
Conversation
|
[CI/CD Fix Attempt 1] |
Replace the hand-maintained 127-line image dimensions map with a small Vite plugin that reads intrinsic dimensions from static/images at build time and exposes them via a `virtual:image-dimensions` module. New images are picked up automatically and dimensions can't drift out of sync with the assets. This also fixes vispositions.svg, whose dimensions were hardcoded as 1000x500 but are actually 100x100 (a 1:1 icon), so its reserved aspect ratio was wrong. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
538ae21 to
828dc3d
Compare
|
[CI/CD Fix Attempt 2] |
|
[CI/CD Fix Attempt 3] Verified that:
|
The ImageLoader faded the image in only once a `loaded` flag flipped, but for cached/server-rendered images the `load` event fires before the listener attaches, so `loaded` stayed false and every publication thumbnail rendered at opacity 0 (invisible) despite loading fine. Stop gating the image's visibility on JS entirely: the image is always rendered, with the skeleton behind it as a best-effort placeholder that the image covers once it paints. This removes the fragile load-timing dependency (and the fade transition that relied on it). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eac-e8c8-4efc-a616-c2b2bb22581a
Context & Rationale
Currently, publication preview images on index and detail pages lack defined dimensions. Consequently, they collapse to a height of
0pxbefore loading, causing jarring Cumulative Layout Shift (CLS) when they finally render. This visual instability degrades the user experience and impacts our SEO metrics.To solve this, this PR introduces a stateful, reusable
<ImageLoader>component. By extending our project metadata to include image dimensions, we can dynamically calculate and reserve the exact aspect ratio on page load using active skeleton placeholders. Additionally, we normalized asset paths within this component to prevent broken resource paths on nested detail pages, and added a smooth fade-in transition to eliminate abrupt loading pops.Key Decisions
bg-primary/10 animate-pulse) and a smooth fade-in transition to improve perceived application responsiveness.Detailed Changes
1. Schema & Data Pipeline
src/lib/types.ts: ExtendedProjectandResearchProjectclasses to accept an optionalimageDimensions: { width: number; height: number }parameter without breaking backwards compatibility.src/lib/helpers/projectsProvider.ts: Generated and injected an asset dimension map to automatically populateimageDimensionsfor research and fun projects before they are served to the frontend.2. Component Implementation
src/lib/components/ImageLoader.svelte: Created the stateful image loader component. It:aspect-ratiodynamically.3. View Migration
src/routes/publications/+page.svelte: Replaced standard layout-unstable<img>tags with<ImageLoader>on the publication index page.src/routes/publications/[paper]/+page.svelte: Updated the detail view hero image to use<ImageLoader>.Verification & Testing
0on both list and detail views.