feat: Complete visual redesign with indigo/Swiss glassmorphism theme#20
feat: Complete visual redesign with indigo/Swiss glassmorphism theme#20
Conversation
Redesign the entire Prep platform with a cohesive indigo/violet accent color system, refined glassmorphism surfaces, CSS mesh gradient background, and Framer Motion animations throughout. Key changes: - New color system: indigo/violet accents, layered surface tokens, gradient text - CSS mesh gradient ambient background (replaces external image dependency) - Redesigned home page with animated hero, staggered card reveals, features section - Redesigned junior frontend page with numbered topic cards, progress bar, status badges - Redesigned content page components: section cards, code blocks, typography, callouts - Fixed width switcher hydration bug: state now initializes from persisted value after hydration instead of reading dataset during useState init - Redesigned table of contents: IntersectionObserver for active section tracking, ref-based click-outside detection (replaces fragile querySelector), clean mobile slide-over with backdrop, explicit toggle/close/pin buttons - All pages responsive across mobile (375px), tablet (768px), desktop (1440px) - Zero TypeScript errors, zero console errors, production build passes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR delivers a cohesive indigo/violet “Swiss glassmorphism” visual redesign across core pages/components, while also improving content-width persistence and replacing the table-of-contents behavior with a more robust, ref/IntersectionObserver-based implementation.
Changes:
- Introduces a new design system via CSS variables/utilities (glass/surface layers, mesh gradient ambient background, gradient text, light mode tokens).
- Refactors content width persistence/hydration to sync from persisted values on mount and avoid the prior hydration mismatch.
- Rebuilds the Table of Contents UI/UX (mobile toggle/backdrop, pin/close controls, active heading tracking, click-outside handling).
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/components/width-switcher/width-switcher.tsx | Updated width switcher styling and preset button UI |
| src/components/typography/text.tsx | Switched text colors to CSS-variable tokens |
| src/components/typography/subheader.tsx | Updated subheader styling to new token system |
| src/components/typography/header.tsx | Updated header styling + accent underline token |
| src/components/typography/code-span.tsx | Updated inline code styling to new surfaces/accent |
| src/components/typography/callout.tsx | Updated callout styling to new surfaces/accent |
| src/components/table-of-contents/table-of-contents.tsx | Major TOC redesign with IntersectionObserver + mobile UX |
| src/components/section-card/section-card.tsx | Updated section card styling + gradient title |
| src/components/page-header/page-header.tsx | Updated header styling and simplified breakpoint listener |
| src/components/notes-area/notes-area.tsx | Updated notes UI to new surface/border tokens |
| src/components/layout/page-container.tsx | Refactored width persistence + hydration gating for switcher |
| src/components/layout/content-page.tsx | Updated base text color to variable token |
| src/components/code-block/code-block.tsx | Updated code block styling + font token usage |
| src/components/ambient-background/ambient-background.tsx | Replaced external image background with CSS mesh/noise |
| src/app/layout.tsx | Updated metadata description (and retains width bootstrapping) |
| src/app/globals.css | New palette/tokens, utilities (glass/surface/gradient text), light mode |
| src/app/frontend/junior/frontend-junior.tsx | Redesigned Junior Frontend page with motion + new components styling |
| src/app/(main)/home.tsx | Redesigned Home page with hero + features section + motion |
| REDESIGN_PROMPT.md | Added redesign prompt documentation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <section | ||
| className='mb-12 rounded-lg border border-zinc-800 bg-zinc-900/90 p-6 backdrop-blur supports-[backdrop-filter]:bg-zinc-900/65' | ||
| className='mb-10 rounded-xl border border-[var(--border)] bg-[var(--surface-1)] p-6 sm:p-8' | ||
| id={id} | ||
| > | ||
| <h2 | ||
| className='mb-4 border-zinc-700 border-b pb-2 font-bold text-2xl text-white' | ||
| className='mb-5 border-[var(--border-strong)] border-b pb-3 font-bold text-2xl text-[var(--foreground)]' | ||
| id={id} | ||
| > |
There was a problem hiding this comment.
SectionCard assigns the same id to both the wrapping <section> and the <h2>. Duplicate IDs are invalid HTML and can break TOC behavior (e.g., document.getElementById() may return the <section> instead of the heading, so scroll offsets / intersection tracking won’t match the heading). Use a single element as the anchor target (typically keep the id on the heading and remove it from the wrapper, or generate distinct IDs).
| const touchStartRef = useRef<number | null>(null); | ||
| const openRef = useRef(open); | ||
| const pinnedRef = useRef(pinned); | ||
| const navRef = useRef<HTMLDivElement>(null); |
There was a problem hiding this comment.
navRef is typed as HTMLDivElement, but it’s attached to a <motion.nav> element. With strict TS this can cause a ref type mismatch (a <nav> is not a HTMLDivElement). Type the ref as HTMLElement/HTMLNavElement (or React.ElementRef<'nav'>) to match the element actually being referenced.
| const navRef = useRef<HTMLDivElement>(null); | |
| const navRef = useRef<HTMLElement | null>(null); |
| <button | ||
| aria-label='Open table of contents' | ||
| className={`fixed left-4 z-50 rounded-lg p-2 transition-all duration-200 ${ | ||
| open ? 'pointer-events-none opacity-0' : 'opacity-100' | ||
| } glass hover:bg-[var(--surface-2)]`} | ||
| onClick={() => setOpen(true)} |
There was a problem hiding this comment.
When open is true, the TOC toggle button is visually hidden via opacity-0/pointer-events-none but remains focusable for keyboard users and still exposed to assistive tech. Prefer conditionally rendering the button only when closed, or set tabIndex={-1} / disabled / aria-hidden when open is true to keep it out of the tab order.
| const presets: { key: WidthPreset; icon: string }[] = [ | ||
| { key: 'narrow', icon: '┃' }, | ||
| { key: 'comfortable', icon: '┃┃' }, | ||
| { key: 'wide', icon: '┃┃┃' }, | ||
| { key: 'full', icon: '┃┃┃┃' }, |
There was a problem hiding this comment.
presets includes an icon field but it’s never used (the button renders preset.key). Either render the icon or drop the unused property to avoid dead data and keep the component easier to maintain.
| const presets: { key: WidthPreset; icon: string }[] = [ | |
| { key: 'narrow', icon: '┃' }, | |
| { key: 'comfortable', icon: '┃┃' }, | |
| { key: 'wide', icon: '┃┃┃' }, | |
| { key: 'full', icon: '┃┃┃┃' }, | |
| const presets: { key: WidthPreset }[] = [ | |
| { key: 'narrow' }, | |
| { key: 'comfortable' }, | |
| { key: 'wide' }, | |
| { key: 'full' }, |
Summary
dataset.contentWidthduringuseStateinit which caused wrong defaultIntersectionObserverfor active section tracking,useRef-based click-outside detection (replaces fragilequerySelector('nav[style*="top:"]')), clean mobile slide-over with backdrop, explicit toggle/close/pin buttonsPages redesigned:
/): Hero section with animated entrance, gradient text, staggered card reveals, features section with scroll-triggered animations/frontend/junior): Numbered topic cards with status badges, progress bar, back navigation, animated grid/frontend/junior/html&css): Redesigned section cards, code blocks with indigo highlights, typography system, callouts/test): Inherits new themeDesign system:
#818cf8→#a78bfa→#c084fc)--surface-0through--surface-3)backdrop-filtertext-gradientutility classprefers-color-schemeTest plan
/and verify hero animation, card hover, features section/frontend/juniorand verify numbered cards, progress bar, disabled states/frontend/junior/html&cssand verify:bunx tsc --noEmitpassesbun run buildpasses🤖 Generated with Claude Code