Feat v0.2.5 ui polish dead code #9

Merged
xcaliber merged 20 commits from feat/v0.2.5-ui-polish-dead-code into main 2026-03-27 14:16:36 +00:00
Showing only changes of commit b7cae62d27 - Show all commits

View File

@@ -1,66 +1,35 @@
/**
* GeneralSection — user preferences (model, system prompt, max tokens, temperature)
* GeneralSection — user preferences (default surface)
*/
const { html } = window;
const { useState, useEffect, useCallback, useRef } = hooks;
const { useState, useEffect, useCallback } = hooks;
export function GeneralSection() {
const [models, setModels] = useState([]);
const [settings, setSettings] = useState({});
const [surfaces, setSurfaces] = useState([]);
const [defaultSurface, setDefaultSurface] = useState('');
const [saving, setSaving] = useState(false);
const [maxHint, setMaxHint] = useState('');
const tempRef = useRef(null);
// Load settings + models
useEffect(() => {
(async () => {
try {
const s = await sw.api.profile.settings();
const m = sw.api.models?.enabled ? await sw.api.models.enabled() : null;
const [s, surfList] = await Promise.all([
sw.api.profile.settings(),
sw.api.get('/api/v1/surfaces').catch(() => []),
]);
const sObj = s || {};
setSettings({
model: sObj.model || '',
system_prompt: sObj.system_prompt || '',
max_tokens: sObj.max_tokens || 0,
temperature: sObj.temperature ?? 0.7,
show_thinking: sObj.show_thinking || false,
});
const modelList = (m?.data || []).filter(x => !x.hidden);
setModels(modelList);
// Set initial max hint
const active = modelList.find(x => x.id === sObj.model);
if (active?.capabilities?.max_output_tokens > 0) {
setMaxHint(`(model max: ${(active.capabilities.max_output_tokens / 1000).toFixed(0)}K)`);
}
setDefaultSurface(sObj.default_surface || '');
setSurfaces((surfList || []).filter(s => s.source !== 'core' && s.enabled));
} catch (e) {
console.warn('[settings/general] Load failed:', e.message);
}
})();
}, []);
const onModelChange = useCallback((e) => {
const id = e.target.value;
setSettings(s => ({ ...s, model: id }));
const m = models.find(x => x.id === id);
const cap = m?.capabilities || {};
setMaxHint(cap.max_output_tokens > 0
? `(model max: ${(cap.max_output_tokens / 1000).toFixed(0)}K)` : '');
}, [models]);
const onTempInput = useCallback((e) => {
setSettings(s => ({ ...s, temperature: parseFloat(e.target.value) }));
}, []);
const save = useCallback(async () => {
setSaving(true);
try {
await sw.api.profile.updateSettings({
model: settings.model,
system_prompt: settings.system_prompt,
max_tokens: settings.max_tokens,
temperature: settings.temperature,
show_thinking: settings.show_thinking,
default_surface: defaultSurface,
});
sw.emit('toast', { message: 'Settings saved', variant: 'success' });
} catch (e) {
@@ -68,57 +37,22 @@ export function GeneralSection() {
} finally {
setSaving(false);
}
}, [settings]);
}, [defaultSurface]);
return html`
<div class="settings-section">
<h3>Defaults</h3>
<h3>Default Surface</h3>
<div class="form-group">
<label>Default Model</label>
<select value=${settings.model} onChange=${onModelChange}>
${models.map(m => html`
<option value=${m.id}>
${m.name || m.id}${m.provider ? ` (${m.provider})` : ''}
</option>
`)}
<label>Landing page after login</label>
<select value=${defaultSurface} onChange=${e => setDefaultSurface(e.target.value)}>
<option value="">-- Use global default --</option>
${surfaces.map(s => html`<option key=${s.id} value=${s.id}>${s.icon ? s.icon + ' ' : ''}${s.title || s.id}</option>`)}
</select>
</div>
<div class="form-group">
<label>System Prompt</label>
<textarea rows="3" placeholder="Optional system prompt\u2026"
style="max-width:100%;"
value=${settings.system_prompt}
onInput=${e => setSettings(s => ({ ...s, system_prompt: e.target.value }))} />
</div>
<div style="display:flex;gap:16px;">
<div class="form-group" style="flex:1;">
<label>Max Tokens${' '}
<span style="font-weight:400;color:var(--text-3);">${maxHint}</span>
</label>
<input type="number" placeholder="default"
value=${settings.max_tokens || ''}
onInput=${e => setSettings(s => ({ ...s, max_tokens: parseInt(e.target.value) || 0 }))} />
</div>
<div class="form-group" style="flex:1;">
<label>Temperature</label>
<div style="display:flex;align-items:center;gap:8px;">
<input type="range" min="0" max="2" step="0.1"
ref=${tempRef}
value=${settings.temperature}
onInput=${onTempInput}
style="flex:1;" />
<span style="font-size:12px;color:var(--text-2);font-family:var(--mono);">
${settings.temperature}
</span>
</div>
</div>
</div>
<label style="display:flex;align-items:center;gap:8px;font-size:13px;color:var(--text-2);cursor:pointer;margin-top:4px;">
<input type="checkbox"
checked=${settings.show_thinking}
onChange=${e => setSettings(s => ({ ...s, show_thinking: e.target.checked }))} />
Show thinking blocks
</label>
<span style="font-size:12px;color:var(--text-3);">
Override the global default set by your administrator.
If your chosen surface is uninstalled, the global default is used.
</span>
</div>
<button class="btn-md btn-primary" style="margin-top:12px;"
disabled=${saving} onClick=${save}>