Skip to content

Commit 5e9cf8c

Browse files
committed
Add usage guide modal
1 parent 9a3061f commit 5e9cf8c

4 files changed

Lines changed: 190 additions & 2 deletions

File tree

public/locales/en/translation.json

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,5 +126,32 @@
126126
"configModal.example2": "Start: 50, End: empty → shows data points 51-end",
127127
"configModal.example3": "Start: 0, End: empty → shows all data points (default)",
128128
"configModal.cancel": "Cancel",
129-
"configModal.save": "Save Config"
129+
"configModal.save": "Save Config",
130+
"guide.button": "Usage Guide",
131+
"guide.title": "Quick Usage Guide",
132+
"guide.subtitle": "Start in minutes",
133+
"guide.lead": "Follow these simple steps to parse logs and compare metrics.",
134+
"guide.close": "Close usage guide",
135+
"guide.upload.title": "Upload your logs",
136+
"guide.upload.desc": "Drop training logs or click the upload card to import text files.",
137+
"guide.upload.bullet1": "Supports plain text, .log, and any readable training output.",
138+
"guide.upload.bullet2": "Multiple files are accepted at once; they stay persisted locally.",
139+
"guide.upload.bullet3": "Large files are parsed in a worker to keep the UI smooth.",
140+
"guide.configure.title": "Configure metrics",
141+
"guide.configure.desc": "Use global parsing rules or fine-tune per file to extract values.",
142+
"guide.configure.bullet1": "Choose keyword or regex mode for each metric you want to chart.",
143+
"guide.configure.bullet2": "Open \"Configure file\" on any file to override defaults.",
144+
"guide.configure.bullet3": "Sync from global config when you need consistent parsing across files.",
145+
"guide.visualize.title": "Visualize results",
146+
"guide.visualize.desc": "Charts appear automatically after parsing and can be resized.",
147+
"guide.visualize.bullet1": "Drag the corner handles or Shift-drag on charts to zoom into a range.",
148+
"guide.visualize.bullet2": "Export PNG or CSV from each chart toolbar.",
149+
"guide.visualize.bullet3": "Toggle metrics to focus on the curves that matter.",
150+
"guide.compare.title": "Compare runs",
151+
"guide.compare.desc": "Switch comparison modes to measure absolute or relative differences.",
152+
"guide.compare.bullet1": "Pick a baseline file or enable pairwise comparison for all pairs.",
153+
"guide.compare.bullet2": "Tune relative and absolute baselines to highlight acceptable error.",
154+
"guide.compare.bullet3": "Use the control panel to switch display modes without reuploading.",
155+
"guide.footer": "Tip: drag files anywhere on the page to start parsing instantly.",
156+
"guide.start": "Got it, start analyzing"
130157
}

public/locales/zh/translation.json

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,5 +126,32 @@
126126
"configModal.example2": "起始: 50, 结束: 留空 → 显示第51个数据点到结尾",
127127
"configModal.example3": "起始: 0, 结束: 留空 → 显示全部数据点(默认)",
128128
"configModal.cancel": "取消",
129-
"configModal.save": "保存配置"
129+
"configModal.save": "保存配置",
130+
"guide.button": "使用指南",
131+
"guide.title": "快速上手指南",
132+
"guide.subtitle": "几步完成分析",
133+
"guide.lead": "按照以下步骤即可完成日志解析与对比。",
134+
"guide.close": "关闭使用指南",
135+
"guide.upload.title": "上传日志",
136+
"guide.upload.desc": "拖拽训练日志或点击上传卡片导入文本文件。",
137+
"guide.upload.bullet1": "支持纯文本、.log 以及任何可读取的训练输出。",
138+
"guide.upload.bullet2": "可一次上传多个文件,数据会保存在本地存储。",
139+
"guide.upload.bullet3": "大文件在 Web Worker 中解析,界面保持流畅。",
140+
"guide.configure.title": "配置指标",
141+
"guide.configure.desc": "使用全局解析规则或按文件细调以提取数值。",
142+
"guide.configure.bullet1": "每个指标可选择关键字或正则模式进行提取。",
143+
"guide.configure.bullet2": "在文件列表点击“配置文件”可单独覆盖默认设置。",
144+
"guide.configure.bullet3": "需要统一规则时可一键同步全局配置。",
145+
"guide.visualize.title": "查看图表",
146+
"guide.visualize.desc": "解析完成后自动生成图表,支持调整尺寸。",
147+
"guide.visualize.bullet1": "拖拽角落或按住 Shift 在图表上拖动即可缩放范围。",
148+
"guide.visualize.bullet2": "每个图表工具栏都支持导出 PNG 或 CSV。",
149+
"guide.visualize.bullet3": "切换指标可聚焦在更重要的曲线。",
150+
"guide.compare.title": "对比多次实验",
151+
"guide.compare.desc": "切换对比模式以查看绝对或相对差异。",
152+
"guide.compare.bullet1": "选择基准文件或启用成对对比以遍历所有文件对。",
153+
"guide.compare.bullet2": "调节相对与绝对基准线,突出可接受的误差范围。",
154+
"guide.compare.bullet3": "通过控制面板快速切换显示模式,无需重新上传。",
155+
"guide.footer": "提示:将文件拖到页面任意位置即可立即开始解析。",
156+
"guide.start": "知道了,开始分析"
130157
}

src/App.jsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { FileList } from './components/FileList';
66
import ChartContainer from './components/ChartContainer';
77
import { ComparisonControls } from './components/ComparisonControls';
88
import { FileConfigModal } from './components/FileConfigModal';
9+
import { GuideModal } from './components/GuideModal';
910
import { ThemeToggle } from './components/ThemeToggle';
1011
import { Header } from './components/Header';
1112
import { PanelLeftClose, PanelLeftOpen } from 'lucide-react';
@@ -51,6 +52,7 @@ function App() {
5152
const [absoluteBaseline, setAbsoluteBaseline] = useState(0.005);
5253
const [configModalOpen, setConfigModalOpen] = useState(false);
5354
const [configFile, setConfigFile] = useState(null);
55+
const [guideOpen, setGuideOpen] = useState(false);
5456
const [globalDragOver, setGlobalDragOver] = useState(false);
5557
const [, setDragCounter] = useState(0);
5658
const [xRange, setXRange] = useState({ min: undefined, max: undefined });
@@ -496,6 +498,14 @@ function App() {
496498
>
497499
{t('resetConfig')}
498500
</button>
501+
<button
502+
type="button"
503+
onClick={() => setGuideOpen(true)}
504+
className="inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-700 hover:bg-blue-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:bg-blue-900 dark:text-blue-100"
505+
aria-label={t('guide.button')}
506+
>
507+
📖 {t('guide.button')}
508+
</button>
499509
</div>
500510
</div>
501511

@@ -622,6 +632,8 @@ function App() {
622632
</main>
623633
</div>
624634

635+
<GuideModal isOpen={guideOpen} onClose={() => setGuideOpen(false)} />
636+
625637
<FileConfigModal
626638
file={configFile}
627639
isOpen={configModalOpen}

src/components/GuideModal.jsx

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import React from 'react';
2+
import { useTranslation } from 'react-i18next';
3+
import { X, UploadCloud, Settings2, LineChart, GitCompare } from 'lucide-react';
4+
5+
export function GuideModal({ isOpen, onClose }) {
6+
const { t } = useTranslation();
7+
8+
if (!isOpen) return null;
9+
10+
const sections = [
11+
{
12+
icon: UploadCloud,
13+
title: t('guide.upload.title'),
14+
desc: t('guide.upload.desc'),
15+
bullets: [
16+
t('guide.upload.bullet1'),
17+
t('guide.upload.bullet2'),
18+
t('guide.upload.bullet3')
19+
]
20+
},
21+
{
22+
icon: Settings2,
23+
title: t('guide.configure.title'),
24+
desc: t('guide.configure.desc'),
25+
bullets: [
26+
t('guide.configure.bullet1'),
27+
t('guide.configure.bullet2'),
28+
t('guide.configure.bullet3')
29+
]
30+
},
31+
{
32+
icon: LineChart,
33+
title: t('guide.visualize.title'),
34+
desc: t('guide.visualize.desc'),
35+
bullets: [
36+
t('guide.visualize.bullet1'),
37+
t('guide.visualize.bullet2'),
38+
t('guide.visualize.bullet3')
39+
]
40+
},
41+
{
42+
icon: GitCompare,
43+
title: t('guide.compare.title'),
44+
desc: t('guide.compare.desc'),
45+
bullets: [
46+
t('guide.compare.bullet1'),
47+
t('guide.compare.bullet2'),
48+
t('guide.compare.bullet3')
49+
]
50+
}
51+
];
52+
53+
return (
54+
<div
55+
className="fixed inset-0 z-50 flex items-start justify-center px-4 py-8 bg-black/50 overflow-y-auto"
56+
role="dialog"
57+
aria-modal="true"
58+
aria-label={t('guide.title')}
59+
>
60+
<div className="bg-white dark:bg-gray-900 rounded-2xl shadow-2xl w-full max-w-4xl border border-gray-200 dark:border-gray-700">
61+
<div className="flex items-start justify-between p-6 border-b border-gray-200 dark:border-gray-800">
62+
<div>
63+
<p className="text-xs font-semibold uppercase tracking-wide text-blue-600 dark:text-blue-300">
64+
{t('guide.subtitle')}
65+
</p>
66+
<h2 className="text-2xl font-bold text-gray-900 dark:text-gray-100 mt-1">
67+
{t('guide.title')}
68+
</h2>
69+
<p className="text-sm text-gray-600 dark:text-gray-300 mt-1">
70+
{t('guide.lead')}
71+
</p>
72+
</div>
73+
<button
74+
type="button"
75+
onClick={onClose}
76+
className="inline-flex items-center justify-center p-2 rounded-full text-gray-500 hover:text-gray-900 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:text-gray-400 dark:hover:text-gray-200 dark:hover:bg-gray-800"
77+
aria-label={t('guide.close')}
78+
>
79+
<X size={18} aria-hidden="true" />
80+
</button>
81+
</div>
82+
83+
<div className="grid md:grid-cols-2 gap-4 p-6">
84+
{sections.map(({ icon: Icon, title, desc, bullets }) => (
85+
<article key={title} className="rounded-xl border border-gray-200 dark:border-gray-800 p-4 bg-gray-50 dark:bg-gray-800/60">
86+
<div className="flex items-center gap-3 mb-3">
87+
<span className="p-2 rounded-lg bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-100">
88+
<Icon size={18} aria-hidden="true" />
89+
</span>
90+
<div>
91+
<h3 className="text-base font-semibold text-gray-900 dark:text-gray-100">{title}</h3>
92+
<p className="text-sm text-gray-600 dark:text-gray-300">{desc}</p>
93+
</div>
94+
</div>
95+
<ul className="space-y-2 text-sm text-gray-700 dark:text-gray-200">
96+
{bullets.map((bullet, idx) => (
97+
<li key={idx} className="flex items-start gap-2">
98+
<span className="mt-1 text-blue-500" aria-hidden="true"></span>
99+
<span>{bullet}</span>
100+
</li>
101+
))}
102+
</ul>
103+
</article>
104+
))}
105+
</div>
106+
107+
<div className="px-6 py-4 border-t border-gray-200 dark:border-gray-800 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 bg-gray-50 dark:bg-gray-800/70 rounded-b-2xl">
108+
<div className="text-sm text-gray-600 dark:text-gray-300">
109+
{t('guide.footer')}
110+
</div>
111+
<button
112+
type="button"
113+
onClick={onClose}
114+
className="inline-flex items-center justify-center px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-lg shadow focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
115+
>
116+
{t('guide.start')}
117+
</button>
118+
</div>
119+
</div>
120+
</div>
121+
);
122+
}

0 commit comments

Comments
 (0)