Skip to content

Commit 180ba88

Browse files
authored
fix(editor): compact preferences and clarify script editing (#37)
1 parent 4150b17 commit 180ba88

2 files changed

Lines changed: 140 additions & 40 deletions

File tree

‎src/lib/components/ConfigEditor.svelte‎

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
let initialPayload: any = null;
1818
let rawMode = $state(false);
1919
let rawJson = $state('');
20+
let scriptTextarea = $state<HTMLTextAreaElement | null>(null);
2021
2122
let formData = $state({
2223
name: '',
@@ -432,19 +433,26 @@
432433
<!-- SCRIPT -->
433434
<section class="col-full">
434435
<p class="eyebrow"><span class="gt">&gt;</span> SCRIPT</p>
435-
<div class="term">
436+
<div class="term script-term">
436437
<div class="term-head">
437438
<span class="dot dot-red"></span><span class="dot dot-amber"></span><span class="dot dot-green"></span>
438-
<span class="term-name">post-install.sh — runs after packages</span>
439-
<span class="term-edit"><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.12 2.12 0 0 1 3 3L12 15l-4 1 1-4Z"/></svg>editable</span>
439+
<label class="term-name" for="post-install-script">post-install.sh</label>
440+
<button type="button" class="term-edit" onclick={() => scriptTextarea?.focus()}><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.12 2.12 0 0 1 3 3L12 15l-4 1 1-4Z"/></svg>Edit script</button>
440441
</div>
441442
<textarea
443+
id="post-install-script"
442444
class="script-textarea"
445+
bind:this={scriptTextarea}
443446
bind:value={formData.custom_script}
447+
aria-describedby="script-hint"
448+
rows="10"
444449
spellcheck="false"
450+
autocomplete="off"
451+
autocapitalize="off"
445452
placeholder={scriptPlaceholder}
446453
></textarea>
447454
</div>
455+
<p class="field-hint" id="script-hint">Edit the script above, then click Save changes. Runs after packages, shell, dotfiles, and macOS preferences.</p>
448456
</section>
449457
</div>
450458
{/if}
@@ -858,21 +866,42 @@
858866
display: inline-flex;
859867
align-items: center;
860868
gap: 5px;
861-
font-size: 0.68rem;
869+
padding: 5px 8px;
870+
border: 1px solid var(--border-hover);
871+
border-radius: 6px;
872+
background: var(--bg-tertiary);
873+
font-family: inherit;
874+
font-size: 0.72rem;
862875
color: var(--accent);
876+
cursor: pointer;
877+
}
878+
879+
.term-edit:hover {
880+
border-color: var(--accent);
881+
}
882+
883+
.term-edit:focus-visible {
884+
outline: 2px solid var(--accent);
885+
outline-offset: 2px;
886+
}
887+
888+
.script-term:focus-within {
889+
border-color: var(--accent);
890+
box-shadow: 0 0 0 1px var(--accent);
863891
}
864892
865893
.script-textarea {
894+
display: block;
866895
width: 100%;
867-
min-height: 148px;
896+
min-height: 220px;
868897
padding: 18px 20px;
869898
background: transparent;
870899
border: none;
871900
outline: none;
872901
resize: vertical;
873902
font-family: inherit;
874903
font-size: 0.8rem;
875-
line-height: 1.9;
904+
line-height: 1.7;
876905
color: var(--text-secondary);
877906
}
878907
@@ -931,4 +960,10 @@
931960
grid-template-columns: 1fr;
932961
}
933962
}
963+
964+
@media (max-width: 480px) {
965+
.script-term .dot {
966+
display: none;
967+
}
968+
}
934969
</style>

‎src/lib/components/MacOSPreferencesEditor.svelte‎

Lines changed: 99 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -54,39 +54,52 @@
5454
</script>
5555

5656
<div class="prefs">
57+
<p class="prefs-hint">{macosPrefs.length} configured. Expand a category to manage settings.</p>
5758
{#each byCategory as group (group.cat)}
58-
<div class="group">
59-
<div class="group-label">{group.cat}</div>
60-
{#each group.items as item (item.id)}
61-
{@const on = isOn(item)}
62-
<div class="row">
63-
<div class="row-text">
64-
<div class="row-name">{item.label}</div>
65-
<div class="row-desc">{item.description}</div>
59+
<details class="group" name="macos-preference-category">
60+
<summary>
61+
<span class="group-label">{group.cat}</span>
62+
<span class="group-count">{group.items.filter(isOn).length} / {group.items.length} included</span>
63+
<svg class="chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m9 5 7 7-7 7" /></svg>
64+
</summary>
65+
<div class="group-items">
66+
{#each group.items as item (item.id)}
67+
{@const on = isOn(item)}
68+
<div class="row">
69+
<div class="row-text">
70+
<div class="row-name">{item.label}</div>
71+
<div class="row-desc">{item.description}</div>
72+
</div>
73+
<button class="knob" class:on role="switch" aria-checked={on} aria-label={item.label} onclick={() => toggle(item)}>
74+
<span class="knob-dot"></span>
75+
</button>
6676
</div>
67-
<button class="knob" class:on role="switch" aria-checked={on} aria-label={item.label} onclick={() => toggle(item)}>
68-
<span class="knob-dot"></span>
69-
</button>
70-
</div>
71-
{/each}
72-
</div>
77+
{/each}
78+
</div>
79+
</details>
7380
{/each}
7481

7582
{#if customPrefs.length > 0}
76-
<div class="group">
77-
<div class="group-label">Custom</div>
78-
{#each customPrefs as pref (pref.domain + ':' + pref.key)}
79-
<div class="row">
80-
<div class="row-text">
81-
<div class="row-name">{pref.desc || pref.key}</div>
82-
<div class="row-desc">{pref.domain} {pref.key} = {pref.value}</div>
83+
<details class="group" name="macos-preference-category">
84+
<summary>
85+
<span class="group-label">Custom</span>
86+
<span class="group-count">{customPrefs.length} included</span>
87+
<svg class="chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m9 5 7 7-7 7" /></svg>
88+
</summary>
89+
<div class="group-items">
90+
{#each customPrefs as pref (pref.domain + ':' + pref.key)}
91+
<div class="row">
92+
<div class="row-text">
93+
<div class="row-name">{pref.desc || pref.key}</div>
94+
<div class="row-desc">{pref.domain} {pref.key} = {pref.value}</div>
95+
</div>
96+
<button class="knob on" role="switch" aria-checked="true" aria-label="Remove {pref.key}" onclick={() => removeCustom(pref)}>
97+
<span class="knob-dot"></span>
98+
</button>
8399
</div>
84-
<button class="knob on" role="switch" aria-checked="true" aria-label="Remove {pref.key}" onclick={() => removeCustom(pref)}>
85-
<span class="knob-dot"></span>
86-
</button>
87-
</div>
88-
{/each}
89-
</div>
100+
{/each}
101+
</div>
102+
</details>
90103
{/if}
91104
</div>
92105

@@ -96,17 +109,68 @@
96109
flex-direction: column;
97110
}
98111
99-
.group + .group {
100-
margin-top: 14px;
112+
.prefs-hint {
113+
font-size: 0.72rem;
114+
color: var(--text-muted);
115+
line-height: 1.5;
116+
margin: 0 0 10px;
117+
}
118+
119+
.group {
120+
border-bottom: 1px solid var(--border);
121+
}
122+
123+
summary {
124+
display: flex;
125+
align-items: center;
126+
gap: 12px;
127+
padding: 13px 4px;
128+
cursor: pointer;
129+
list-style: none;
130+
border-radius: 5px;
131+
}
132+
133+
summary::-webkit-details-marker {
134+
display: none;
135+
}
136+
137+
summary:hover {
138+
background: var(--bg-tertiary);
139+
}
140+
141+
summary:focus-visible,
142+
.knob:focus-visible {
143+
outline: 2px solid var(--accent);
144+
outline-offset: 2px;
101145
}
102146
103147
.group-label {
104-
font-size: 0.66rem;
105-
font-weight: 600;
106-
text-transform: uppercase;
107-
letter-spacing: 0.1em;
148+
font-size: 0.8rem;
149+
color: var(--text-primary);
150+
}
151+
152+
.group-count {
153+
margin-left: auto;
154+
font-size: 0.68rem;
108155
color: var(--text-muted);
109-
padding: 8px 0 2px;
156+
white-space: nowrap;
157+
}
158+
159+
.chevron {
160+
flex-shrink: 0;
161+
color: var(--text-muted);
162+
}
163+
164+
.group[open] .chevron {
165+
transform: rotate(90deg);
166+
}
167+
168+
.group-items {
169+
max-height: 340px;
170+
overflow-y: auto;
171+
overscroll-behavior: contain;
172+
scrollbar-gutter: stable;
173+
padding: 0 4px 8px;
110174
}
111175
112176
.row {
@@ -120,6 +184,7 @@
120184
121185
.row-text {
122186
min-width: 0;
187+
overflow-wrap: anywhere;
123188
}
124189
125190
.row-name {

0 commit comments

Comments
 (0)