feat(ux): 素材类型选择器改为图标卡片布局
每个素材类型使用内联 SVG 图标 + 文字垂直排列的卡片式选择器, 选中态高亮边框与背景色。
This commit is contained in:
@@ -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>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user