Skip to content

Commit e706710

Browse files
authored
feat: add dark mode toggle (#43)
* feat: add dark mode support * feat: improve dark mode styling * feat: add system auto theme and fix preset select dark styles * chore: remove unused header import * fix: guard matchMedia in theme toggle tests
1 parent 2f1536a commit e706710

15 files changed

+307
-186
lines changed

src/App.jsx

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { RegexControls } from './components/RegexControls';
44
import { FileList } from './components/FileList';
55
import ChartContainer from './components/ChartContainer';
66
import { ComparisonControls } from './components/ComparisonControls';
7-
import { Header } from './components/Header';
87
import { FileConfigModal } from './components/FileConfigModal';
8+
import { ThemeToggle } from './components/ThemeToggle';
99
import { PanelLeftClose, PanelLeftOpen } from 'lucide-react';
1010
import { mergeFilesWithReplacement } from './utils/mergeFiles.js';
1111

@@ -238,14 +238,14 @@ function App() {
238238
}, [handleGlobalDragEnter, handleGlobalDragOver, handleGlobalDragLeave, handleGlobalDrop]);
239239

240240
return (
241-
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 relative page-fade-in">
241+
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-700 relative page-fade-in">
242242
{/* 全页面拖拽覆盖层 */}
243243
{globalDragOver && (
244244
<div
245-
className="fixed inset-0 bg-blue-600 bg-opacity-95 z-50 flex items-center justify-center backdrop-blur-sm drag-overlay-fade-in"
245+
className="fixed inset-0 bg-blue-600 dark:bg-blue-950 bg-opacity-95 z-50 flex items-center justify-center backdrop-blur-sm drag-overlay-fade-in"
246246
>
247-
<div
248-
className="bg-white rounded-xl shadow-2xl p-8 text-center max-w-md mx-4 border-4 border-dashed border-blue-300 drag-modal-scale-in"
247+
<div
248+
className="bg-white dark:bg-gray-800 rounded-xl shadow-2xl p-8 text-center max-w-md mx-4 border-4 border-dashed border-blue-300 dark:border-blue-700 drag-modal-scale-in"
249249
>
250250
<div className="mb-6">
251251
<div className="relative">
@@ -270,13 +270,13 @@ function App() {
270270
</div>
271271
</div>
272272
</div>
273-
<h3 className="text-xl font-bold text-gray-900 mb-3">
273+
<h3 className="text-xl font-bold text-gray-900 dark:text-gray-100 mb-3">
274274
🎯 释放文件以上传
275275
</h3>
276-
<p className="text-sm text-gray-600 mb-2">
276+
<p className="text-sm text-gray-600 dark:text-gray-300 mb-2">
277277
支持 <span className="font-semibold text-blue-600">所有文本格式</span> 文件
278278
</p>
279-
<p className="text-xs text-gray-500">
279+
<p className="text-xs text-gray-500 dark:text-gray-400">
280280
拖拽到页面任意位置即可快速上传文件
281281
</p>
282282
</div>
@@ -286,7 +286,7 @@ function App() {
286286
{!sidebarVisible && (
287287
<button
288288
onClick={() => setSidebarVisible(true)}
289-
className="fixed top-3 left-3 z-40 p-2 bg-white rounded-full shadow-md text-gray-600 hover:text-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500"
289+
className="fixed top-3 left-3 z-40 p-2 bg-white dark:bg-gray-800 rounded-full shadow-md text-gray-600 dark:text-gray-200 hover:text-gray-800 dark:hover:text-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500"
290290
aria-label="显示工具栏"
291291
>
292292
<PanelLeftOpen size={20} aria-hidden="true" />
@@ -307,32 +307,33 @@ function App() {
307307
aria-label="控制面板"
308308
>
309309
{/* 标题信息 */}
310-
<div className="bg-white rounded-lg shadow-md p-3">
310+
<div className="card">
311311
<div className="flex items-center gap-2 mb-2">
312-
<div className="p-2 bg-blue-100 rounded-lg">
312+
<div className="p-2 bg-blue-100 dark:bg-blue-900 rounded-lg">
313313
<svg className="w-5 h-5 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
314314
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
315315
</svg>
316316
</div>
317317
<h1 className="text-lg font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-blue-600 via-purple-500 to-indigo-600 animate-gradient-slow">
318318
Log Analyzer
319319
</h1>
320+
<ThemeToggle className="ml-auto" />
320321
<button
321322
onClick={() => setSidebarVisible(false)}
322-
className="ml-auto p-1 text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 rounded"
323+
className="p-1 text-gray-400 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 rounded"
323324
aria-label="隐藏工具栏"
324325
>
325326
<PanelLeftClose size={16} aria-hidden="true" />
326327
</button>
327328
</div>
328-
<p className="text-sm text-gray-600 mb-3">
329+
<p className="text-sm text-gray-600 dark:text-gray-300 mb-3">
329330
📊 分析和可视化大模型训练日志中的损失函数和梯度范数数据
330331
</p>
331332

332333
{/* 状态和链接按钮 */}
333334
<div className="flex items-center gap-2" role="group" aria-label="工具状态和链接">
334-
<span
335-
className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800"
335+
<span
336+
className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"
336337
aria-label="当前为在线版本"
337338
>
338339
<span aria-hidden="true">🌐</span>
@@ -342,7 +343,7 @@ function App() {
342343
href="https://github.com/JavaZeroo/log-parser"
343344
target="_blank"
344345
rel="noopener noreferrer"
345-
className="inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium bg-gray-100 text-gray-700 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
346+
className="inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium bg-gray-100 text-gray-700 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
346347
aria-label="访问 GitHub 仓库(在新窗口中打开)"
347348
>
348349
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
@@ -385,26 +386,26 @@ function App() {
385386
/>
386387
)}
387388

388-
<section className="bg-white rounded-lg shadow-md p-3" aria-labelledby="display-options-heading">
389-
<h3
389+
<section className="card" aria-labelledby="display-options-heading">
390+
<h3
390391
id="display-options-heading"
391-
className="text-base font-semibold text-gray-800 mb-2"
392+
className="card-title mb-2"
392393
>
393394
🎛️ 显示选项
394395
</h3>
395396
<div className="space-y-3">
396397
<div>
397-
<h4 className="text-xs font-medium text-gray-700 mb-2">📊 图表显示</h4>
398-
<p className="text-xs text-gray-500">上传文件后自动展示所有已配置的指标图表</p>
398+
<h4 className="text-xs font-medium text-gray-700 dark:text-gray-300 mb-2">📊 图表显示</h4>
399+
<p className="text-xs text-gray-500 dark:text-gray-400">上传文件后自动展示所有已配置的指标图表</p>
399400
</div>
400401

401-
<div className="border-t pt-3">
402-
<h4 className="text-xs font-medium text-gray-700 mb-2">基准线设置</h4>
402+
<div className="border-t border-gray-200 dark:border-gray-700 pt-3">
403+
<h4 className="text-xs font-medium text-gray-700 dark:text-gray-300 mb-2">基准线设置</h4>
403404
<div className="space-y-3">
404405
<div>
405-
<label
406+
<label
406407
htmlFor="relative-baseline"
407-
className="block text-xs font-medium text-gray-700 mb-1"
408+
className="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1"
408409
>
409410
相对误差 Baseline
410411
</label>
@@ -414,7 +415,7 @@ function App() {
414415
step="0.001"
415416
value={relativeBaseline}
416417
onChange={(e) => setRelativeBaseline(parseFloat(e.target.value) || 0)}
417-
className="w-full px-2 py-1 text-xs border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:outline-none"
418+
className="input-field"
418419
placeholder="0.002"
419420
aria-describedby="relative-baseline-description"
420421
/>
@@ -427,9 +428,9 @@ function App() {
427428
</div>
428429

429430
<div>
430-
<label
431+
<label
431432
htmlFor="absolute-baseline"
432-
className="block text-xs font-medium text-gray-700 mb-1"
433+
className="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1"
433434
>
434435
绝对误差 Baseline
435436
</label>
@@ -439,7 +440,7 @@ function App() {
439440
step="0.001"
440441
value={absoluteBaseline}
441442
onChange={(e) => setAbsoluteBaseline(parseFloat(e.target.value) || 0)}
442-
className="w-full px-2 py-1 text-xs border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:outline-none"
443+
className="input-field"
443444
placeholder="0.005"
444445
aria-describedby="absolute-baseline-description"
445446
/>

src/components/ChartContainer.jsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,8 @@ export default function ChartContainer({
586586

587587
if (parsedData.length === 0) {
588588
return (
589-
<div className="bg-white rounded-lg shadow-md p-8">
590-
<div className="text-center text-gray-500">
589+
<div className="card p-8">
590+
<div className="text-center text-gray-500 dark:text-gray-400">
591591
<p className="text-lg mb-2">📊 暂无数据</p>
592592
<p>📁 请上传日志文件开始分析</p>
593593
</div>
@@ -613,8 +613,8 @@ export default function ChartContainer({
613613

614614
if (metrics.length === 0) {
615615
return (
616-
<div className="bg-white rounded-lg shadow-md p-8">
617-
<div className="text-center text-gray-500">
616+
<div className="card p-8">
617+
<div className="text-center text-gray-500 dark:text-gray-400">
618618
<p className="text-lg mb-2 font-medium">🎯 请选择要显示的图表</p>
619619
</div>
620620
</div>
@@ -758,8 +758,8 @@ export default function ChartContainer({
758758
</ResizablePanel>
759759
{comparisonChart}
760760
{stats && (
761-
<div className="bg-white rounded-lg shadow-md p-3">
762-
<h4 className="text-sm font-medium text-gray-700 mb-1">{key} 差值统计</h4>
761+
<div className="card">
762+
<h4 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">{key} 差值统计</h4>
763763
<div className="space-y-1 text-xs">
764764
<p>平均误差 (normal): {stats.meanNormal.toFixed(6)}</p>
765765
<p>平均误差 (absolute): {stats.meanAbsolute.toFixed(6)}</p>

src/components/ComparisonControls.jsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ export function ComparisonControls({
1313
];
1414

1515
return (
16-
<section className="bg-white rounded-lg shadow-md p-3" aria-labelledby="comparison-controls-heading">
16+
<section className="card" aria-labelledby="comparison-controls-heading">
1717
<div className="flex items-center gap-2 mb-2">
18-
<BarChart2
19-
size={16}
20-
className="text-gray-600"
18+
<BarChart2
19+
size={16}
20+
className="text-gray-600 dark:text-gray-300"
2121
aria-hidden="true"
2222
/>
23-
<h3
23+
<h3
2424
id="comparison-controls-heading"
25-
className="text-base font-semibold text-gray-800"
25+
className="card-title"
2626
>
2727
⚖️ 对比模式
2828
</h3>
@@ -31,26 +31,26 @@ export function ComparisonControls({
3131
<fieldset className="space-y-2">
3232
<legend className="sr-only">选择数据对比模式</legend>
3333
{modes.map(mode => (
34-
<label
35-
key={mode.value}
36-
className="flex items-center cursor-pointer hover:bg-gray-50 p-1 rounded"
34+
<label
35+
key={mode.value}
36+
className="flex items-center cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 p-1 rounded"
3737
>
3838
<input
3939
type="radio"
4040
name="compareMode"
4141
value={mode.value}
4242
checked={compareMode === mode.value}
4343
onChange={(e) => onCompareModeChange(e.target.value)}
44-
className="text-blue-600 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
44+
className="radio"
4545
aria-describedby={`mode-${mode.value}-description`}
4646
/>
4747
<div className="ml-2">
48-
<div className="text-xs font-medium text-gray-700">
48+
<div className="text-xs font-medium text-gray-700 dark:text-gray-300">
4949
{mode.label}
5050
</div>
51-
<div
51+
<div
5252
id={`mode-${mode.value}-description`}
53-
className="text-xs text-gray-500"
53+
className="text-xs text-gray-500 dark:text-gray-400"
5454
>
5555
{mode.description}
5656
</div>

0 commit comments

Comments
 (0)