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
This commit is contained in:
juanatsap
2025-11-19 14:31:17 +00:00
parent f8948413bc
commit f7cda5dba3
41 changed files with 12804 additions and 4740 deletions
+151
View File
@@ -0,0 +1,151 @@
#!/usr/bin/env bun
/**
* AWARDS VISUAL TEST
* Check awards section layout and icons
*/
import { chromium } from "playwright";
const URL = "http://localhost:1999";
async function testAwards() {
console.log("🧪 AWARDS VISUAL TEST\n");
console.log("=".repeat(70));
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage({ viewport: { width: 1400, height: 1080 } });
await page.goto(URL);
await page.waitForTimeout(2000);
// Scroll to awards section
await page.evaluate(() => {
const awards = document.querySelector('#awards');
if (awards) awards.scrollIntoView({ behavior: 'smooth', block: 'start' });
});
await page.waitForTimeout(1000);
console.log("\n1️⃣ Checking Awards Section:");
const awardsInfo = await page.evaluate(() => {
const awardsSection = document.querySelector('#awards');
const awardItems = document.querySelectorAll('.award-item');
const awardLogos = document.querySelectorAll('.award-logo');
const results = {
sectionExists: !!awardsSection,
itemCount: awardItems.length,
logoCount: awardLogos.length,
items: []
};
awardItems.forEach((item, i) => {
const logo = item.querySelector('.award-logo');
const logoImg = logo?.querySelector('img');
const content = item.querySelector('.award-content');
const logoStyle = logo ? window.getComputedStyle(logo) : null;
const imgStyle = logoImg ? window.getComputedStyle(logoImg) : null;
const itemStyle = window.getComputedStyle(item);
results.items.push({
index: i,
hasLogo: !!logo,
hasImg: !!logoImg,
imgSrc: logoImg?.src || 'none',
logoDisplay: logoStyle?.display,
logoWidth: logoStyle?.width,
logoHeight: logoStyle?.height,
imgWidth: imgStyle?.width,
imgHeight: imgStyle?.height,
imgObjectFit: imgStyle?.objectFit,
itemDisplay: itemStyle?.display,
itemGap: itemStyle?.gap,
contentExists: !!content
});
});
return results;
});
console.log(` Section exists: ${awardsInfo.sectionExists}`);
console.log(` Award items: ${awardsInfo.itemCount}`);
console.log(` Award logos: ${awardsInfo.logoCount}`);
awardsInfo.items.forEach(item => {
console.log(`\n Award #${item.index + 1}:`);
console.log(` Has logo: ${item.hasLogo}`);
console.log(` Has img: ${item.hasImg}`);
console.log(` Img src: ${item.imgSrc}`);
console.log(` Logo display: ${item.logoDisplay}`);
console.log(` Logo size: ${item.logoWidth} × ${item.logoHeight}`);
console.log(` Img size: ${item.imgWidth} × ${item.imgHeight}`);
console.log(` Img object-fit: ${item.imgObjectFit}`);
console.log(` Item display: ${item.itemDisplay}`);
console.log(` Item gap: ${item.itemGap}`);
console.log(` Has content: ${item.contentExists}`);
});
console.log("\n2️⃣ Testing icon toggle:");
// Turn icons OFF
await page.click('label:has(#iconToggle)');
await page.waitForTimeout(500);
const afterOff = await page.evaluate(() => {
const awardLogos = document.querySelectorAll('.award-logo');
const results = [];
awardLogos.forEach((logo, i) => {
const style = window.getComputedStyle(logo);
results.push({
index: i,
opacity: style.opacity,
width: style.width,
height: style.height
});
});
return results;
});
console.log(" Icons OFF:");
afterOff.forEach(logo => {
console.log(` Logo #${logo.index + 1}: opacity=${logo.opacity}, size=${logo.width}×${logo.height}`);
});
// Turn icons ON
await page.click('label:has(#iconToggle)');
await page.waitForTimeout(500);
const afterOn = await page.evaluate(() => {
const awardLogos = document.querySelectorAll('.award-logo');
const results = [];
awardLogos.forEach((logo, i) => {
const style = window.getComputedStyle(logo);
results.push({
index: i,
opacity: style.opacity,
width: style.width,
height: style.height
});
});
return results;
});
console.log("\n Icons ON:");
afterOn.forEach(logo => {
console.log(` Logo #${logo.index + 1}: opacity=${logo.opacity}, size=${logo.width}×${logo.height}`);
});
await page.screenshot({ path: 'tests/screenshots/awards-visual-test.png', fullPage: false });
console.log("\n📸 Screenshot saved to tests/screenshots/awards-visual-test.png");
console.log("\n" + "=".repeat(70));
console.log("\nBrowser will stay open for 60 seconds for visual inspection...");
await page.waitForTimeout(60000);
await browser.close();
}
await testAwards();