@a83/orbiter-admin 0.3.35 → 0.3.37
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/package.json +1 -1
- package/public/style.css +44 -44
- package/public/xfce.js +254 -176
package/package.json
CHANGED
package/public/style.css
CHANGED
|
@@ -2046,73 +2046,73 @@ a.xfce-sb-logo:hover { opacity: .8; }
|
|
|
2046
2046
|
opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto;
|
|
2047
2047
|
}
|
|
2048
2048
|
|
|
2049
|
-
/* ──
|
|
2050
|
-
.xfce-
|
|
2049
|
+
/* ── Command Palette ─────────────────────────────────────── */
|
|
2050
|
+
.xfce-palette {
|
|
2051
2051
|
display: none; position: fixed; inset: 0; z-index: 10000;
|
|
2052
2052
|
background: rgba(0,0,0,0);
|
|
2053
2053
|
align-items: flex-end; justify-content: center;
|
|
2054
2054
|
padding-bottom: calc(var(--dock-h, 76px) + 20px);
|
|
2055
2055
|
transition: background .18s;
|
|
2056
2056
|
}
|
|
2057
|
-
.xfce-
|
|
2057
|
+
.xfce-palette.open {
|
|
2058
2058
|
display: flex;
|
|
2059
2059
|
background: rgba(0,0,0,.28);
|
|
2060
2060
|
}
|
|
2061
2061
|
|
|
2062
|
-
.xfce-
|
|
2063
|
-
width: min(
|
|
2064
|
-
background:
|
|
2065
|
-
border: 1px solid
|
|
2066
|
-
border-top: 2px solid var(--accent, #7c6fcd);
|
|
2062
|
+
.xfce-palette-inner {
|
|
2063
|
+
width: min(560px, 92vw);
|
|
2064
|
+
background: var(--glass-bg, color-mix(in srgb, var(--bg1) 90%, transparent));
|
|
2065
|
+
border: 1px solid var(--line);
|
|
2067
2066
|
border-radius: 12px;
|
|
2068
|
-
box-shadow: 0 -2px
|
|
2067
|
+
box-shadow: 0 -2px 32px rgba(0,0,0,.25), 0 0 0 1px color-mix(in srgb,var(--accent) 20%,transparent);
|
|
2069
2068
|
overflow: hidden;
|
|
2070
|
-
|
|
2071
|
-
|
|
2069
|
+
transform: translateY(14px);
|
|
2070
|
+
opacity: 0;
|
|
2072
2071
|
transition: transform .2s cubic-bezier(.34,1.15,.64,1), opacity .15s;
|
|
2073
2072
|
}
|
|
2074
|
-
.xfce-
|
|
2075
|
-
transform: translateY(0);
|
|
2073
|
+
.xfce-palette.open .xfce-palette-inner {
|
|
2074
|
+
transform: translateY(0);
|
|
2075
|
+
opacity: 1;
|
|
2076
2076
|
}
|
|
2077
2077
|
|
|
2078
|
-
.xfce-
|
|
2079
|
-
display: flex; align-items: center;
|
|
2080
|
-
padding:
|
|
2081
|
-
}
|
|
2082
|
-
.xfce-term-title {
|
|
2083
|
-
font-family: var(--mono); font-size: 9px; letter-spacing: .12em;
|
|
2084
|
-
text-transform: uppercase; color: var(--accent, #7c6fcd);
|
|
2078
|
+
.xfce-palette-bar {
|
|
2079
|
+
display: flex; align-items: center; gap: 8px;
|
|
2080
|
+
padding: 10px 14px; border-bottom: 1px solid var(--line);
|
|
2085
2081
|
}
|
|
2086
|
-
.xfce-
|
|
2087
|
-
|
|
2088
|
-
background:
|
|
2089
|
-
|
|
2082
|
+
.xfce-palette-cmd { color: var(--accent); font-size: 13px; flex-shrink: 0; }
|
|
2083
|
+
.xfce-palette-inp {
|
|
2084
|
+
flex: 1; background: none; border: none; outline: none;
|
|
2085
|
+
font-family: var(--mono); font-size: 13px; color: var(--heading);
|
|
2090
2086
|
}
|
|
2087
|
+
.xfce-palette-inp::placeholder { color: var(--muted); }
|
|
2088
|
+
.xfce-palette-hint { font-size: 8px; color: var(--muted); font-family: var(--mono); white-space: nowrap; }
|
|
2091
2089
|
|
|
2092
|
-
.xfce-
|
|
2093
|
-
|
|
2094
|
-
font-family: var(--mono); font-size: 11px; line-height: 1.7;
|
|
2090
|
+
.xfce-palette-results {
|
|
2091
|
+
max-height: 360px; overflow-y: auto; padding: 6px 0;
|
|
2095
2092
|
}
|
|
2096
|
-
.xfce-
|
|
2097
|
-
|
|
2098
|
-
.
|
|
2099
|
-
|
|
2100
|
-
.xfce-term-dim { color: rgba(150,150,190,.6); }
|
|
2101
|
-
.xfce-term-muted { color: rgba(120,120,170,.45); }
|
|
2102
|
-
|
|
2103
|
-
.xfce-term-input-row {
|
|
2104
|
-
display: flex; align-items: center; gap: 8px;
|
|
2105
|
-
padding: 10px 16px; border-top: 1px solid rgba(255,255,255,.06); flex-shrink: 0;
|
|
2093
|
+
.xfce-pal-group {
|
|
2094
|
+
font-size: 8px; font-family: var(--mono); color: var(--muted);
|
|
2095
|
+
letter-spacing: .08em; text-transform: uppercase;
|
|
2096
|
+
padding: 8px 14px 4px;
|
|
2106
2097
|
}
|
|
2107
|
-
.xfce-
|
|
2108
|
-
|
|
2109
|
-
|
|
2098
|
+
.xfce-pal-item {
|
|
2099
|
+
display: flex; align-items: center; gap: 10px;
|
|
2100
|
+
padding: 7px 14px; cursor: pointer; transition: background .1s;
|
|
2110
2101
|
}
|
|
2111
|
-
.xfce-
|
|
2112
|
-
|
|
2113
|
-
font-family: var(--mono); font-size: 11px; color: rgba(220,220,255,.9);
|
|
2114
|
-
caret-color: var(--accent, #7c6fcd);
|
|
2102
|
+
.xfce-pal-item:hover, .xfce-pal-item.pal-active {
|
|
2103
|
+
background: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
2115
2104
|
}
|
|
2105
|
+
.xfce-pal-icon { width: 20px; text-align: center; font-size: 13px; color: var(--accent); flex-shrink: 0; }
|
|
2106
|
+
.xfce-pal-label { font-size: 12px; color: var(--heading); font-family: var(--mono); flex: 1; }
|
|
2107
|
+
.xfce-pal-hint-r { font-size: 10px; color: var(--muted); font-family: var(--mono); white-space: nowrap; }
|
|
2108
|
+
.xfce-pal-empty { padding: 20px 14px; color: var(--muted); font-size: 11px; font-family: var(--mono); }
|
|
2109
|
+
.xfce-pal-output { padding: 8px 14px; font-size: 11px; font-family: var(--mono); color: var(--body); line-height: 1.6; }
|
|
2110
|
+
.xfce-pal-output code { color: var(--accent); }
|
|
2111
|
+
.xfce-pal-dim { color: var(--muted); }
|
|
2112
|
+
.xfce-pal-ok { color: var(--success, #5dc97e); }
|
|
2113
|
+
.xfce-pal-err { color: var(--danger, #e06c6c); }
|
|
2114
|
+
.xfce-pal-muted { color: var(--muted); opacity: .7; }
|
|
2115
|
+
.xfce-pal-cmd-hint { color: var(--accent); }
|
|
2116
2116
|
|
|
2117
2117
|
/* ── Toast host (above dock) ─────────────────────────────── */
|
|
2118
2118
|
.xfce-toast-host {
|
package/public/xfce.js
CHANGED
|
@@ -28,8 +28,11 @@
|
|
|
28
28
|
{ icon: '☑', label: 'To-do', pane: 'todos' },
|
|
29
29
|
];
|
|
30
30
|
|
|
31
|
-
// collections
|
|
32
|
-
var
|
|
31
|
+
// palette items — nav + tools pre-seeded; collections appended after /api/info
|
|
32
|
+
var _palItems = NAV.concat(TOOLS).map(function (n) {
|
|
33
|
+
return { icon: n.icon, label: n.label, href: n.href, group: n.key in { schema:1, build:1, import:1 } ? 'Tools' : 'Nav' };
|
|
34
|
+
});
|
|
35
|
+
var _termCols = []; // collection metadata for palette commands
|
|
33
36
|
|
|
34
37
|
// ── Helpers ───────────────────────────────────────────────────────────
|
|
35
38
|
function el(tag, cls, html) {
|
|
@@ -94,7 +97,7 @@
|
|
|
94
97
|
// Palette trigger in status bar
|
|
95
98
|
document.getElementById('xfce-sb-palette-btn').addEventListener('click', function (e) {
|
|
96
99
|
e.stopPropagation();
|
|
97
|
-
|
|
100
|
+
openPalette();
|
|
98
101
|
});
|
|
99
102
|
}
|
|
100
103
|
|
|
@@ -160,7 +163,7 @@
|
|
|
160
163
|
palBtn.addEventListener('click', function (e) {
|
|
161
164
|
e.stopPropagation();
|
|
162
165
|
toolsPopup.classList.remove('open');
|
|
163
|
-
|
|
166
|
+
openPalette();
|
|
164
167
|
});
|
|
165
168
|
toolsPopup.appendChild(palBtn);
|
|
166
169
|
document.body.appendChild(toolsPopup);
|
|
@@ -210,227 +213,305 @@
|
|
|
210
213
|
if (colCreateEl) colCreateEl.classList.remove('visible');
|
|
211
214
|
}
|
|
212
215
|
|
|
213
|
-
// ──
|
|
214
|
-
var
|
|
215
|
-
|
|
216
|
-
var
|
|
217
|
-
var NAV_DEST = {
|
|
216
|
+
// ── Command Palette ───────────────────────────────────────────────────
|
|
217
|
+
var palette, paletteInp, paletteResults, palActive = -1;
|
|
218
|
+
|
|
219
|
+
var NAV_DEST = {
|
|
218
220
|
dashboard: '/dashboard.html', media: '/media.html', settings: '/settings.html',
|
|
219
221
|
users: '/users.html', schema: '/schema.html', build: '/build.html',
|
|
220
222
|
import: '/import.html', account: '/account.html',
|
|
221
223
|
};
|
|
222
224
|
|
|
223
|
-
function
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
'<div class="xfce-
|
|
228
|
-
'<div class="xfce-
|
|
229
|
-
'<span class="xfce-
|
|
230
|
-
'<
|
|
231
|
-
|
|
232
|
-
'<div id="xfce-term-output" class="xfce-term-output"></div>',
|
|
233
|
-
'<div class="xfce-term-input-row">',
|
|
234
|
-
'<span class="xfce-term-prompt">orbiter $</span>',
|
|
235
|
-
'<input id="xfce-term-input" class="xfce-term-input" autocomplete="off" spellcheck="false" />',
|
|
225
|
+
function buildPalette() {
|
|
226
|
+
palette = el('div', 'xfce-palette');
|
|
227
|
+
palette.id = 'xfce-palette';
|
|
228
|
+
palette.innerHTML = [
|
|
229
|
+
'<div class="xfce-palette-inner">',
|
|
230
|
+
'<div class="xfce-palette-bar">',
|
|
231
|
+
'<span class="xfce-palette-cmd">⌘</span>',
|
|
232
|
+
'<input id="xfce-palette-inp" class="xfce-palette-inp" placeholder="Go to page or collection… › type > for commands" autocomplete="off" spellcheck="false" />',
|
|
233
|
+
'<span class="xfce-palette-hint">ESC to close</span>',
|
|
236
234
|
'</div>',
|
|
235
|
+
'<div id="xfce-palette-results" class="xfce-palette-results"></div>',
|
|
237
236
|
'</div>',
|
|
238
237
|
].join('');
|
|
239
|
-
document.body.appendChild(
|
|
238
|
+
document.body.appendChild(palette);
|
|
240
239
|
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
paletteInp = document.getElementById('xfce-palette-inp');
|
|
241
|
+
paletteResults = document.getElementById('xfce-palette-results');
|
|
243
242
|
|
|
244
|
-
|
|
245
|
-
|
|
243
|
+
paletteInp.addEventListener('input', function () {
|
|
244
|
+
palActive = -1;
|
|
245
|
+
renderPalette(paletteInp.value);
|
|
246
|
+
});
|
|
246
247
|
|
|
247
|
-
|
|
248
|
+
paletteInp.addEventListener('keydown', function (e) {
|
|
249
|
+
var val = paletteInp.value.trim();
|
|
248
250
|
if (e.key === 'Enter') {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
251
|
+
if (val.startsWith('>')) {
|
|
252
|
+
e.preventDefault();
|
|
253
|
+
execPaletteCmd(val.slice(1).trim());
|
|
254
|
+
} else {
|
|
255
|
+
var active = paletteResults.querySelector('.xfce-pal-item.pal-active');
|
|
256
|
+
if (active && active.dataset.href) { location.href = active.dataset.href; closePalette(); }
|
|
257
|
+
else {
|
|
258
|
+
var first = paletteResults.querySelector('.xfce-pal-item[data-href]');
|
|
259
|
+
if (first) { location.href = first.dataset.href; closePalette(); }
|
|
260
|
+
}
|
|
261
|
+
}
|
|
260
262
|
} else if (e.key === 'ArrowDown') {
|
|
261
263
|
e.preventDefault();
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
264
|
+
var items = paletteResults.querySelectorAll('.xfce-pal-item[data-href]');
|
|
265
|
+
palActive = Math.min(palActive + 1, items.length - 1);
|
|
266
|
+
updatePalActive(items);
|
|
267
|
+
} else if (e.key === 'ArrowUp') {
|
|
265
268
|
e.preventDefault();
|
|
266
|
-
|
|
269
|
+
var items = paletteResults.querySelectorAll('.xfce-pal-item[data-href]');
|
|
270
|
+
palActive = Math.max(palActive - 1, 0);
|
|
271
|
+
updatePalActive(items);
|
|
267
272
|
} else if (e.key === 'Escape') {
|
|
268
|
-
|
|
273
|
+
closePalette();
|
|
269
274
|
}
|
|
270
275
|
});
|
|
271
276
|
|
|
272
|
-
|
|
273
|
-
if (e.target ===
|
|
277
|
+
palette.addEventListener('click', function (e) {
|
|
278
|
+
if (e.target === palette) closePalette();
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function updatePalActive(items) {
|
|
283
|
+
items.forEach(function (it, i) {
|
|
284
|
+
it.classList.toggle('pal-active', i === palActive);
|
|
285
|
+
if (i === palActive) it.scrollIntoView({ block: 'nearest' });
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function renderPalette(q) {
|
|
290
|
+
q = (q || '').trim();
|
|
291
|
+
|
|
292
|
+
if (q.startsWith('>')) {
|
|
293
|
+
var cmd = q.slice(1).trim();
|
|
294
|
+
paletteResults.innerHTML = cmd
|
|
295
|
+
? '<div class="xfce-pal-output xfce-pal-cmd-hint">↵ run: ' + escHtml(cmd) + '</div>'
|
|
296
|
+
: '<div class="xfce-pal-output xfce-pal-dim">commands: ls · go <page> · new <col> · search <term> · build · export <col> · info</div>';
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
q = q.toLowerCase();
|
|
301
|
+
var filtered = q
|
|
302
|
+
? _palItems.filter(function (it) { return it.label.toLowerCase().includes(q); })
|
|
303
|
+
: _palItems;
|
|
304
|
+
|
|
305
|
+
if (!filtered.length) {
|
|
306
|
+
paletteResults.innerHTML = '<div class="xfce-pal-empty">No results</div>';
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
var groups = {};
|
|
311
|
+
filtered.forEach(function (it) {
|
|
312
|
+
var g = it.group || 'Nav';
|
|
313
|
+
if (!groups[g]) groups[g] = [];
|
|
314
|
+
groups[g].push(it);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
var html = '';
|
|
318
|
+
Object.keys(groups).forEach(function (g) {
|
|
319
|
+
html += '<div class="xfce-pal-group">' + g + '</div>';
|
|
320
|
+
groups[g].forEach(function (it) {
|
|
321
|
+
html += '<div class="xfce-pal-item" data-href="' + it.href + '">'
|
|
322
|
+
+ '<span class="xfce-pal-icon">' + it.icon + '</span>'
|
|
323
|
+
+ '<span class="xfce-pal-label">' + escHtml(it.label) + '</span>'
|
|
324
|
+
+ (it.meta ? '<span class="xfce-pal-hint-r">' + escHtml(it.meta) + '</span>' : '')
|
|
325
|
+
+ '</div>';
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
paletteResults.innerHTML = html;
|
|
329
|
+
|
|
330
|
+
paletteResults.querySelectorAll('.xfce-pal-item[data-href]').forEach(function (item) {
|
|
331
|
+
item.addEventListener('click', function () {
|
|
332
|
+
location.href = item.dataset.href;
|
|
333
|
+
closePalette();
|
|
334
|
+
});
|
|
335
|
+
item.addEventListener('mouseenter', function () {
|
|
336
|
+
var items = paletteResults.querySelectorAll('.xfce-pal-item[data-href]');
|
|
337
|
+
palActive = Array.from(items).indexOf(item);
|
|
338
|
+
updatePalActive(items);
|
|
339
|
+
});
|
|
274
340
|
});
|
|
275
341
|
}
|
|
276
342
|
|
|
277
|
-
function
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
line.textContent = text;
|
|
281
|
-
termOutput.appendChild(line);
|
|
282
|
-
termOutput.scrollTop = termOutput.scrollHeight;
|
|
343
|
+
function palPrint(html, cls) {
|
|
344
|
+
paletteResults.insertAdjacentHTML('beforeend',
|
|
345
|
+
'<div class="xfce-pal-output' + (cls ? ' xfce-pal-' + cls : '') + '">' + html + '</div>');
|
|
283
346
|
}
|
|
284
347
|
|
|
285
|
-
function
|
|
348
|
+
function palSetItems(html) {
|
|
349
|
+
paletteResults.innerHTML = html;
|
|
350
|
+
paletteResults.querySelectorAll('.xfce-pal-item[data-href]').forEach(function (item) {
|
|
351
|
+
item.addEventListener('click', function () { location.href = item.dataset.href; closePalette(); });
|
|
352
|
+
item.addEventListener('mouseenter', function () {
|
|
353
|
+
var items = paletteResults.querySelectorAll('.xfce-pal-item[data-href]');
|
|
354
|
+
palActive = Array.from(items).indexOf(item);
|
|
355
|
+
updatePalActive(items);
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
}
|
|
286
359
|
|
|
287
|
-
function
|
|
360
|
+
function execPaletteCmd(raw) {
|
|
361
|
+
if (!raw) return;
|
|
288
362
|
var parts = raw.trim().split(/\s+/);
|
|
289
363
|
var cmd = parts[0].toLowerCase();
|
|
290
364
|
var args = parts.slice(1);
|
|
365
|
+
paletteResults.innerHTML = '';
|
|
366
|
+
|
|
291
367
|
switch (cmd) {
|
|
292
|
-
case 'help':
|
|
293
|
-
case '
|
|
294
|
-
case '
|
|
295
|
-
case '
|
|
296
|
-
case '
|
|
297
|
-
case '
|
|
298
|
-
case '
|
|
299
|
-
case '
|
|
300
|
-
|
|
301
|
-
default: termPrint('command not found: ' + cmd + ' (try \'help\')', 'err');
|
|
368
|
+
case 'help': palHelp(); break;
|
|
369
|
+
case 'info': palInfo(); break;
|
|
370
|
+
case 'ls': palLs(args); break;
|
|
371
|
+
case 'go': palGo(args); break;
|
|
372
|
+
case 'new': palNew(args); break;
|
|
373
|
+
case 'search': palSearch(args.join(' ')); break;
|
|
374
|
+
case 'build': palBuild(); break;
|
|
375
|
+
case 'export': palExport(args); break;
|
|
376
|
+
default: palPrint('unknown: <b>' + escHtml(cmd) + '</b> — try <b>> help</b>', 'err');
|
|
302
377
|
}
|
|
303
|
-
termPrint('', '');
|
|
304
378
|
}
|
|
305
379
|
|
|
306
|
-
function
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
'
|
|
310
|
-
'
|
|
311
|
-
'
|
|
312
|
-
'
|
|
313
|
-
'
|
|
314
|
-
'
|
|
315
|
-
|
|
316
|
-
' clear clear terminal',
|
|
317
|
-
' help show this message',
|
|
318
|
-
'',
|
|
319
|
-
' shortcuts: ↑↓ history · Tab completion · ⌘K toggle',
|
|
320
|
-
].forEach(function (l) { termPrint(l, 'dim'); });
|
|
380
|
+
function palHelp() {
|
|
381
|
+
palPrint([
|
|
382
|
+
'<code>go <page|collection></code> — navigate',
|
|
383
|
+
'<code>new <collection></code> — new entry',
|
|
384
|
+
'<code>ls [collection]</code> — list collections or entries',
|
|
385
|
+
'<code>search <term></code> — full-text search',
|
|
386
|
+
'<code>info</code> — pod & version info',
|
|
387
|
+
'<code>build</code> — trigger deploy',
|
|
388
|
+
'<code>export <col> [--md] [--drafts]</code> — download',
|
|
389
|
+
].join('<br>'), 'dim');
|
|
321
390
|
}
|
|
322
391
|
|
|
323
|
-
function
|
|
392
|
+
function palInfo() {
|
|
324
393
|
fetch('/api/info', { credentials: 'include' })
|
|
325
394
|
.then(function (r) { return r.ok ? r.json() : null; })
|
|
326
395
|
.then(function (d) {
|
|
327
|
-
if (!d) {
|
|
396
|
+
if (!d) { palPrint('error fetching info', 'err'); return; }
|
|
328
397
|
var total = (d.collections || []).reduce(function (s, c) { return s + (c.total || 0); }, 0);
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
termPrint(' published ' + total + ' entries', 'dim');
|
|
398
|
+
palPrint([
|
|
399
|
+
'Pod: <b>' + escHtml(d.podPath.split('/').pop()) + '</b>',
|
|
400
|
+
'Format: v' + d.formatVersion + ' · Admin: v' + d.adminVersion,
|
|
401
|
+
'Collections: ' + (d.collections || []).length + ' · Published: ' + total,
|
|
402
|
+
].join('<br>'), 'dim');
|
|
335
403
|
});
|
|
336
404
|
}
|
|
337
405
|
|
|
338
|
-
function
|
|
406
|
+
function palLs(args) {
|
|
339
407
|
if (!args.length) {
|
|
340
|
-
if (!_termCols.length) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
408
|
+
if (!_termCols.length) { palPrint('no collections loaded yet', 'muted'); return; }
|
|
409
|
+
var html = _termCols.map(function (col) {
|
|
410
|
+
var href = col.singleton
|
|
411
|
+
? '/editor.html?collection=' + encodeURIComponent(col.id) + '&singleton=1'
|
|
412
|
+
: '/entries.html?col=' + encodeURIComponent(col.id) + '&label=' + encodeURIComponent(col.label);
|
|
413
|
+
var abbr = col.label.substring(0, 2).toUpperCase();
|
|
414
|
+
var meta = col.total + (col.total === 1 ? ' entry' : ' entries') + (col.drafts > 0 ? ', ' + col.drafts + ' draft' + (col.drafts === 1 ? '' : 's') : '');
|
|
415
|
+
return '<div class="xfce-pal-item" data-href="' + href + '">'
|
|
416
|
+
+ '<span class="xfce-pal-icon">' + abbr + '</span>'
|
|
417
|
+
+ '<span class="xfce-pal-label">' + escHtml(col.label) + '</span>'
|
|
418
|
+
+ '<span class="xfce-pal-hint-r">' + meta + '</span>'
|
|
419
|
+
+ '</div>';
|
|
420
|
+
}).join('');
|
|
421
|
+
palSetItems(html);
|
|
347
422
|
return;
|
|
348
423
|
}
|
|
349
424
|
var colId = args[0];
|
|
350
|
-
|
|
425
|
+
palPrint('loading…', 'muted');
|
|
426
|
+
fetch('/api/collections/' + encodeURIComponent(colId) + '/entries?status=published&limit=20', { credentials: 'include' })
|
|
351
427
|
.then(function (r) { return r.ok ? r.json() : null; })
|
|
352
428
|
.then(function (d) {
|
|
353
|
-
|
|
429
|
+
paletteResults.innerHTML = '';
|
|
430
|
+
if (!d) { palPrint('collection not found: ' + escHtml(colId), 'err'); return; }
|
|
354
431
|
var entries = d.entries || (Array.isArray(d) ? d : []);
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
432
|
+
if (!entries.length) { palPrint('(no published entries)', 'muted'); return; }
|
|
433
|
+
var html = entries.map(function (e) {
|
|
434
|
+
var href = '/editor.html?collection=' + encodeURIComponent(colId) + '&id=' + encodeURIComponent(e.id || '');
|
|
358
435
|
var date = (e.updated_at || e.created_at || '').substring(0, 10);
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
436
|
+
return '<div class="xfce-pal-item" data-href="' + href + '">'
|
|
437
|
+
+ '<span class="xfce-pal-icon">✎</span>'
|
|
438
|
+
+ '<span class="xfce-pal-label">' + escHtml(e.slug || e.id || '') + '</span>'
|
|
439
|
+
+ '<span class="xfce-pal-hint-r">' + date + '</span>'
|
|
440
|
+
+ '</div>';
|
|
441
|
+
}).join('');
|
|
442
|
+
palSetItems(html);
|
|
443
|
+
if (d.total > entries.length) palPrint('… ' + (d.total - entries.length) + ' more', 'muted');
|
|
362
444
|
});
|
|
363
445
|
}
|
|
364
446
|
|
|
365
|
-
function
|
|
366
|
-
if (!args.length) {
|
|
447
|
+
function palGo(args) {
|
|
448
|
+
if (!args.length) { palPrint('usage: go <page|collection>', 'err'); return; }
|
|
367
449
|
var dest = args[0].toLowerCase();
|
|
368
|
-
if (NAV_DEST[dest]) {
|
|
369
|
-
termPrint('→ ' + dest, 'ok');
|
|
370
|
-
closeTerminal();
|
|
371
|
-
setTimeout(function () { location.href = NAV_DEST[dest]; }, 180);
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
450
|
+
if (NAV_DEST[dest]) { closePalette(); setTimeout(function () { location.href = NAV_DEST[dest]; }, 120); return; }
|
|
374
451
|
var col = _termCols.find(function (c) { return c.id === dest || c.label.toLowerCase() === dest; });
|
|
375
452
|
if (col) {
|
|
376
|
-
|
|
377
|
-
closeTerminal();
|
|
453
|
+
closePalette();
|
|
378
454
|
var href = col.singleton
|
|
379
455
|
? '/editor.html?collection=' + encodeURIComponent(col.id) + '&singleton=1'
|
|
380
456
|
: '/entries.html?col=' + encodeURIComponent(col.id) + '&label=' + encodeURIComponent(col.label);
|
|
381
|
-
setTimeout(function () { location.href = href; },
|
|
457
|
+
setTimeout(function () { location.href = href; }, 120);
|
|
382
458
|
return;
|
|
383
459
|
}
|
|
384
|
-
|
|
460
|
+
palPrint('not found: ' + escHtml(dest), 'err');
|
|
385
461
|
}
|
|
386
462
|
|
|
387
|
-
function
|
|
388
|
-
if (!args.length) {
|
|
463
|
+
function palNew(args) {
|
|
464
|
+
if (!args.length) { palPrint('usage: new <collection>', 'err'); return; }
|
|
389
465
|
var dest = args[0].toLowerCase();
|
|
390
466
|
var col = _termCols.find(function (c) { return c.id === dest || c.label.toLowerCase() === dest; });
|
|
391
|
-
if (!col) {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
setTimeout(function () { location.href = '/editor.html?collection=' + encodeURIComponent(col.id); }, 180);
|
|
467
|
+
if (!col) { palPrint('collection not found: ' + escHtml(dest), 'err'); return; }
|
|
468
|
+
closePalette();
|
|
469
|
+
setTimeout(function () { location.href = '/editor.html?collection=' + encodeURIComponent(col.id); }, 120);
|
|
395
470
|
}
|
|
396
471
|
|
|
397
|
-
function
|
|
398
|
-
if (!term) {
|
|
399
|
-
|
|
472
|
+
function palSearch(term) {
|
|
473
|
+
if (!term) { palPrint('usage: search <term>', 'err'); return; }
|
|
474
|
+
palPrint('searching…', 'muted');
|
|
400
475
|
fetch('/api/search?q=' + encodeURIComponent(term), { credentials: 'include' })
|
|
401
476
|
.then(function (r) { return r.ok ? r.json() : null; })
|
|
402
477
|
.then(function (d) {
|
|
403
|
-
|
|
478
|
+
paletteResults.innerHTML = '';
|
|
479
|
+
if (!d) { palPrint('search error', 'err'); return; }
|
|
404
480
|
var results = d.results || (Array.isArray(d) ? d : []);
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
481
|
+
if (!results.length) { palPrint('no results for “' + escHtml(term) + '”', 'muted'); return; }
|
|
482
|
+
var html = results.slice(0, 15).map(function (r) {
|
|
483
|
+
var href = '/editor.html?collection=' + encodeURIComponent(r.collection || '') + '&id=' + encodeURIComponent(r.id || '');
|
|
484
|
+
return '<div class="xfce-pal-item" data-href="' + href + '">'
|
|
485
|
+
+ '<span class="xfce-pal-icon">⌕</span>'
|
|
486
|
+
+ '<span class="xfce-pal-label">' + escHtml(r.title || r.slug || r.id || '') + '</span>'
|
|
487
|
+
+ '<span class="xfce-pal-hint-r">' + escHtml(r.collection || '') + '</span>'
|
|
488
|
+
+ '</div>';
|
|
489
|
+
}).join('');
|
|
490
|
+
palSetItems(html);
|
|
491
|
+
if (results.length > 15) palPrint('… ' + (results.length - 15) + ' more', 'muted');
|
|
412
492
|
});
|
|
413
493
|
}
|
|
414
494
|
|
|
415
|
-
function
|
|
416
|
-
|
|
495
|
+
function palBuild() {
|
|
496
|
+
palPrint('triggering build…', 'muted');
|
|
417
497
|
fetch('/api/build', { method: 'POST', credentials: 'include' })
|
|
418
498
|
.then(function (r) { return r.json(); })
|
|
419
499
|
.then(function (d) {
|
|
420
|
-
|
|
421
|
-
|
|
500
|
+
paletteResults.innerHTML = '';
|
|
501
|
+
if (d.ok || d.message) { palPrint('✓ ' + (d.message || 'build triggered'), 'ok'); setTimeout(closePalette, 900); }
|
|
502
|
+
else palPrint('build error: ' + escHtml(d.error || JSON.stringify(d)), 'err');
|
|
422
503
|
})
|
|
423
|
-
.catch(function () {
|
|
504
|
+
.catch(function () { paletteResults.innerHTML = ''; palPrint('build request failed', 'err'); });
|
|
424
505
|
}
|
|
425
506
|
|
|
426
|
-
function
|
|
427
|
-
if (!args.length) {
|
|
507
|
+
function palExport(args) {
|
|
508
|
+
if (!args.length) { palPrint('usage: export <collection> [--md] [--drafts]', 'err'); return; }
|
|
428
509
|
var colId = args[0];
|
|
429
510
|
var format = args.indexOf('--md') !== -1 ? 'md' : 'json';
|
|
430
511
|
var drafts = args.indexOf('--drafts') !== -1 ? '1' : '0';
|
|
431
512
|
var col = _termCols.find(function (c) { return c.id === colId; });
|
|
432
|
-
if (!col) {
|
|
433
|
-
|
|
513
|
+
if (!col) { palPrint('collection not found: ' + escHtml(colId), 'err'); return; }
|
|
514
|
+
palPrint('exporting…', 'muted');
|
|
434
515
|
fetch('/api/terminal/export?col=' + encodeURIComponent(colId) + '&format=' + format + '&drafts=' + drafts, { credentials: 'include' })
|
|
435
516
|
.then(function (r) {
|
|
436
517
|
if (!r.ok) return r.json().then(function (e) { throw new Error(e.error || r.status); });
|
|
@@ -439,48 +520,37 @@
|
|
|
439
520
|
a.href = URL.createObjectURL(blob);
|
|
440
521
|
a.download = colId + '.' + format;
|
|
441
522
|
document.body.appendChild(a); a.click(); a.remove();
|
|
442
|
-
|
|
523
|
+
paletteResults.innerHTML = '';
|
|
524
|
+
palPrint('✓ downloaded ' + colId + '.' + format, 'ok');
|
|
525
|
+
setTimeout(closePalette, 900);
|
|
443
526
|
});
|
|
444
527
|
})
|
|
445
|
-
.catch(function (err) {
|
|
528
|
+
.catch(function (err) { paletteResults.innerHTML = ''; palPrint('export failed: ' + escHtml(err.message), 'err'); });
|
|
446
529
|
}
|
|
447
530
|
|
|
448
|
-
function
|
|
449
|
-
|
|
450
|
-
var parts = val.split(/\s+/);
|
|
451
|
-
if (parts.length === 1) {
|
|
452
|
-
var p = parts[0].toLowerCase();
|
|
453
|
-
var m = TERM_CMDS.filter(function (c) { return c.startsWith(p); });
|
|
454
|
-
if (m.length === 1) termInput.value = m[0] + ' ';
|
|
455
|
-
else if (m.length > 1) termPrint(m.join(' '), 'muted');
|
|
456
|
-
} else if (parts.length === 2) {
|
|
457
|
-
var cmd2 = parts[0].toLowerCase(), p2 = parts[1].toLowerCase();
|
|
458
|
-
var pool = _termCols.map(function (c) { return c.id; });
|
|
459
|
-
if (cmd2 === 'go') pool = pool.concat(Object.keys(NAV_DEST));
|
|
460
|
-
if (['go','new','ls','export'].indexOf(cmd2) !== -1) {
|
|
461
|
-
var m2 = pool.filter(function (c) { return c.startsWith(p2); });
|
|
462
|
-
if (m2.length === 1) termInput.value = parts[0] + ' ' + m2[0];
|
|
463
|
-
else if (m2.length > 1) termPrint(m2.join(' '), 'muted');
|
|
464
|
-
}
|
|
465
|
-
}
|
|
531
|
+
function escHtml(s) {
|
|
532
|
+
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
466
533
|
}
|
|
467
534
|
|
|
468
|
-
function
|
|
469
|
-
if (!
|
|
470
|
-
|
|
535
|
+
function openPalette() {
|
|
536
|
+
if (!palette) buildPalette();
|
|
537
|
+
palette.style.display = 'flex';
|
|
538
|
+
paletteInp.value = '';
|
|
539
|
+
palActive = -1;
|
|
540
|
+
renderPalette('');
|
|
471
541
|
requestAnimationFrame(function () {
|
|
472
542
|
requestAnimationFrame(function () {
|
|
473
|
-
|
|
474
|
-
setTimeout(function () {
|
|
543
|
+
palette.classList.add('open');
|
|
544
|
+
setTimeout(function () { paletteInp.focus(); }, 40);
|
|
475
545
|
});
|
|
476
546
|
});
|
|
477
547
|
}
|
|
478
548
|
|
|
479
|
-
function
|
|
480
|
-
if (!
|
|
481
|
-
|
|
549
|
+
function closePalette() {
|
|
550
|
+
if (!palette) return;
|
|
551
|
+
palette.classList.remove('open');
|
|
482
552
|
setTimeout(function () {
|
|
483
|
-
if (!
|
|
553
|
+
if (!palette.classList.contains('open')) palette.style.display = 'none';
|
|
484
554
|
}, 200);
|
|
485
555
|
}
|
|
486
556
|
|
|
@@ -968,7 +1038,8 @@
|
|
|
968
1038
|
|
|
969
1039
|
colGroup.appendChild(item);
|
|
970
1040
|
|
|
971
|
-
// Add to
|
|
1041
|
+
// Add to palette fuzzy search and command list
|
|
1042
|
+
_palItems.push({ icon: abbr, label: col.label, href: href, group: 'Collections' });
|
|
972
1043
|
_termCols.push({ id: col.id, label: col.label, total: col.total || 0, drafts: col.drafts || 0, singleton: !!col.singleton });
|
|
973
1044
|
});
|
|
974
1045
|
}
|
|
@@ -1024,14 +1095,21 @@
|
|
|
1024
1095
|
|
|
1025
1096
|
// ── Keyboard shortcuts ────────────────────────────────────────────────
|
|
1026
1097
|
function bindKeys() {
|
|
1098
|
+
// Capture-phase ⌘K: fires before admin-utils.js bubble-phase listener, stops it
|
|
1099
|
+
document.addEventListener('keydown', function (e) {
|
|
1100
|
+
if ((e.metaKey || e.ctrlKey) && !e.shiftKey && (e.key === 'k' || e.key === 'K')) {
|
|
1101
|
+
e.preventDefault();
|
|
1102
|
+
e.stopImmediatePropagation();
|
|
1103
|
+
if (palette && palette.classList.contains('open')) closePalette();
|
|
1104
|
+
else openPalette();
|
|
1105
|
+
}
|
|
1106
|
+
}, true);
|
|
1107
|
+
|
|
1027
1108
|
document.addEventListener('keydown', function (e) {
|
|
1028
1109
|
var mod = e.metaKey || e.ctrlKey;
|
|
1029
1110
|
|
|
1030
|
-
// ⌘K
|
|
1111
|
+
// ⌘K handled above in capture phase
|
|
1031
1112
|
if (mod && !e.shiftKey && (e.key === 'k' || e.key === 'K')) {
|
|
1032
|
-
e.preventDefault();
|
|
1033
|
-
if (terminal && terminal.classList.contains('open')) closeTerminal();
|
|
1034
|
-
else openTerminal();
|
|
1035
1113
|
return;
|
|
1036
1114
|
}
|
|
1037
1115
|
|