mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-06-29 01:45:54 +08:00
refactor: 清理 LOW 问题 — 样式去重、死代码删除、命名修正
- 抽取 buttons.ts 共享按钮样式,消除 3 个组件的重复定义 - store 删除未调用的 canUndo/canRedo 方法 - importFromContent 变量 ext→lower 修正确性 - CSV 导出修复 BOM 重复(exportToCsv 自带 BOM) - Rust error.rs 添加 allow(dead_code) 消除编译警告 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
/// 传给前端的统一错误类型(保留供未来使用,当前命令返回 Result<T, String>)
|
/// 传给前端的统一错误类型(保留供未来迁移使用,届时所有命令改为返回 Result<T, AppError>)
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct AppError {
|
pub struct AppError {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useAppStore } from '@/store/app-store';
|
import { useAppStore } from '@/store/app-store';
|
||||||
|
import { btnClass, btnStyle } from '@/components/ui/buttons';
|
||||||
|
|
||||||
interface ActionButtonsProps {
|
interface ActionButtonsProps {
|
||||||
onNew: () => void;
|
onNew: () => void;
|
||||||
@@ -24,14 +25,6 @@ export function ActionButtons({
|
|||||||
const isAdmin = useAppStore((s) => s.isAdmin);
|
const isAdmin = useAppStore((s) => s.isAdmin);
|
||||||
const disabled = !isAdmin;
|
const disabled = !isAdmin;
|
||||||
|
|
||||||
const btnClass =
|
|
||||||
'px-3 py-1 text-sm rounded border transition-colors disabled:opacity-40 disabled:cursor-not-allowed';
|
|
||||||
const btnStyle = {
|
|
||||||
backgroundColor: 'var(--app-bg)',
|
|
||||||
color: 'var(--app-fg)',
|
|
||||||
borderColor: 'var(--app-border)',
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-1 flex-wrap">
|
<div className="flex gap-1 flex-wrap">
|
||||||
<button className={btnClass} style={btnStyle} disabled={disabled} onClick={onNew}>
|
<button className={btnClass} style={btnStyle} disabled={disabled} onClick={onNew}>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useAppStore } from '@/store/app-store';
|
import { useAppStore } from '@/store/app-store';
|
||||||
|
import { btnClass, btnStyle } from '@/components/ui/buttons';
|
||||||
import { SearchInput } from './SearchInput';
|
import { SearchInput } from './SearchInput';
|
||||||
import { ActionButtons } from './ActionButtons';
|
import { ActionButtons } from './ActionButtons';
|
||||||
import { UndoRedoButtons } from './UndoRedoButtons';
|
import { UndoRedoButtons } from './UndoRedoButtons';
|
||||||
@@ -26,14 +27,6 @@ export function ToolBar(props: ToolBarProps) {
|
|||||||
const isAdmin = useAppStore((s) => s.isAdmin);
|
const isAdmin = useAppStore((s) => s.isAdmin);
|
||||||
const isModified = useAppStore((s) => s.isModified);
|
const isModified = useAppStore((s) => s.isModified);
|
||||||
|
|
||||||
const sysBtnClass =
|
|
||||||
'px-3 py-1 text-sm rounded border transition-colors disabled:opacity-40 disabled:cursor-not-allowed';
|
|
||||||
const sysBtnStyle = {
|
|
||||||
backgroundColor: 'var(--app-bg)',
|
|
||||||
color: 'var(--app-fg)',
|
|
||||||
borderColor: 'var(--app-border)',
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-2 pb-2 border-b" style={{ borderColor: 'var(--app-border)' }}>
|
<div className="space-y-2 pb-2 border-b" style={{ borderColor: 'var(--app-border)' }}>
|
||||||
{/* 第一行: 搜索 + 系统按钮 */}
|
{/* 第一行: 搜索 + 系统按钮 */}
|
||||||
@@ -42,38 +35,38 @@ export function ToolBar(props: ToolBarProps) {
|
|||||||
<div className="flex-1" />
|
<div className="flex-1" />
|
||||||
<UndoRedoButtons />
|
<UndoRedoButtons />
|
||||||
<button
|
<button
|
||||||
className={sysBtnClass}
|
className={btnClass}
|
||||||
style={sysBtnStyle}
|
style={btnStyle}
|
||||||
disabled={!isAdmin}
|
disabled={!isAdmin}
|
||||||
onClick={props.onImport}
|
onClick={props.onImport}
|
||||||
>
|
>
|
||||||
{t('button.import')}
|
{t('button.import')}
|
||||||
</button>
|
</button>
|
||||||
<button className={sysBtnClass} style={sysBtnStyle} onClick={props.onExport}>
|
<button className={btnClass} style={btnStyle} onClick={props.onExport}>
|
||||||
{t('button.export')}
|
{t('button.export')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className={sysBtnClass}
|
className={btnClass}
|
||||||
style={{
|
style={{
|
||||||
...sysBtnStyle,
|
...btnStyle,
|
||||||
backgroundColor: isModified ? '#2563eb' : sysBtnStyle.backgroundColor,
|
backgroundColor: isModified ? '#2563eb' : btnStyle.backgroundColor,
|
||||||
color: isModified ? '#fff' : sysBtnStyle.color,
|
color: isModified ? '#fff' : btnStyle.color,
|
||||||
}}
|
}}
|
||||||
disabled={!isAdmin}
|
disabled={!isAdmin}
|
||||||
onClick={props.onSave}
|
onClick={props.onSave}
|
||||||
>
|
>
|
||||||
{t('button.save')}
|
{t('button.save')}
|
||||||
</button>
|
</button>
|
||||||
<button className={sysBtnClass} style={sysBtnStyle} onClick={props.onCancel}>
|
<button className={btnClass} style={btnStyle} onClick={props.onCancel}>
|
||||||
{t('button.cancel')}
|
{t('button.cancel')}
|
||||||
</button>
|
</button>
|
||||||
<button className={sysBtnClass} style={sysBtnStyle} onClick={props.onHelp}>
|
<button className={btnClass} style={btnStyle} onClick={props.onHelp}>
|
||||||
{t('button.help')}
|
{t('button.help')}
|
||||||
</button>
|
</button>
|
||||||
<button className={sysBtnClass} style={sysBtnStyle} onClick={props.onLanguage}>
|
<button className={btnClass} style={btnStyle} onClick={props.onLanguage}>
|
||||||
{t('button.language')}
|
{t('button.language')}
|
||||||
</button>
|
</button>
|
||||||
<button className={sysBtnClass} style={sysBtnStyle} onClick={props.onDarkMode}>
|
<button className={btnClass} style={btnStyle} onClick={props.onDarkMode}>
|
||||||
{t('button.darkMode')}
|
{t('button.darkMode')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useAppStore } from '@/store/app-store';
|
import { useAppStore } from '@/store/app-store';
|
||||||
|
import { btnClass, btnStyle } from '@/components/ui/buttons';
|
||||||
|
|
||||||
export function UndoRedoButtons() {
|
export function UndoRedoButtons() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -8,14 +9,6 @@ export function UndoRedoButtons() {
|
|||||||
const undo = useAppStore((s) => s.undo);
|
const undo = useAppStore((s) => s.undo);
|
||||||
const redo = useAppStore((s) => s.redo);
|
const redo = useAppStore((s) => s.redo);
|
||||||
|
|
||||||
const btnClass =
|
|
||||||
'px-3 py-1 text-sm rounded border transition-colors disabled:opacity-40 disabled:cursor-not-allowed';
|
|
||||||
const btnStyle = {
|
|
||||||
backgroundColor: 'var(--app-bg)',
|
|
||||||
color: 'var(--app-fg)',
|
|
||||||
borderColor: 'var(--app-border)',
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export const btnClass = 'px-3 py-1 text-sm rounded border transition-colors disabled:opacity-40 disabled:cursor-not-allowed';
|
||||||
|
|
||||||
|
export const btnStyle: React.CSSProperties = {
|
||||||
|
backgroundColor: 'var(--app-bg)',
|
||||||
|
color: 'var(--app-fg)',
|
||||||
|
borderColor: 'var(--app-border)',
|
||||||
|
};
|
||||||
@@ -193,10 +193,10 @@ export function importFromContent(
|
|||||||
content: string,
|
content: string,
|
||||||
filepath: string,
|
filepath: string,
|
||||||
): ImportResult {
|
): ImportResult {
|
||||||
const ext = filepath.toLowerCase();
|
const lower = filepath.toLowerCase();
|
||||||
if (ext.endsWith('.csv')) {
|
if (lower.endsWith('.csv')) {
|
||||||
return importFromCsv(content);
|
return importFromCsv(content);
|
||||||
} else if (ext.endsWith('.json')) {
|
} else if (lower.endsWith('.json')) {
|
||||||
return importFromJson(content);
|
return importFromJson(content);
|
||||||
} else {
|
} else {
|
||||||
// TXT 文件:所有路径放入 system(用户后续可选择目标)
|
// TXT 文件:所有路径放入 system(用户后续可选择目标)
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export function useAppActions(activeTab: TabId, dialogs: DialogState) {
|
|||||||
const content = isCsv ? exportToCsv(data) : exportToJson(data);
|
const content = isCsv ? exportToCsv(data) : exportToJson(data);
|
||||||
const mime = isCsv ? 'text/csv' : 'application/json';
|
const mime = isCsv ? 'text/csv' : 'application/json';
|
||||||
const ext = isCsv ? '.csv' : '.json';
|
const ext = isCsv ? '.csv' : '.json';
|
||||||
const blob = new Blob([isCsv ? '' : '', content], { type: mime });
|
const blob = new Blob([content], { type: mime });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = url;
|
a.href = url;
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ interface AppState {
|
|||||||
|
|
||||||
undo: () => void;
|
undo: () => void;
|
||||||
redo: () => void;
|
redo: () => void;
|
||||||
canUndo: () => boolean;
|
|
||||||
canRedo: () => boolean;
|
|
||||||
|
|
||||||
loadPaths: () => Promise<void>;
|
loadPaths: () => Promise<void>;
|
||||||
savePaths: () => Promise<void>;
|
savePaths: () => Promise<void>;
|
||||||
@@ -227,9 +225,6 @@ export const useAppStore = create<AppState>((set, get) => ({
|
|||||||
set({ isModified: !(arraysEqual(sysPaths, _savedSys) && arraysEqual(userPaths, _savedUser)) });
|
set({ isModified: !(arraysEqual(sysPaths, _savedSys) && arraysEqual(userPaths, _savedUser)) });
|
||||||
},
|
},
|
||||||
|
|
||||||
canUndo: () => get().undoRedo.canUndo(),
|
|
||||||
canRedo: () => get().undoRedo.canRedo(),
|
|
||||||
|
|
||||||
loadPaths: async () => {
|
loadPaths: async () => {
|
||||||
try {
|
try {
|
||||||
set({ isLoading: true });
|
set({ isLoading: true });
|
||||||
|
|||||||
Reference in New Issue
Block a user