@loudpacks/theme-web
v0.2.2
Published
Web/Next.js theme picker modal with animations and live theme previews
Maintainers
Readme
@loudpacks/theme-web
Web/Next.js theme picker modal with smooth animations and live theme previews powered by Framer Motion.
Installation
npm install @loudpacks/theme-web @loudpacks/theme-core
# or
pnpm add @loudpacks/theme-web @loudpacks/theme-core
# or
yarn add @loudpacks/theme-web @loudpacks/theme-coreRequirements
- React ≥18.0.0
- React DOM ≥18.0.0
- Tailwind CSS ≥3.0.0 (required for styling)
Features
- 🎨 Live theme previews with light/dark mode toggle
- ✨ Smooth animations powered by Framer Motion
- ⌨️ Keyboard navigation (Escape to close)
- 🔒 Body scroll lock when modal is open
- 🎯 Portal-based rendering for proper z-index handling
- 🌐 SSR-friendly with Next.js App Router support
- 📱 Responsive grid layout
- ♿ Accessible with ARIA attributes
- ✅ Fully tested with 25+ test cases
Usage
Basic Setup
'use client'; // Required for Next.js App Router
import { ThemePickerModal } from '@loudpacks/theme-web';
import type { ThemeDefinitions } from '@loudpacks/theme-core';
import { useState } from 'react';
const themes: ThemeDefinitions = {
monochrome: {
displayName: 'Monochrome',
description: 'Clean monochrome design',
light: {
background: '#fafafa',
surface: '#ffffff',
text: '#1a1a1a',
// ... other color definitions
},
dark: {
background: '#121212',
surface: '#1e1e1e',
text: '#f5f5f5',
// ... other color definitions
},
},
// ... more themes
};
function App() {
const [showPicker, setShowPicker] = useState(false);
const [currentTheme, setCurrentTheme] = useState('monochrome');
return (
<>
<button onClick={() => setShowPicker(true)}>
Change Theme
</button>
<ThemePickerModal
visible={showPicker}
onClose={() => setShowPicker(false)}
currentTheme={currentTheme}
onSelectTheme={setCurrentTheme}
themes={themes}
initialPreviewMode="light"
config={{
showPreviewToggle: true,
closeOnSelect: true,
animationDuration: 300,
}}
/>
</>
);
}With System Color Scheme Detection
import { useSystemColorScheme } from '@loudpacks/theme-core';
function App() {
const systemScheme = useSystemColorScheme();
const [colorScheme, setColorScheme] = useState<'light' | 'dark'>(
systemScheme || 'light'
);
return (
<ThemePickerModal
// ... other props
initialPreviewMode={colorScheme}
/>
);
}With LocalStorage Persistence
import { useEffect } from 'react';
function App() {
const [currentTheme, setCurrentTheme] = useState('monochrome');
// Load saved theme on mount
useEffect(() => {
const saved = localStorage.getItem('app_theme');
if (saved) setCurrentTheme(saved);
}, []);
const handleSelectTheme = (themeKey: string) => {
setCurrentTheme(themeKey);
localStorage.setItem('app_theme', themeKey);
};
return (
<ThemePickerModal
// ... other props
onSelectTheme={handleSelectTheme}
/>
);
}Components
ThemePickerModal
The main modal component for selecting themes with animations.
Props:
visible(boolean): Controls modal visibilityonClose(() => void): Callback when modal is closedcurrentTheme(string): Currently selected theme keyonSelectTheme((themeKey: string) => void): Callback when theme is selectedthemes(ThemeDefinitions): Object containing all available themesinitialPreviewMode('light' | 'dark', optional): Initial preview modeheaderTitle(string, optional): Modal header text (default: "Choose Theme")className(string, optional): Additional CSS classes for the modalconfig(object, optional): Configuration options
ThemeCard
Individual theme preview card component with hover effects.
Props:
themeKey(string): Theme identifiertheme(ThemeMetadata): Theme dataisSelected(boolean): Whether this theme is currently selectedpreviewMode('light' | 'dark'): Which color scheme to previewonSelect(() => void): Callback when card is clicked
Configuration Options
{
showPreviewToggle: boolean; // Show light/dark toggle (default: true)
closeOnSelect: boolean; // Close modal after selection (default: false)
gridColumns: number; // Number of columns (default: 2)
animationDuration: number; // Animation duration in ms (default: 250)
}Styling
The component uses Tailwind CSS classes for styling. Tailwind CSS is required for proper styling.
Tailwind Setup
If you don't have Tailwind CSS installed, follow the official installation guide.
For Next.js projects:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -pEnsure your tailwind.config.js includes:
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx}',
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./node_modules/@loudpacks/theme-web/**/*.{js,mjs}', // Include theme-web
],
darkMode: 'class', // or 'media'
// ... rest of config
}Styling Features
The modal renders via React Portal and includes:
- Backdrop with opacity fade
- Modal with scale + opacity animation
- Responsive grid layout
- Dark mode support via Tailwind's
dark:variant - Hover effects on theme cards
- Focus states for accessibility
Examples
See the examples directory for complete working examples including:
- Basic Next.js setup
- LocalStorage persistence
- System color scheme detection
- CSS variable integration
License
MIT
