docs: refactor skeleton loader architecture from overlay to component-based

Changed skeleton loader implementation strategy from separate overlay to built-in component states:

ARCHITECTURE CHANGE:
- Before: Separate skeleton-loader.html overlay positioned absolutely over content
- After: Each component contains both actual content and skeleton state markup
- Skeleton states toggle via CSS classes (.loading) on component wrappers
- No separate overlay layer - skeleton lives inside each component

IMPLEMENTATION
This commit is contained in:
juanatsap
2025-11-17 13:50:45 +00:00
parent ad6f72f92c
commit 836e1e228d
+83 -59
View File
@@ -32,7 +32,7 @@ This will transform the current instant language switch into a premium, modern w
**Desired User Experience (from screenshots):**
1. User clicks language button (EN or ES)
2. Current content fades out (200-300ms)
3. Skeleton loaders appear - gray pulsing boxes matching the layout structure
3. Skeleton loaders appear - gray pulsing boxes matching INSIDE of the CV (so, a toggle of the content)
4. New language content loads from server
5. Skeleton loaders fade out and new content fades in (200-300ms)
6. Total smooth, professional transition feel
@@ -98,15 +98,22 @@ This will transform the current instant language switch into a premium, modern w
<implementation>
**Recommended Implementation Strategy:**
**Step 1: Create Skeleton Loader HTML Structure**
**Step 1: Add Skeleton States to Existing Components**
Create a new template or partial: `templates/partials/skeleton-loader.html`
Modify existing CV component templates to include built-in skeleton states:
This should contain a simplified version of your CV layout with placeholder boxes:
- Header skeleton (circular avatar placeholder, horizontal bars for name/title)
- Left sidebar skeleton (rectangular blocks for skills)
- Main content skeleton (blocks for experience entries)
- Right sidebar skeleton (blocks for additional skills)
- `templates/partials/cv-header.html` - Add skeleton state markup inside the component
- `templates/partials/skills-*.html` - Add skeleton placeholders for skill blocks
- `templates/partials/experience-entry.html` - Add skeleton placeholders for experience blocks
- Each component should have both actual content and skeleton markup, toggled via CSS classes
Example structure:
```html
<div class="component-wrapper">
<div class="actual-content"><!-- Real CV content --></div>
<div class="skeleton-content hidden"><!-- Skeleton placeholders --></div>
</div>
```
**Step 2: Create Skeleton CSS Animations**
@@ -126,21 +133,29 @@ Add to `static/css/main.css` or create `static/css/skeleton.css`:
50% { background-position: 0 0; }
}
/* Skeleton container - hidden by default */
.skeleton-overlay {
/* Component state toggling */
.component-wrapper .actual-content {
opacity: 1;
transition: opacity 250ms ease;
}
.component-wrapper .skeleton-content {
opacity: 0;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
z-index: 10;
opacity: 0;
pointer-events: none;
transition: opacity 250ms ease;
}
.skeleton-overlay.active {
/* Loading state - toggle content visibility */
.component-wrapper.loading .actual-content {
opacity: 0;
pointer-events: none;
}
.component-wrapper.loading .skeleton-content {
opacity: 1;
pointer-events: all;
}
@@ -160,36 +175,39 @@ Add to `static/css/main.css` or create `static/css/skeleton.css`:
Modify `templates/partials/navigation/language-selector.html`:
- Add `hx-swap="outerHTML swap:250ms settle:250ms"`
- Add `hx-indicator="#skeleton-loader"` to show skeleton during request
- Add hyperscript to manage skeleton visibility
- Add hyperscript to toggle `.loading` class on component wrappers
- Coordinate timing with component fade-in/out transitions
**Step 4: Add Skeleton Loader to Main Template**
**Step 4: Ensure Component Wrappers Have Proper Classes**
Insert the skeleton loader overlay into your main CV template:
- Position it absolutely over the content area
- Initially hidden with `opacity: 0`
- Activated via HTMX events or hyperscript
Verify that CV component wrappers in templates have:
- `.component-wrapper` class for CSS targeting
- Both `.actual-content` and `.skeleton-content` children
- Proper positioning context (relative positioning on wrapper)
**Step 5: HTMX Event Handling with Hyperscript**
Add hyperscript behavior to show/hide skeleton:
Add hyperscript behavior to toggle loading state on components:
```hyperscript
on htmx:beforeRequest from #language-selector
add .active to #skeleton-loader
add .loading to .component-wrapper in #cv-inner-content-page-1
add .loading to .component-wrapper in #cv-inner-content-page-2
end
on htmx:afterSwap from #language-selector
wait 100ms -- Brief delay to ensure content is rendered
remove .active from #skeleton-loader
remove .loading from .component-wrapper in #cv-inner-content-page-1
remove .loading from .component-wrapper in #cv-inner-content-page-2
end
```
**Alternative Approach (Pure HTMX):**
Use `hx-indicator` attribute with CSS to control visibility:
- `hx-indicator="#skeleton-loader"` on language buttons
- HTMX automatically adds `.htmx-request` class during requests
- CSS: `#skeleton-loader.htmx-request { opacity: 1; }`
**Alternative Approach (CSS-based):**
Use HTMX's automatic class management:
- Add `.component-wrapper` to elements receiving OOB swaps
- Use HTMX classes: `.htmx-swapping` triggers skeleton state
- CSS: `.component-wrapper.htmx-swapping .actual-content { opacity: 0; }`
- CSS: `.component-wrapper.htmx-swapping .skeleton-content { opacity: 1; }`
**Step 6: Content Fade Transitions**
@@ -210,13 +228,15 @@ Add fade-in/out to actual content sections:
```
**What to Prioritize:**
1. Get basic skeleton structure showing/hiding correctly
2. Add pulsing animation
3. Refine skeleton shapes to better match layout
4. Polish timing and transitions
5. Add accessibility features
1. Add skeleton markup inside each existing component (dual-state structure)
2. Implement CSS toggling between actual content and skeleton content
3. Add pulsing animation to skeleton elements
4. Refine skeleton shapes to better match layout
5. Polish timing and transitions
6. Add accessibility features
**What to Avoid:**
- Don't create a separate overlay layer - skeleton states live inside components
- Don't create overly complex skeleton markup - simple boxes are fine
- Don't make the skeleton identical to real content - approximate is better
- Don't use JavaScript animations - stick to CSS for performance
@@ -233,22 +253,23 @@ Add fade-in/out to actual content sections:
<output>
Create/modify the following files:
1. **`./templates/partials/skeleton-loader.html`** (NEW)
- Skeleton loader HTML structure
- Simplified CV layout with placeholder boxes
- Should mirror the structure of CV content sections
1. **Modify existing component templates** (UPDATE)
- `./templates/partials/cv-header.html` - Add skeleton state inside component
- `./templates/partials/skills-*.html` - Add skeleton placeholders
- `./templates/partials/experience-entry.html` - Add skeleton placeholders
- Each component gets dual-state structure (actual content + skeleton content)
2. **`./static/css/skeleton.css`** (NEW)
- Skeleton loader styles
- Pulsing animation keyframes
- Skeleton overlay positioning and transitions
- Component state toggling styles (`.loading` class behavior)
- Responsive skeleton layouts
- Accessibility overrides for `prefers-reduced-motion`
3. **`./templates/partials/navigation/language-selector.html`**
- Add HTMX swap timing modifiers
- Add skeleton loader indicator reference
- Add hyperscript for skeleton show/hide events
- Add hyperscript to toggle `.loading` class on component wrappers
- Coordinate skeleton state transitions with HTMX events
4. **`./templates/language-switch.html`**
- May need to coordinate OOB swap timing
@@ -259,10 +280,10 @@ Create/modify the following files:
- Import skeleton.css if created separately
- Add HTMX animation class styles
6. **Include skeleton loader in main template** (wherever CV content lives)
- Add `<div id="skeleton-loader" class="skeleton-overlay">...</div>`
- Position over content area
- Initially hidden, shown during language switch
6. **Ensure component wrappers are properly structured**
- Each component should have `.component-wrapper` class
- Components contain both `.actual-content` and `.skeleton-content`
- Skeleton content is hidden by default, shown when `.loading` class is added
</output>
@@ -270,10 +291,11 @@ Create/modify the following files:
Before declaring complete, perform these tests:
**1. Visual Verification:**
- [ ] Click EN button: Content fades out → Skeleton appears → New content fades in
- [ ] Click EN button: Content fades out → Skeleton appears inside components → New content fades in
- [ ] Click ES button: Same smooth transition with skeleton
- [ ] Skeleton boxes pulse/shimmer smoothly
- [ ] Skeleton boxes pulse/shimmer smoothly inside each component
- [ ] Skeleton roughly matches CV layout (recognizable structure)
- [ ] Each component toggles between actual content and skeleton state
- [ ] No flashing or jarring jumps during transition
**2. Timing Verification:**
@@ -314,7 +336,8 @@ Before declaring complete, perform these tests:
- [ ] Page refresh during skeleton display - recovers gracefully
**Success Indicators:**
Skeleton loaders appear during language transitions
Components toggle between actual content and skeleton states during language transitions
✅ Skeleton states appear INSIDE each component (not as separate overlay)
✅ Pulsing animation is smooth and subtle
✅ Total transition time feels professional (500-700ms)
✅ No jarring content jumps or flashes
@@ -324,16 +347,17 @@ Before declaring complete, perform these tests:
</verification>
<success_criteria>
1. Skeleton loaders with pulsing animation appear during language switching
2. Three-phase transition: fade-out → skeleton → fade-in
3. Total transition time: 500-700ms (feels premium, not sluggish)
4. Skeleton structure roughly matches CV layout (recognizable)
5. Animations are GPU-accelerated and buttery smooth (60fps)
6. Respects `prefers-reduced-motion` accessibility setting
7. Handles rapid clicking without breaking or visual glitches
8. Works consistently across modern browsers and device sizes
9. Code follows existing project patterns and conventions
10. Implementation is maintainable and doesn't overcomplicate the codebase
1. Each CV component toggles between actual content and skeleton state during language switching
2. Skeleton loaders with pulsing animation appear INSIDE components (not as separate overlay)
3. Three-phase transition: fade-out → skeleton → fade-in
4. Total transition time: 500-700ms (feels premium, not sluggish)
5. Skeleton structure roughly matches CV layout (recognizable)
6. Animations are GPU-accelerated and buttery smooth (60fps)
7. Respects `prefers-reduced-motion` accessibility setting
8. Handles rapid clicking without breaking or visual glitches
9. Works consistently across modern browsers and device sizes
10. Code follows existing project patterns and conventions
11. Implementation is maintainable and doesn't overcomplicate the codebase
</success_criteria>
<references>