Files
gen2d/frontend/src/components/ProjectConfigPanel.tsx
T
Gmarker689 f44fd56e22 fix: 自定义标签融入原生标签栏,点击切换而非消失
- StyleSelector 新增 customTags 属性,自定义标签作为「自定义标签」行展示在原生标签栏中
- 自定义标签点击切换 true/false,不再移除 key,解决点击消失问题
- CustomTagsEditor 简化为仅输入框+添加按钮
- extractTags 仅提取激活态自定义标签(value=true)
- 导出 CUSTOM_PREFIX 供组件使用
2026-05-25 19:55:29 +08:00

118 lines
3.2 KiB
TypeScript

import { useEffect } from 'react'
import { useParams } from 'react-router-dom'
import { useProjectStore } from '../stores/project'
import { useToastStore } from '../stores/toast'
import { PROJECT_TYPES, PROJECT_TYPE_KEY, getCustomTags } from '../utils/style'
import StyleSelector from './StyleSelector'
import CustomTagsEditor from './CustomTagsEditor'
import Skeleton from './Skeleton'
export default function ProjectConfigPanel() {
const { projectId = '' } = useParams()
const {
draftName,
draftStyle,
hasUnsavedChanges,
loading,
loadProject,
loadStyle,
startEditing,
updateDraft,
setDraftStyle,
setDraftName,
discardDraft,
commitDraft,
} = useProjectStore()
const addToast = useToastStore(s => s.addToast)
useEffect(() => {
if (projectId) {
loadProject(projectId)
loadStyle(projectId)
startEditing()
}
}, [projectId, loadProject, loadStyle, startEditing])
const handleSave = async () => {
try {
await commitDraft()
addToast({ type: 'success', message: '配置已保存' })
} catch {
addToast({ type: 'error', message: '保存失败' })
}
}
if (loading) {
return (
<div style={{ padding: 16 }}>
<Skeleton variant="text" lines={6} />
</div>
)
}
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<div style={{ padding: '16px 16px 12px', borderBottom: '1px solid var(--border)' }}>
<input
type="text"
value={draftName}
onChange={e => setDraftName(e.target.value)}
style={{
width: '100%',
fontSize: 16,
fontWeight: 600,
padding: '4px 0',
border: 'none',
background: 'transparent',
outline: 'none',
borderBottom: '2px solid transparent',
}}
onFocus={e => (e.target.style.borderBottomColor = 'var(--accent)')}
onBlur={e => (e.target.style.borderBottomColor = 'transparent')}
/>
</div>
<div style={{ flex: 1, overflow: 'auto', padding: '12px 16px' }}>
<StyleSelector
value={draftStyle}
onChange={updateDraft}
compact
categories={[{
key: PROJECT_TYPE_KEY,
label: '工程类型',
options: PROJECT_TYPES.map(p => ({ value: p.value, label: p.label })),
}]}
customTags={getCustomTags(draftStyle)}
/>
<CustomTagsEditor style={draftStyle} onChange={setDraftStyle} />
</div>
<div
style={{
padding: 12,
borderTop: '1px solid var(--border)',
display: 'flex',
gap: 8,
}}
>
<button
className="btn-primary"
onClick={handleSave}
disabled={!hasUnsavedChanges}
style={{ flex: 1, padding: '8px 0', fontSize: 13 }}
>
保存
</button>
<button
className="btn-secondary"
onClick={discardDraft}
disabled={!hasUnsavedChanges}
style={{ flex: 1, padding: '8px 0', fontSize: 13 }}
>
取消
</button>
</div>
</div>
)
}