tmux-weblink 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/dist/assets/addon-fit-D5N335P2.js +16 -0
- package/dist/assets/terminal-client.js +4 -0
- package/dist/assets/xterm-NI46XXQY.js +51 -0
- package/dist/assets/xterm.css +285 -0
- package/dist/browser/terminal-client.js +4 -0
- package/dist/frontend.js +1 -0
- package/dist/index.js +12 -0
- package/dist/lib/agent-detect.js +3 -0
- package/dist/lib/agents-watch.js +2 -0
- package/dist/lib/atomicWrite.js +1 -0
- package/dist/lib/auditLog.js +1 -0
- package/dist/lib/auth.js +2 -0
- package/dist/lib/cli.js +32 -0
- package/dist/lib/commandbar.js +555 -0
- package/dist/lib/db.js +1 -0
- package/dist/lib/drawer-resize.js +166 -0
- package/dist/lib/drawer-script.js +8 -0
- package/dist/lib/ext-loader.js +1 -0
- package/dist/lib/html.js +1 -0
- package/dist/lib/icons.js +1 -0
- package/dist/lib/image-upload.js +1 -0
- package/dist/lib/load-env.js +6 -0
- package/dist/lib/mobile-toolbar.js +313 -0
- package/dist/lib/notes-db.js +18 -0
- package/dist/lib/notes-drawer.js +210 -0
- package/dist/lib/notes-utils.js +15 -0
- package/dist/lib/pages/agents-index.js +105 -0
- package/dist/lib/pages/history-index.js +85 -0
- package/dist/lib/pages/landing.js +78 -0
- package/dist/lib/pages/login.js +191 -0
- package/dist/lib/pages/notes-index.js +65 -0
- package/dist/lib/pages/notes-page.js +158 -0
- package/dist/lib/pages/quick-commands.js +361 -0
- package/dist/lib/pages/schedule-index.js +392 -0
- package/dist/lib/pages/settings.js +206 -0
- package/dist/lib/pages/terminal.js +364 -0
- package/dist/lib/pinned-views.js +1 -0
- package/dist/lib/plugins.js +3 -0
- package/dist/lib/quick-commands.js +1 -0
- package/dist/lib/rateLimiter.js +2 -0
- package/dist/lib/schedule-delay.js +9 -0
- package/dist/lib/scheduler-drawer.js +379 -0
- package/dist/lib/scheduler.js +1 -0
- package/dist/lib/security-config.js +2 -0
- package/dist/lib/session-access.js +1 -0
- package/dist/lib/session-windows.js +1 -0
- package/dist/lib/sessions-drawer.js +634 -0
- package/dist/lib/sessions-sidebar.js +1 -0
- package/dist/lib/settings.js +2 -0
- package/dist/lib/setup-features.js +1 -0
- package/dist/lib/setup-prompts.js +3 -0
- package/dist/lib/shared-layout.js +412 -0
- package/dist/lib/state-paths.js +1 -0
- package/dist/lib/terminal-config.js +1 -0
- package/dist/lib/theme-store.js +2 -0
- package/dist/lib/theme.js +28 -0
- package/dist/lib/themes/dark-cove.js +1 -0
- package/dist/lib/themes/ghostty.js +1 -0
- package/dist/lib/themes/index.js +1 -0
- package/dist/lib/themes/types.js +0 -0
- package/dist/lib/themes/vscode.js +1 -0
- package/dist/lib/themes/warm-clay.js +1 -0
- package/dist/lib/tmux-capture.js +5 -0
- package/dist/lib/tmux-control.js +2 -0
- package/dist/lib/tmux-panes.js +2 -0
- package/dist/lib/tmux-windows.js +4 -0
- package/dist/lib/watched-panes.js +1 -0
- package/dist/lib/window-history.js +1 -0
- package/dist/lib/window-labels.js +1 -0
- package/dist/lib/windows-drawer.js +364 -0
- package/dist/lib/ws-message.js +1 -0
- package/dist/sessions.js +2 -0
- package/package.json +62 -0
- package/scripts/fix-pty-perms.mjs +16 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import{cssVarsStyle as l}from"../theme.js";import{commandbarCSS as p,commandbarHTML as m,commandbarScript as u}from"../commandbar.js";import{sharedLayoutCSS as b,sharedHeader as f,sharedSidebar as v,newSessionModalHTML as x,newSessionModalScript as g}from"../shared-layout.js";import{icon as o}from"../icons.js";function t(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function k(e){return`<article class="quick-item" data-id="${t(e.id)}">
|
|
2
|
+
<div class="quick-card-head">
|
|
3
|
+
<div>
|
|
4
|
+
<div class="quick-title">${t(e.title)}</div>
|
|
5
|
+
<div class="quick-meta">${t(e.description||"No description")}</div>
|
|
6
|
+
</div>
|
|
7
|
+
<div class="quick-icon-actions">
|
|
8
|
+
<button class="quick-icon-btn quick-edit" type="button" title="Edit command" aria-label="Edit ${t(e.title)}">
|
|
9
|
+
${o("edit")}
|
|
10
|
+
</button>
|
|
11
|
+
<button class="quick-icon-btn quick-delete" type="button" title="Delete command" aria-label="Delete ${t(e.title)}">
|
|
12
|
+
${o("delete")}
|
|
13
|
+
</button>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
<pre class="quick-command-preview"><code>${t(e.command)}</code></pre>
|
|
17
|
+
</article>`}function E(e,a,r=!1,i=[],n=!1){const c=JSON.stringify(e).replace(/</g,"\\u003c"),s=e.length?e.map(k).join(`
|
|
18
|
+
`):'<p class="empty">No quick commands yet. Add one below, then use it from the terminal commandbar.</p>',d=`
|
|
19
|
+
.intro {
|
|
20
|
+
margin: 0 0 18px; color: var(--panel-muted); font-size: var(--text-sm); line-height: 1.6;
|
|
21
|
+
}
|
|
22
|
+
.quick-section-title {
|
|
23
|
+
color: var(--panel-accent); font-size: var(--text-xs); letter-spacing: 0.08em;
|
|
24
|
+
margin: 24px 0 10px; text-transform: uppercase;
|
|
25
|
+
}
|
|
26
|
+
.quick-card {
|
|
27
|
+
display: flex; flex-direction: column; gap: 12px;
|
|
28
|
+
padding: 16px; border: 1px solid var(--panel-border); border-radius: 12px;
|
|
29
|
+
margin-bottom: 12px; background: var(--panel-bg);
|
|
30
|
+
}
|
|
31
|
+
.quick-item {
|
|
32
|
+
display: flex; flex-direction: column; gap: 12px;
|
|
33
|
+
padding: 14px 16px; border: 1px solid var(--panel-border); border-radius: 12px;
|
|
34
|
+
margin-bottom: 10px; background: var(--panel-bg);
|
|
35
|
+
transition: border-color 0.15s, transform 0.1s;
|
|
36
|
+
}
|
|
37
|
+
.quick-item:hover {
|
|
38
|
+
border-color: var(--panel-accent); transform: translateY(-1px);
|
|
39
|
+
}
|
|
40
|
+
.quick-card-head {
|
|
41
|
+
display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
|
|
42
|
+
}
|
|
43
|
+
.quick-title {
|
|
44
|
+
color: var(--page-fg); font-size: var(--text-base); font-weight: 600; margin-bottom: 4px;
|
|
45
|
+
}
|
|
46
|
+
.quick-meta {
|
|
47
|
+
color: var(--panel-muted); font-size: var(--text-xs); line-height: 1.5;
|
|
48
|
+
}
|
|
49
|
+
.quick-command-preview {
|
|
50
|
+
margin: 0; padding: 10px 12px; border: 1px solid color-mix(in srgb, var(--panel-accent) 15%, transparent);
|
|
51
|
+
border-radius: 8px; background: color-mix(in srgb, var(--page-bg) 60%, transparent);
|
|
52
|
+
color: var(--panel-accent); font-size: var(--text-xs); line-height: 1.5;
|
|
53
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
54
|
+
}
|
|
55
|
+
.quick-icon-actions {
|
|
56
|
+
display: flex; gap: 6px; flex-shrink: 0;
|
|
57
|
+
}
|
|
58
|
+
.quick-icon-btn {
|
|
59
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
60
|
+
width: 36px; height: 36px; border: 1px solid var(--panel-border); border-radius: 8px;
|
|
61
|
+
background: none; color: var(--panel-muted); cursor: pointer;
|
|
62
|
+
transition: border-color 0.15s, color 0.15s, background 0.15s;
|
|
63
|
+
}
|
|
64
|
+
.quick-icon-btn svg {
|
|
65
|
+
width: 16px; height: 16px; fill: currentColor;
|
|
66
|
+
}
|
|
67
|
+
.quick-icon-btn:hover {
|
|
68
|
+
border-color: var(--panel-accent); color: var(--panel-accent); background: color-mix(in srgb, var(--panel-accent) 8%, transparent);
|
|
69
|
+
}
|
|
70
|
+
.quick-icon-btn:focus-visible { box-shadow: 0 0 0 2px var(--panel-accent); outline: none; }
|
|
71
|
+
.quick-delete:hover {
|
|
72
|
+
border-color: #fc8181; color: #fc8181; background: color-mix(in srgb, #fc8181 8%, transparent);
|
|
73
|
+
}
|
|
74
|
+
.quick-form label {
|
|
75
|
+
display: flex; flex-direction: column; gap: 6px;
|
|
76
|
+
}
|
|
77
|
+
.quick-form label span {
|
|
78
|
+
color: var(--panel-muted); font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase;
|
|
79
|
+
}
|
|
80
|
+
.quick-form input,
|
|
81
|
+
.quick-form textarea {
|
|
82
|
+
width: 100%; border: 1px solid var(--panel-border); border-radius: 8px;
|
|
83
|
+
background: var(--page-bg); color: var(--page-fg); font: inherit; font-size: var(--text-sm);
|
|
84
|
+
padding: 10px 12px; outline: none; transition: border-color 0.15s, box-shadow 0.15s;
|
|
85
|
+
}
|
|
86
|
+
.quick-form textarea {
|
|
87
|
+
min-height: 90px; resize: vertical; line-height: 1.5;
|
|
88
|
+
}
|
|
89
|
+
.quick-form input:focus,
|
|
90
|
+
.quick-form textarea:focus {
|
|
91
|
+
border-color: var(--panel-accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--panel-accent) 8%, transparent);
|
|
92
|
+
}
|
|
93
|
+
.quick-actions {
|
|
94
|
+
display: flex; justify-content: flex-end; gap: 8px;
|
|
95
|
+
}
|
|
96
|
+
.quick-save,
|
|
97
|
+
.quick-cancel {
|
|
98
|
+
border: 1px solid var(--panel-border); border-radius: 8px;
|
|
99
|
+
background: none; color: var(--page-fg); font: inherit; font-size: var(--text-sm);
|
|
100
|
+
padding: 10px 16px; cursor: pointer; transition: border-color 0.15s, color 0.15s, background 0.15s;
|
|
101
|
+
min-height: 44px;
|
|
102
|
+
}
|
|
103
|
+
.quick-save {
|
|
104
|
+
border-color: var(--panel-success); color: var(--panel-success);
|
|
105
|
+
}
|
|
106
|
+
.quick-save:hover {
|
|
107
|
+
background: color-mix(in srgb, var(--panel-success) 12%, transparent);
|
|
108
|
+
}
|
|
109
|
+
.quick-save:focus-visible { box-shadow: 0 0 0 2px var(--panel-success); outline: none; }
|
|
110
|
+
.quick-cancel:hover {
|
|
111
|
+
border-color: var(--panel-accent); color: var(--panel-accent); background: color-mix(in srgb, var(--panel-accent) 8%, transparent);
|
|
112
|
+
}
|
|
113
|
+
.quick-cancel:focus-visible { box-shadow: 0 0 0 2px var(--panel-accent); outline: none; }
|
|
114
|
+
.quick-drawer-backdrop {
|
|
115
|
+
position: fixed; inset: 0; z-index: 600; background: rgba(0, 0, 0, 0.48);
|
|
116
|
+
opacity: 0; pointer-events: none; transition: opacity 0.18s ease;
|
|
117
|
+
}
|
|
118
|
+
.quick-drawer-backdrop.open { opacity: 1; pointer-events: auto; }
|
|
119
|
+
.quick-drawer {
|
|
120
|
+
position: fixed; top: 0; right: 0; z-index: 601; height: 100vh;
|
|
121
|
+
width: min(460px, calc(100vw - 24px)); padding: 24px;
|
|
122
|
+
background: var(--panel-bg); border-left: 1px solid var(--panel-border);
|
|
123
|
+
box-shadow: -18px 0 60px rgba(0, 0, 0, 0.45);
|
|
124
|
+
transform: translateX(100%); transition: transform 0.2s ease;
|
|
125
|
+
}
|
|
126
|
+
.quick-drawer.open { transform: translateX(0); }
|
|
127
|
+
.quick-drawer-header {
|
|
128
|
+
display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
|
|
129
|
+
margin-bottom: 18px;
|
|
130
|
+
}
|
|
131
|
+
.quick-drawer-header h2 {
|
|
132
|
+
margin: 0 0 6px; color: var(--panel-accent); font-size: var(--text-sm);
|
|
133
|
+
letter-spacing: 0.08em; text-transform: uppercase;
|
|
134
|
+
}
|
|
135
|
+
.quick-drawer-header p {
|
|
136
|
+
margin: 0; color: var(--panel-muted); font-size: var(--text-xs); line-height: 1.5;
|
|
137
|
+
}
|
|
138
|
+
.quick-drawer-close {
|
|
139
|
+
display: flex; align-items: center; justify-content: center;
|
|
140
|
+
background: none; border: none; color: var(--panel-muted); cursor: pointer;
|
|
141
|
+
font-size: var(--text-xl); line-height: 1; min-width: 44px; min-height: 44px; padding: 8px; border-radius: 8px;
|
|
142
|
+
transition: color 0.15s, background 0.15s;
|
|
143
|
+
}
|
|
144
|
+
.quick-drawer-close:hover { color: var(--panel-accent); background: color-mix(in srgb, var(--panel-accent) 8%, transparent); }
|
|
145
|
+
.quick-drawer-close:focus-visible { box-shadow: 0 0 0 2px var(--panel-accent); outline: none; }
|
|
146
|
+
#quick-edit-form {
|
|
147
|
+
display: flex; flex-direction: column; gap: 12px;
|
|
148
|
+
}
|
|
149
|
+
.quick-error {
|
|
150
|
+
display: none; margin: 0 0 12px; color: #fc8181; font-size: var(--text-xs);
|
|
151
|
+
}
|
|
152
|
+
.quick-error.open { display: block; }
|
|
153
|
+
.empty { font-size: var(--text-sm); color: var(--panel-muted); line-height: 1.6; margin: 0 0 16px; }
|
|
154
|
+
@media (max-width: 560px) {
|
|
155
|
+
.quick-card-head { flex-wrap: wrap; }
|
|
156
|
+
.quick-icon-actions { width: 100%; justify-content: flex-end; }
|
|
157
|
+
}
|
|
158
|
+
${r?p():""}`;return`<!DOCTYPE html>
|
|
159
|
+
<html lang="en">
|
|
160
|
+
<head>
|
|
161
|
+
<meta charset="UTF-8" />
|
|
162
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
163
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
164
|
+
<title>Quick Commands - tmux-web</title>
|
|
165
|
+
<style>
|
|
166
|
+
${l(a.shell)}
|
|
167
|
+
${b(d)}
|
|
168
|
+
</style>
|
|
169
|
+
</head>
|
|
170
|
+
<body>
|
|
171
|
+
|
|
172
|
+
${f({commandbarEnabled:r,title:"Quick Commands",themeTemplate:a.template})}
|
|
173
|
+
|
|
174
|
+
<div class="page-wrap">
|
|
175
|
+
<div class="page-layout">
|
|
176
|
+
${v({activePage:"quickCommands",agentsEnabled:n,refreshHref:"/quick-commands"})}
|
|
177
|
+
<main class="main-panel">
|
|
178
|
+
<p class="intro">Configure reusable snippets that can be pasted into the active tmux pane from the terminal commandbar.</p>
|
|
179
|
+
<p class="quick-error" id="quick-error"></p>
|
|
180
|
+
|
|
181
|
+
<h2 class="quick-section-title">Add Command</h2>
|
|
182
|
+
<form class="quick-card quick-form" id="quick-create">
|
|
183
|
+
<label>
|
|
184
|
+
<span>Title</span>
|
|
185
|
+
<input name="title" type="text" placeholder="Run tests" autocomplete="off" />
|
|
186
|
+
</label>
|
|
187
|
+
<label>
|
|
188
|
+
<span>Command</span>
|
|
189
|
+
<textarea name="command" placeholder="bun run test" spellcheck="false"></textarea>
|
|
190
|
+
</label>
|
|
191
|
+
<label>
|
|
192
|
+
<span>Description</span>
|
|
193
|
+
<input name="description" type="text" placeholder="Optional context shown in the commandbar" autocomplete="off" />
|
|
194
|
+
</label>
|
|
195
|
+
<div class="quick-actions">
|
|
196
|
+
<button class="quick-save" type="submit">Add Command</button>
|
|
197
|
+
</div>
|
|
198
|
+
</form>
|
|
199
|
+
|
|
200
|
+
<h2 class="quick-section-title">Configured</h2>
|
|
201
|
+
<div id="quick-list">${s}</div>
|
|
202
|
+
</main>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
${x()}
|
|
207
|
+
<div class="quick-drawer-backdrop" id="quick-edit-backdrop"></div>
|
|
208
|
+
<aside class="quick-drawer" id="quick-edit-drawer" aria-hidden="true" aria-label="Edit quick command">
|
|
209
|
+
<div class="quick-drawer-header">
|
|
210
|
+
<div>
|
|
211
|
+
<h2>Edit Command</h2>
|
|
212
|
+
<p>Changes apply to the commandbar immediately after save.</p>
|
|
213
|
+
</div>
|
|
214
|
+
<button class="quick-drawer-close" id="quick-edit-close" type="button" aria-label="Close edit drawer">×</button>
|
|
215
|
+
</div>
|
|
216
|
+
<form class="quick-form" id="quick-edit-form">
|
|
217
|
+
<input name="id" type="hidden" />
|
|
218
|
+
<label>
|
|
219
|
+
<span>Title</span>
|
|
220
|
+
<input name="title" type="text" autocomplete="off" />
|
|
221
|
+
</label>
|
|
222
|
+
<label>
|
|
223
|
+
<span>Command</span>
|
|
224
|
+
<textarea name="command" spellcheck="false"></textarea>
|
|
225
|
+
</label>
|
|
226
|
+
<label>
|
|
227
|
+
<span>Description</span>
|
|
228
|
+
<input name="description" type="text" autocomplete="off" />
|
|
229
|
+
</label>
|
|
230
|
+
<div class="quick-actions">
|
|
231
|
+
<button class="quick-cancel" id="quick-edit-cancel" type="button">Cancel</button>
|
|
232
|
+
<button class="quick-save" type="submit">Save</button>
|
|
233
|
+
</div>
|
|
234
|
+
</form>
|
|
235
|
+
</aside>
|
|
236
|
+
${r?m():""}
|
|
237
|
+
|
|
238
|
+
<script type="module">
|
|
239
|
+
const commands = ${c};
|
|
240
|
+
const errorEl = document.getElementById('quick-error');
|
|
241
|
+
const editBackdrop = document.getElementById('quick-edit-backdrop');
|
|
242
|
+
const editDrawer = document.getElementById('quick-edit-drawer');
|
|
243
|
+
const editForm = document.getElementById('quick-edit-form');
|
|
244
|
+
|
|
245
|
+
function showError(message) {
|
|
246
|
+
errorEl.textContent = message || '';
|
|
247
|
+
errorEl.classList.toggle('open', !!message);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function openEditDrawer(command) {
|
|
251
|
+
showError('');
|
|
252
|
+
editForm.elements.id.value = command.id;
|
|
253
|
+
editForm.elements.title.value = command.title || '';
|
|
254
|
+
editForm.elements.command.value = command.command || '';
|
|
255
|
+
editForm.elements.description.value = command.description || '';
|
|
256
|
+
editDrawer.classList.add('open');
|
|
257
|
+
editBackdrop.classList.add('open');
|
|
258
|
+
editDrawer.setAttribute('aria-hidden', 'false');
|
|
259
|
+
setTimeout(() => editForm.elements.title.focus(), 50);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function closeEditDrawer() {
|
|
263
|
+
editDrawer.classList.remove('open');
|
|
264
|
+
editBackdrop.classList.remove('open');
|
|
265
|
+
editDrawer.setAttribute('aria-hidden', 'true');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function payloadFromForm(form) {
|
|
269
|
+
const data = new FormData(form);
|
|
270
|
+
return {
|
|
271
|
+
title: String(data.get('title') || ''),
|
|
272
|
+
command: String(data.get('command') || ''),
|
|
273
|
+
description: String(data.get('description') || ''),
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async function sendJson(url, method, body) {
|
|
278
|
+
const res = await fetch(url, {
|
|
279
|
+
method,
|
|
280
|
+
headers: { 'Content-Type': 'application/json' },
|
|
281
|
+
body: JSON.stringify(body),
|
|
282
|
+
});
|
|
283
|
+
if (!res.ok) {
|
|
284
|
+
let message = 'request failed';
|
|
285
|
+
try {
|
|
286
|
+
const json = await res.json();
|
|
287
|
+
if (json && json.error) message = json.error;
|
|
288
|
+
} catch {}
|
|
289
|
+
throw new Error(message);
|
|
290
|
+
}
|
|
291
|
+
return res.json();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
document.getElementById('quick-create').addEventListener('submit', async (event) => {
|
|
295
|
+
event.preventDefault();
|
|
296
|
+
showError('');
|
|
297
|
+
const form = event.currentTarget;
|
|
298
|
+
const button = form.querySelector('button[type="submit"]');
|
|
299
|
+
button.disabled = true;
|
|
300
|
+
try {
|
|
301
|
+
await sendJson('/api/quick-commands', 'POST', payloadFromForm(form));
|
|
302
|
+
location.reload();
|
|
303
|
+
} catch (err) {
|
|
304
|
+
showError(err instanceof Error ? err.message : 'failed to add command');
|
|
305
|
+
button.disabled = false;
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
editForm.addEventListener('submit', async (event) => {
|
|
310
|
+
event.preventDefault();
|
|
311
|
+
showError('');
|
|
312
|
+
const id = String(editForm.elements.id.value || '');
|
|
313
|
+
if (!id) return;
|
|
314
|
+
const button = editForm.querySelector('button[type="submit"]');
|
|
315
|
+
button.disabled = true;
|
|
316
|
+
try {
|
|
317
|
+
await sendJson('/api/quick-commands/' + encodeURIComponent(id), 'PATCH', payloadFromForm(editForm));
|
|
318
|
+
location.reload();
|
|
319
|
+
} catch (err) {
|
|
320
|
+
showError(err instanceof Error ? err.message : 'failed to save command');
|
|
321
|
+
button.disabled = false;
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
document.getElementById('quick-list').addEventListener('click', async (event) => {
|
|
326
|
+
const editButton = event.target.closest('.quick-edit');
|
|
327
|
+
if (editButton) {
|
|
328
|
+
const card = editButton.closest('.quick-item');
|
|
329
|
+
const command = commands.find((entry) => entry.id === card?.dataset.id);
|
|
330
|
+
if (command) openEditDrawer(command);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const button = event.target.closest('.quick-delete');
|
|
335
|
+
if (!button) return;
|
|
336
|
+
const card = button.closest('.quick-item');
|
|
337
|
+
if (!card || !card.dataset.id) return;
|
|
338
|
+
showError('');
|
|
339
|
+
button.disabled = true;
|
|
340
|
+
try {
|
|
341
|
+
const res = await fetch('/api/quick-commands/' + encodeURIComponent(card.dataset.id), { method: 'DELETE' });
|
|
342
|
+
if (!res.ok) throw new Error('failed to delete command');
|
|
343
|
+
location.reload();
|
|
344
|
+
} catch (err) {
|
|
345
|
+
showError(err instanceof Error ? err.message : 'failed to delete command');
|
|
346
|
+
button.disabled = false;
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
document.getElementById('quick-edit-close').addEventListener('click', closeEditDrawer);
|
|
351
|
+
document.getElementById('quick-edit-cancel').addEventListener('click', closeEditDrawer);
|
|
352
|
+
editBackdrop.addEventListener('click', closeEditDrawer);
|
|
353
|
+
document.addEventListener('keydown', (event) => {
|
|
354
|
+
if (event.key === 'Escape' && editDrawer.classList.contains('open')) closeEditDrawer();
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
${r?u(i,[]):""}
|
|
358
|
+
${g()}
|
|
359
|
+
</script>
|
|
360
|
+
</body>
|
|
361
|
+
</html>`}export{E as renderQuickCommandsPage};
|