feat(v3): add global settings section to SettingsTab
Add Global section with theme flavor dropdown, default shell input, and default CWD input. All settings persisted via settings-bridge. Fix a11y by using wrapping <label> elements for project fields. Clean up unused CSS selectors.
This commit is contained in:
parent
6ea1ed1dfd
commit
3b2c1353fa
1 changed files with 120 additions and 15 deletions
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import {
|
||||
getActiveProjectId,
|
||||
getActiveGroup,
|
||||
|
|
@ -12,6 +13,9 @@
|
|||
switchGroup,
|
||||
} from '../../stores/workspace.svelte';
|
||||
import { deriveIdentifier } from '../../types/groups';
|
||||
import { getSetting, setSetting } from '../../adapters/settings-bridge';
|
||||
import { getCurrentFlavor, setFlavor } from '../../stores/theme.svelte';
|
||||
import type { CatppuccinFlavor } from '../../styles/themes';
|
||||
|
||||
let activeGroupId = $derived(getActiveGroupId());
|
||||
let activeGroup = $derived(getActiveGroup());
|
||||
|
|
@ -22,6 +26,35 @@
|
|||
activeGroup?.projects.find(p => p.id === activeProjectId),
|
||||
);
|
||||
|
||||
// Global settings
|
||||
let defaultShell = $state('');
|
||||
let defaultCwd = $state('');
|
||||
let themeFlavor = $state<CatppuccinFlavor>(getCurrentFlavor());
|
||||
const flavors: CatppuccinFlavor[] = ['latte', 'frappe', 'macchiato', 'mocha'];
|
||||
|
||||
onMount(async () => {
|
||||
const [shell, cwd] = await Promise.all([
|
||||
getSetting('default_shell'),
|
||||
getSetting('default_cwd'),
|
||||
]);
|
||||
defaultShell = shell ?? '';
|
||||
defaultCwd = cwd ?? '';
|
||||
themeFlavor = getCurrentFlavor();
|
||||
});
|
||||
|
||||
async function saveGlobalSetting(key: string, value: string) {
|
||||
try {
|
||||
await setSetting(key, value);
|
||||
} catch (e) {
|
||||
console.error(`Failed to save setting ${key}:`, e);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleThemeChange(flavor: CatppuccinFlavor) {
|
||||
themeFlavor = flavor;
|
||||
await setFlavor(flavor);
|
||||
}
|
||||
|
||||
// New project form
|
||||
let newName = $state('');
|
||||
let newCwd = $state('');
|
||||
|
|
@ -55,6 +88,42 @@
|
|||
</script>
|
||||
|
||||
<div class="settings-tab">
|
||||
<section class="settings-section">
|
||||
<h2>Global</h2>
|
||||
<div class="global-settings">
|
||||
<div class="setting-row">
|
||||
<label for="theme-flavor">Theme</label>
|
||||
<select
|
||||
id="theme-flavor"
|
||||
value={themeFlavor}
|
||||
onchange={e => handleThemeChange((e.target as HTMLSelectElement).value as CatppuccinFlavor)}
|
||||
>
|
||||
{#each flavors as f}
|
||||
<option value={f}>{f.charAt(0).toUpperCase() + f.slice(1)}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<label for="default-shell">Default shell</label>
|
||||
<input
|
||||
id="default-shell"
|
||||
value={defaultShell}
|
||||
placeholder="/bin/bash"
|
||||
onchange={e => { defaultShell = (e.target as HTMLInputElement).value; saveGlobalSetting('default_shell', defaultShell); }}
|
||||
/>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<label for="default-cwd">Default CWD</label>
|
||||
<input
|
||||
id="default-cwd"
|
||||
value={defaultCwd}
|
||||
placeholder="~"
|
||||
onchange={e => { defaultCwd = (e.target as HTMLInputElement).value; saveGlobalSetting('default_cwd', defaultCwd); }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="settings-section">
|
||||
<h2>Groups</h2>
|
||||
<div class="group-list">
|
||||
|
|
@ -85,36 +154,36 @@
|
|||
|
||||
{#each activeGroup.projects as project}
|
||||
<div class="project-settings-row">
|
||||
<div class="project-field">
|
||||
<label>Name</label>
|
||||
<label class="project-field">
|
||||
<span class="field-label">Name</span>
|
||||
<input
|
||||
value={project.name}
|
||||
onchange={e => updateProject(activeGroupId, project.id, { name: (e.target as HTMLInputElement).value })}
|
||||
/>
|
||||
</div>
|
||||
<div class="project-field">
|
||||
<label>CWD</label>
|
||||
</label>
|
||||
<label class="project-field">
|
||||
<span class="field-label">CWD</span>
|
||||
<input
|
||||
value={project.cwd}
|
||||
onchange={e => updateProject(activeGroupId, project.id, { cwd: (e.target as HTMLInputElement).value })}
|
||||
/>
|
||||
</div>
|
||||
<div class="project-field">
|
||||
<label>Icon</label>
|
||||
</label>
|
||||
<label class="project-field">
|
||||
<span class="field-label">Icon</span>
|
||||
<input
|
||||
value={project.icon}
|
||||
onchange={e => updateProject(activeGroupId, project.id, { icon: (e.target as HTMLInputElement).value })}
|
||||
style="width: 60px"
|
||||
/>
|
||||
</div>
|
||||
<div class="project-field">
|
||||
<label>Enabled</label>
|
||||
</label>
|
||||
<label class="project-field">
|
||||
<span class="field-label">Enabled</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={project.enabled}
|
||||
onchange={e => updateProject(activeGroupId, project.id, { enabled: (e.target as HTMLInputElement).checked })}
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
<button class="btn-danger" onclick={() => removeProject(activeGroupId, project.id)}>
|
||||
Remove
|
||||
</button>
|
||||
|
|
@ -155,6 +224,43 @@
|
|||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.global-settings {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.setting-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 6px 10px;
|
||||
background: var(--ctp-surface0);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.setting-row label {
|
||||
font-size: 0.8rem;
|
||||
color: var(--ctp-subtext0);
|
||||
min-width: 100px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.setting-row input,
|
||||
.setting-row select {
|
||||
padding: 4px 8px;
|
||||
background: var(--ctp-base);
|
||||
border: 1px solid var(--ctp-surface1);
|
||||
border-radius: 3px;
|
||||
color: var(--ctp-text);
|
||||
font-size: 0.8rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.setting-row select {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.group-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -208,14 +314,13 @@
|
|||
gap: 2px;
|
||||
}
|
||||
|
||||
.project-field label {
|
||||
.field-label {
|
||||
font-size: 0.7rem;
|
||||
color: var(--ctp-overlay0);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.project-field input[type="text"],
|
||||
.project-field input:not([type]) {
|
||||
.project-field input:not([type="checkbox"]) {
|
||||
padding: 4px 8px;
|
||||
background: var(--ctp-base);
|
||||
border: 1px solid var(--ctp-surface1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue