Skip to main content

Overview

The portfolio uses a sophisticated theme system built with React Context API, supporting both light and dark modes with persistent user preferences. The theme is powered by CSS custom properties and Tailwind CSS.

Theme System Architecture

ThemeContext

The theme is managed through a React Context located at src/contexts/ThemeContext.jsx:
src/contexts/ThemeContext.jsx
import React, { createContext, useContext, useEffect, useState } from 'react';

const ThemeContext = createContext();

export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
};

export const ThemeProvider = ({ children }) => {
  const [isDark, setIsDark] = useState(() => {
    const saved = localStorage.getItem('theme');
    return saved ? saved === 'dark' : true; // Default to dark
  });

  useEffect(() => {
    localStorage.setItem('theme', isDark ? 'dark' : 'light');
    document.documentElement.classList.toggle('dark', isDark);
  }, [isDark]);

  const toggleTheme = () => setIsDark(!isDark);

  return (
    <ThemeContext.Provider value={{ isDark, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

Using the Theme Hook

Access theme state in any component:
import { useTheme } from '@/contexts/ThemeContext';

function MyComponent() {
  const { isDark, toggleTheme } = useTheme();
  
  return (
    <button onClick={toggleTheme}>
      Current theme: {isDark ? 'Dark' : 'Light'}
    </button>
  );
}

Color System

CSS Custom Properties

The theme uses CSS variables defined in src/index.css:
src/index.css
:root {
  --bg-color: #080808;
  --second-bg-color: #131313;
  --text-color: white;
  --main-color: #00ffee;
}

.dark {
  --bg-primary: #0f172a;
  --bg-secondary: #1e293b;
  --bg-tertiary: #334155;
  --text-primary: #f1f5f9;
  --text-secondary: #cbd5e1;
  --text-tertiary: #94a3b8;
  --border-color: #475569;
  --accent-color: #3b82f6;
}
1
Change the Default Theme
2
Modify the default theme preference in ThemeContext.jsx:
3
// Change from dark to light as default
const [isDark, setIsDark] = useState(() => {
  const saved = localStorage.getItem('theme');
  return saved ? saved === 'dark' : false; // Now defaults to light
});
4
Customize Dark Mode Colors
5
Update the dark mode color variables in src/index.css:
6
.dark {
  --bg-primary: #1a1a2e;        /* Changed from #0f172a */
  --bg-secondary: #16213e;       /* Changed from #1e293b */
  --accent-color: #e94560;       /* Changed from #3b82f6 */
}
7
Customize Light Mode Colors
8
Modify the root variables for light mode:
9
:root {
  --bg-color: #f8f9fa;          /* Changed from #080808 */
  --text-color: #212529;         /* Changed from white */
  --main-color: #0066cc;         /* Changed from #00ffee */
}
The portfolio uses a professional navy color palette defined in tailwind.config.js:
tailwind.config.js
colors: {
  navy: {
    50: '#f8fafc',
    100: '#f1f5f9',
    200: '#e2e8f0',
    300: '#cbd5e1',
    400: '#94a3b8',
    500: '#64748b',
    600: '#475569',
    700: '#334155',
    800: '#1e293b',
    900: '#0f172a',
  },
}
Use these navy shades consistently across components with classes like bg-navy-800, text-navy-300, or border-navy-500.

Customizing the Color Palette

// tailwind.config.js
colors: {
  brand: {
    50: '#faf5ff',
    100: '#f3e8ff',
    200: '#e9d5ff',
    300: '#d8b4fe',
    400: '#c084fc',
    500: '#a855f7',
    600: '#9333ea',
    700: '#7e22ce',
    800: '#6b21a8',
    900: '#581c87',
  },
}
After changing the color palette name (e.g., from navy to brand), you’ll need to update all component files that reference the old color name. Use find and replace: navy-brand-

Theme Toggle Component

The theme toggle is implemented using an animated component:
src/components/ThemeToggle.jsx
import { AnimatedThemeToggler } from './ui/animated-theme-toggler';

const ThemeToggle = () => {
  return <AnimatedThemeToggler />;
};

export default ThemeToggle;

Customizing the Toggle Appearance

You can modify the animated theme toggler component or create your own custom toggle:
Custom Toggle Example
import { useTheme } from '@/contexts/ThemeContext';
import { Moon, Sun } from 'lucide-react';

const CustomThemeToggle = () => {
  const { isDark, toggleTheme } = useTheme();
  
  return (
    <button
      onClick={toggleTheme}
      className="p-2 rounded-lg bg-navy-100 dark:bg-slate-800 hover:bg-navy-200 dark:hover:bg-slate-700 transition-colors"
    >
      {isDark ? <Sun size={20} /> : <Moon size={20} />}
    </button>
  );
};

Shadcn UI Color System

The portfolio also integrates Shadcn UI’s color system:
tailwind.config.js
colors: {
  background: 'hsl(var(--background))',
  foreground: 'hsl(var(--foreground))',
  primary: {
    DEFAULT: 'hsl(var(--primary))',
    foreground: 'hsl(var(--primary-foreground))'
  },
  secondary: {
    DEFAULT: 'hsl(var(--secondary))',
    foreground: 'hsl(var(--secondary-foreground))'
  },
  // ... more colors
}
These are defined as HSL values in your CSS for easy theming:
:root {
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --primary: 222.2 47.4% 11.2%;
}

.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 98%;
  --primary: 210 40% 98%;
}
Use the Shadcn themes generator to create custom color schemes that integrate seamlessly with the existing components.

Disable Theme Switching

To lock the portfolio to a single theme:
1
Remove Theme Toggle
2
Remove or comment out the ThemeToggle component from your navigation:
3
// import ThemeToggle from './ThemeToggle';

// Remove from render:
// <ThemeToggle />
4
Set Fixed Theme
5
Modify the ThemeContext to always use one theme:
6
export const ThemeProvider = ({ children }) => {
  const [isDark] = useState(true); // Always dark
  // Remove setIsDark and toggleTheme
  
  useEffect(() => {
    document.documentElement.classList.add('dark');
  }, []);
  
  return (
    <ThemeContext.Provider value={{ isDark }}>
      {children}
    </ThemeContext.Provider>
  );
};

Best Practices

  • Consistency: Use the same color palette throughout your components
  • Accessibility: Ensure sufficient contrast between text and background colors
  • Testing: Test all components in both light and dark modes after making changes
  • CSS Variables: Prefer CSS custom properties for values that change between themes
  • Tailwind Classes: Use Tailwind’s dark: variant for theme-specific styling

Next Steps

Styling Guide

Learn about Tailwind configuration and component styling

Content Updates

Update personal information, projects, and services

Build docs developers (and LLMs) love