feat(ux): 素材类型选择器改为图标卡片布局

每个素材类型使用内联 SVG 图标 + 文字垂直排列的卡片式选择器,
选中态高亮边框与背景色。
This commit is contained in:
2026-05-24 21:19:44 +08:00
parent a7decf86ec
commit 60c752fad9
+47 -5
View File
@@ -5,6 +5,29 @@ import { mergeStyles } from '../utils/style'
import StyleSelector from './StyleSelector' import StyleSelector from './StyleSelector'
import PromptEditor from './PromptEditor' import PromptEditor from './PromptEditor'
const ASSET_TYPE_ICONS: Record<AssetType, JSX.Element> = {
sprite: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2a3 3 0 0 1 3 3c0 1.1-.6 2.1-1.5 2.6L17 12h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-1.2l-1.4 5.5a1 1 0 0 1-1 .5H10.6a1 1 0 0 1-1-.5L8.2 16H7a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1h2l3.5-4.4A3 3 0 0 1 12 2z" />
</svg>
),
background: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2zm0 2v8.6l4.3-4.3a1.5 1.5 0 0 1 2.1 0L14 13.9l2.4-2.4a1.5 1.5 0 0 1 2.1 0L20 13V6H4zm0 12h16v-1.4l-3.5-3.5-2.4 2.4a1.5 1.5 0 0 1-2.1 0L6.4 12 4 14.4V18z" />
</svg>
),
ui: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M3 4h18a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1zm0 2v12h18V6H3zm2 2h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1zm1 1v4h2V9H6zm7-1h5a1 1 0 0 1 0 2h-5a1 1 0 0 1 0-2zm0 4h3a1 1 0 0 1 0 2h-3a1 1 0 0 1 0-2z" />
</svg>
),
animation: (
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M8 5v14l11-7L8 5zm-2 1.5L16 12 6 17.5V6.5z" />
</svg>
),
}
const ASSET_TYPES: { value: AssetType; label: string }[] = [ const ASSET_TYPES: { value: AssetType; label: string }[] = [
{ value: 'sprite', label: '精灵' }, { value: 'sprite', label: '精灵' },
{ value: 'background', label: '背景' }, { value: 'background', label: '背景' },
@@ -58,18 +81,37 @@ export default function GenerateForm({ onSubmit, submitting }: GenerateFormProps
<h3 style={{ marginBottom: 12, fontSize: 14, color: 'var(--text-secondary)' }}> <h3 style={{ marginBottom: 12, fontSize: 14, color: 'var(--text-secondary)' }}>
素材类型 素材类型
</h3> </h3>
<div style={{ display: 'flex', gap: 8 }}> <div style={{ display: 'flex', gap: 12 }}>
{ASSET_TYPES.map(t => ( {ASSET_TYPES.map(t => {
const isSelected = assetType === t.value
return (
<button <button
key={t.value} key={t.value}
type="button" type="button"
className={assetType === t.value ? 'btn-primary' : 'btn-secondary'}
onClick={() => setAssetType(t.value)} onClick={() => setAssetType(t.value)}
style={{ padding: '8px 20px' }} style={{
width: 80,
height: 72,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
gap: 6,
borderRadius: 'var(--radius-lg)',
border: `2px solid ${isSelected ? 'var(--accent)' : 'var(--border)'}`,
background: isSelected ? 'var(--accent-dim)' : 'transparent',
color: isSelected ? 'var(--accent)' : 'var(--text-secondary)',
cursor: 'pointer',
transition: 'all 0.2s ease',
fontSize: 13,
fontWeight: isSelected ? 600 : 400,
}}
> >
{ASSET_TYPE_ICONS[t.value]}
{t.label} {t.label}
</button> </button>
))} )
})}
</div> </div>
</div> </div>