Skip to content

Commit 28c3959

Browse files
fullstackjamfullstackjam
authored andcommitted
feat: fullscreen modal editor for post-install script
1 parent 448c7a5 commit 28c3959

File tree

1 file changed

+207
-12
lines changed

1 file changed

+207
-12
lines changed

src/lib/components/ConfigEditor.svelte

Lines changed: 207 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
let saving = $state(false);
2020
let error = $state('');
2121
let editingConfig = $state<any>(null);
22+
let showScriptModal = $state(false);
23+
let scriptDraft = $state('');
2224
2325
let formData = $state({
2426
name: '',
@@ -607,19 +609,63 @@
607609
<div class="script-card">
608610
<div class="script-bar">
609611
<span class="script-filename">post-install.sh</span>
612+
<button
613+
class="script-edit-btn"
614+
type="button"
615+
onclick={() => { scriptDraft = formData.custom_script; showScriptModal = true; }}
616+
>
617+
{formData.custom_script ? 'Edit' : 'Add Script'}
618+
</button>
610619
</div>
611-
<textarea
612-
class="script-textarea"
613-
bind:value={formData.custom_script}
614-
placeholder="#!/bin/bash&#10;# Commands to run after package installation"
615-
spellcheck="false"
616-
></textarea>
620+
<!-- svelte-ignore a11y_click_events_have_key_events -->
621+
<!-- svelte-ignore a11y_no_static_element_interactions -->
622+
{#if formData.custom_script}
623+
<pre class="script-preview" onclick={() => { scriptDraft = formData.custom_script; showScriptModal = true; }}>{formData.custom_script}</pre>
624+
{:else}
625+
<div class="script-empty" onclick={() => { scriptDraft = ''; showScriptModal = true; }}>No post-install script — click to add</div>
626+
{/if}
617627
</div>
618628
</section>
619629
</div>
620630
</div>
621631
{/if}
622632

633+
{#if showScriptModal}
634+
<!-- svelte-ignore a11y_no_static_element_interactions -->
635+
<div class="script-modal-overlay" onkeydown={(e) => { if (e.key === 'Escape') showScriptModal = false; }}>
636+
<!-- svelte-ignore a11y_click_events_have_key_events -->
637+
<div class="script-modal-backdrop" onclick={() => showScriptModal = false}></div>
638+
<div class="script-modal">
639+
<div class="script-modal-bar">
640+
<span class="script-modal-filename">post-install.sh</span>
641+
<div class="script-modal-actions">
642+
<button
643+
type="button"
644+
class="script-modal-cancel"
645+
onclick={() => showScriptModal = false}
646+
>Cancel</button>
647+
<button
648+
type="button"
649+
class="script-modal-save"
650+
onclick={() => { formData.custom_script = scriptDraft; showScriptModal = false; }}
651+
>Save</button>
652+
</div>
653+
</div>
654+
<div class="script-modal-body">
655+
<textarea
656+
class="script-modal-textarea"
657+
bind:value={scriptDraft}
658+
placeholder="#!/bin/bash&#10;# Commands to run after package installation&#10;&#10;# Example:&#10;# mkdir -p ~/Projects&#10;# npm install -g vercel&#10;# defaults write com.apple.dock autohide -bool true"
659+
spellcheck="false"
660+
></textarea>
661+
</div>
662+
<div class="script-modal-hint">
663+
Commands run sequentially in your home directory after packages, shell, dotfiles, and macOS preferences are applied.
664+
</div>
665+
</div>
666+
</div>
667+
{/if}
668+
623669
<style>
624670
.editor-loading {
625671
display: flex;
@@ -1289,6 +1335,9 @@
12891335
padding: 12px 18px;
12901336
background: var(--bg-tertiary);
12911337
border-bottom: 1px solid var(--border);
1338+
display: flex;
1339+
align-items: center;
1340+
justify-content: space-between;
12921341
}
12931342
12941343
.script-filename {
@@ -1298,23 +1347,169 @@
12981347
color: var(--text-secondary);
12991348
}
13001349
1301-
.script-textarea {
1350+
.script-edit-btn {
1351+
padding: 5px 14px;
1352+
background: none;
1353+
border: 1px solid var(--border);
1354+
border-radius: 6px;
1355+
color: var(--accent);
1356+
font-size: 0.8rem;
1357+
font-family: inherit;
1358+
cursor: pointer;
1359+
transition: all 0.15s;
1360+
}
1361+
1362+
.script-edit-btn:hover {
1363+
border-color: var(--accent);
1364+
background: rgba(34, 197, 94, 0.08);
1365+
}
1366+
1367+
.script-preview {
1368+
padding: 16px 20px;
1369+
margin: 0;
1370+
color: var(--text-secondary);
1371+
font-family: 'JetBrains Mono', monospace;
1372+
font-size: 0.82rem;
1373+
line-height: 1.7;
1374+
white-space: pre-wrap;
1375+
word-break: break-all;
1376+
max-height: 160px;
1377+
overflow: hidden;
1378+
cursor: pointer;
1379+
}
1380+
1381+
.script-empty {
1382+
padding: 24px 20px;
1383+
color: var(--text-muted);
1384+
font-size: 0.85rem;
1385+
text-align: center;
1386+
cursor: pointer;
1387+
}
1388+
1389+
.script-empty:hover {
1390+
color: var(--text-secondary);
1391+
}
1392+
1393+
/* Script modal */
1394+
.script-modal-overlay {
1395+
position: fixed;
1396+
inset: 0;
1397+
z-index: 1000;
1398+
display: flex;
1399+
align-items: center;
1400+
justify-content: center;
1401+
padding: 32px;
1402+
}
1403+
1404+
.script-modal-backdrop {
1405+
position: absolute;
1406+
inset: 0;
1407+
background: rgba(0, 0, 0, 0.7);
1408+
backdrop-filter: blur(4px);
1409+
}
1410+
1411+
.script-modal {
1412+
position: relative;
1413+
width: 100%;
1414+
max-width: 760px;
1415+
height: 80vh;
1416+
max-height: 700px;
1417+
background: var(--bg-primary);
1418+
border: 1px solid var(--border);
1419+
border-radius: 16px;
1420+
display: flex;
1421+
flex-direction: column;
1422+
overflow: hidden;
1423+
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.4);
1424+
}
1425+
1426+
.script-modal-bar {
1427+
padding: 14px 20px;
1428+
background: var(--bg-tertiary);
1429+
border-bottom: 1px solid var(--border);
1430+
display: flex;
1431+
align-items: center;
1432+
justify-content: space-between;
1433+
flex-shrink: 0;
1434+
}
1435+
1436+
.script-modal-filename {
1437+
font-family: 'JetBrains Mono', monospace;
1438+
font-size: 0.85rem;
1439+
font-weight: 600;
1440+
color: var(--text-secondary);
1441+
}
1442+
1443+
.script-modal-actions {
1444+
display: flex;
1445+
gap: 8px;
1446+
}
1447+
1448+
.script-modal-cancel {
1449+
padding: 6px 16px;
1450+
background: none;
1451+
border: 1px solid var(--border);
1452+
border-radius: 8px;
1453+
color: var(--text-secondary);
1454+
font-size: 0.82rem;
1455+
font-family: inherit;
1456+
cursor: pointer;
1457+
transition: all 0.15s;
1458+
}
1459+
1460+
.script-modal-cancel:hover {
1461+
border-color: var(--text-muted);
1462+
}
1463+
1464+
.script-modal-save {
1465+
padding: 6px 16px;
1466+
background: var(--accent);
1467+
border: none;
1468+
border-radius: 8px;
1469+
color: #000;
1470+
font-size: 0.82rem;
1471+
font-weight: 600;
1472+
font-family: inherit;
1473+
cursor: pointer;
1474+
transition: all 0.15s;
1475+
}
1476+
1477+
.script-modal-save:hover {
1478+
opacity: 0.9;
1479+
}
1480+
1481+
.script-modal-body {
1482+
flex: 1;
1483+
overflow: hidden;
1484+
}
1485+
1486+
.script-modal-textarea {
13021487
width: 100%;
1303-
min-height: 200px;
1488+
height: 100%;
13041489
padding: 20px;
13051490
background: var(--bg-primary);
13061491
border: none;
13071492
color: var(--text-primary);
13081493
font-family: 'JetBrains Mono', monospace;
13091494
font-size: 0.85rem;
1310-
line-height: 1.6;
1311-
resize: vertical;
1495+
line-height: 1.7;
1496+
resize: none;
13121497
outline: none;
1498+
tab-size: 4;
13131499
}
13141500
1315-
.script-textarea::placeholder {
1501+
.script-modal-textarea::placeholder {
13161502
color: var(--text-muted);
1317-
opacity: 0.5;
1503+
opacity: 0.4;
1504+
}
1505+
1506+
.script-modal-hint {
1507+
padding: 10px 20px;
1508+
background: var(--bg-tertiary);
1509+
border-top: 1px solid var(--border);
1510+
color: var(--text-muted);
1511+
font-size: 0.75rem;
1512+
flex-shrink: 0;
13181513
}
13191514
13201515
@media (max-width: 768px) {

0 commit comments

Comments
 (0)