Skip to content

Commit 7575cc6

Browse files
CopilotStan2032
andcommitted
Session 233: Complete visual audit at all zoom×viewport combinations + responsive regression test
Visual audit complete: 11 pages × 9 viewport configurations (375/768/1280px at 100/125/150% zoom) = 99 combinations tested with zero overflow issues. Added responsive-layout.test.js (4 tests) to catch future overflow regressions: - Fixed widths >480px without responsive prefix - App root overflow-x-hidden guard - Large min-widths without scroll containers Updated TODO.md with visual audit completion. Co-authored-by: Stan2032 <68326386+Stan2032@users.noreply.github.com>
1 parent fa58f9a commit 7575cc6

2 files changed

Lines changed: 108 additions & 2 deletions

File tree

_agents/TODO.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Global Anti-CCP Resistance Hub — Active To-Do List
22

3-
> Last Updated: March 7, 2026 (Session 231)
3+
> Last Updated: March 8, 2026 (Session 233)
44
>
55
> **Location:** `_agents/TODO.md` — Active tasks only.
66
> **Completed tasks:** See `_agents/TODO_COMPLETED.md` for full archive.
@@ -51,7 +51,7 @@
5151
> **ALL COMPLETE** — Sessions 50-215. See `_agents/TODO_COMPLETED.md` and session history for details.
5252
> 47 completed items covering: mobile responsiveness, dark mode, sort/filter, dashboard usability, breadcrumbs, recent updates, region filters, contrast overhaul, deep usability, per-source loading, event countdown, alert sharing, data hygiene, live statistics JSON extraction, real data export, design system enforcement, URL validation, no-hashtags policy, profile page tests, 100% page test coverage, cross-JSON consistency, accessibility audit, keyboard navigation, performance resilience, sitemap freshness, route integrity, defensive coding, meta-test coverage, security audit, performance budget, ARIA live regions, data API, content analytics, API docs, data changelog, influence network, data comparison, advocacy letters, case timeline, international response tracker, sanction impact analyzer, HR org directory, overseas police stations, source diversity, prisoner dashboard, legal case tracker, cross-dataset insights, data integrity monitor.
5353
54-
- [x] **Visual overlap fixes**: ✅ InteractiveTimeline year labels fixed (Session 222) — adaptive 5-year intervals with min-gap endpoint exclusion, min-w-[540px] for mobile horizontal scroll. Verified zero overlaps at 375px (30px gaps), 768px (52px gaps), 1280px (69px gaps). Remaining audit: check ALL components at zoom levels 100%/125%/150% × viewports 375/768/1280px for any other text overlap or truncation issues. *(Originally reported by human, Session 221)*
54+
- [x] **Visual overlap fixes**: ✅ InteractiveTimeline year labels fixed (Session 222) — adaptive 5-year intervals with min-gap endpoint exclusion, min-w-[540px] for mobile horizontal scroll. Verified zero overlaps at 375px (30px gaps), 768px (52px gaps), 1280px (69px gaps). **Full visual audit complete (Sessions 232-233)**: All 11 pages tested at 100%/125%/150% zoom × 375/768/1280px viewports (99 combinations). Zero horizontal overflow, zero heading truncation, zero content-too-narrow issues. Session 232 fixed: QuickStartGuide dot overflow at 375px (WCAG 44px touch target inflating decorative dots), TakeAction horizontal scroll at 375px (p-6→p-4 sm:p-6 + AdvocacyLetterGenerator flex-wrap), added overflow-x-hidden on App root. *(Originally reported by human, Session 221)*
5555
- [x] **Placeholder text standardization**: ✅ Session 225 — All 48 placeholder instances across 30 files standardized to `placeholder:text-slate-400` (Tailwind v3+ syntax). Fixed 2 `placeholder-slate-600` violations, converted 19 `placeholder-slate-500` and 9 `placeholder-slate-400` (old syntax). Added 11th design system compliance test preventing reintroduction. Focus colors also standardized: 7 components fixed from non-terminal colors (emerald/green/cyan/amber/red) to terminal palette (`#4afa82`/`#22d3ee`).
5656
- [x] **Non-functional interactive elements audit & fix**: ✅ Session 230 — Full site audit for broken buttons, forms, and misleading UI. Fixed 9 issues across 8 files:
5757
- **EducationalResources.jsx**: "Start Course" button (no onClick) → replaced with "Course content coming soon" notice. Download buttons (no onClick, no URL) → replaced with disabled-style indicators.

src/test/responsive-layout.test.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { readFileSync, readdirSync, statSync } from 'fs';
3+
import { resolve, join } from 'path';
4+
5+
/**
6+
* Responsive Layout Compliance Tests
7+
*
8+
* Prevents common causes of horizontal overflow at mobile viewports:
9+
* - Fixed widths that exceed mobile screens (e.g., w-[500px])
10+
* - Excessive padding without responsive breakpoints on wrapper divs
11+
* - Missing overflow protection on containers with inline content
12+
*
13+
* These tests complement the visual audit (Sessions 232-233) which verified
14+
* all 11 pages at 100%/125%/150% zoom × 375/768/1280px with zero overflow.
15+
*/
16+
17+
const SRC_DIR = resolve(__dirname, '..');
18+
19+
function findJsxFiles(dir) {
20+
const files = [];
21+
for (const entry of readdirSync(dir)) {
22+
const full = join(dir, entry);
23+
if (entry === 'node_modules' || entry === 'test') continue;
24+
const stat = statSync(full);
25+
if (stat.isDirectory()) {
26+
files.push(...findJsxFiles(full));
27+
} else if (entry.endsWith('.jsx')) {
28+
files.push(full);
29+
}
30+
}
31+
return files;
32+
}
33+
34+
const jsxFiles = findJsxFiles(SRC_DIR);
35+
36+
describe('Responsive layout compliance', () => {
37+
it('finds JSX files to scan', () => {
38+
expect(jsxFiles.length).toBeGreaterThan(50);
39+
});
40+
41+
it('no fixed widths wider than 480px without responsive prefix', () => {
42+
// Fixed widths like w-[500px] or w-[600px] will overflow 375px mobile.
43+
// Allowed: w-[NNNpx] with sm:/md:/lg: prefix, or inside min-w-/max-w- context
44+
const FIXED_WIDTH = /(?<![:\w-])w-\[(\d+)px\]/g;
45+
const violations = [];
46+
for (const filePath of jsxFiles) {
47+
const content = readFileSync(filePath, 'utf-8');
48+
const relativePath = filePath.replace(SRC_DIR + '/', '');
49+
const lines = content.split('\n');
50+
lines.forEach((line, idx) => {
51+
// Skip comments and strings that aren't className
52+
if (/^\s*\/\//.test(line) || /^\s*\*/.test(line)) return;
53+
let match;
54+
const regex = /(?<![:\w-])w-\[(\d+)px\]/g;
55+
while ((match = regex.exec(line)) !== null) {
56+
const width = parseInt(match[1], 10);
57+
if (width > 480) {
58+
// Check if it has a responsive prefix (sm: md: lg: xl:)
59+
const before = line.substring(0, match.index);
60+
if (/(?:sm|md|lg|xl|2xl):$/.test(before.trim())) continue;
61+
// Check if it's min-w- or max-w- (not bare w-)
62+
if (/(?:min-w|max-w)-\[$/.test(before.slice(-6))) continue;
63+
violations.push(`${relativePath}:${idx + 1}: w-[${width}px] — fixed width exceeds mobile viewport`);
64+
}
65+
}
66+
});
67+
}
68+
expect(violations, `Fixed widths >480px without responsive prefix:\n${violations.join('\n')}`).toEqual([]);
69+
});
70+
71+
it('App root has overflow-x-hidden to prevent stray horizontal scroll', () => {
72+
const appPath = jsxFiles.find(f => f.endsWith('/App.jsx'));
73+
expect(appPath).toBeTruthy();
74+
const content = readFileSync(appPath, 'utf-8');
75+
expect(content).toContain('overflow-x-hidden');
76+
});
77+
78+
it('no hardcoded min-width wider than 540px without horizontal scroll container', () => {
79+
// min-w-[NNN] > 540px on a non-scroll container will break mobile.
80+
// Exception: elements inside overflow-x-auto or overflow-x-scroll containers
81+
const MIN_WIDTH = /min-w-\[(\d+)px\]/g;
82+
const violations = [];
83+
for (const filePath of jsxFiles) {
84+
const content = readFileSync(filePath, 'utf-8');
85+
const relativePath = filePath.replace(SRC_DIR + '/', '');
86+
const lines = content.split('\n');
87+
lines.forEach((line, idx) => {
88+
if (/^\s*\/\//.test(line) || /^\s*\*/.test(line)) return;
89+
let match;
90+
const regex = /min-w-\[(\d+)px\]/g;
91+
while ((match = regex.exec(line)) !== null) {
92+
const width = parseInt(match[1], 10);
93+
if (width > 540) {
94+
// Check if there's an overflow-x-auto/scroll on same line or nearby
95+
if (/overflow-x-(auto|scroll)/.test(line)) continue;
96+
// Check 3 lines before for scroll container
97+
const context = lines.slice(Math.max(0, idx - 3), idx + 1).join('\n');
98+
if (/overflow-x-(auto|scroll)/.test(context)) continue;
99+
violations.push(`${relativePath}:${idx + 1}: min-w-[${width}px] — may overflow mobile without scroll container`);
100+
}
101+
}
102+
});
103+
}
104+
expect(violations, `Large min-width without scroll container:\n${violations.join('\n')}`).toEqual([]);
105+
});
106+
});

0 commit comments

Comments
 (0)