Add light mode support.

This commit is contained in:
Jaret Burkett
2026-03-31 16:54:55 -06:00
parent ad474e3d06
commit 853ffaf207
23 changed files with 183 additions and 79 deletions

View File

@@ -55,27 +55,27 @@ export default function DatasetPage({ params }: { params: { datasetName: string
text = 'Loading Images';
subtitle = 'Please wait while we fetch your dataset images...';
showIt = true;
bgColor = 'bg-gray-50 dark:bg-gray-800/50';
textColor = 'text-gray-900 dark:text-gray-100';
iconColor = 'text-gray-500 dark:text-gray-400';
bgColor = 'bg-gray-800/50';
textColor = 'text-gray-100';
iconColor = 'text-gray-400';
}
if (status == 'error') {
icon = <LuBan className="w-8 h-8" />;
text = 'Error Loading Images';
subtitle = 'There was a problem fetching the images. Please try refreshing the page.';
showIt = true;
bgColor = 'bg-red-50 dark:bg-red-950/20';
textColor = 'text-red-900 dark:text-red-100';
iconColor = 'text-red-600 dark:text-red-400';
bgColor = 'bg-red-600/20';
textColor = 'text-red-100';
iconColor = 'text-red-400';
}
if (status == 'success' && imgList.length === 0) {
icon = <LuImageOff className="w-8 h-8" />;
text = 'No Images Found';
subtitle = 'This dataset is empty. Click "Add Images" to get started.';
showIt = true;
bgColor = 'bg-gray-50 dark:bg-gray-800/50';
textColor = 'text-gray-900 dark:text-gray-100';
iconColor = 'text-gray-500 dark:text-gray-400';
bgColor = 'bg-gray-800/50';
textColor = 'text-gray-100';
iconColor = 'text-gray-400';
}
if (!showIt) return null;
@@ -106,7 +106,7 @@ export default function DatasetPage({ params }: { params: { datasetName: string
<div className="flex-1"></div>
<div>
<Button
className="text-gray-200 bg-slate-600 px-3 py-1 rounded-md"
className="text-white bg-slate-600 px-3 py-1 rounded-md"
onClick={() => openImagesModal(datasetName, () => refreshImageList(datasetName))}
>
Add Images

View File

@@ -114,12 +114,12 @@ export default function Datasets() {
<>
<TopBar>
<div>
<h1 className="text-2xl font-semibold text-gray-100">Datasets</h1>
<h1 className="text-lg">Datasets</h1>
</div>
<div className="flex-1"></div>
<div>
<Button
className="text-gray-200 bg-slate-600 px-4 py-2 rounded-md hover:bg-slate-500 transition-colors"
className="text-white bg-slate-600 px-3 py-1 rounded-md hover:bg-slate-500 transition-colors"
onClick={() => openNewDatasetModal()}
>
New Dataset

View File

@@ -2,16 +2,39 @@
@tailwind components;
@tailwind utilities;
/* Light mode (default root values, overridden by .dark) */
:root {
--background: #ffffff;
--background: #fafafa;
--foreground: #171717;
/* Gray scale: inverted for light mode so bg-gray-950 = light bg, text-gray-100 = dark text */
--gray-950: 235 235 235;
--gray-900: 215 215 215;
--gray-800: 195 195 195;
--gray-700: 175 175 175;
--gray-600: 163 163 163;
--gray-500: 115 115 115;
--gray-400: 82 82 82;
--gray-300: 64 64 64;
--gray-200: 38 38 38;
--gray-100: 23 23 23;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
/* Dark mode */
.dark {
--background: #0a0a0a;
--foreground: #ededed;
--gray-950: 10 10 10;
--gray-900: 23 23 23;
--gray-800: 38 38 38;
--gray-700: 64 64 64;
--gray-600: 82 82 82;
--gray-500: 115 115 115;
--gray-400: 163 163 163;
--gray-300: 212 212 212;
--gray-200: 229 229 229;
--gray-100: 245 245 245;
}
body {
@@ -28,12 +51,12 @@ body {
/* selected label */
.aitk-react-select-container .aitk-react-select__single-value {
@apply flex-1 min-w-0 truncate text-sm text-neutral-200;
@apply flex-1 min-w-0 truncate text-sm text-gray-200;
}
/* invisible input (keeps focus & typing, never wraps) */
.aitk-react-select-container .aitk-react-select__input-container {
@apply text-neutral-200;
@apply text-gray-200;
}
/* focus */
@@ -48,7 +71,7 @@ body {
/* options */
.aitk-react-select-container .aitk-react-select__option {
@apply text-sm text-neutral-200 bg-gray-800 hover:bg-gray-700;
@apply text-sm text-gray-200 bg-gray-800 hover:bg-gray-700;
}
/* indicator separator */
@@ -64,9 +87,6 @@ body {
/* placeholder */
.aitk-react-select-container .aitk-react-select__placeholder {
@apply text-sm text-neutral-200;
@apply text-sm text-gray-200;
}
}

View File

@@ -107,7 +107,7 @@ export default function JobPage({ params }: { params: { jobID: string } }) {
<Button
key={page.value}
onClick={() => setPageKey(page.value)}
className={`px-4 py-1 h-8 flex items-center gap-1.5 ${page.value === pageKey ? 'bg-gray-300 dark:bg-gray-700' : ''}`}
className={`px-4 py-1 h-8 flex items-center gap-1.5 ${page.value === pageKey ? 'bg-gray-300 dark:bg-gray-700 text-white' : ''}`}
>
<page.icon className="text-sm" />
{page.name}

View File

@@ -6,6 +6,7 @@ import Editor, { OnMount } from '@monaco-editor/react';
import type { editor } from 'monaco-editor';
import { Settings } from '@/hooks/useSettings';
import { migrateJobConfig } from './jobConfig';
import { useTheme } from '@/components/ThemeProvider';
type Props = {
jobConfig: JobConfig;
@@ -35,6 +36,7 @@ const yamlConfig: YAML.DocumentOptions &
};
export default function AdvancedJob({ jobConfig, setJobConfig, settings }: Props) {
const { theme } = useTheme();
const [editorValue, setEditorValue] = useState<string>('');
const lastJobConfigUpdateStringRef = useRef('');
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
@@ -132,7 +134,7 @@ export default function AdvancedJob({ jobConfig, setJobConfig, settings }: Props
width="100%"
defaultLanguage="yaml"
value={editorValue}
theme="vs-dark"
theme={theme === 'dark' ? 'vs-dark' : 'light'}
onChange={handleChange}
onMount={handleEditorDidMount}
options={{

View File

@@ -783,7 +783,7 @@ export default function SimpleJob({
'config.process[0].datasets',
)
}
className="bg-red-800 hover:bg-red-700 rounded-full p-2 text-sm transition-colors"
className="bg-red-600 hover:bg-red-700 text-white rounded-full p-2 text-sm transition-colors"
title="Remove Dataset"
>
<X className="w-4 h-4" />

View File

@@ -210,10 +210,7 @@ export default function TrainingForm() {
</div>
<div className="mx-4 bg-gray-200 dark:bg-gray-800 w-1 h-6"></div>
<div>
<Button
className="text-gray-200 bg-gray-800 px-3 py-1 rounded-md"
onClick={handleImportConfig}
>
<Button className="text-gray-200 bg-gray-800 px-3 py-1 rounded-md" onClick={handleImportConfig}>
Import Config
</Button>
</div>
@@ -263,7 +260,7 @@ export default function TrainingForm() {
</div>
<div>
<Button
className="text-gray-200 bg-green-800 px-3 py-1 rounded-md"
className="text-white bg-green-600 hover:bg-green-700 px-3 py-1 rounded-md"
onClick={() => saveJob()}
disabled={status === 'saving'}
>

View File

@@ -13,7 +13,7 @@ export default function Dashboard() {
</div>
<div className="flex-1"></div>
<div>
<Link href="/jobs/new" className="text-gray-200 bg-slate-600 px-3 py-1 rounded-md">
<Link href="/jobs/new" className="text-white bg-slate-600 px-3 py-1 rounded-md">
New Training Job
</Link>
</div>

View File

@@ -25,9 +25,19 @@ export default function RootLayout({ children }: { children: React.ReactNode })
const platform = os.platform();
return (
<html lang="en" className="dark">
<html lang="en" suppressHydrationWarning>
<head>
<meta name="apple-mobile-web-app-title" content="AI-Toolkit" />
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
var theme = localStorage.getItem('theme') || 'dark';
if (theme === 'dark') document.documentElement.classList.add('dark');
})();
`,
}}
/>
</head>
<body className={inter.className}>
<script dangerouslySetInnerHTML={{ __html: `window.server_platform = "${platform}";` }} />