@a83/orbiter-admin 0.3.42 → 0.3.44
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 +68 -0
- package/public/xfce.js +111 -0
- package/src/routes/search.js +9 -7
package/package.json
CHANGED
package/public/style.css
CHANGED
|
@@ -2196,6 +2196,74 @@ html[data-style="xfce"][data-dock-pos="left"] .xfce-ws-overlay {
|
|
|
2196
2196
|
bottom: auto; left: 110px; top: 50%; transform: translateY(-50%);
|
|
2197
2197
|
}
|
|
2198
2198
|
|
|
2199
|
+
/* ── Bell / Notification Center ─────────────────────────── */
|
|
2200
|
+
.xfce-sb-bell {
|
|
2201
|
+
background: none; border: none; cursor: pointer; padding: 0 2px;
|
|
2202
|
+
color: var(--muted); font-size: 12px; line-height: 1;
|
|
2203
|
+
position: relative; display: flex; align-items: center; gap: 2px;
|
|
2204
|
+
transition: color .15s;
|
|
2205
|
+
}
|
|
2206
|
+
.xfce-sb-bell:hover { color: var(--accent); }
|
|
2207
|
+
.xfce-sb-bell-badge {
|
|
2208
|
+
position: absolute; top: -3px; right: -4px;
|
|
2209
|
+
background: var(--accent); color: var(--bg1);
|
|
2210
|
+
font-size: 8px; font-family: var(--mono); font-weight: 700;
|
|
2211
|
+
border-radius: 6px; padding: 0 3px; min-width: 12px; text-align: center;
|
|
2212
|
+
line-height: 13px; pointer-events: none;
|
|
2213
|
+
}
|
|
2214
|
+
.xfce-notif-panel {
|
|
2215
|
+
position: fixed; top: calc(var(--sb-h) + 6px); right: 12px;
|
|
2216
|
+
width: 300px; max-height: 340px;
|
|
2217
|
+
background: var(--bg1); border: 1px solid var(--line);
|
|
2218
|
+
border-radius: 10px; box-shadow: 0 8px 32px rgba(0,0,0,.45);
|
|
2219
|
+
z-index: 100000; display: none; flex-direction: column; overflow: hidden;
|
|
2220
|
+
font-family: var(--mono); font-size: 11px;
|
|
2221
|
+
}
|
|
2222
|
+
.xfce-notif-panel.open { display: flex; }
|
|
2223
|
+
.xfce-notif-bar {
|
|
2224
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
2225
|
+
padding: 8px 12px; border-bottom: 1px solid var(--line);
|
|
2226
|
+
background: var(--bg2); flex-shrink: 0;
|
|
2227
|
+
}
|
|
2228
|
+
.xfce-notif-title { color: var(--accent); font-weight: 700; font-size: 10px; letter-spacing: .06em; }
|
|
2229
|
+
.xfce-notif-clear {
|
|
2230
|
+
background: none; border: 1px solid var(--line); border-radius: 4px;
|
|
2231
|
+
color: var(--muted); font-size: 9px; font-family: var(--mono);
|
|
2232
|
+
padding: 1px 7px; cursor: pointer; transition: color .15s, border-color .15s;
|
|
2233
|
+
}
|
|
2234
|
+
.xfce-notif-clear:hover { color: var(--accent); border-color: var(--accent); }
|
|
2235
|
+
.xfce-notif-list {
|
|
2236
|
+
overflow-y: auto; flex: 1; padding: 4px 0;
|
|
2237
|
+
}
|
|
2238
|
+
.xfce-notif-list::-webkit-scrollbar { width: 4px; }
|
|
2239
|
+
.xfce-notif-list::-webkit-scrollbar-thumb { background: var(--line); border-radius: 2px; }
|
|
2240
|
+
.xfce-notif-item {
|
|
2241
|
+
display: flex; align-items: flex-start; justify-content: space-between;
|
|
2242
|
+
gap: 8px; padding: 6px 12px;
|
|
2243
|
+
border-bottom: 1px solid rgba(255,255,255,.04);
|
|
2244
|
+
}
|
|
2245
|
+
.xfce-notif-item:last-child { border-bottom: none; }
|
|
2246
|
+
.xfce-notif-msg { flex: 1; color: var(--text); font-size: 10px; line-height: 1.4; }
|
|
2247
|
+
.xfce-notif-time { color: var(--muted); font-size: 9px; white-space: nowrap; flex-shrink: 0; margin-top: 1px; }
|
|
2248
|
+
.xfce-notif-ok .xfce-notif-msg { color: var(--jade); }
|
|
2249
|
+
.xfce-notif-err .xfce-notif-msg { color: var(--red); }
|
|
2250
|
+
.xfce-notif-empty { padding: 20px 12px; color: var(--muted); font-size: 10px; text-align: center; }
|
|
2251
|
+
|
|
2252
|
+
/* ── HUD Drafts section ──────────────────────────────────── */
|
|
2253
|
+
.xfce-hud-draft-row {
|
|
2254
|
+
display: flex; align-items: baseline; justify-content: space-between;
|
|
2255
|
+
gap: 8px; padding: 4px 0; border-bottom: 1px solid rgba(255,255,255,.04);
|
|
2256
|
+
}
|
|
2257
|
+
.xfce-hud-draft-row:last-child { border-bottom: none; }
|
|
2258
|
+
.xfce-hud-draft-link {
|
|
2259
|
+
color: var(--accent); text-decoration: none; font-size: 10px;
|
|
2260
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1;
|
|
2261
|
+
max-width: 160px;
|
|
2262
|
+
}
|
|
2263
|
+
.xfce-hud-draft-link:hover { text-decoration: underline; }
|
|
2264
|
+
.xfce-hud-draft-meta { color: var(--muted); font-size: 9px; white-space: nowrap; flex-shrink: 0; }
|
|
2265
|
+
.xfce-hud-empty { color: var(--muted); font-size: 10px; padding: 4px 0; }
|
|
2266
|
+
|
|
2199
2267
|
/* ── Toast host (above dock) ─────────────────────────────── */
|
|
2200
2268
|
.xfce-toast-host {
|
|
2201
2269
|
position: fixed; bottom: 90px; left: 50%; transform: translateX(-50%);
|
package/public/xfce.js
CHANGED
|
@@ -64,6 +64,8 @@
|
|
|
64
64
|
'<div class="xfce-sb-center" id="xfce-sb-title"></div>',
|
|
65
65
|
'<div class="xfce-sb-right">',
|
|
66
66
|
'<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>',
|
|
67
|
+
'<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>',
|
|
68
|
+
'<span class="xfce-sb-div">·</span>',
|
|
67
69
|
'<button id="xfce-sb-palette-btn" class="xfce-sb-palette-btn" title="Command palette (⌘K)">⌘</button>',
|
|
68
70
|
'<span class="xfce-sb-div">·</span>',
|
|
69
71
|
'<span id="xfce-sb-build" class="xfce-sb-build" title="Last build"></span>',
|
|
@@ -102,6 +104,12 @@
|
|
|
102
104
|
e.stopPropagation();
|
|
103
105
|
openPalette();
|
|
104
106
|
});
|
|
107
|
+
|
|
108
|
+
// Bell / notification center
|
|
109
|
+
document.getElementById('xfce-sb-bell').addEventListener('click', function (e) {
|
|
110
|
+
e.stopPropagation();
|
|
111
|
+
toggleNotifPanel();
|
|
112
|
+
});
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
// ── HUD Meta Panel ────────────────────────────────────────────────────
|
|
@@ -120,6 +128,8 @@
|
|
|
120
128
|
'<div id="xfce-hud-pod" class="xfce-hud-rows"></div>',
|
|
121
129
|
'<div class="xfce-hud-section-label" style="margin-top:16px">Collections</div>',
|
|
122
130
|
'<div id="xfce-hud-cols" class="xfce-hud-rows"></div>',
|
|
131
|
+
'<div class="xfce-hud-section-label" style="margin-top:16px">Drafts</div>',
|
|
132
|
+
'<div id="xfce-hud-drafts" class="xfce-hud-rows xfce-hud-drafts"></div>',
|
|
123
133
|
'<div class="xfce-hud-section-label" style="margin-top:16px">Navigation</div>',
|
|
124
134
|
'<div class="xfce-hud-nav-links" id="xfce-hud-nav"></div>',
|
|
125
135
|
'</div>',
|
|
@@ -158,6 +168,13 @@
|
|
|
158
168
|
a.innerHTML = '<span class="xfce-tools-icon">' + t.icon + '</span><span>' + t.label + '</span>';
|
|
159
169
|
toolsPopup.appendChild(a);
|
|
160
170
|
});
|
|
171
|
+
var settingsSep = document.createElement('div');
|
|
172
|
+
settingsSep.className = 'xfce-tools-sep';
|
|
173
|
+
toolsPopup.appendChild(settingsSep);
|
|
174
|
+
var settingsLink = el('a', 'xfce-tools-item' + (page === 'settings' ? ' active' : ''));
|
|
175
|
+
settingsLink.href = '/settings.html';
|
|
176
|
+
settingsLink.innerHTML = '<span class="xfce-tools-icon">⚙</span><span>Settings</span>';
|
|
177
|
+
toolsPopup.appendChild(settingsLink);
|
|
161
178
|
var sep = document.createElement('div');
|
|
162
179
|
sep.className = 'xfce-tools-sep';
|
|
163
180
|
toolsPopup.appendChild(sep);
|
|
@@ -707,6 +724,7 @@
|
|
|
707
724
|
t.classList.remove('show');
|
|
708
725
|
setTimeout(function () { t.remove(); }, 300);
|
|
709
726
|
}, 2500);
|
|
727
|
+
pushNotif(msg, type);
|
|
710
728
|
};
|
|
711
729
|
|
|
712
730
|
function observeSavedFlash() {
|
|
@@ -719,6 +737,77 @@
|
|
|
719
737
|
}).observe(flash, { attributes: true, attributeFilter: ['style'] });
|
|
720
738
|
}
|
|
721
739
|
|
|
740
|
+
// ── Notification Center ───────────────────────────────────────────────
|
|
741
|
+
var _notifications = [], _notifUnread = 0, _notifPanel = null;
|
|
742
|
+
|
|
743
|
+
function pushNotif(msg, type) {
|
|
744
|
+
_notifications.unshift({ msg: msg, type: type || 'info', time: Date.now() });
|
|
745
|
+
if (_notifications.length > 40) _notifications.pop();
|
|
746
|
+
_notifUnread++;
|
|
747
|
+
var badge = document.getElementById('xfce-sb-bell-badge');
|
|
748
|
+
var icon = document.getElementById('xfce-sb-bell-icon');
|
|
749
|
+
if (badge) { badge.textContent = _notifUnread > 9 ? '9+' : _notifUnread; badge.style.display = ''; }
|
|
750
|
+
if (icon) { icon.textContent = '●'; }
|
|
751
|
+
if (_notifPanel && _notifPanel.classList.contains('open')) renderNotifList();
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
function buildNotifPanel() {
|
|
755
|
+
_notifPanel = el('div', 'xfce-notif-panel');
|
|
756
|
+
_notifPanel.id = 'xfce-notif-panel';
|
|
757
|
+
_notifPanel.innerHTML = '<div class="xfce-notif-bar">'
|
|
758
|
+
+ '<span class="xfce-notif-title">Notifications</span>'
|
|
759
|
+
+ '<button id="xfce-notif-clear" class="xfce-notif-clear">Clear all</button>'
|
|
760
|
+
+ '</div>'
|
|
761
|
+
+ '<div id="xfce-notif-list" class="xfce-notif-list"></div>';
|
|
762
|
+
document.body.appendChild(_notifPanel);
|
|
763
|
+
document.getElementById('xfce-notif-clear').addEventListener('click', function () {
|
|
764
|
+
_notifications = []; _notifUnread = 0;
|
|
765
|
+
renderNotifList();
|
|
766
|
+
var badge = document.getElementById('xfce-sb-bell-badge');
|
|
767
|
+
var icon = document.getElementById('xfce-sb-bell-icon');
|
|
768
|
+
if (badge) badge.style.display = 'none';
|
|
769
|
+
if (icon) icon.textContent = '○';
|
|
770
|
+
});
|
|
771
|
+
document.addEventListener('click', function (e) {
|
|
772
|
+
if (_notifPanel && _notifPanel.classList.contains('open')
|
|
773
|
+
&& !_notifPanel.contains(e.target)
|
|
774
|
+
&& e.target.id !== 'xfce-sb-bell') closeNotifPanel();
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function renderNotifList() {
|
|
779
|
+
var list = document.getElementById('xfce-notif-list');
|
|
780
|
+
if (!list) return;
|
|
781
|
+
if (!_notifications.length) {
|
|
782
|
+
list.innerHTML = '<div class="xfce-notif-empty">No notifications yet</div>';
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
list.innerHTML = _notifications.map(function (n) {
|
|
786
|
+
var ago = Math.floor((Date.now() - n.time) / 1000);
|
|
787
|
+
var t = ago < 60 ? ago + 's' : ago < 3600 ? Math.floor(ago/60) + 'm' : Math.floor(ago/3600) + 'h';
|
|
788
|
+
var cls = n.type === 'success' ? 'ok' : n.type === 'error' ? 'err' : 'info';
|
|
789
|
+
return '<div class="xfce-notif-item xfce-notif-' + cls + '">'
|
|
790
|
+
+ '<span class="xfce-notif-msg">' + escHtml(n.msg) + '</span>'
|
|
791
|
+
+ '<span class="xfce-notif-time">' + t + '</span>'
|
|
792
|
+
+ '</div>';
|
|
793
|
+
}).join('');
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
function toggleNotifPanel() {
|
|
797
|
+
if (!_notifPanel) buildNotifPanel();
|
|
798
|
+
var isOpen = _notifPanel.classList.toggle('open');
|
|
799
|
+
if (isOpen) {
|
|
800
|
+
_notifUnread = 0;
|
|
801
|
+
var badge = document.getElementById('xfce-sb-bell-badge');
|
|
802
|
+
if (badge) badge.style.display = 'none';
|
|
803
|
+
renderNotifList();
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
function closeNotifPanel() {
|
|
808
|
+
if (_notifPanel) _notifPanel.classList.remove('open');
|
|
809
|
+
}
|
|
810
|
+
|
|
722
811
|
// ── Workspace overlay (Notes + To-do) ────────────────────────────────
|
|
723
812
|
var wsOverlay, wsActivePane = 'notes', wsNotesTimer, wsTodosData = [];
|
|
724
813
|
|
|
@@ -1206,6 +1295,28 @@
|
|
|
1206
1295
|
})
|
|
1207
1296
|
.catch(function () {});
|
|
1208
1297
|
|
|
1298
|
+
// HUD Drafts
|
|
1299
|
+
fetch('/api/search/recent?status=draft&limit=10', { credentials: 'include' })
|
|
1300
|
+
.then(function (r) { return r.ok ? r.json() : []; })
|
|
1301
|
+
.then(function (drafts) {
|
|
1302
|
+
var hudDrafts = document.getElementById('xfce-hud-drafts');
|
|
1303
|
+
if (!hudDrafts) return;
|
|
1304
|
+
if (!drafts.length) {
|
|
1305
|
+
hudDrafts.innerHTML = '<div class="xfce-hud-empty">No drafts</div>';
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
hudDrafts.innerHTML = drafts.map(function (d) {
|
|
1309
|
+
var href = '/collections/' + encodeURIComponent(d.collection) + '/entries/' + encodeURIComponent(d.slug);
|
|
1310
|
+
var ago = Math.floor((Date.now() - new Date(d.updated_at).getTime()) / 60000);
|
|
1311
|
+
var t = ago < 60 ? ago + 'm' : Math.floor(ago / 60) + 'h';
|
|
1312
|
+
return '<div class="xfce-hud-draft-row">'
|
|
1313
|
+
+ '<a class="xfce-hud-draft-link" href="' + href + '">' + escHtml(d.title || d.slug) + '</a>'
|
|
1314
|
+
+ '<span class="xfce-hud-draft-meta">' + escHtml(d.label) + ' · ' + t + '</span>'
|
|
1315
|
+
+ '</div>';
|
|
1316
|
+
}).join('');
|
|
1317
|
+
})
|
|
1318
|
+
.catch(function () {});
|
|
1319
|
+
|
|
1209
1320
|
// Site meta
|
|
1210
1321
|
fetch('/api/meta/site~name', { credentials: 'include' })
|
|
1211
1322
|
.then(function (r) { return r.ok ? r.json() : null; })
|
package/src/routes/search.js
CHANGED
|
@@ -5,17 +5,19 @@ export const searchRoutes = new Hono();
|
|
|
5
5
|
|
|
6
6
|
// GET /api/search/recent — last N entries across all collections
|
|
7
7
|
searchRoutes.get('/recent', (c) => {
|
|
8
|
-
const limit
|
|
9
|
-
const
|
|
10
|
-
const
|
|
8
|
+
const limit = Math.min(parseInt(c.req.query('limit') ?? '10', 10), 50);
|
|
9
|
+
const status = c.req.query('status') ?? null;
|
|
10
|
+
const db = openPod(c.get('podPath'));
|
|
11
|
+
const cols = db.getCollections();
|
|
11
12
|
const colMap = Object.fromEntries(cols.map(c => [c.id, c.label]));
|
|
12
13
|
|
|
13
|
-
const rows =
|
|
14
|
-
.prepare(`SELECT
|
|
15
|
-
.all(limit);
|
|
14
|
+
const rows = status
|
|
15
|
+
? db.db.prepare(`SELECT * FROM _entries WHERE status = ? ORDER BY updated_at DESC LIMIT ?`).all(status, limit)
|
|
16
|
+
: db.db.prepare(`SELECT * FROM _entries ORDER BY updated_at DESC LIMIT ?`).all(limit);
|
|
16
17
|
|
|
17
18
|
const results = rows.map(r => {
|
|
18
|
-
|
|
19
|
+
let data = {};
|
|
20
|
+
try { data = JSON.parse(r.data); } catch {}
|
|
19
21
|
return {
|
|
20
22
|
collection: r.collection_id,
|
|
21
23
|
label: colMap[r.collection_id] ?? r.collection_id,
|