@delt/claude-alarm 0.3.5 → 0.3.7
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/dist/dashboard/index.html +102 -13
- package/package.json +1 -1
- package/src/dashboard/index.html +102 -13
|
@@ -98,6 +98,10 @@
|
|
|
98
98
|
letter-spacing: 0.5px;
|
|
99
99
|
color: var(--text-dim);
|
|
100
100
|
padding: 8px 8px 12px;
|
|
101
|
+
position: sticky;
|
|
102
|
+
top: 0;
|
|
103
|
+
background: var(--bg);
|
|
104
|
+
z-index: 1;
|
|
101
105
|
}
|
|
102
106
|
.session-card {
|
|
103
107
|
background: var(--surface);
|
|
@@ -207,6 +211,28 @@
|
|
|
207
211
|
margin-top: 4px;
|
|
208
212
|
}
|
|
209
213
|
|
|
214
|
+
/* Scroll to bottom button */
|
|
215
|
+
.scroll-bottom {
|
|
216
|
+
position: absolute;
|
|
217
|
+
bottom: 80px;
|
|
218
|
+
right: 30px;
|
|
219
|
+
width: 36px;
|
|
220
|
+
height: 36px;
|
|
221
|
+
border-radius: 50%;
|
|
222
|
+
background: var(--surface);
|
|
223
|
+
border: 1px solid var(--border);
|
|
224
|
+
color: var(--text);
|
|
225
|
+
cursor: pointer;
|
|
226
|
+
font-size: 16px;
|
|
227
|
+
display: none;
|
|
228
|
+
align-items: center;
|
|
229
|
+
justify-content: center;
|
|
230
|
+
z-index: 5;
|
|
231
|
+
transition: border-color 0.15s;
|
|
232
|
+
}
|
|
233
|
+
.scroll-bottom:hover { border-color: var(--accent); }
|
|
234
|
+
.scroll-bottom.visible { display: flex; }
|
|
235
|
+
|
|
210
236
|
/* Image preview */
|
|
211
237
|
.image-preview {
|
|
212
238
|
border-top: 1px solid var(--border);
|
|
@@ -308,13 +334,7 @@
|
|
|
308
334
|
overflow-y: auto;
|
|
309
335
|
padding: 12px;
|
|
310
336
|
}
|
|
311
|
-
.notifications-panel
|
|
312
|
-
font-size: 13px;
|
|
313
|
-
text-transform: uppercase;
|
|
314
|
-
letter-spacing: 0.5px;
|
|
315
|
-
color: var(--text-dim);
|
|
316
|
-
padding: 8px 8px 12px;
|
|
317
|
-
}
|
|
337
|
+
.notifications-panel > .notif-header + #notifList { /* spacer */ }
|
|
318
338
|
.notif-item {
|
|
319
339
|
background: var(--surface);
|
|
320
340
|
border: 1px solid var(--border);
|
|
@@ -325,9 +345,43 @@
|
|
|
325
345
|
cursor: pointer;
|
|
326
346
|
}
|
|
327
347
|
.notif-item:hover { border-color: var(--accent); }
|
|
328
|
-
.notif-item .notif-
|
|
348
|
+
.notif-item:hover .notif-dismiss { opacity: 1; }
|
|
349
|
+
.notif-item .notif-title { font-weight: 500; margin-bottom: 2px; display: flex; align-items: center; }
|
|
350
|
+
.notif-item .notif-title-text { flex: 1; }
|
|
351
|
+
.notif-dismiss {
|
|
352
|
+
opacity: 0;
|
|
353
|
+
background: none;
|
|
354
|
+
border: none;
|
|
355
|
+
color: var(--text-dim);
|
|
356
|
+
cursor: pointer;
|
|
357
|
+
font-size: 14px;
|
|
358
|
+
padding: 0 2px;
|
|
359
|
+
transition: opacity 0.15s;
|
|
360
|
+
}
|
|
361
|
+
.notif-dismiss:hover { color: var(--red); }
|
|
329
362
|
.notif-item .notif-message { color: var(--text-dim); }
|
|
330
363
|
.notif-item .notif-time { font-size: 11px; color: var(--text-dim); margin-top: 4px; }
|
|
364
|
+
.notif-header {
|
|
365
|
+
display: flex;
|
|
366
|
+
align-items: center;
|
|
367
|
+
justify-content: space-between;
|
|
368
|
+
padding: 8px 8px 12px;
|
|
369
|
+
position: sticky;
|
|
370
|
+
top: 0;
|
|
371
|
+
background: var(--bg);
|
|
372
|
+
z-index: 1;
|
|
373
|
+
}
|
|
374
|
+
.notif-header h2 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-dim); padding: 0; }
|
|
375
|
+
.notif-clear-all {
|
|
376
|
+
background: none;
|
|
377
|
+
border: 1px solid var(--border);
|
|
378
|
+
border-radius: 4px;
|
|
379
|
+
color: var(--text-dim);
|
|
380
|
+
cursor: pointer;
|
|
381
|
+
font-size: 11px;
|
|
382
|
+
padding: 2px 8px;
|
|
383
|
+
}
|
|
384
|
+
.notif-clear-all:hover { border-color: var(--red); color: var(--red); }
|
|
331
385
|
.notif-level {
|
|
332
386
|
display: inline-block;
|
|
333
387
|
width: 6px; height: 6px;
|
|
@@ -455,6 +509,7 @@
|
|
|
455
509
|
<div class="messages-list" id="messagesList">
|
|
456
510
|
<div class="empty-state">Select a session to view messages</div>
|
|
457
511
|
</div>
|
|
512
|
+
<button class="scroll-bottom" id="scrollBottom" title="Scroll to bottom">↓</button>
|
|
458
513
|
<div class="drag-overlay" id="dragOverlay">Drop image here</div>
|
|
459
514
|
<div class="image-preview" id="imagePreview">
|
|
460
515
|
<img id="previewImg" src="" alt="preview">
|
|
@@ -470,7 +525,10 @@
|
|
|
470
525
|
</div>
|
|
471
526
|
|
|
472
527
|
<div class="notifications-panel">
|
|
473
|
-
<
|
|
528
|
+
<div class="notif-header">
|
|
529
|
+
<h2>Notifications</h2>
|
|
530
|
+
<button class="notif-clear-all" id="notifClearAll">Clear all</button>
|
|
531
|
+
</div>
|
|
474
532
|
<div id="notifList">
|
|
475
533
|
<div class="empty-state">No notifications yet</div>
|
|
476
534
|
</div>
|
|
@@ -587,6 +645,8 @@
|
|
|
587
645
|
if (!state.messages[msg.sessionId]) state.messages[msg.sessionId] = [];
|
|
588
646
|
state.messages[msg.sessionId].push({ from: 'session', content: msg.content, time: msg.timestamp });
|
|
589
647
|
if (state.selectedSession === msg.sessionId) renderMessages();
|
|
648
|
+
state.notifications.unshift({ sessionId: msg.sessionId, title: 'Reply', message: msg.content.slice(0, 100), level: 'info', time: msg.timestamp });
|
|
649
|
+
renderNotifications();
|
|
590
650
|
break;
|
|
591
651
|
case 'notification':
|
|
592
652
|
state.notifications.unshift({ sessionId: msg.sessionId, title: msg.title, message: msg.message, level: msg.level || 'info', time: msg.timestamp });
|
|
@@ -701,26 +761,38 @@
|
|
|
701
761
|
|
|
702
762
|
function renderNotifications() {
|
|
703
763
|
const el = $('#notifList');
|
|
764
|
+
const clearBtn = $('#notifClearAll');
|
|
704
765
|
if (!state.notifications.length) {
|
|
705
766
|
el.innerHTML = '<div class="empty-state">No notifications yet</div>';
|
|
767
|
+
clearBtn.style.display = 'none';
|
|
706
768
|
return;
|
|
707
769
|
}
|
|
708
|
-
|
|
770
|
+
clearBtn.style.display = 'block';
|
|
771
|
+
el.innerHTML = state.notifications.slice(0, 50).map((n, i) => {
|
|
709
772
|
const timeStr = new Date(n.time).toLocaleTimeString();
|
|
710
773
|
const session = state.sessions[n.sessionId];
|
|
711
774
|
const sName = session ? session.name : n.sessionId.slice(0, 8);
|
|
712
|
-
return `<div class="notif-item" data-session="${n.sessionId}">
|
|
713
|
-
<div class="notif-title"><span class="notif-level ${n.level}"></span>${esc(n.title)}</div>
|
|
775
|
+
return `<div class="notif-item" data-session="${n.sessionId}" data-index="${i}">
|
|
776
|
+
<div class="notif-title"><span class="notif-level ${n.level}"></span><span class="notif-title-text">${esc(n.title)}</span><button class="notif-dismiss" data-index="${i}">×</button></div>
|
|
714
777
|
<div class="notif-message">${esc(n.message)}</div>
|
|
715
778
|
<div class="notif-time">${sName} · ${timeStr}</div>
|
|
716
779
|
</div>`;
|
|
717
780
|
}).join('');
|
|
718
781
|
el.querySelectorAll('.notif-item').forEach(item => {
|
|
719
|
-
item.addEventListener('click', () => {
|
|
782
|
+
item.addEventListener('click', (e) => {
|
|
783
|
+
if (e.target.classList.contains('notif-dismiss')) return;
|
|
720
784
|
const sid = item.dataset.session;
|
|
721
785
|
if (sid && state.sessions[sid]) selectSession(sid);
|
|
722
786
|
});
|
|
723
787
|
});
|
|
788
|
+
el.querySelectorAll('.notif-dismiss').forEach(btn => {
|
|
789
|
+
btn.addEventListener('click', (e) => {
|
|
790
|
+
e.stopPropagation();
|
|
791
|
+
const idx = parseInt(btn.dataset.index);
|
|
792
|
+
state.notifications.splice(idx, 1);
|
|
793
|
+
renderNotifications();
|
|
794
|
+
});
|
|
795
|
+
});
|
|
724
796
|
}
|
|
725
797
|
|
|
726
798
|
// --- Image handling ---
|
|
@@ -870,6 +942,23 @@
|
|
|
870
942
|
return html;
|
|
871
943
|
}
|
|
872
944
|
|
|
945
|
+
// Clear all notifications
|
|
946
|
+
$('#notifClearAll').addEventListener('click', () => {
|
|
947
|
+
state.notifications = [];
|
|
948
|
+
renderNotifications();
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
// Scroll to bottom button
|
|
952
|
+
const msgList = $('#messagesList');
|
|
953
|
+
const scrollBtn = $('#scrollBottom');
|
|
954
|
+
msgList.addEventListener('scroll', () => {
|
|
955
|
+
const gap = msgList.scrollHeight - msgList.scrollTop - msgList.clientHeight;
|
|
956
|
+
scrollBtn.classList.toggle('visible', gap > 100);
|
|
957
|
+
});
|
|
958
|
+
scrollBtn.addEventListener('click', () => {
|
|
959
|
+
msgList.scrollTo({ top: msgList.scrollHeight, behavior: 'smooth' });
|
|
960
|
+
});
|
|
961
|
+
|
|
873
962
|
state.token = getToken();
|
|
874
963
|
connect();
|
|
875
964
|
})();
|
package/package.json
CHANGED
package/src/dashboard/index.html
CHANGED
|
@@ -98,6 +98,10 @@
|
|
|
98
98
|
letter-spacing: 0.5px;
|
|
99
99
|
color: var(--text-dim);
|
|
100
100
|
padding: 8px 8px 12px;
|
|
101
|
+
position: sticky;
|
|
102
|
+
top: 0;
|
|
103
|
+
background: var(--bg);
|
|
104
|
+
z-index: 1;
|
|
101
105
|
}
|
|
102
106
|
.session-card {
|
|
103
107
|
background: var(--surface);
|
|
@@ -207,6 +211,28 @@
|
|
|
207
211
|
margin-top: 4px;
|
|
208
212
|
}
|
|
209
213
|
|
|
214
|
+
/* Scroll to bottom button */
|
|
215
|
+
.scroll-bottom {
|
|
216
|
+
position: absolute;
|
|
217
|
+
bottom: 80px;
|
|
218
|
+
right: 30px;
|
|
219
|
+
width: 36px;
|
|
220
|
+
height: 36px;
|
|
221
|
+
border-radius: 50%;
|
|
222
|
+
background: var(--surface);
|
|
223
|
+
border: 1px solid var(--border);
|
|
224
|
+
color: var(--text);
|
|
225
|
+
cursor: pointer;
|
|
226
|
+
font-size: 16px;
|
|
227
|
+
display: none;
|
|
228
|
+
align-items: center;
|
|
229
|
+
justify-content: center;
|
|
230
|
+
z-index: 5;
|
|
231
|
+
transition: border-color 0.15s;
|
|
232
|
+
}
|
|
233
|
+
.scroll-bottom:hover { border-color: var(--accent); }
|
|
234
|
+
.scroll-bottom.visible { display: flex; }
|
|
235
|
+
|
|
210
236
|
/* Image preview */
|
|
211
237
|
.image-preview {
|
|
212
238
|
border-top: 1px solid var(--border);
|
|
@@ -308,13 +334,7 @@
|
|
|
308
334
|
overflow-y: auto;
|
|
309
335
|
padding: 12px;
|
|
310
336
|
}
|
|
311
|
-
.notifications-panel
|
|
312
|
-
font-size: 13px;
|
|
313
|
-
text-transform: uppercase;
|
|
314
|
-
letter-spacing: 0.5px;
|
|
315
|
-
color: var(--text-dim);
|
|
316
|
-
padding: 8px 8px 12px;
|
|
317
|
-
}
|
|
337
|
+
.notifications-panel > .notif-header + #notifList { /* spacer */ }
|
|
318
338
|
.notif-item {
|
|
319
339
|
background: var(--surface);
|
|
320
340
|
border: 1px solid var(--border);
|
|
@@ -325,9 +345,43 @@
|
|
|
325
345
|
cursor: pointer;
|
|
326
346
|
}
|
|
327
347
|
.notif-item:hover { border-color: var(--accent); }
|
|
328
|
-
.notif-item .notif-
|
|
348
|
+
.notif-item:hover .notif-dismiss { opacity: 1; }
|
|
349
|
+
.notif-item .notif-title { font-weight: 500; margin-bottom: 2px; display: flex; align-items: center; }
|
|
350
|
+
.notif-item .notif-title-text { flex: 1; }
|
|
351
|
+
.notif-dismiss {
|
|
352
|
+
opacity: 0;
|
|
353
|
+
background: none;
|
|
354
|
+
border: none;
|
|
355
|
+
color: var(--text-dim);
|
|
356
|
+
cursor: pointer;
|
|
357
|
+
font-size: 14px;
|
|
358
|
+
padding: 0 2px;
|
|
359
|
+
transition: opacity 0.15s;
|
|
360
|
+
}
|
|
361
|
+
.notif-dismiss:hover { color: var(--red); }
|
|
329
362
|
.notif-item .notif-message { color: var(--text-dim); }
|
|
330
363
|
.notif-item .notif-time { font-size: 11px; color: var(--text-dim); margin-top: 4px; }
|
|
364
|
+
.notif-header {
|
|
365
|
+
display: flex;
|
|
366
|
+
align-items: center;
|
|
367
|
+
justify-content: space-between;
|
|
368
|
+
padding: 8px 8px 12px;
|
|
369
|
+
position: sticky;
|
|
370
|
+
top: 0;
|
|
371
|
+
background: var(--bg);
|
|
372
|
+
z-index: 1;
|
|
373
|
+
}
|
|
374
|
+
.notif-header h2 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-dim); padding: 0; }
|
|
375
|
+
.notif-clear-all {
|
|
376
|
+
background: none;
|
|
377
|
+
border: 1px solid var(--border);
|
|
378
|
+
border-radius: 4px;
|
|
379
|
+
color: var(--text-dim);
|
|
380
|
+
cursor: pointer;
|
|
381
|
+
font-size: 11px;
|
|
382
|
+
padding: 2px 8px;
|
|
383
|
+
}
|
|
384
|
+
.notif-clear-all:hover { border-color: var(--red); color: var(--red); }
|
|
331
385
|
.notif-level {
|
|
332
386
|
display: inline-block;
|
|
333
387
|
width: 6px; height: 6px;
|
|
@@ -455,6 +509,7 @@
|
|
|
455
509
|
<div class="messages-list" id="messagesList">
|
|
456
510
|
<div class="empty-state">Select a session to view messages</div>
|
|
457
511
|
</div>
|
|
512
|
+
<button class="scroll-bottom" id="scrollBottom" title="Scroll to bottom">↓</button>
|
|
458
513
|
<div class="drag-overlay" id="dragOverlay">Drop image here</div>
|
|
459
514
|
<div class="image-preview" id="imagePreview">
|
|
460
515
|
<img id="previewImg" src="" alt="preview">
|
|
@@ -470,7 +525,10 @@
|
|
|
470
525
|
</div>
|
|
471
526
|
|
|
472
527
|
<div class="notifications-panel">
|
|
473
|
-
<
|
|
528
|
+
<div class="notif-header">
|
|
529
|
+
<h2>Notifications</h2>
|
|
530
|
+
<button class="notif-clear-all" id="notifClearAll">Clear all</button>
|
|
531
|
+
</div>
|
|
474
532
|
<div id="notifList">
|
|
475
533
|
<div class="empty-state">No notifications yet</div>
|
|
476
534
|
</div>
|
|
@@ -587,6 +645,8 @@
|
|
|
587
645
|
if (!state.messages[msg.sessionId]) state.messages[msg.sessionId] = [];
|
|
588
646
|
state.messages[msg.sessionId].push({ from: 'session', content: msg.content, time: msg.timestamp });
|
|
589
647
|
if (state.selectedSession === msg.sessionId) renderMessages();
|
|
648
|
+
state.notifications.unshift({ sessionId: msg.sessionId, title: 'Reply', message: msg.content.slice(0, 100), level: 'info', time: msg.timestamp });
|
|
649
|
+
renderNotifications();
|
|
590
650
|
break;
|
|
591
651
|
case 'notification':
|
|
592
652
|
state.notifications.unshift({ sessionId: msg.sessionId, title: msg.title, message: msg.message, level: msg.level || 'info', time: msg.timestamp });
|
|
@@ -701,26 +761,38 @@
|
|
|
701
761
|
|
|
702
762
|
function renderNotifications() {
|
|
703
763
|
const el = $('#notifList');
|
|
764
|
+
const clearBtn = $('#notifClearAll');
|
|
704
765
|
if (!state.notifications.length) {
|
|
705
766
|
el.innerHTML = '<div class="empty-state">No notifications yet</div>';
|
|
767
|
+
clearBtn.style.display = 'none';
|
|
706
768
|
return;
|
|
707
769
|
}
|
|
708
|
-
|
|
770
|
+
clearBtn.style.display = 'block';
|
|
771
|
+
el.innerHTML = state.notifications.slice(0, 50).map((n, i) => {
|
|
709
772
|
const timeStr = new Date(n.time).toLocaleTimeString();
|
|
710
773
|
const session = state.sessions[n.sessionId];
|
|
711
774
|
const sName = session ? session.name : n.sessionId.slice(0, 8);
|
|
712
|
-
return `<div class="notif-item" data-session="${n.sessionId}">
|
|
713
|
-
<div class="notif-title"><span class="notif-level ${n.level}"></span>${esc(n.title)}</div>
|
|
775
|
+
return `<div class="notif-item" data-session="${n.sessionId}" data-index="${i}">
|
|
776
|
+
<div class="notif-title"><span class="notif-level ${n.level}"></span><span class="notif-title-text">${esc(n.title)}</span><button class="notif-dismiss" data-index="${i}">×</button></div>
|
|
714
777
|
<div class="notif-message">${esc(n.message)}</div>
|
|
715
778
|
<div class="notif-time">${sName} · ${timeStr}</div>
|
|
716
779
|
</div>`;
|
|
717
780
|
}).join('');
|
|
718
781
|
el.querySelectorAll('.notif-item').forEach(item => {
|
|
719
|
-
item.addEventListener('click', () => {
|
|
782
|
+
item.addEventListener('click', (e) => {
|
|
783
|
+
if (e.target.classList.contains('notif-dismiss')) return;
|
|
720
784
|
const sid = item.dataset.session;
|
|
721
785
|
if (sid && state.sessions[sid]) selectSession(sid);
|
|
722
786
|
});
|
|
723
787
|
});
|
|
788
|
+
el.querySelectorAll('.notif-dismiss').forEach(btn => {
|
|
789
|
+
btn.addEventListener('click', (e) => {
|
|
790
|
+
e.stopPropagation();
|
|
791
|
+
const idx = parseInt(btn.dataset.index);
|
|
792
|
+
state.notifications.splice(idx, 1);
|
|
793
|
+
renderNotifications();
|
|
794
|
+
});
|
|
795
|
+
});
|
|
724
796
|
}
|
|
725
797
|
|
|
726
798
|
// --- Image handling ---
|
|
@@ -870,6 +942,23 @@
|
|
|
870
942
|
return html;
|
|
871
943
|
}
|
|
872
944
|
|
|
945
|
+
// Clear all notifications
|
|
946
|
+
$('#notifClearAll').addEventListener('click', () => {
|
|
947
|
+
state.notifications = [];
|
|
948
|
+
renderNotifications();
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
// Scroll to bottom button
|
|
952
|
+
const msgList = $('#messagesList');
|
|
953
|
+
const scrollBtn = $('#scrollBottom');
|
|
954
|
+
msgList.addEventListener('scroll', () => {
|
|
955
|
+
const gap = msgList.scrollHeight - msgList.scrollTop - msgList.clientHeight;
|
|
956
|
+
scrollBtn.classList.toggle('visible', gap > 100);
|
|
957
|
+
});
|
|
958
|
+
scrollBtn.addEventListener('click', () => {
|
|
959
|
+
msgList.scrollTo({ top: msgList.scrollHeight, behavior: 'smooth' });
|
|
960
|
+
});
|
|
961
|
+
|
|
873
962
|
state.token = getToken();
|
|
874
963
|
connect();
|
|
875
964
|
})();
|