Files
cv-site/static/css/06-effects/_skeleton.css
T
juanatsap f7cda5dba3 refactor: Modularize CSS and fix theme-aware text colors
CSS Restructuring:
- Reorganize monolithic main.css into modular architecture
- Create foundation/ (reset, variables, typography, themes)
- Create layout/ (container, page, grid, paper)
- Create components/ (8 component files)
- Create interactive/ (toggles, remaining for future split)
- Create effects/ (skeleton loading)
- Create contexts/ (print styles)

Theme Support Fixes:
- Replace all hardcoded text colors with CSS variables
- Fix .section-title: rgb(51,51,51) → var(--text-primary)
- Fix .cv-name, .intro-text: hardcoded → theme-aware
- Fix .experience-period, .duration-text: #555/#aaa → variables
- Fix course/project/experience text colors
- Support proper light/dark theme text contrast

Icon & Layout Fixes:
- Standardize all icon sizes to 80×80px
- Change all icon backgrounds to transparent
- Fix award section layout (missing flexbox)
- Update HTML templates (experience.html, awards.html) to width='80'
- Fix default icon sizing conflicts

View Switcher Fix:
- Fix toggleTheme() to target .cv-container instead of body
- Ensures clean/default theme toggle works correctly

Files: 40+ CSS files modularized, 3 templates updated, 7 tests added
2025-11-19 14:31:17 +00:00

604 lines
10 KiB
CSS

/**
* Component-Level Skeleton Loaders for Language Transitions
* ==========================================================
* Each CV component has dual-state structure:
* - .actual-content (real CV content)
* - .skeleton-content (gray pulsing placeholders)
*
* Loading state controlled via .loading class on component wrapper
*/
/* ========================================================================
BASE SKELETON STYLES
======================================================================== */
.skeleton {
background: linear-gradient(
90deg,
#f0f0f0 0%,
#e8e8e8 20%,
#f0f0f0 40%,
#f0f0f0 100%
);
background-size: 200% 100%;
animation: skeleton-shimmer 1.8s ease-in-out infinite;
border-radius: 4px;
will-change: background-position;
}
@keyframes skeleton-shimmer {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
/* ========================================================================
COMPONENT WRAPPER STATE TOGGLING
======================================================================== */
/* Default state: Show actual content, hide skeleton */
.component-wrapper {
position: relative;
}
.component-wrapper .actual-content {
opacity: 1;
transition: opacity 250ms ease-out;
}
.component-wrapper .skeleton-content {
position: absolute;
top: 0;
left: 0;
right: 0;
opacity: 0;
pointer-events: none;
transition: opacity 250ms ease-out;
}
/* Loading state: Hide actual content, show skeleton */
/* 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,
.loading .component-wrapper .skeleton-content {
opacity: 1;
pointer-events: all;
}
/* ========================================================================
SKELETON SHAPE DEFINITIONS
======================================================================== */
/* Header Section Skeleton */
/* Matches actual header layout with photo absolutely positioned on right */
.skeleton-header {
position: relative;
padding-right: 185px; /* Match .cv-header-left padding */
min-height: 200px; /* Ensure space for photo */
}
.skeleton-header-text {
position: relative;
z-index: 1;
}
.skeleton-name {
height: 40px; /* Larger to match h1 */
width: 75%;
margin-bottom: 12px;
}
.skeleton-experience-years {
height: 24px; /* Larger subtitle */
width: 55%;
margin-bottom: 24px;
}
.skeleton-photo {
width: 150px; /* Match actual photo */
height: 200px; /* Match actual photo */
border-radius: 0; /* No border-radius on actual photo */
border: 3px solid #e8e8e8; /* Match photo border style */
/* Absolute positioning to match actual layout */
position: absolute;
top: 15px;
right: 15px;
flex-shrink: 0;
}
.skeleton-intro {
height: 90px; /* Taller for 3-4 lines of text */
width: 100%;
margin-top: 12px;
}
/* Section Title Skeleton */
.skeleton-section-title {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
}
.skeleton-icon {
width: 24px;
height: 24px;
border-radius: 4px;
flex-shrink: 0;
}
.skeleton-title-text {
height: 24px;
width: 40%;
}
/* Skill Item Skeleton (Sidebar) */
.skeleton-skill-category {
margin-bottom: 20px;
}
.skeleton-skill-title {
height: 20px;
width: 60%;
margin-bottom: 12px;
}
.skeleton-skill-items {
display: flex;
flex-direction: column;
gap: 8px;
}
.skeleton-skill-item {
height: 32px;
width: 100%;
}
.skeleton-skill-item:nth-child(2) {
width: 85%;
}
.skeleton-skill-item:nth-child(3) {
width: 90%;
}
.skeleton-skill-item:nth-child(4) {
width: 75%;
}
/* Experience Entry Skeleton */
.skeleton-experience-item {
display: flex;
gap: 16px;
margin-bottom: 24px;
}
.skeleton-company-logo {
width: 60px;
height: 60px;
border-radius: 8px;
flex-shrink: 0;
}
.skeleton-experience-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
/* NEW: Structural skeleton lines for experience */
.skeleton-position-line {
height: 20px;
width: 80%;
}
.skeleton-date-line {
height: 14px;
width: 50%;
}
.skeleton-description-line {
height: 16px;
width: 100%;
margin-top: 4px;
}
.skeleton-responsibility-line {
height: 14px;
width: 100%;
margin-left: 16px; /* Indent like list items */
}
/* Legacy styles (keeping for backward compatibility) */
.skeleton-position {
height: 20px;
width: 80%;
}
.skeleton-company-info {
height: 16px;
width: 60%;
}
.skeleton-description {
height: 40px;
width: 100%;
margin-top: 4px;
}
.skeleton-description.short {
width: 85%;
}
/* Section Skeleton Base */
.skeleton-section {
padding: 16px 0;
}
.skeleton-section-title {
height: 28px;
width: 35%;
margin-bottom: 20px;
}
/* Education Item Skeleton */
.skeleton-education-item {
height: 48px;
width: 100%;
margin-bottom: 12px;
}
.skeleton-education-item:last-child {
margin-bottom: 0;
}
/* Skills Summary Skeleton */
.skeleton-summary-paragraph {
height: 18px;
width: 100%;
margin-bottom: 10px;
}
.skeleton-summary-paragraph:last-child {
margin-bottom: 0;
}
/* Award Item Skeleton */
.skeleton-award-item {
display: flex;
gap: 16px;
margin-bottom: 24px;
}
.skeleton-award-logo {
width: 60px;
height: 60px;
border-radius: 8px;
flex-shrink: 0;
}
.skeleton-award-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
/* NEW: Structural skeleton lines for awards */
.skeleton-award-title-line {
height: 20px;
width: 70%;
}
.skeleton-award-info-line {
height: 14px;
width: 50%;
}
/* Legacy styles (keeping for backward compatibility) */
.skeleton-award-title {
height: 20px;
width: 70%;
}
.skeleton-award-info {
height: 16px;
width: 50%;
}
.skeleton-award-description {
height: 40px;
width: 100%;
margin-top: 4px;
}
/* Project Item Skeleton */
.skeleton-project-item {
display: flex;
gap: 16px;
margin-bottom: 24px;
}
.skeleton-project-icon {
width: 80px;
height: 80px;
border-radius: 8px;
flex-shrink: 0;
}
.skeleton-project-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
/* NEW: Structural skeleton lines for projects */
.skeleton-project-title-line {
height: 20px;
width: 75%;
}
.skeleton-tech-line {
height: 14px;
width: 85%;
margin-top: 4px;
}
.skeleton-footer-line {
height: 16px;
width: 70%;
margin-top: 16px;
}
/* Legacy styles (keeping for backward compatibility) */
.skeleton-project-title {
height: 20px;
width: 75%;
}
.skeleton-project-info {
height: 16px;
width: 55%;
}
.skeleton-project-description {
height: 40px;
width: 100%;
margin-top: 4px;
}
.skeleton-project-description.short {
width: 80%;
}
/* Course Item Skeleton */
.skeleton-course-item {
display: flex;
gap: 16px;
margin-bottom: 20px;
}
.skeleton-course-icon {
width: 80px;
height: 80px;
border-radius: 8px;
flex-shrink: 0;
}
.skeleton-course-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
/* NEW: Structural skeleton lines for courses */
.skeleton-course-title-line {
height: 18px;
width: 70%;
}
.skeleton-course-info-line {
height: 14px;
width: 60%;
}
/* Legacy styles (keeping for backward compatibility) */
.skeleton-course-title {
height: 18px;
width: 70%;
}
.skeleton-course-info {
height: 16px;
width: 60%;
}
/* Language Item Skeleton */
.skeleton-language-item {
height: 20px;
width: 100%;
margin-bottom: 12px;
}
.skeleton-language-item:last-child {
margin-bottom: 0;
}
/* Reference Item Skeleton */
.skeleton-reference-item {
height: 22px;
width: 100%;
margin-bottom: 10px;
}
.skeleton-reference-item:last-child {
margin-bottom: 0;
}
/* Other Section Skeleton */
.skeleton-other-item {
height: 20px;
width: 60%;
}
/* Sidebar Skeleton */
.skeleton-sidebar {
padding: 16px 0;
}
.skeleton-sidebar-header {
height: 28px;
width: 80%;
margin-bottom: 20px;
}
/* Skill Item Skeleton (Sidebar) - Already defined above but keeping for reference */
/* Footer Skeleton */
.skeleton-footer {
display: flex;
flex-direction: column;
gap: 12px;
padding: 16px 0;
}
.skeleton-footer-item {
height: 20px;
width: 100%;
}
.skeleton-footer-item:nth-child(2) {
width: 90%;
}
.skeleton-footer-item:nth-child(3) {
width: 85%;
}
.skeleton-footer-item:nth-child(4) {
width: 80%;
}
.skeleton-footer-item:nth-child(5) {
width: 75%;
}
/* Text Block Skeletons (Generic) */
.skeleton-text {
height: 16px;
margin-bottom: 8px;
}
.skeleton-text.short {
width: 60%;
}
.skeleton-text.medium {
width: 80%;
}
.skeleton-text.long {
width: 95%;
}
/* ========================================================================
RESPONSIVE ADJUSTMENTS
======================================================================== */
@media (max-width: 768px) {
.skeleton-header {
flex-direction: column;
align-items: center;
}
.skeleton-header-text {
text-align: center;
width: 100%;
}
.skeleton-name,
.skeleton-experience-years {
width: 80%;
margin-left: auto;
margin-right: auto;
}
.skeleton-photo {
width: 100px;
height: 100px;
border-radius: 8px;
}
.skeleton-experience-item {
flex-direction: column;
gap: 12px;
}
.skeleton-company-logo {
width: 50px;
height: 50px;
}
}
/* ========================================================================
ACCESSIBILITY - REDUCED MOTION
======================================================================== */
@media (prefers-reduced-motion: reduce) {
.skeleton {
animation: none;
background: #e8e8e8;
}
.component-wrapper .actual-content,
.component-wrapper .skeleton-content {
transition: none;
}
}
/* ========================================================================
PRINT STYLES
======================================================================== */
@media print {
.skeleton-content {
display: none !important;
}
.component-wrapper .actual-content {
opacity: 1 !important;
}
}
/* ========================================================================
PERFORMANCE OPTIMIZATIONS
======================================================================== */
/* Force GPU acceleration for skeleton elements */
.skeleton {
transform: translateZ(0);
backface-visibility: hidden;
}
/* Contain layout/paint/style to prevent reflow */
.component-wrapper {
contain: layout style;
}
/* Optimize skeleton rendering */
.skeleton-content {
contain: layout paint;
}