feat(ui): phase-01 style & markup polish

- Drop italic on .hero .subtitle; use letter-spacing instead (Be Vietnam
  Pro italic renders rough on Linux).
- Migrate anchor underlines from border-bottom dotted to native
  text-decoration-style: dotted (figcaption + credit).
- Bump .card h3 to 1.2rem with thin gold rule under each Ngũ Hành
  label; reduce letter-spacing 1.2px → 0.4px so Vietnamese diacritics
  don't drift.
- Tighten .credit ul indent (move 1.25rem from margin to padding).
- Strengthen chip border 0.18 → 0.22 so pale chips (Rust-class) read
  against the cream page bg.
- Add role="list" to .chips and role="listitem" to chip spans for
  screen-reader semantics; aria-label per element bucket.
- Document 5-card-row decision (auto-fit retained) and chip contrast
  policy (best-effort WCAG luminance) as inline CSS comments.

Closes phase-01 of plan 260428-1003-implement-all-remaining (items
5-10, 13, 14, 15).
This commit is contained in:
tiennm99 committed 2026-04-28 10:56:42 +07:00
1 parent 0bee3d4759
commit 51d2b0515f
3 files changed
+33 -12

No files matched your search

+3
View File
@@ -23,6 +23,7 @@ function pickTextColor(hex) {
function buildChip(name, color, { rank = null } = {}) {
const span = document.createElement('span');
span.className = 'chip' + (rank ? ' chip-tiobe' : ' chip-other');
span.setAttribute('role', 'listitem');
span.textContent = name;
if (color) {
span.style.background = color;
@@ -53,6 +54,8 @@ export function renderGrid(buckets, mountEl) {
: `${langs.length} ngôn ngữ`;
const chips = document.createElement('div');
chips.className = 'chips';
chips.setAttribute('role', 'list');
chips.setAttribute('aria-label', `Ngôn ngữ thuộc ${label}`);
for (const { name, color, rank } of langs) chips.appendChild(buildChip(name, color, { rank }));
card.append(h3, count, chips);
fragment.appendChild(card);
@@ -15,7 +15,7 @@ Single pass through every remaining item in `plans/todo.md` and the post-cleanup
| # | Title | Status | Items |
|---|-------|--------|-------|
| 01 | Style & markup polish | pending | items 5–10, 13, 14, 15 (CSS one-liners + chip role + decision docs) |
| 01 | Style & markup polish | **done** | items 5–10, 13, 14, 15 (CSS one-liners + chip role + decision docs) |
| 02 | Functional toggles & tooltip | pending | items 2, 3, 4 (URL persistence, GitLab tooltip, hide empty KIM in TIOBE view) |
| 03 | Additive features | pending | items 11, 12 (Top-5 non-TIOBE peek, lunar SVG body texture) |
| 04 | OG social card image | pending | item 1 (generate `assets/og-card.png`, may block on tooling) |
+29 -11
View File
@@ -78,7 +78,7 @@ body {
font-size: clamp(1.55rem, 4.4vw, 2.5rem);
line-height: 1.2; color: var(--accent); letter-spacing: 0.2px; font-weight: 700;
}
.hero .subtitle { margin: 0.5rem auto 0; max-width: 38ch; color: var(--muted); font-style: italic; }
.hero .subtitle { margin: 0.5rem auto 0; max-width: 38ch; color: var(--muted); letter-spacing: 0.15px; }
.hero-ribbon {
display: flex; justify-content: center; gap: 8px;
margin: 1rem auto 0; width: max-content; max-width: 100%;
@@ -121,10 +121,13 @@ body {
text-align: center; margin-top: 0.6rem; color: var(--muted); font-size: 0.9rem;
}
.original-image figcaption a {
color: var(--accent-ink); text-decoration: none;
border-bottom: 1px dotted var(--accent);
color: var(--accent-ink);
text-decoration: underline;
text-decoration-style: dotted;
text-decoration-color: var(--accent);
text-underline-offset: 2px;
}
.original-image figcaption a:hover { color: var(--gold); border-bottom-color: var(--gold); }
.original-image figcaption a:hover { color: var(--gold); text-decoration-color: var(--gold); }
/* ---------- Section headings ---------- */
.elements h2, .credit h2 {
@@ -137,6 +140,8 @@ body {
}
/* ---------- Card grid ---------- */
/* Grid stays auto-fit (not forced 5-col) — the Ngũ-Hành wheel reads at any
viewport above 720px without crushing chip names. See plan 260428-1003. */
.grid {
display: grid;
gap: 1rem;
@@ -158,7 +163,14 @@ body {
.card:hover { transform: none; }
}
.card h3 { margin: 0 0 0.45rem; font-size: 1.05rem; letter-spacing: 1.2px; font-weight: 700; }
.card h3 {
margin: 0 0 0.5rem;
font-size: 1.2rem;
letter-spacing: 0.4px;
font-weight: 700;
padding-bottom: 0.4rem;
border-bottom: 1px solid color-mix(in oklch, var(--gold) 60%, transparent);
}
.card p { margin: 0; color: var(--fg); }
.card.kim { border-top-color: var(--kim); background: color-mix(in oklch, var(--kim) 6%, var(--card-bg)); }
@@ -181,13 +193,16 @@ body {
padding: 1.25rem 1.4rem 1.4rem; box-shadow: var(--shadow-sm);
}
.credit p { margin: 0.4rem 0; }
.credit ul { margin: 0.5rem 0 0.75rem 1.25rem; padding: 0; }
.credit ul { margin: 0.5rem 0 0.75rem; padding-left: 1.25rem; }
.credit a {
color: var(--accent-ink); text-decoration: none;
border-bottom: 1px dotted var(--accent);
transition: color 0.15s ease, border-color 0.15s ease;
color: var(--accent-ink);
text-decoration: underline;
text-decoration-style: dotted;
text-decoration-color: var(--accent);
text-underline-offset: 2px;
transition: color 0.15s ease, text-decoration-color 0.15s ease;
}
.credit a:hover { color: var(--gold); border-bottom-color: var(--gold); }
.credit a:hover { color: var(--gold); text-decoration-color: var(--gold); }
.credit a:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 3px; }
.credit .note { font-size: 0.85rem; color: var(--muted); font-style: italic; }
@@ -225,11 +240,14 @@ body {
background: var(--border-strong); border-radius: 3px;
}
/* Chip text contrast policy: best-effort via WCAG luminance picker
(render-elements.js pickTextColor). Worst post-fix case ~3.5:1
(Swift, MATLAB) is acceptable for decorative chips. */
.chip {
display: inline-flex; align-items: center;
padding: 0.22rem 0.6rem; border-radius: 999px;
font-size: 0.78rem; line-height: 1.4;
border: 1px solid rgba(0, 0, 0, 0.18);
border: 1px solid rgba(0, 0, 0, 0.22);
background: var(--bg); color: var(--fg);
max-width: 100%;
white-space: normal;