chore: 前端工程化 + Git hooks + 对齐 PathEditor 规范

- 新增 .gitattributes(CRLF 统一)+ rust-toolchain.toml
- 新增 Prettier + ESLint + markdownlint 配置
- 新增 Husky Git hooks(pre-commit lint-staged + commit-msg commitlint)
- 新增 vitest 前端测试(12 tests, utils/qrText.ts)
- 新增 @ 路径别名(vite + tsconfig)
- 新增 ROADMAP / SUPPORT / CODEOWNERS / FUNDING / dependabot
- 更新 .gitignore + .editorconfig
- 更新 package.json(新增 lint/format/test 脚本)
- 全项目 prettier 格式化 + eslint 通过
- 更新 CLAUDE.md + README.md
This commit is contained in:
2026-06-19 19:42:13 +08:00
parent ce8063431e
commit c3956f0f36
40 changed files with 4034 additions and 148 deletions
+44 -39
View File
@@ -40,7 +40,9 @@ export async function persistHistory(history: HistoryEntry[]): Promise<void> {
const store = await getStore();
await store.set(HISTORY_KEY, history);
await store.save();
} catch { /* store 不可用时静默忽略 */ }
} catch {
/* store 不可用时静默忽略 */
}
}
/** 从 store 加载历史记录(应用启动时调用) */
@@ -66,46 +68,49 @@ export function useQrEncode() {
};
}, []);
const encode = useCallback((text: string) => {
if (!text.trim()) {
dispatch({ type: 'SET_PREVIEW', payload: null });
return;
}
dispatch({ type: 'SET_LOADING', payload: true });
if (timerRef.current) clearTimeout(timerRef.current);
timerRef.current = setTimeout(async () => {
try {
const result = await invoke<QrResponse>('encode_qr', {
text,
level: state.config.level,
margin: state.config.margin,
});
dispatch({ type: 'SET_PREVIEW', payload: result });
// 保存到历史(内存 + 持久化)
const entryId = Date.now().toString();
const currentMode = modeRef.current;
const entry: HistoryEntry = {
id: entryId,
mode: currentMode,
content: sanitizeContent(currentMode, text),
timestamp: Date.now(),
formData: { ...state.formData },
};
dispatch({ type: 'ADD_HISTORY', payload: entry });
// 从内存状态持久化(避免 store 读写竞态)
// 注意: dispatch ADD_HISTORY 是异步的,这里手动计算最新列表
// 确保持久化的数据与内存一致
persistHistory([entry, ...state.history].slice(0, 50));
} catch {
// 编码失败时清空预览
const encode = useCallback(
(text: string) => {
if (!text.trim()) {
dispatch({ type: 'SET_PREVIEW', payload: null });
return;
}
}, 200);
}, [state.config.level, state.config.margin, state.formData, state.history, dispatch]);
dispatch({ type: 'SET_LOADING', payload: true });
if (timerRef.current) clearTimeout(timerRef.current);
timerRef.current = setTimeout(async () => {
try {
const result = await invoke<QrResponse>('encode_qr', {
text,
level: state.config.level,
margin: state.config.margin,
});
dispatch({ type: 'SET_PREVIEW', payload: result });
// 保存到历史(内存 + 持久化)
const entryId = Date.now().toString();
const currentMode = modeRef.current;
const entry: HistoryEntry = {
id: entryId,
mode: currentMode,
content: sanitizeContent(currentMode, text),
timestamp: Date.now(),
formData: { ...state.formData },
};
dispatch({ type: 'ADD_HISTORY', payload: entry });
// 从内存状态持久化(避免 store 读写竞态)
// 注意: dispatch ADD_HISTORY 是异步的,这里手动计算最新列表
// 确保持久化的数据与内存一致
persistHistory([entry, ...state.history].slice(0, 50));
} catch {
// 编码失败时清空预览
dispatch({ type: 'SET_PREVIEW', payload: null });
}
}, 200);
},
[state.config.level, state.config.margin, state.formData, state.history, dispatch],
);
return { encode, persistHistory };
}