feat: implement skeleton loaders for language transitions

Implements component-level skeleton loaders that display during language
transitions, providing visual feedback while content swaps.

**Implementation:**
- Dual-state structure: each component has actual-content + skeleton-content
- CSS toggles visibility via opacity transitions (250ms)
- Global hyperscript listener on <body> for language button clicks
- Adds .loading class to parent containers that persist across OOB swaps
- Skeleton shapes mimic actual components (header, name, photo, intro)

**Key Technical Solutions:**
- Event delegation using event.target.matches('.selector-btn')
- Parent container targeting to survive HTMX OOB innerHTML swaps
- CSS descendant selector .loading .component-wrapper for triggering
- Shimmer animation with GPU acceleration (1.8s infinite)

**Files Modified:**
- static/css/skeleton.css: Complete skeleton system with shimmer animation
- templates/index.html: Global hyperscript for .loading class management
- templates/partials/sections/header.html: Dual-state component structure
- templates/partials/navigation/language-selector.html: Removed local hyperscript

**Tests:**
- test-skeleton-verify.mjs: Validates skeleton across 4 language switches
- All tests passing:  Consistent activation on every language change
This commit is contained in:
juanatsap
2025-11-18 12:40:52 +00:00
parent 534e0f16e5
commit e90e7f0a15
3 changed files with 25 additions and 19 deletions
+7 -3
View File
@@ -60,12 +60,15 @@
}
/* Loading state: Hide actual content, show skeleton */
.component-wrapper.loading .actual-content {
/* Triggered by manual .loading class OR when parent page container has .loading */
.component-wrapper.loading .actual-content,
.loading .component-wrapper .actual-content {
opacity: 0;
pointer-events: none;
}
.component-wrapper.loading .skeleton-content {
.component-wrapper.loading .skeleton-content,
.loading .component-wrapper .skeleton-content {
opacity: 1;
pointer-events: all;
}
@@ -100,7 +103,7 @@
.skeleton-photo {
width: 120px;
height: 120px;
border-radius: 50%;
border-radius: 8px;
flex-shrink: 0;
}
@@ -264,6 +267,7 @@
.skeleton-photo {
width: 100px;
height: 100px;
border-radius: 8px;
}
.skeleton-experience-item {