feat: P0e 模型选择器升级 — 卡片式下拉
- ModelSelector 组件:标签/提供商/描述/选中状态 - 替换 sandbox page + workshop page 原生 select - 模型数据增加 provider/desc 字段
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { AVAILABLE_MODELS, type ModelOption } from '@/lib/models';
|
||||
|
||||
interface ModelSelectorProps {
|
||||
value: string;
|
||||
onChange: (id: string) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function ModelSelector({ value, onChange, className = '' }: ModelSelectorProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const selected = AVAILABLE_MODELS.find(m => m.id === value) || AVAILABLE_MODELS[0];
|
||||
|
||||
return (
|
||||
<div className={`relative ${className}`}>
|
||||
<button onClick={() => setOpen(!open)}
|
||||
className="flex items-center gap-2 px-3 py-2 border border-border rounded-lg bg-background hover:bg-accent transition-colors text-sm w-full text-left">
|
||||
<span className="w-2 h-2 rounded-full bg-brand-600 shrink-0" />
|
||||
<span className="text-foreground font-medium">{selected.label}</span>
|
||||
<svg className={`w-3.5 h-3.5 ml-auto text-muted-foreground transition-transform ${open ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
{open && (
|
||||
<>
|
||||
<div className="fixed inset-0 z-10" onClick={() => setOpen(false)} />
|
||||
<div className="absolute right-0 top-full mt-1 z-20 w-64 bg-card border border-border rounded-xl shadow-lg overflow-hidden">
|
||||
{AVAILABLE_MODELS.map(m => (
|
||||
<button key={m.id} onClick={() => { onChange(m.id); setOpen(false); }}
|
||||
className={`w-full text-left px-4 py-3 hover:bg-accent transition-colors flex items-center gap-3 ${m.id === value ? 'bg-accent' : ''}`}>
|
||||
<span className={`w-2 h-2 rounded-full shrink-0 ${m.id === value ? 'bg-brand-600' : 'bg-muted-foreground/30'}`} />
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-sm font-medium text-foreground">{m.label}</div>
|
||||
<div className="text-xs text-muted-foreground">{m.provider} · {m.desc}</div>
|
||||
</div>
|
||||
{m.id === value && (
|
||||
<svg className="w-4 h-4 text-brand-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user