add settings form fields

This commit is contained in:
bluemoehre
2026-07-01 00:24:27 +02:00
parent 473b6cdf1c
commit 387cd14e77
2 changed files with 147 additions and 4 deletions
+20
View File
@@ -0,0 +1,20 @@
import * as React from "react"
import { Input as InputPrimitive } from "@base-ui/react/input"
import { cn } from "@/lib/utils"
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return (
<InputPrimitive
type={type}
data-slot="input"
className={cn(
"h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
className
)}
{...props}
/>
)
}
export { Input }
+127 -4
View File
@@ -1,7 +1,130 @@
export function SettingsView() {
import { useState, type SubmitEvent } from 'react'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Button } from '@/components/ui/button'
import { DialogFooter } from '@/components/ui/dialog'
interface SettingsViewProps {
onClose?: () => void
}
export function SettingsView({ onClose }: SettingsViewProps) {
const [settings, setSettings] = useState({
llmUrl: '',
llmKey: '',
sttUrl: '',
sttKey: '',
ttsUrl: '',
ttsKey: '',
mcpUrl: '',
})
const handleChange = (field: keyof typeof settings) => (e: React.ChangeEvent<HTMLInputElement>) => {
setSettings((prev) => ({ ...prev, [field]: e.target.value }))
}
const handleSave = (e: SubmitEvent) => {
e.preventDefault()
// TODO: persist settings
onClose?.()
}
const handleReload = () => {
window.location.reload()
}
return (
<div className="flex flex-1 flex-col gap-1 p-4">
<p className="text-sm text-muted-foreground">Settings coming soon.</p>
</div>
<form onSubmit={handleSave} className="flex flex-col gap-5">
<div className="flex flex-col gap-2">
<Label htmlFor="llmUrl">Chat Model URL</Label>
<Input
id="llmUrl"
type="url"
placeholder="https://api.openai.com/v1/chat/completions"
value={settings.llmUrl}
onChange={handleChange('llmUrl')}
disabled
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="llmKey">Chat Model API Key</Label>
<Input
id="llmKey"
type="text"
placeholder="No key"
value={settings.llmKey}
onChange={handleChange('llmKey')}
disabled
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="sttUrl">Speech to Text URL</Label>
<Input
id="sttUrl"
type="url"
placeholder="https://api.openai.com/v1/audio/transcriptions"
value={settings.sttUrl}
onChange={handleChange('sttUrl')}
disabled
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="sttKey">Speech to Text API Key</Label>
<Input
id="sttKey"
type="text"
placeholder="No key"
value={settings.sttKey}
onChange={handleChange('sttKey')}
disabled
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="ttsUrl">Text to Speech URL</Label>
<Input
id="ttsUrl"
type="url"
placeholder="https://api.openai.com/v1/audio/speech"
value={settings.ttsUrl}
onChange={handleChange('ttsUrl')}
required
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="ttsKey">Text to Speech API Key</Label>
<Input
id="ttsKey"
type="text"
placeholder="No key"
value={settings.ttsKey}
onChange={handleChange('ttsKey')}
disabled
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="mcpUrl">MCP URL</Label>
<Input
id="mcpUrl"
type="url"
placeholder="https://api.openai.com/mcp"
value={settings.mcpUrl}
onChange={handleChange('mcpUrl')}
disabled
/>
</div>
<DialogFooter>
<Button type="button" variant="destructive" onClick={handleReload}>
Reload App
</Button>
<Button type="submit">Save</Button>
</DialogFooter>
</form>
)
}