88 lines
3.1 KiB
TypeScript
88 lines
3.1 KiB
TypeScript
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
|
import { useAuth } from 'hooks/useAuth';
|
|
import type { ModelOption } from '@/state/useModels';
|
|
import type { ChatMessage } from 'apps/Chat';
|
|
import { OpenCodeModelPicker } from './OpenCodeModelPicker';
|
|
|
|
type SettingsProps = {
|
|
provider: 'claude' | 'opencode';
|
|
messages: ChatMessage[];
|
|
onProviderChange?: (provider: 'claude' | 'opencode') => void;
|
|
availableModels: ModelOption[];
|
|
selectedModel: string | null;
|
|
onModelChange: (modelId: string) => void;
|
|
model: string | null;
|
|
isConnected: boolean;
|
|
isGenerating: boolean;
|
|
};
|
|
|
|
export const Settings = ({
|
|
provider,
|
|
messages,
|
|
onProviderChange,
|
|
availableModels,
|
|
selectedModel,
|
|
onModelChange,
|
|
model,
|
|
isConnected,
|
|
isGenerating,
|
|
}: SettingsProps) => {
|
|
const { user } = useAuth();
|
|
|
|
const fallbackModelId = availableModels[0]?.id ?? null;
|
|
|
|
return (
|
|
<div className="flex items-center justify-between mt-2">
|
|
{messages.length > 0 ? (
|
|
<span className="rounded-md bg-duck-dark/80 px-3 py-1 text-xs font-medium text-white">
|
|
{provider === 'claude' ? 'Claude' : 'OpenCode'}
|
|
</span>
|
|
) : (
|
|
<div className="flex items-center gap-1 rounded-lg bg-background/60 p-1">
|
|
{(['claude', 'opencode'] as const).map((value) => (
|
|
<button
|
|
key={value}
|
|
onClick={() => onProviderChange?.(value)}
|
|
className={`rounded-md px-3 py-1 text-xs font-medium transition-colors ${
|
|
provider === value ? 'bg-background text-duck-dark shadow-sm' : 'text-duck-dark/70 hover:text-duck-dark/90'
|
|
} ${!onProviderChange ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}`}
|
|
>
|
|
{value === 'claude' ? 'Claude' : 'OpenCode'}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
<div className="text-xs text-duck-dark/50">
|
|
{availableModels.length > 0 && provider === 'opencode' ? (
|
|
<OpenCodeModelPicker
|
|
models={availableModels}
|
|
selectedModel={selectedModel ?? fallbackModelId}
|
|
onSelect={onModelChange}
|
|
isConnected={isConnected}
|
|
isGenerating={isGenerating}
|
|
/>
|
|
) : availableModels.length > 0 ? (
|
|
<Select
|
|
value={selectedModel ?? fallbackModelId ?? undefined}
|
|
onValueChange={(v) => onModelChange(v)}
|
|
disabled={isGenerating || !isConnected}
|
|
>
|
|
<SelectTrigger className="h-auto border-0 bg-transparent p-0 text-xs text-duck-dark/50 shadow-none focus:ring-0 gap-1 cursor-pointer">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent className="z-[800]" side="top">
|
|
{availableModels.map((m) => (
|
|
<SelectItem key={m.id} value={m.id}>
|
|
{m.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
) : (
|
|
<span>{model ?? (provider === 'claude' ? 'Claude' : 'OpenCode')}</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|