61 lines
4.5 KiB
Svelte
61 lines
4.5 KiB
Svelte
<script lang="ts">
|
|
import { changeConfigValue, configLines, configWarnings } from '$lib/config-workbench.js';
|
|
let { text = $bindable(''), overlay = false, disabled = false }: { text?: string; overlay?: boolean; disabled?: boolean } = $props();
|
|
let mode = $state<'raw' | 'settings'>('raw');
|
|
let search = $state('');
|
|
const entries = $derived(configLines(text));
|
|
const visible = $derived(entries.filter(e => `${e.key} ${e.value}`.toLowerCase().includes(search.toLowerCase())));
|
|
const warnings = $derived(configWarnings(text, overlay));
|
|
</script>
|
|
|
|
<div class="editor">
|
|
<div class="toolbar">
|
|
<div class="switch" aria-label="Editor view">
|
|
<button type="button" class:active={mode === 'raw'} aria-pressed={mode === 'raw'} onclick={() => mode = 'raw'}>Raw .cfg</button>
|
|
<button type="button" class:active={mode === 'settings'} aria-pressed={mode === 'settings'} onclick={() => mode = 'settings'}>Settings <span>{entries.length}</span></button>
|
|
</div>
|
|
<span class="hint">{text.split(/\r?\n/).length} lines</span>
|
|
</div>
|
|
{#if mode === 'raw'}
|
|
<textarea aria-label="Config contents" bind:value={text} {disabled} spellcheck="false" rows="12" placeholder={'// Add your settings\nset g_inactivity "0"'}></textarea>
|
|
{:else}
|
|
<div class="settings">
|
|
<input class="search" aria-label="Find a setting" bind:value={search} placeholder="Find a setting…" />
|
|
<p class="hint">Edit values and inline comments. Other commands and formatting stay in the raw file.</p>
|
|
{#each visible as entry (entry.index)}
|
|
<label class="setting"><span><code>{entry.key}</code><small>Line {entry.index + 1}</small></span>
|
|
<input value={entry.value} {disabled} aria-label={`${entry.key}, line ${entry.index + 1}`} oninput={e => text = changeConfigValue(text, entry.index, e.currentTarget.value)} />
|
|
</label>
|
|
{:else}<p class="hint">{entries.length ? 'No matching settings.' : 'Add set KEY VALUE lines in the raw editor to get started.'}</p>{/each}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
{#if warnings.length}
|
|
<details class="warnings"><summary>{warnings.length} configuration {warnings.length === 1 ? 'note' : 'notes'}</summary>
|
|
<ul>{#each warnings as warning}<li>{warning}</li>{/each}</ul>
|
|
</details>
|
|
{/if}
|
|
|
|
<style>
|
|
.editor { border: 1px solid var(--border-strong); border-radius: var(--radius-md); overflow: hidden; background: var(--surface-sunken); }
|
|
.toolbar { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; gap: 12px; border-bottom: 1px solid var(--border-subtle); }
|
|
.switch { display: flex; gap: 4px; }
|
|
button { font: inherit; font-size: var(--text-sm); color: var(--text-secondary); border: 0; border-radius: var(--radius-sm); padding: 8px 12px; background: transparent; cursor: pointer; }
|
|
button.active { color: var(--text-primary); background: var(--surface-raised); }
|
|
button span { margin-left: 8px; color: var(--text-secondary); }
|
|
button:focus-visible, input:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: -2px; }
|
|
textarea { display: block; width: 100%; height: 360px; min-height: 240px; box-sizing: border-box; resize: vertical; border: 0; padding: var(--space-5); background: transparent; color: var(--text-primary); font: var(--text-sm)/1.8 var(--font-mono); tab-size: 4; }
|
|
textarea:disabled, input:disabled { opacity: .65; }
|
|
.settings { padding: var(--space-4); max-height: 520px; overflow: auto; }
|
|
input { box-sizing: border-box; background: var(--surface); color: var(--text-primary); border: 1px solid var(--border-strong); border-radius: var(--radius-sm); padding: 9px 12px; font: var(--text-sm) var(--font-mono); width: 100%; }
|
|
.setting { display: grid; grid-template-columns: minmax(140px, 1fr) minmax(0, 1.4fr); align-items: center; gap: 16px; padding: 12px 0; border-top: 1px solid var(--border-subtle); }
|
|
.setting span { min-width: 0; overflow-wrap: anywhere; }
|
|
code { font: var(--text-sm) var(--font-mono); }
|
|
small { display: block; color: var(--text-secondary); font-size: 11px; margin-top: 4px; }
|
|
.hint { color: var(--text-secondary); font-size: var(--text-xs); }
|
|
.warnings { color: var(--state-warning); font-size: var(--text-sm); padding: 12px 0 0; }
|
|
summary { cursor: pointer; }
|
|
li { margin: 6px 0; }
|
|
@media (max-width: 600px) { .setting { grid-template-columns: 1fr; gap: 8px; } .toolbar > .hint { display: none; } }
|
|
</style>
|