@@ -4,11 +4,12 @@ import { PhotoUpload } from './components/PhotoUpload';
44import { PaddingSettingsPanel } from './components/PaddingSettingsPanel' ;
55import { PhotoGrid } from './components/PhotoGrid' ;
66import { useLocalStorage } from './hooks/useLocalStorage' ;
7+ import { useDarkMode , type Theme } from './hooks/useDarkMode' ;
78import type { UploadedPhoto , PaddingSettings } from './types' ;
89import { ASPECT_RATIO_PRESETS } from './types' ;
910import { getImageDimensions , findMaxAspectRatio , padImageToAspectRatio } from './lib/imageUtils' ;
1011import { processFilesForHeic } from './lib/heicUtils' ;
11- import { Download , Trash2 , Layers } from 'lucide-react' ;
12+ import { Download , Trash2 , Layers , Sun , Moon , Monitor } from 'lucide-react' ;
1213
1314const DEFAULT_SETTINGS : PaddingSettings = {
1415 fillType : 'color' ,
@@ -43,6 +44,13 @@ export default function App() {
4344 const [ isProcessing , setIsProcessing ] = useState ( false ) ;
4445 const [ isProcessed , setIsProcessed ] = useState ( false ) ;
4546 const [ progress , setProgress ] = useState ( 0 ) ;
47+ const [ theme , setTheme ] = useDarkMode ( ) ;
48+
49+ const THEME_OPTIONS : { value : Theme ; icon : typeof Sun ; label : string } [ ] = [
50+ { value : 'light' , icon : Sun , label : 'Light' } ,
51+ { value : 'dark' , icon : Moon , label : 'Dark' } ,
52+ { value : 'system' , icon : Monitor , label : 'System' } ,
53+ ] ;
4654
4755 const maxAspectRatio = findMaxAspectRatio ( photos ) ;
4856
@@ -127,16 +135,33 @@ export default function App() {
127135 } ;
128136
129137 return (
130- < div className = "min-h-screen bg-gray-50" >
138+ < div className = "min-h-screen bg-gray-50 dark:bg-gray-950 transition-colors " >
131139 { /* Header */ }
132- < header className = "bg-white border-b border-gray-200 px-4 py-4" >
140+ < header className = "bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 px-4 py-4" >
133141 < div className = "max-w-6xl mx-auto flex items-center gap-3" >
134142 < div className = "bg-indigo-600 text-white rounded-xl p-2" >
135143 < Layers className = "w-5 h-5" />
136144 </ div >
137- < div >
138- < h1 className = "text-lg font-bold text-gray-900 leading-tight" > Squarify</ h1 >
139- < p className = "text-xs text-gray-500" > Pad photos to a uniform aspect ratio</ p >
145+ < div className = "flex-1" >
146+ < h1 className = "text-lg font-bold text-gray-900 dark:text-gray-100 leading-tight" > Squarify</ h1 >
147+ < p className = "text-xs text-gray-500 dark:text-gray-400" > Pad photos to a uniform aspect ratio</ p >
148+ </ div >
149+ { /* Theme toggle */ }
150+ < div className = "flex items-center bg-gray-100 dark:bg-gray-800 rounded-lg p-0.5" >
151+ { THEME_OPTIONS . map ( ( { value, icon : Icon , label } ) => (
152+ < button
153+ key = { value }
154+ onClick = { ( ) => setTheme ( value ) }
155+ title = { label }
156+ className = { `p-1.5 rounded-md transition-colors ${
157+ theme === value
158+ ? 'bg-white dark:bg-gray-700 text-indigo-600 dark:text-indigo-400 shadow-sm'
159+ : 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300'
160+ } `}
161+ >
162+ < Icon className = "w-4 h-4" />
163+ </ button >
164+ ) ) }
140165 </ div >
141166 </ div >
142167 </ header >
@@ -149,7 +174,7 @@ export default function App() {
149174
150175 { /* Stats bar */ }
151176 { photos . length > 0 && (
152- < div className = "flex items-center justify-between text-sm text-gray-600 bg-white border border-gray-200 rounded-lg px-4 py-2" >
177+ < div className = "flex items-center justify-between text-sm text-gray-600 dark:text-gray-400 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg px-4 py-2" >
153178 < span > { photos . length } photo{ photos . length !== 1 ? 's' : '' } · Target: < span className = "font-mono font-medium" > { settings . aspectRatio === 'auto' ? `Auto (${ maxAspectRatio . toFixed ( 3 ) } )` : settings . aspectRatio } </ span > { settings . borderPadding > 0 && ` · Border: ${ settings . borderPadding } px` } </ span >
154179 < button onClick = { handleClearAll } className = "flex items-center gap-1 text-xs text-red-500 hover:text-red-700 transition-colors" >
155180 < Trash2 className = "w-3 h-3" /> Clear all
@@ -170,11 +195,11 @@ export default function App() {
170195 { /* Progress */ }
171196 { isProcessing && (
172197 < div className = "space-y-2" >
173- < div className = "flex justify-between text-xs text-gray-600" >
198+ < div className = "flex justify-between text-xs text-gray-600 dark:text-gray-400 " >
174199 < span > Processing images…</ span >
175200 < span > { progress } %</ span >
176201 </ div >
177- < div className = "h-2 bg-gray-200 rounded-full overflow-hidden" >
202+ < div className = "h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden" >
178203 < div
179204 className = "h-full bg-indigo-500 rounded-full transition-all duration-200"
180205 style = { { width : `${ progress } %` } }
0 commit comments