feat: Complete visual redesign with aurora/gradient theme#19
feat: Complete visual redesign with aurora/gradient theme#19
Conversation
Replace the dark-first yellow-accent design with a new deep-space aurora theme featuring indigo/violet/pink/cyan gradients, animated mesh background, and modern glass morphism effects. Redesign all pages including homepage hero section with animated scroll reveals, topic selection with progress tracking, and content pages with updated typography and code block styling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Bump Next.js from 16.0.1 to 16.1.6 and React/react-dom from 19.0.0 to 19.2.4 to address CVE in React Server Components (vercel.com/kb/bulletin/react2shell). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR implements a comprehensive visual redesign of the interview preparation platform, transitioning from a yellow-accent dark theme to a modern aurora/gradient theme with deep-space navy base colors and indigo/violet/pink/cyan gradients.
Changes:
- Introduces a new CSS variable-based color system supporting both dark and light modes
- Replaces static background with animated gradient orbs using Framer Motion
- Redesigns homepage with hero section, animated badge, gradient text, scroll indicator, and features grid
- Redesigns topics page with progress bar, numbered cards with color-coded icons, and animations
- Updates all shared components (PageHeader, SectionCard, CodeBlock, TableOfContents, typography components, etc.) to use CSS variables for consistent theming
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/app/globals.css | New color system with CSS variables, glass effects, gradient utilities, and custom scrollbar/selection styles |
| src/components/ambient-background/ambient-background.tsx | Animated background with 4 floating gradient orbs, noise texture, and edge glow |
| src/app/(main)/home.tsx | Complete homepage redesign with hero section, topic cards, and features grid using Framer Motion |
| src/app/frontend/junior/frontend-junior.tsx | Redesigned topics page with progress bar, numbered topic cards, and icons |
| src/components/typography/*.tsx | Updated all typography components (Text, Header, Subheader, CodeSpan, Callout) to use CSS variables |
| src/components/page-header/page-header.tsx | Updated colors to use CSS variables |
| src/components/section-card/section-card.tsx | Updated styling with new border radius and CSS variables |
| src/components/code-block/code-block.tsx | Updated colors for highlighted lines to match new theme |
| src/components/table-of-contents/table-of-contents.tsx | Updated colors to use CSS variables |
| src/components/width-switcher/width-switcher.tsx | Updated colors to use CSS variables |
| src/components/notes-area/notes-area.tsx | Updated styling with new border radius and CSS variables |
| src/components/layout/content-page.tsx | Updated text color to use CSS variable |
| .gitignore | Added .claude directory to ignore list |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <motion.div | ||
| animate={{ | ||
| x: [0, 30, -20, 0], | ||
| y: [0, -40, 20, 0], | ||
| scale: [1, 1.1, 0.95, 1], | ||
| }} | ||
| className='motion-safe-only absolute top-[-10%] left-[15%] h-[500px] w-[500px] rounded-full' | ||
| style={{ | ||
| background: | ||
| 'radial-gradient(circle, rgba(99, 102, 241, 0.2), transparent 70%)', | ||
| filter: 'blur(60px)', | ||
| }} | ||
| transition={{ | ||
| duration: 20, | ||
| repeat: Number.POSITIVE_INFINITY, | ||
| ease: 'easeInOut', | ||
| }} | ||
| /> | ||
|
|
||
| <motion.div | ||
| animate={{ | ||
| x: [0, -40, 30, 0], | ||
| y: [0, 30, -30, 0], | ||
| scale: [1, 0.9, 1.1, 1], | ||
| }} | ||
| className='motion-safe-only absolute top-[20%] right-[10%] h-[600px] w-[600px] rounded-full' | ||
| style={{ | ||
| background: | ||
| 'radial-gradient(circle, rgba(236, 72, 153, 0.12), transparent 70%)', | ||
| filter: 'blur(80px)', | ||
| }} | ||
| transition={{ | ||
| duration: 25, | ||
| repeat: Number.POSITIVE_INFINITY, | ||
| ease: 'easeInOut', | ||
| }} | ||
| /> | ||
|
|
||
| <motion.div | ||
| animate={{ | ||
| x: [0, 50, -30, 0], | ||
| y: [0, -20, 40, 0], | ||
| scale: [1, 1.15, 0.9, 1], | ||
| }} | ||
| className='motion-safe-only absolute bottom-[-5%] left-[30%] h-[500px] w-[500px] rounded-full' | ||
| style={{ | ||
| background: | ||
| 'radial-gradient(circle, rgba(6, 182, 212, 0.15), transparent 70%)', | ||
| filter: 'blur(70px)', | ||
| }} | ||
| transition={{ | ||
| duration: 22, | ||
| repeat: Number.POSITIVE_INFINITY, | ||
| ease: 'easeInOut', | ||
| }} | ||
| /> | ||
|
|
||
| <motion.div | ||
| animate={{ | ||
| x: [0, -30, 40, 0], | ||
| y: [0, 40, -20, 0], | ||
| }} | ||
| className='motion-safe-only absolute top-[50%] left-[60%] h-[400px] w-[400px] rounded-full' | ||
| style={{ | ||
| background: | ||
| 'radial-gradient(circle, rgba(139, 92, 246, 0.1), transparent 70%)', | ||
| filter: 'blur(60px)', | ||
| }} | ||
| transition={{ | ||
| duration: 18, | ||
| repeat: Number.POSITIVE_INFINITY, | ||
| ease: 'easeInOut', | ||
| }} | ||
| /> |
There was a problem hiding this comment.
The motion-safe-only class with animation: none; transition: none; in CSS won't disable Framer Motion animations. Framer Motion uses JavaScript-driven animations with inline styles, not CSS animations. To properly support prefers-reduced-motion, you should use Framer Motion's useReducedMotion hook or pass a motion config to the MotionConfig provider. Consider wrapping the aurora orbs with a conditional check for reduced motion preferences.
| mask: | ||
| linear-gradient(#fff 0 0) content-box, | ||
| linear-gradient(#fff 0 0); | ||
| mask-composite: exclude; |
There was a problem hiding this comment.
The mask-composite: exclude property has limited browser support. While you've added -webkit-mask-composite: xor for WebKit browsers, Firefox requires -moz-mask-composite: exclude. Consider adding a fallback for browsers that don't support mask-composite, such as a simple border or using an SVG-based approach. Alternatively, add the Firefox-specific property: -moz-mask-composite: exclude;
| mask-composite: exclude; | |
| mask-composite: exclude; | |
| -moz-mask-composite: exclude; |
| .gradient-text { | ||
| background: linear-gradient( | ||
| 135deg, | ||
| var(--aurora-1), | ||
| var(--aurora-2), | ||
| var(--aurora-3) | ||
| ); | ||
| -webkit-background-clip: text; | ||
| -webkit-text-fill-color: transparent; | ||
| background-clip: text; | ||
| } |
There was a problem hiding this comment.
The gradient text using -webkit-text-fill-color: transparent may cause accessibility issues. When users select this text, it may not be visible in the selection highlight. Additionally, some screen readers and browser extensions might not properly render this text. Consider testing with various assistive technologies and ensuring the underlying text color provides sufficient contrast as a fallback.
| @keyframes aurora-shift { | ||
| 0%, | ||
| 100% { | ||
| background-position: 0% 50%; | ||
| } | ||
| 25% { | ||
| background-position: 100% 0%; | ||
| } | ||
| 50% { | ||
| background-position: 100% 100%; | ||
| } | ||
| 75% { | ||
| background-position: 0% 100%; | ||
| } | ||
| } | ||
|
|
||
| @keyframes float { | ||
| 0%, | ||
| 100% { | ||
| transform: translateY(0) scale(1); | ||
| } | ||
| 50% { | ||
| transform: translateY(-20px) scale(1.05); | ||
| } | ||
| } | ||
|
|
||
| @keyframes pulse-glow { | ||
| 0%, | ||
| 100% { | ||
| opacity: 0.4; | ||
| transform: scale(1); | ||
| } | ||
| 50% { | ||
| opacity: 0.7; | ||
| transform: scale(1.1); | ||
| } | ||
| } |
There was a problem hiding this comment.
The keyframe animations aurora-shift, float, and pulse-glow are defined but not used anywhere in the codebase. Consider removing them to reduce bundle size, or if they're intended for future use, add a comment explaining that.
| <motion.div | ||
| animate={{ | ||
| x: [0, 30, -20, 0], | ||
| y: [0, -40, 20, 0], | ||
| scale: [1, 1.1, 0.95, 1], | ||
| }} | ||
| className='motion-safe-only absolute top-[-10%] left-[15%] h-[500px] w-[500px] rounded-full' | ||
| style={{ | ||
| background: | ||
| 'radial-gradient(circle, rgba(99, 102, 241, 0.2), transparent 70%)', | ||
| filter: 'blur(60px)', | ||
| }} | ||
| transition={{ | ||
| duration: 20, | ||
| repeat: Number.POSITIVE_INFINITY, | ||
| ease: 'easeInOut', | ||
| }} | ||
| /> | ||
|
|
||
| <motion.div | ||
| animate={{ | ||
| x: [0, -40, 30, 0], | ||
| y: [0, 30, -30, 0], | ||
| scale: [1, 0.9, 1.1, 1], | ||
| }} | ||
| className='motion-safe-only absolute top-[20%] right-[10%] h-[600px] w-[600px] rounded-full' | ||
| style={{ | ||
| background: | ||
| 'radial-gradient(circle, rgba(236, 72, 153, 0.12), transparent 70%)', | ||
| filter: 'blur(80px)', | ||
| }} | ||
| transition={{ | ||
| duration: 25, | ||
| repeat: Number.POSITIVE_INFINITY, | ||
| ease: 'easeInOut', | ||
| }} | ||
| /> | ||
|
|
||
| <motion.div | ||
| animate={{ | ||
| x: [0, 50, -30, 0], | ||
| y: [0, -20, 40, 0], | ||
| scale: [1, 1.15, 0.9, 1], | ||
| }} | ||
| className='motion-safe-only absolute bottom-[-5%] left-[30%] h-[500px] w-[500px] rounded-full' | ||
| style={{ | ||
| background: | ||
| 'radial-gradient(circle, rgba(6, 182, 212, 0.15), transparent 70%)', | ||
| filter: 'blur(70px)', | ||
| }} | ||
| transition={{ | ||
| duration: 22, | ||
| repeat: Number.POSITIVE_INFINITY, | ||
| ease: 'easeInOut', | ||
| }} | ||
| /> | ||
|
|
||
| <motion.div | ||
| animate={{ | ||
| x: [0, -30, 40, 0], | ||
| y: [0, 40, -20, 0], | ||
| }} | ||
| className='motion-safe-only absolute top-[50%] left-[60%] h-[400px] w-[400px] rounded-full' | ||
| style={{ | ||
| background: | ||
| 'radial-gradient(circle, rgba(139, 92, 246, 0.1), transparent 70%)', | ||
| filter: 'blur(60px)', | ||
| }} | ||
| transition={{ | ||
| duration: 18, | ||
| repeat: Number.POSITIVE_INFINITY, | ||
| ease: 'easeInOut', | ||
| }} | ||
| /> |
There was a problem hiding this comment.
The ambient background renders 4 continuously animating orbs with blur filters and transforms. While visually appealing, this could impact performance on lower-end devices. Consider using will-change: transform on the motion.div elements to optimize rendering, or implementing a performance-based toggle to disable these animations on devices with limited GPU resources.
| className={`card-glow group relative flex items-center gap-5 rounded-2xl border border-[var(--border)] bg-[var(--card-bg)] p-6 text-left backdrop-blur-sm transition-all duration-300 hover:border-[var(--border-hover)] ${ | ||
| section.inProgress | ||
| ? 'cursor-default opacity-60' | ||
| : 'hover:bg-[var(--glass-bg)]' |
There was a problem hiding this comment.
The disabled topic cards still have hover:border-[var(--border-hover)] in their className, which will apply hover styles even when disabled. Consider moving this hover class into the conditional className logic so it only applies when the button is not in progress.
| className={`card-glow group relative flex items-center gap-5 rounded-2xl border border-[var(--border)] bg-[var(--card-bg)] p-6 text-left backdrop-blur-sm transition-all duration-300 hover:border-[var(--border-hover)] ${ | |
| section.inProgress | |
| ? 'cursor-default opacity-60' | |
| : 'hover:bg-[var(--glass-bg)]' | |
| className={`card-glow group relative flex items-center gap-5 rounded-2xl border border-[var(--border)] bg-[var(--card-bg)] p-6 text-left backdrop-blur-sm transition-all duration-300 ${ | |
| section.inProgress | |
| ? 'cursor-default opacity-60' | |
| : 'hover:border-[var(--border-hover)] hover:bg-[var(--glass-bg)]' |
| --glass-strong-bg: rgba(248, 250, 252, 0.85); | ||
| --card-bg: rgba(255, 255, 255, 0.7); | ||
| --surface-1: #ffffff; | ||
| --surface-2: #f1f5f9; |
There was a problem hiding this comment.
In light mode, the accent colors (--accent, --accent-light, --secondary, --tertiary) are not redefined and will use the same values as dark mode. While this provides color consistency, some of these colors may not provide sufficient contrast against the light background (#f8fafc). Consider testing the color contrast ratios for WCAG compliance and potentially adjusting these colors for light mode to ensure accessibility.
| --surface-2: #f1f5f9; | |
| --surface-2: #f1f5f9; | |
| /* Light-mode accent system tuned for contrast on #f8fafc */ | |
| --accent: #4f46e5; /* indigo-600: stronger contrast than indigo-500 on light bg */ | |
| --accent-light: #6366f1; /* indigo-500: used for lighter accents against dark text */ | |
| --accent-glow: rgba(79, 70, 229, 0.25); | |
| --secondary: #db2777; /* pink-600: higher contrast than pink-400 on light bg */ | |
| --secondary-glow: rgba(219, 39, 119, 0.25); | |
| --tertiary: #059669; /* emerald-600: higher contrast than emerald-400 on light bg */ |
Summary
prefers-reduced-motionsupportprefers-color-schemewith distinct palettes for both modesTest plan
/) — verify hero section, gradient text, CTA button, scroll animations/frontend/junior— verify progress bar, topic cards, icon colors/frontend/junior/html&css— verify content page header, code blocks, callouts, typographyprefers-reduced-motiondisables background animations🤖 Generated with Claude Code