leedab 0.2.2 → 0.2.4
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/routes.js
CHANGED
|
@@ -145,7 +145,7 @@ export function createRoutes(config) {
|
|
|
145
145
|
}
|
|
146
146
|
},
|
|
147
147
|
/**
|
|
148
|
-
* GET /api/whoami — current OS user's first name
|
|
148
|
+
* GET /api/whoami — current OS user's first name + configured agent name
|
|
149
149
|
*/
|
|
150
150
|
"GET /api/whoami": async (_req, res) => {
|
|
151
151
|
let firstName = userInfo().username;
|
|
@@ -156,7 +156,7 @@ export function createRoutes(config) {
|
|
|
156
156
|
firstName = fullName.split(/\s+/)[0];
|
|
157
157
|
}
|
|
158
158
|
catch { }
|
|
159
|
-
json(res, { name: firstName });
|
|
159
|
+
json(res, { name: firstName, agent: config.agent?.name ?? "LeedAB" });
|
|
160
160
|
},
|
|
161
161
|
/**
|
|
162
162
|
* GET /api/status — channel health status
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
<style>
|
|
12
12
|
.page-header { display:flex; align-items:center; justify-content:space-between; padding:0 20px; height:52px; border-bottom:1px solid var(--border); background:var(--bg); }
|
|
13
13
|
.page-header-left { display:flex; align-items:center; gap:10px; }
|
|
14
|
-
.page-header-title {
|
|
14
|
+
.page-header-title { display:flex; align-items:center; }
|
|
15
|
+
.page-header-title .logo-img { height:22px; width:auto; display:block; }
|
|
15
16
|
.page-nav { display:flex; align-items:center; gap:2px; }
|
|
16
17
|
.page-nav a, .page-nav button { color:var(--text-dim); text-decoration:none; display:flex; align-items:center; gap:5px; padding:6px 12px; border-radius:8px; font-size:13px; font-weight:450; transition:all 0.15s; background:none; border:none; cursor:pointer; font-family:inherit; }
|
|
17
18
|
.page-nav a:hover, .page-nav button:hover { color:var(--text-secondary); background:var(--surface-raised); }
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
|
|
57
58
|
<div class="page-header">
|
|
58
59
|
<div class="page-header-left">
|
|
59
|
-
<a href="/" class="page-header-title"
|
|
60
|
+
<a href="/" class="page-header-title" aria-label="LeedAB"><img class="logo-img" alt="LeedAB"></a>
|
|
60
61
|
</div>
|
|
61
62
|
<div class="page-nav">
|
|
62
63
|
<button class="theme-btn" onclick="toggleTheme()" title="Toggle theme">
|
|
@@ -272,6 +273,7 @@
|
|
|
272
273
|
const saved = localStorage.getItem("leedab-theme") || "dark";
|
|
273
274
|
document.documentElement.setAttribute("data-theme", saved);
|
|
274
275
|
updateThemeIcon(saved);
|
|
276
|
+
updateLogo(saved);
|
|
275
277
|
}
|
|
276
278
|
function toggleTheme() {
|
|
277
279
|
const current = document.documentElement.getAttribute("data-theme") || "dark";
|
|
@@ -279,6 +281,11 @@
|
|
|
279
281
|
document.documentElement.setAttribute("data-theme", next);
|
|
280
282
|
localStorage.setItem("leedab-theme", next);
|
|
281
283
|
updateThemeIcon(next);
|
|
284
|
+
updateLogo(next);
|
|
285
|
+
}
|
|
286
|
+
function updateLogo(theme) {
|
|
287
|
+
const src = theme === "dark" ? "/logo-dark.png" : "/logo-light.png";
|
|
288
|
+
document.querySelectorAll(".logo-img").forEach(img => img.src = src);
|
|
282
289
|
}
|
|
283
290
|
function updateThemeIcon(theme) {
|
|
284
291
|
const sun = document.getElementById("theme-icon-sun");
|
|
@@ -75,9 +75,14 @@
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
.header-title {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.header-logo {
|
|
83
|
+
height: 22px;
|
|
84
|
+
width: auto;
|
|
85
|
+
display: block;
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
|
|
@@ -105,6 +110,40 @@
|
|
|
105
110
|
background: var(--surface-raised);
|
|
106
111
|
}
|
|
107
112
|
|
|
113
|
+
/* ── Main column below header ── */
|
|
114
|
+
.main-col {
|
|
115
|
+
flex: 1;
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-direction: column;
|
|
118
|
+
min-height: 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Empty state: center the chat content + input bar together */
|
|
122
|
+
body.empty-mode .main-col {
|
|
123
|
+
justify-content: center;
|
|
124
|
+
padding-top: 5vh;
|
|
125
|
+
}
|
|
126
|
+
body.empty-mode .chat-wrap {
|
|
127
|
+
flex: 0 0 auto;
|
|
128
|
+
overflow: visible;
|
|
129
|
+
}
|
|
130
|
+
body.empty-mode .chat-wrap::before,
|
|
131
|
+
body.empty-mode .chat-wrap::after {
|
|
132
|
+
display: none;
|
|
133
|
+
}
|
|
134
|
+
body.empty-mode .chat-area {
|
|
135
|
+
height: auto;
|
|
136
|
+
overflow: visible;
|
|
137
|
+
padding: 0 24px;
|
|
138
|
+
}
|
|
139
|
+
body.empty-mode .empty-state {
|
|
140
|
+
flex: 0 0 auto;
|
|
141
|
+
padding: 0;
|
|
142
|
+
}
|
|
143
|
+
body.empty-mode .input-bar {
|
|
144
|
+
padding-top: 36px;
|
|
145
|
+
}
|
|
146
|
+
|
|
108
147
|
/* ── Chat area ── */
|
|
109
148
|
.chat-wrap {
|
|
110
149
|
flex: 1;
|
|
@@ -355,64 +394,44 @@
|
|
|
355
394
|
align-items: center;
|
|
356
395
|
justify-content: center;
|
|
357
396
|
text-align: center;
|
|
397
|
+
opacity: 0;
|
|
398
|
+
transition: opacity 0.3s ease;
|
|
399
|
+
}
|
|
400
|
+
.empty-state.ready {
|
|
401
|
+
opacity: 1;
|
|
358
402
|
}
|
|
359
403
|
|
|
360
404
|
.empty-inner {
|
|
361
405
|
max-width: 480px;
|
|
362
406
|
}
|
|
363
407
|
|
|
364
|
-
.empty-logo {
|
|
365
|
-
width: 48px;
|
|
366
|
-
height: 48px;
|
|
367
|
-
border-radius: 14px;
|
|
368
|
-
margin: 0 auto 20px;
|
|
369
|
-
position: relative;
|
|
370
|
-
overflow: hidden;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
.empty-logo img {
|
|
374
|
-
width: 100%;
|
|
375
|
-
height: 100%;
|
|
376
|
-
object-fit: cover;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
.empty-logo::after {
|
|
380
|
-
content: '';
|
|
381
|
-
position: absolute;
|
|
382
|
-
inset: -8px;
|
|
383
|
-
border-radius: 20px;
|
|
384
|
-
background: var(--accent);
|
|
385
|
-
opacity: 0.06;
|
|
386
|
-
filter: blur(16px);
|
|
387
|
-
z-index: -1;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
408
|
.empty-state h3 {
|
|
391
|
-
font-size:
|
|
409
|
+
font-size: 26px;
|
|
392
410
|
font-weight: 600;
|
|
393
|
-
margin-bottom:
|
|
411
|
+
margin-bottom: 4px;
|
|
394
412
|
color: var(--text);
|
|
395
|
-
letter-spacing: -0.
|
|
413
|
+
letter-spacing: -0.03em;
|
|
396
414
|
}
|
|
397
415
|
|
|
398
|
-
.empty-
|
|
399
|
-
font-size:
|
|
416
|
+
.empty-subtitle {
|
|
417
|
+
font-size: 15px;
|
|
400
418
|
color: var(--text-dim);
|
|
401
419
|
line-height: 1.5;
|
|
420
|
+
margin: 0;
|
|
402
421
|
}
|
|
403
422
|
|
|
404
423
|
.suggestions {
|
|
405
424
|
display: grid;
|
|
406
425
|
grid-template-columns: 1fr 1fr;
|
|
407
|
-
gap:
|
|
408
|
-
margin-top:
|
|
426
|
+
gap: 12px;
|
|
427
|
+
margin-top: 44px;
|
|
409
428
|
}
|
|
410
429
|
|
|
411
430
|
.suggestion {
|
|
412
431
|
display: flex;
|
|
413
432
|
align-items: flex-start;
|
|
414
|
-
gap:
|
|
415
|
-
padding:
|
|
433
|
+
gap: 14px;
|
|
434
|
+
padding: 18px;
|
|
416
435
|
background: var(--surface);
|
|
417
436
|
border: 1px solid var(--border);
|
|
418
437
|
border-radius: var(--radius-md);
|
|
@@ -424,6 +443,18 @@
|
|
|
424
443
|
text-align: left;
|
|
425
444
|
}
|
|
426
445
|
|
|
446
|
+
.suggestion-icon {
|
|
447
|
+
flex-shrink: 0;
|
|
448
|
+
width: 36px;
|
|
449
|
+
height: 36px;
|
|
450
|
+
border-radius: 10px;
|
|
451
|
+
background: var(--accent-soft);
|
|
452
|
+
display: flex;
|
|
453
|
+
align-items: center;
|
|
454
|
+
justify-content: center;
|
|
455
|
+
color: var(--accent);
|
|
456
|
+
}
|
|
457
|
+
|
|
427
458
|
.suggestion:hover {
|
|
428
459
|
border-color: var(--accent);
|
|
429
460
|
background: var(--accent-soft);
|
|
@@ -431,6 +462,11 @@
|
|
|
431
462
|
transform: translateY(-1px);
|
|
432
463
|
}
|
|
433
464
|
|
|
465
|
+
.suggestion:hover .suggestion-icon {
|
|
466
|
+
background: var(--accent);
|
|
467
|
+
color: white;
|
|
468
|
+
}
|
|
469
|
+
|
|
434
470
|
.suggestion:active {
|
|
435
471
|
transform: translateY(0);
|
|
436
472
|
}
|
|
@@ -487,11 +523,13 @@
|
|
|
487
523
|
border: 1px solid var(--border);
|
|
488
524
|
border-radius: 18px;
|
|
489
525
|
padding: 4px 4px 4px 16px;
|
|
490
|
-
transition: border-color 0.2s;
|
|
526
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
527
|
+
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
|
|
491
528
|
}
|
|
492
529
|
|
|
493
530
|
.input-wrap:focus-within {
|
|
494
531
|
border-color: var(--border-hover);
|
|
532
|
+
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
|
|
495
533
|
}
|
|
496
534
|
|
|
497
535
|
.input-wrap textarea {
|
|
@@ -542,13 +580,14 @@
|
|
|
542
580
|
font-size: 11px;
|
|
543
581
|
color: var(--text-faint);
|
|
544
582
|
margin-top: 8px;
|
|
583
|
+
opacity: 0.6;
|
|
545
584
|
}
|
|
546
585
|
</style>
|
|
547
586
|
</head>
|
|
548
587
|
<body>
|
|
549
588
|
<div class="header">
|
|
550
589
|
<div class="header-left">
|
|
551
|
-
<a href="/" class="header-title"
|
|
590
|
+
<a href="/" class="header-title" aria-label="LeedAB"><img class="logo-img header-logo" alt="LeedAB"></a>
|
|
552
591
|
</div>
|
|
553
592
|
<div class="header-nav">
|
|
554
593
|
<a href="/admin">
|
|
@@ -566,13 +605,13 @@
|
|
|
566
605
|
</div>
|
|
567
606
|
</div>
|
|
568
607
|
|
|
608
|
+
<div class="main-col">
|
|
569
609
|
<div class="chat-wrap">
|
|
570
610
|
<div class="chat-area" id="chat-area">
|
|
571
611
|
<div class="empty-state" id="empty-state">
|
|
572
612
|
<div class="empty-inner">
|
|
573
|
-
<
|
|
574
|
-
<
|
|
575
|
-
<p></p>
|
|
613
|
+
<h3 id="empty-greeting"></h3>
|
|
614
|
+
<p class="empty-subtitle" id="empty-subtitle">What can I help with?</p>
|
|
576
615
|
<div class="suggestions">
|
|
577
616
|
<div class="suggestion" onclick="sendSuggestion('Which deliveries are delayed today and what\'s the estimated impact on SLAs?')">
|
|
578
617
|
<div class="suggestion-icon">
|
|
@@ -627,6 +666,7 @@
|
|
|
627
666
|
</div>
|
|
628
667
|
<div class="disclaimer">LeedAB is AI. Verify important information.</div>
|
|
629
668
|
</div>
|
|
669
|
+
</div>
|
|
630
670
|
|
|
631
671
|
<script>
|
|
632
672
|
// Theme
|
|
@@ -646,18 +686,46 @@
|
|
|
646
686
|
const input = document.getElementById("msg-input");
|
|
647
687
|
const sendBtn = document.getElementById("send-btn");
|
|
648
688
|
|
|
689
|
+
// Empty-mode centers the welcome + input together; drop it as soon as
|
|
690
|
+
// the conversation starts so the input pins back to the bottom.
|
|
691
|
+
if (emptyState) document.body.classList.add("empty-mode");
|
|
692
|
+
function exitEmptyMode() {
|
|
693
|
+
document.body.classList.remove("empty-mode");
|
|
694
|
+
exitEmptyMode();
|
|
695
|
+
}
|
|
696
|
+
|
|
649
697
|
// Session: "console" default, or from URL for viewing history
|
|
650
698
|
const params = new URLSearchParams(window.location.search);
|
|
651
699
|
let sessionId = params.get("session") || "console";
|
|
652
700
|
|
|
653
701
|
let userName = "You";
|
|
654
702
|
let userInitial = "Y";
|
|
703
|
+
let agentName = "LeedAB";
|
|
655
704
|
fetch("/api/whoami").then(r => r.json()).then(d => {
|
|
656
705
|
if (d.name) {
|
|
657
706
|
userName = d.name;
|
|
658
707
|
userInitial = d.name.charAt(0).toUpperCase();
|
|
659
708
|
}
|
|
660
|
-
|
|
709
|
+
if (d.agent) {
|
|
710
|
+
agentName = d.agent;
|
|
711
|
+
input.placeholder = `Message ${agentName}...`;
|
|
712
|
+
const disc = document.querySelector(".disclaimer");
|
|
713
|
+
if (disc) disc.textContent = `${agentName} is AI. Verify important information.`;
|
|
714
|
+
document.title = agentName;
|
|
715
|
+
}
|
|
716
|
+
// Time-aware greeting
|
|
717
|
+
const greet = document.getElementById("empty-greeting");
|
|
718
|
+
if (greet) {
|
|
719
|
+
const h = new Date().getHours();
|
|
720
|
+
const tod = h < 12 ? "Good morning" : h < 17 ? "Good afternoon" : "Good evening";
|
|
721
|
+
greet.textContent = d.name ? `${tod}, ${d.name}.` : tod + ".";
|
|
722
|
+
}
|
|
723
|
+
if (emptyState) emptyState.classList.add("ready");
|
|
724
|
+
}).catch(() => {
|
|
725
|
+
const greet = document.getElementById("empty-greeting");
|
|
726
|
+
if (greet) greet.textContent = "How can I help?";
|
|
727
|
+
if (emptyState) emptyState.classList.add("ready");
|
|
728
|
+
});
|
|
661
729
|
|
|
662
730
|
input.addEventListener("input", () => {
|
|
663
731
|
input.style.height = "auto";
|
|
@@ -687,7 +755,7 @@
|
|
|
687
755
|
const text = input.value.trim();
|
|
688
756
|
if (!text) return;
|
|
689
757
|
|
|
690
|
-
|
|
758
|
+
exitEmptyMode();
|
|
691
759
|
|
|
692
760
|
appendMessage(text, "user");
|
|
693
761
|
input.value = "";
|
|
@@ -725,7 +793,7 @@
|
|
|
725
793
|
const res = await fetch(`/api/chat/history?session=${encodeURIComponent(sid)}`);
|
|
726
794
|
const messages = await res.json();
|
|
727
795
|
if (messages.length) {
|
|
728
|
-
|
|
796
|
+
exitEmptyMode();
|
|
729
797
|
for (const m of messages) {
|
|
730
798
|
const type = m.role === "user" ? "user" : "agent";
|
|
731
799
|
appendMessage(m.text || m.content || "", type, m.thoughts);
|
|
@@ -759,7 +827,7 @@
|
|
|
759
827
|
|
|
760
828
|
const meta = document.createElement("div");
|
|
761
829
|
meta.className = "msg-meta";
|
|
762
|
-
meta.innerHTML = `<span class="msg-name">${type === "agent" ?
|
|
830
|
+
meta.innerHTML = `<span class="msg-name">${type === "agent" ? agentName : userName}</span><span class="msg-time">${now()}</span>`;
|
|
763
831
|
|
|
764
832
|
content.appendChild(meta);
|
|
765
833
|
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
<style>
|
|
12
12
|
.page-header { display:flex; align-items:center; justify-content:space-between; padding:0 20px; height:52px; border-bottom:1px solid var(--border); background:var(--bg); }
|
|
13
13
|
.page-header-left { display:flex; align-items:center; gap:10px; }
|
|
14
|
-
.page-header-title {
|
|
14
|
+
.page-header-title { display:flex; align-items:center; }
|
|
15
|
+
.page-header-title .logo-img { height:22px; width:auto; display:block; }
|
|
15
16
|
.page-nav { display:flex; align-items:center; gap:2px; }
|
|
16
17
|
.page-nav a, .page-nav button { color:var(--text-dim); text-decoration:none; display:flex; align-items:center; gap:5px; padding:6px 12px; border-radius:8px; font-size:13px; font-weight:450; transition:all 0.15s; background:none; border:none; cursor:pointer; font-family:inherit; }
|
|
17
18
|
.page-nav a:hover, .page-nav button:hover { color:var(--text-secondary); background:var(--surface-raised); }
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
|
|
21
22
|
<div class="page-header">
|
|
22
23
|
<div class="page-header-left">
|
|
23
|
-
<a href="/" class="page-header-title"
|
|
24
|
+
<a href="/" class="page-header-title" aria-label="LeedAB"><img class="logo-img" alt="LeedAB"></a>
|
|
24
25
|
</div>
|
|
25
26
|
<div class="page-nav">
|
|
26
27
|
</div>
|
|
@@ -102,6 +103,8 @@
|
|
|
102
103
|
function initTheme() {
|
|
103
104
|
const saved = localStorage.getItem("leedab-theme") || "dark";
|
|
104
105
|
document.documentElement.setAttribute("data-theme", saved);
|
|
106
|
+
const src = saved === "dark" ? "/logo-dark.png" : "/logo-light.png";
|
|
107
|
+
document.querySelectorAll(".logo-img").forEach(img => img.src = src);
|
|
105
108
|
}
|
|
106
109
|
initTheme();
|
|
107
110
|
|