Skip to content

refactor(landing): Phase 1 cleanup + bundled feature stack#7

Merged
maithuy2610 merged 30 commits into
mainfrom
refactor/phase1-quick-wins
May 24, 2026
Merged

refactor(landing): Phase 1 cleanup + bundled feature stack#7
maithuy2610 merged 30 commits into
mainfrom
refactor/phase1-quick-wins

Conversation

@maithuy2610

Copy link
Copy Markdown
Collaborator

Summary

This branch bundles the local landing-page work that had accumulated ahead of main (≈27 commits), culminating in the Phase 1 clean-code & refactor pass driven by AUDIT-REPORT.md.

⚠️ origin/main was 27 commits behind, so this PR necessarily includes the earlier unmerged feature stack (legacy design port, WebP migration, GA4 analytics, planner mobile-flow + hero map) in addition to the Phase 1 refactor. Review accordingly, or split if a smaller PR is preferred.

Phase 1 — Clean code & refactor (11 findings, behavior-preserving)

Last 8 commits (b5939f4..f88f1b5, + e198b1a docs):

Commit Findings
refactor(home) dead CSS, skip-link a11y, section renumber REQ-04, 05, 09
chore remove temp artifacts, ignore _* REQ-10
refactor(scripts) portable baseline OUT_DIR REQ-08
refactor(micro) remove dead count-up/rotate (−59 lines) REQ-03
refactor(carousel) navigateTo(), strict null, explicit if REQ-07, 11
refactor(planner) cache DOM refs, Set group check REQ-02, 06
refactor(js) IIFE-wrap app-links + menu REQ-01

Verification (Phase 1 only):

  • ✅ lint, format:check, build idempotent
  • ✅ analytics test pass
  • ✅ Behavior-preserving — proven: shipped-artifact diff (02ca9a3..HEAD) shows only the intended skip-link class + 2 dead-CSS-line removals; visual failing-set is identical at baseline (comm -13 = empty → zero new regressions)

Known: visual suite is red (pre-existing, not from Phase 1)

npm run test:visual = 39 fail / 30 pass on this branch and on the pre-Phase-1 commit 02ca9a3 — inherited from the feature work whose snapshots were never refreshed. Breakdown:

  • 16 stale screenshot diffs (need test:visual:update after visual review)
  • ~23 non-screenshot failures (carousel structural assertions, mobile-menu aria, index a11y, and swipe tests failing because playwright.config.js projects don't enable hasTouch)

These belong to finishing the planner-mobile-flow feature, tracked separately.

🤖 Generated with Claude Code

maithuy-cmyk and others added 28 commits May 23, 2026 15:37
- archive/index.html + archive/index 2.html: orphan backups, not referenced anywhere
- .hoangsa/sessions/{chore,design,docs,feat,feature,fix,refactor}/: 223 files of old audit/spec history, no longer needed

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Wrap 8 preview-* <img> tags in <picture> with WEBP source + PNG fallback
  (same pattern as hero banner)
- Add 8 untracked preview-*.webp files that were already on disk
- Restore App Store URL + data-app-link attributes in src/index.src.html
  (previously diverged from built file — commit 3803013 fixed built only)

Image weights:
  preview-user-profile  3,466 KB PNG → 310 KB WEBP  (-92%)
  preview-newsfeed      2,700 KB PNG → 328 KB WEBP  (-88%)
  preview-venue-detail  2,174 KB PNG → 320 KB WEBP  (-86%)
  preview-plan-list       980 KB PNG → 158 KB WEBP  (-84%)
  preview-AI-review       418 KB PNG → 143 KB WEBP  (-66%)
  + 3 more

Also: removed 10 macOS Finder " 2" duplicate files (logo 2.jpg,
preview-* 2.webp, ga 2.js — ~2.2 MB clutter, none referenced).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mpliance

- All 4 pages: load Google Analytics 4 via assets/js/ga.js + GTM
- CSP updated to allow GA/GTM domains across src/*.src.html
- privacy.html: rewrite section 7 to disclose GA usage (compliance)
- assets/js/app-links.js: support data-app-link-placement attribute
  for tracking which CTA was clicked (hero/final_cta)
- tests/app-links.test.js: behavior tests for analytics emission
- package.json: add test:analytics script
- README: document analytics attribute conventions and test:analytics

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures baseline screenshots of index.html across 4 viewports, records
overflow/lazy-load gaps and basic nav info — used when re-baselining
visual regression tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Append to existing lint-staged hook:
- Run `npm run build` to regenerate HTML/CSS from src/
- If working tree drifts from staged content → block commit with
  clear error message pointing to the right workflow

Catches two anti-patterns:
1. Direct edits to root *.html files (README rule violation)
2. Forgetting to rebuild after changing src/*.src.html

Also: .gitignore was ignoring entire .husky/ directory, blocking
contributors from adding hooks. Narrow to just .husky/_/ (Husky v9's
generated dir) so committed hooks like pre-commit can be modified
without -f.

Tested:
- Clean state → exit 0 (commit proceeds)
- `echo ... >> index.html && git add index.html && git commit` →
  exit 1 with explanatory message, husky blocks commit

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Save a frozen snapshot of the earlier index.html design (3,295 lines,
captured 2026-05-23) as design reference. The legacy version contains
sections + a Polaroid loop + a Mobile Sticky Bar that the current
src/index.src.html doesn't have — kept here so future redesigns can
reference layout/copy choices.

Not built or served — pure reference. README explains how to use it
without copying anti-patterns (Tailwind CDN, inline tailwind.config,
Lucide CDN, arbitrary hex colors) into the live source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Port from docs/legacy/index-2026-05-23.html into src/index.src.html:
- Problem + Vision section (id="problem") — timeline 7h/8h30/9h30 with colored cards
- Interactive Planner (id="planner", static demo) — age + vibe + weather filters mock
- Polaroid loop "How It Works" (id="how-it-works-loop") — 3 polaroid cards + outcome band
- Mobile Sticky Bar (id="sticky-bar") with dismiss functionality

Update 4 feature names (F3–F6) in feature grid:
- "Thông tin chi tiết" → "Chi tiết địa điểm"
- "Lưu địa điểm yêu thích" → "Lập kế hoạch cuối tuần"
- "Chia sẻ khoảnh khắc" → "Chỉ đường thông minh"
- "Đánh giá từ phụ huynh" → "Review từ phụ huynh"
+ updated SVG icons + descriptions to match new intent.

Reorder: move Testimonials to AFTER Polaroid loop (Hero → Stats → Problem
→ Planner → Features → Phone → Polaroid → Testimonials → FAQ → Download)
to match legacy narrative flow.

Dependencies added:
- Lucide CDN (https://unpkg.com/lucide@latest) for ~18 icons used by ported sections
- Google Fonts (Nunito, Caveat) for Polaroid typography
- New assets/css/polaroid.css (~80 lines) — Polaroid rotate/hover/tape styling
- New assets/js/sticky.js — dismiss handler
- CSP nới: script-src cho phép unpkg.com; style-src cho phép fonts.googleapis.com;
  font-src cho phép fonts.gstatic.com

Trade-off: ported sections use iOS green arbitrary hex (#34C759 / #24A94B /
#CFF5DA) while existing sections use Tailwind primary token (#22c55e).
Accepted intentionally to ship fast; unify in follow-up.

Spec: .hoangsa/sessions/feat/port-legacy-sections/

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wholesale port of body content from docs/legacy/index-2026-05-23.html
into src/index.src.html, replacing existing src section designs with
the legacy versions. All 12 legacy sections now present:

- Header (legacy nav with iOS green gradient CTA, mobile menu)
- Hero (legacy split layout with stats badge)
- Problem + Vision (already ported in prior commit)
- Interactive Planner (already ported)
- Feature Grid (replaced cards entirely, not just names)
- Phone Carousel (legacy coverflow markup with data-carousel-* attrs)
- Polaroid loop "How It Works" (already ported)
- Community Proof / Testimonials (replaced with legacy version)
- FAQ (replaced)
- Download CTA (replaced)
- Footer (replaced partials/footer.html with legacy 187-line version)
- Mobile Sticky Bar (already ported)

JS dependency fixes:
- menu.js: rename selector menu-toggle → mobile-menu-btn to match legacy header
- src markup: rename .phone-slide → .phone-item + add id=carousel-prev/next
  so existing carousel.js coverflow engine picks up legacy phone images

Stripped during port:
- Inline <style> blocks (already extracted to assets/css/polaroid.css)
- Inline <script> blocks except JSON-LD (we have separate JS modules)
- Tailwind CDN script (compiled CSS via Tailwind CLI is sufficient)
- Inline tailwind.config block (tokens live in tailwind.config.js)

Page now matches legacy design end-to-end. Visual snapshots will need
wholesale re-baselining.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…acy design)

Match legacy design:
- favicon: assets/images/favicon.png → assets/images/logo.jpg
- add apple-touch-icon: assets/images/app-icon-160.png

Applied to all 4 src files (index, privacy, terms, community-standards)
for consistency.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 UI bugs reported after wholesale section port:

1. Phone carousel broken — src's coverflow carousel.js (.phone-item +
   id="carousel-next/prev") doesn't match legacy markup (.phone-slide +
   data-offset attribute + data-carousel-* attrs). Fix:
   - Revert .phone-item rename → .phone-slide in src markup
   - Replace assets/css/carousel.css with full legacy CSS (17 rules
     incl. data-offset positioning + nav buttons + dots + 2 media
     queries for tablet/mobile breakpoints)
   - Replace assets/js/carousel.js with legacy initPhoneCarousel
     (data-offset based, autoplay, title sync, keyboard nav)

2. Lucide icons not rendering reliably — single-shot DOMContentLoaded
   call could miss if CDN was still loading. Fix:
   - Add defer to Lucide script
   - Replace single createIcons() call with retry loop: up to 20
     attempts × 150ms = 3s ceiling, exits early once window.lucide
     is available

3. Polaroid font + sticky bar — verified working in code (CSP allows
   fonts.gstatic.com for Caveat/Nunito; footer has pb-[80px] lg:pb-0
   for sticky bar clearance). No changes needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restore the "Tính năng độc quyền" interactive planner and remaining
hero/scroll micro-interactions that were dropped when the legacy
single-file landing was modularized.

- assets/js/planner.js: toggle groups, PLANNER_VENUES data, render +
  fallback banner, reset handler (ported from legacy inline script)
- assets/js/micro.js: scroll progress bar, nav active-section
  highlight, hero count-up, hero rotating suggestion, scroll reveal
- assets/js/menu.js: fix #year footer (was #copyright-year), add
  aria-label on mobile menu toggle
- assets/js/sticky.js: scroll-based show/hide via .show class
- src/input.css: data-toggle active states, .venue-card,
  #scroll-progress, nav a.is-active, .sticky-bar/.show, .reveal,
  reduce-motion query
- src/index.src.html: wire planner.js + micro.js script tags
- eslint.config.js: allow browser globals (IntersectionObserver,
  requestAnimationFrame)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
planner.js builds venue cards via template strings containing Tailwind
classes (sm:w-[38%], min-h-[160px], h-44, bg-[#F0FAF3], etc.). These
were purged by the JIT because the content config only scanned HTML
and SVG. Adding ./assets/js/**/*.js restores the missing card image
column and color tokens so the planner cards match the legacy design.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
FAQ <details> items rendered both the plus and minus icons stacked
because no CSS keyed icon visibility to the open state. Hide .faq-minus
by default and swap plus/minus on details[open]. CSS-only; markup
unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Checkpoint of in-progress cleanup-and-webp work (webp favicon, src/built
HTML cleanup, tailwind config) before branching off for the planner
mobile-flow feature.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clip horizontal overflow at 360 px from two sources:
- #experience: belt-and-suspenders clip for coverflow side phones
- #problem: decorative blur circle (-right-10 absolute) extended 24 px
  past the right viewport edge, causing scrollWidth > clientWidth

Uses overflow-x: clip (not hidden) on both sections to avoid creating
scroll containers that could flatten .phone-carousel's 3D perspective.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… comments

- src/input.css: drop dead .venue-card.is-hidden and [data-group=city] rules (REQ-04)
- src/index.src.html: skip-link now uses sr-only focus pattern (REQ-05); sequential section numbers (REQ-09)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ull check (REQ-07, REQ-11)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-02, REQ-06)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@netlify

netlify Bot commented May 24, 2026

Copy link
Copy Markdown

Deploy Preview for splendid-speculoos-fd7e51 ready!

Name Link
🔨 Latest commit baf8fae
🔍 Latest deploy log https://app.netlify.com/projects/splendid-speculoos-fd7e51/deploys/6a126b4f44c7af0008468fcf
😎 Deploy Preview https://deploy-preview-7--splendid-speculoos-fd7e51.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ination

#carousel-dots was role=tablist with non-tab button children and aria-selected
on plain buttons (2 critical axe violations: aria-allowed-attr ×8, aria-required-children).
Dots are pagination, not tabs (slides aren't tabpanels), so use role=group +
aria-current instead. Fixes index a11y test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@maithuy2610
maithuy2610 merged commit baf8fae into main May 24, 2026
4 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants