@a83/orbiter-admin 0.3.45 → 0.3.46
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 +32 -0
- package/public/xfce.js +136 -10
package/package.json
CHANGED
package/public/style.css
CHANGED
|
@@ -2023,6 +2023,12 @@ a.xfce-sb-logo:hover { opacity: .8; }
|
|
|
2023
2023
|
font-family: var(--mono); transition: background .15s;
|
|
2024
2024
|
}
|
|
2025
2025
|
.xfce-sb-palette-btn:hover { background: color-mix(in srgb, var(--accent) 14%, transparent); }
|
|
2026
|
+
.xfce-sb-cheat {
|
|
2027
|
+
background: none; border: none; cursor: pointer; padding: 0 3px;
|
|
2028
|
+
font-size: 13px; color: var(--muted); font-family: var(--mono); line-height: 1;
|
|
2029
|
+
transition: color .15s;
|
|
2030
|
+
}
|
|
2031
|
+
.xfce-sb-cheat:hover { color: var(--accent); }
|
|
2026
2032
|
|
|
2027
2033
|
/* Draft badge on dock items */
|
|
2028
2034
|
.xfce-dock-badge {
|
|
@@ -2335,6 +2341,32 @@ html[data-zen="1"] .main {
|
|
|
2335
2341
|
.xfce-notif-err .xfce-notif-msg { color: var(--red); }
|
|
2336
2342
|
.xfce-notif-empty { padding: 20px 12px; color: var(--muted); font-size: 10px; text-align: center; }
|
|
2337
2343
|
|
|
2344
|
+
/* ── Build indicator — running state ────────────────────── */
|
|
2345
|
+
.xfce-sb-build--running {
|
|
2346
|
+
color: var(--accent) !important;
|
|
2347
|
+
animation: xfce-blink .9s step-end infinite;
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
/* ── Status bar breadcrumb ───────────────────────────────── */
|
|
2351
|
+
.xfce-sb-crumb-link {
|
|
2352
|
+
color: var(--accent); text-decoration: none; font-family: var(--mono); font-size: 11px;
|
|
2353
|
+
}
|
|
2354
|
+
.xfce-sb-crumb-link:hover { text-decoration: underline; }
|
|
2355
|
+
.xfce-sb-crumb-sep { color: var(--muted); font-size: 10px; margin: 0 2px; }
|
|
2356
|
+
.xfce-sb-crumb-page { color: var(--text); font-family: var(--mono); font-size: 11px; }
|
|
2357
|
+
|
|
2358
|
+
/* ── HUD Activity feed ───────────────────────────────────── */
|
|
2359
|
+
.xfce-hud-act-row {
|
|
2360
|
+
display: flex; align-items: baseline; justify-content: space-between;
|
|
2361
|
+
gap: 8px; padding: 3px 0; border-bottom: 1px solid rgba(255,255,255,.04);
|
|
2362
|
+
font-size: 10px; font-family: var(--mono);
|
|
2363
|
+
}
|
|
2364
|
+
.xfce-hud-act-row:last-child { border-bottom: none; }
|
|
2365
|
+
.xfce-hud-act-msg { flex: 1; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
2366
|
+
.xfce-hud-act-time { color: var(--line); font-size: 9px; flex-shrink: 0; }
|
|
2367
|
+
.xfce-hud-act-ok .xfce-hud-act-msg { color: var(--jade, #5dc97e); }
|
|
2368
|
+
.xfce-hud-act-err .xfce-hud-act-msg { color: var(--red, #e06c6c); }
|
|
2369
|
+
|
|
2338
2370
|
/* ── HUD Drafts section ──────────────────────────────────── */
|
|
2339
2371
|
.xfce-hud-draft-row {
|
|
2340
2372
|
display: flex; align-items: baseline; justify-content: space-between;
|
package/public/xfce.js
CHANGED
|
@@ -67,6 +67,8 @@
|
|
|
67
67
|
'<span id="xfce-sb-g-ind" class="xfce-sb-g-ind" style="display:none" title="g mode: d=dashboard m=media s=settings u=users b=build i=import h=schema a=account">g ›</span>',
|
|
68
68
|
'<button id="xfce-sb-bell" class="xfce-sb-bell" title="Notifications"><span id="xfce-sb-bell-icon">○</span><span id="xfce-sb-bell-badge" class="xfce-sb-bell-badge" style="display:none"></span></button>',
|
|
69
69
|
'<span class="xfce-sb-div">·</span>',
|
|
70
|
+
'<button id="xfce-sb-cheat" class="xfce-sb-cheat" title="Shortcuts (?)">?</button>',
|
|
71
|
+
'<span class="xfce-sb-div">·</span>',
|
|
70
72
|
'<button id="xfce-sb-palette-btn" class="xfce-sb-palette-btn" title="Command palette (⌘K)">⌘</button>',
|
|
71
73
|
'<span class="xfce-sb-div">·</span>',
|
|
72
74
|
'<span id="xfce-sb-build" class="xfce-sb-build" title="Last build"></span>',
|
|
@@ -80,10 +82,18 @@
|
|
|
80
82
|
].join('');
|
|
81
83
|
document.body.insertBefore(sb, document.body.firstChild);
|
|
82
84
|
|
|
83
|
-
//
|
|
84
|
-
var title = document.title.replace(/\s*—\s*Orbiter.*$/, '').trim();
|
|
85
|
+
// Breadcrumb / page title
|
|
85
86
|
var titleEl = document.getElementById('xfce-sb-title');
|
|
86
|
-
if (titleEl
|
|
87
|
+
if (titleEl) {
|
|
88
|
+
if (activeCol && (page === 'entries' || page === 'editor')) {
|
|
89
|
+
// will be filled in by loadInfo once we know the collection label
|
|
90
|
+
titleEl.dataset.col = activeCol;
|
|
91
|
+
titleEl.dataset.page = page;
|
|
92
|
+
} else {
|
|
93
|
+
var title = document.title.replace(/\s*—\s*Orbiter.*$/, '').trim();
|
|
94
|
+
if (title) titleEl.textContent = title;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
87
97
|
|
|
88
98
|
// Clock
|
|
89
99
|
function tick() {
|
|
@@ -111,6 +121,12 @@
|
|
|
111
121
|
e.stopPropagation();
|
|
112
122
|
toggleNotifPanel();
|
|
113
123
|
});
|
|
124
|
+
|
|
125
|
+
// Cheatsheet
|
|
126
|
+
document.getElementById('xfce-sb-cheat').addEventListener('click', function (e) {
|
|
127
|
+
e.stopPropagation();
|
|
128
|
+
toggleCheatsheet();
|
|
129
|
+
});
|
|
114
130
|
}
|
|
115
131
|
|
|
116
132
|
// ── HUD Meta Panel ────────────────────────────────────────────────────
|
|
@@ -131,6 +147,8 @@
|
|
|
131
147
|
'<div id="xfce-hud-cols" class="xfce-hud-rows"></div>',
|
|
132
148
|
'<div class="xfce-hud-section-label" style="margin-top:16px">Drafts</div>',
|
|
133
149
|
'<div id="xfce-hud-drafts" class="xfce-hud-rows xfce-hud-drafts"></div>',
|
|
150
|
+
'<div class="xfce-hud-section-label" style="margin-top:16px">Activity</div>',
|
|
151
|
+
'<div id="xfce-hud-activity" class="xfce-hud-rows xfce-hud-activity"></div>',
|
|
134
152
|
'<div class="xfce-hud-section-label" style="margin-top:16px">Navigation</div>',
|
|
135
153
|
'<div class="xfce-hud-nav-links" id="xfce-hud-nav"></div>',
|
|
136
154
|
'</div>',
|
|
@@ -155,6 +173,7 @@
|
|
|
155
173
|
function toggleHUD() {
|
|
156
174
|
if (!metaPanel) return;
|
|
157
175
|
metaPanel.classList.toggle('open');
|
|
176
|
+
if (metaPanel.classList.contains('open')) refreshHUDActivity();
|
|
158
177
|
}
|
|
159
178
|
|
|
160
179
|
// ── Tools popup ───────────────────────────────────────────────────────
|
|
@@ -561,6 +580,8 @@
|
|
|
561
580
|
case 'search': palSearch(args.join(' ')); break;
|
|
562
581
|
case 'build': palBuild(); break;
|
|
563
582
|
case 'export': palExport(args); break;
|
|
583
|
+
case 'random': palRandom(); break;
|
|
584
|
+
case '=': palMath(args.join(' ')); break;
|
|
564
585
|
default: palPrint('unknown: <b>' + escHtml(cmd) + '</b> — try <b>> help</b>', 'err');
|
|
565
586
|
}
|
|
566
587
|
}
|
|
@@ -574,6 +595,8 @@
|
|
|
574
595
|
'<code>info</code> — pod & version info',
|
|
575
596
|
'<code>build</code> — trigger deploy',
|
|
576
597
|
'<code>export <col> [--md] [--drafts]</code> — download',
|
|
598
|
+
'<code>random</code> — jump to a random entry',
|
|
599
|
+
'<code>= <expr></code> — evaluate math expression',
|
|
577
600
|
].join('<br>'), 'dim');
|
|
578
601
|
}
|
|
579
602
|
|
|
@@ -690,12 +713,50 @@
|
|
|
690
713
|
.then(function (r) { return r.json(); })
|
|
691
714
|
.then(function (d) {
|
|
692
715
|
paletteResults.innerHTML = '';
|
|
693
|
-
if (d.ok || d.message) {
|
|
694
|
-
|
|
716
|
+
if (d.ok || d.message) {
|
|
717
|
+
palPrint('✓ ' + (d.message || 'build triggered'), 'ok');
|
|
718
|
+
startBuildPoll();
|
|
719
|
+
setTimeout(closePalette, 900);
|
|
720
|
+
} else palPrint('build error: ' + escHtml(d.error || JSON.stringify(d)), 'err');
|
|
695
721
|
})
|
|
696
722
|
.catch(function () { paletteResults.innerHTML = ''; palPrint('build request failed', 'err'); });
|
|
697
723
|
}
|
|
698
724
|
|
|
725
|
+
function palMath(expr) {
|
|
726
|
+
if (!expr) { palPrint('usage: <code>= 2 * 450 + 12</code>', 'dim'); return; }
|
|
727
|
+
try {
|
|
728
|
+
// only allow safe math chars
|
|
729
|
+
if (!/^[\d\s\+\-\*\/\.\(\)%,^]+$/.test(expr)) throw new Error('unsafe');
|
|
730
|
+
// replace ^ with ** for exponentiation
|
|
731
|
+
var safe = expr.replace(/\^/g, '**');
|
|
732
|
+
// eslint-disable-next-line no-new-func
|
|
733
|
+
var result = Function('"use strict"; return (' + safe + ')')();
|
|
734
|
+
if (typeof result !== 'number' || !isFinite(result)) throw new Error('not a number');
|
|
735
|
+
palPrint('<span style="font-size:15px;color:var(--accent)">' + result + '</span>'
|
|
736
|
+
+ ' <span style="color:var(--muted);font-size:10px">= ' + escHtml(expr) + '</span>', '');
|
|
737
|
+
} catch (e) {
|
|
738
|
+
palPrint('invalid expression', 'err');
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function palRandom() {
|
|
743
|
+
palPrint('picking a random entry…', 'muted');
|
|
744
|
+
fetch('/api/search/recent?limit=50', { credentials: 'include' })
|
|
745
|
+
.then(function (r) { return r.ok ? r.json() : []; })
|
|
746
|
+
.then(function (rows) {
|
|
747
|
+
var published = rows.filter(function (r) { return r.status === 'published'; });
|
|
748
|
+
if (!published.length) { paletteResults.innerHTML = ''; palPrint('no published entries found', 'muted'); return; }
|
|
749
|
+
var pick = published[Math.floor(Math.random() * published.length)];
|
|
750
|
+
var href = '/collections/' + encodeURIComponent(pick.collection) + '/entries/' + encodeURIComponent(pick.slug);
|
|
751
|
+
paletteResults.innerHTML = '';
|
|
752
|
+
palPrint('✦ <a href="' + href + '" style="color:var(--accent)">' + escHtml(pick.title || pick.slug) + '</a>'
|
|
753
|
+
+ ' <span style="color:var(--muted)">in ' + escHtml(pick.label) + '</span>', '');
|
|
754
|
+
setTimeout(function () { location.href = href; closePalette(); }, 1200);
|
|
755
|
+
})
|
|
756
|
+
.catch(function () { paletteResults.innerHTML = ''; palPrint('error fetching entries', 'err'); });
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
|
|
699
760
|
function palExport(args) {
|
|
700
761
|
if (!args.length) { palPrint('usage: export <collection> [--md] [--drafts]', 'err'); return; }
|
|
701
762
|
var colId = args[0];
|
|
@@ -789,6 +850,7 @@
|
|
|
789
850
|
if (badge) { badge.textContent = _notifUnread > 9 ? '9+' : _notifUnread; badge.style.display = ''; }
|
|
790
851
|
if (icon) { icon.textContent = '●'; }
|
|
791
852
|
if (_notifPanel && _notifPanel.classList.contains('open')) renderNotifList();
|
|
853
|
+
refreshHUDActivity();
|
|
792
854
|
}
|
|
793
855
|
|
|
794
856
|
function buildNotifPanel() {
|
|
@@ -833,6 +895,24 @@
|
|
|
833
895
|
}).join('');
|
|
834
896
|
}
|
|
835
897
|
|
|
898
|
+
function refreshHUDActivity() {
|
|
899
|
+
var el2 = document.getElementById('xfce-hud-activity');
|
|
900
|
+
if (!el2) return;
|
|
901
|
+
if (!_notifications.length) {
|
|
902
|
+
el2.innerHTML = '<div class="xfce-hud-empty">No activity yet</div>';
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
el2.innerHTML = _notifications.slice(0, 8).map(function (n) {
|
|
906
|
+
var ago = Math.floor((Date.now() - n.time) / 1000);
|
|
907
|
+
var t = ago < 60 ? ago + 's' : ago < 3600 ? Math.floor(ago / 60) + 'm' : Math.floor(ago / 3600) + 'h';
|
|
908
|
+
var cls = n.type === 'success' ? 'xfce-hud-act-ok' : n.type === 'error' ? 'xfce-hud-act-err' : '';
|
|
909
|
+
return '<div class="xfce-hud-act-row' + (cls ? ' ' + cls : '') + '">'
|
|
910
|
+
+ '<span class="xfce-hud-act-msg">' + escHtml(n.msg) + '</span>'
|
|
911
|
+
+ '<span class="xfce-hud-act-time">' + t + '</span>'
|
|
912
|
+
+ '</div>';
|
|
913
|
+
}).join('');
|
|
914
|
+
}
|
|
915
|
+
|
|
836
916
|
function toggleNotifPanel() {
|
|
837
917
|
if (!_notifPanel) buildNotifPanel();
|
|
838
918
|
var isOpen = _notifPanel.classList.toggle('open');
|
|
@@ -1335,6 +1415,17 @@
|
|
|
1335
1415
|
return hudRow(col.label, col.total + ' published' + draftTxt);
|
|
1336
1416
|
}).join('');
|
|
1337
1417
|
}
|
|
1418
|
+
|
|
1419
|
+
// Breadcrumb in status bar center
|
|
1420
|
+
var titleEl = document.getElementById('xfce-sb-title');
|
|
1421
|
+
if (titleEl && titleEl.dataset.col) {
|
|
1422
|
+
var colMeta = (info.collections || []).find(function (c) { return c.id === titleEl.dataset.col; });
|
|
1423
|
+
var colLabel = colMeta ? colMeta.label : titleEl.dataset.col;
|
|
1424
|
+
var crumbPage = titleEl.dataset.page === 'editor' ? 'Editor' : 'Entries';
|
|
1425
|
+
titleEl.innerHTML = '<a href="/entries.html?col=' + encodeURIComponent(titleEl.dataset.col) + '" class="xfce-sb-crumb-link">' + escHtml(colLabel) + '</a>'
|
|
1426
|
+
+ '<span class="xfce-sb-crumb-sep"> › </span>'
|
|
1427
|
+
+ '<span class="xfce-sb-crumb-page">' + crumbPage + '</span>';
|
|
1428
|
+
}
|
|
1338
1429
|
})
|
|
1339
1430
|
.catch(function () {});
|
|
1340
1431
|
|
|
@@ -1442,6 +1533,8 @@
|
|
|
1442
1533
|
cheatRow('> search <q>', 'Search entries'),
|
|
1443
1534
|
cheatRow('> build', 'Trigger site build'),
|
|
1444
1535
|
cheatRow('> export <col>', 'Export collection'),
|
|
1536
|
+
cheatRow('> random', 'Jump to random entry'),
|
|
1537
|
+
cheatRow('> = <expr>', 'Evaluate math'),
|
|
1445
1538
|
cheatRow('> info', 'Show pod info'),
|
|
1446
1539
|
cheatRow('> help', 'Show command help'),
|
|
1447
1540
|
'</div>',
|
|
@@ -1573,19 +1666,40 @@
|
|
|
1573
1666
|
}
|
|
1574
1667
|
|
|
1575
1668
|
// ── Build status in status bar ────────────────────────────────────────
|
|
1669
|
+
var _buildPolling = false;
|
|
1670
|
+
|
|
1576
1671
|
function loadBuildStatus() {
|
|
1577
1672
|
fetch('/api/build/status', { credentials: 'include' })
|
|
1578
1673
|
.then(function (r) { return r.ok ? r.json() : null; })
|
|
1579
1674
|
.then(function (d) {
|
|
1580
|
-
if (!d
|
|
1675
|
+
if (!d) return;
|
|
1581
1676
|
var el2 = document.getElementById('xfce-sb-build');
|
|
1582
1677
|
var sep = document.getElementById('xfce-sb-build-sep');
|
|
1583
1678
|
if (!el2) return;
|
|
1584
|
-
|
|
1585
|
-
var
|
|
1586
|
-
|
|
1679
|
+
|
|
1680
|
+
var running = d.running === true;
|
|
1681
|
+
el2.classList.toggle('xfce-sb-build--running', running);
|
|
1682
|
+
|
|
1683
|
+
if (running) {
|
|
1684
|
+
el2.textContent = '◉ building…';
|
|
1685
|
+
el2.title = 'Build in progress';
|
|
1686
|
+
if (sep) sep.style.display = '';
|
|
1687
|
+
if (!_buildPolling) {
|
|
1688
|
+
_buildPolling = true;
|
|
1689
|
+
setTimeout(function poll() {
|
|
1690
|
+
loadBuildStatus();
|
|
1691
|
+
if (_buildPolling) setTimeout(poll, 4000);
|
|
1692
|
+
}, 4000);
|
|
1693
|
+
}
|
|
1694
|
+
return;
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
_buildPolling = false;
|
|
1698
|
+
if (!d.lastTriggered) return;
|
|
1699
|
+
var dt = new Date(d.lastTriggered.replace(' ', 'T'));
|
|
1700
|
+
var diffM = Math.floor((Date.now() - dt) / 60000);
|
|
1587
1701
|
var label = diffM < 1 ? 'built now'
|
|
1588
|
-
: diffM < 60
|
|
1702
|
+
: diffM < 60 ? 'built ' + diffM + 'm ago'
|
|
1589
1703
|
: diffM < 1440 ? 'built ' + Math.floor(diffM / 60) + 'h ago'
|
|
1590
1704
|
: 'built ' + dt.toLocaleDateString([], { month: 'short', day: 'numeric' });
|
|
1591
1705
|
el2.textContent = '◉ ' + label;
|
|
@@ -1594,6 +1708,18 @@
|
|
|
1594
1708
|
});
|
|
1595
1709
|
}
|
|
1596
1710
|
|
|
1711
|
+
function startBuildPoll() {
|
|
1712
|
+
_buildPolling = true;
|
|
1713
|
+
var el2 = document.getElementById('xfce-sb-build');
|
|
1714
|
+
var sep = document.getElementById('xfce-sb-build-sep');
|
|
1715
|
+
if (el2) { el2.textContent = '◉ building…'; el2.classList.add('xfce-sb-build--running'); }
|
|
1716
|
+
if (sep) sep.style.display = '';
|
|
1717
|
+
setTimeout(function poll() {
|
|
1718
|
+
loadBuildStatus();
|
|
1719
|
+
if (_buildPolling) setTimeout(poll, 4000);
|
|
1720
|
+
}, 3000);
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1597
1723
|
|
|
1598
1724
|
// ── Init ──────────────────────────────────────────────────────────────
|
|
1599
1725
|
function init() {
|