vibespot 0.4.0 → 0.4.3
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/README.md +5 -1
- package/assets/conversion-guide.md +2 -2
- package/dist/index.js +22 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/ui/chat.js +64 -12
- package/ui/index.html +15 -4
- package/ui/styles.css +141 -17
package/package.json
CHANGED
package/ui/chat.js
CHANGED
|
@@ -78,13 +78,19 @@ function handleWsMessage(msg) {
|
|
|
78
78
|
statusEngine.textContent = msg.engine || "";
|
|
79
79
|
fetchHsAccountStatus();
|
|
80
80
|
|
|
81
|
+
// Populate chat header
|
|
82
|
+
const chatHeaderTitle = document.getElementById("chat-header-title");
|
|
83
|
+
const chatHeaderContext = document.getElementById("chat-header-context");
|
|
84
|
+
if (chatHeaderTitle) chatHeaderTitle.textContent = msg.themeName || "Chat";
|
|
85
|
+
if (chatHeaderContext) chatHeaderContext.textContent = msg.engine || "";
|
|
86
|
+
|
|
81
87
|
// Restore chat history from server
|
|
82
88
|
if (msg.messages && msg.messages.length > 0) {
|
|
83
89
|
for (const m of msg.messages) {
|
|
84
90
|
if (m.role === "user") {
|
|
85
|
-
appendUserMessage(m.content);
|
|
91
|
+
appendUserMessage(m.content, m.timestamp);
|
|
86
92
|
} else if (m.role === "assistant") {
|
|
87
|
-
appendRestoredAssistantMessage(m.content);
|
|
93
|
+
appendRestoredAssistantMessage(m.content, m.timestamp);
|
|
88
94
|
}
|
|
89
95
|
}
|
|
90
96
|
scrollToBottom();
|
|
@@ -167,10 +173,25 @@ function sendMessage(text) {
|
|
|
167
173
|
// Message rendering
|
|
168
174
|
// ---------------------------------------------------------------------------
|
|
169
175
|
|
|
170
|
-
function
|
|
176
|
+
function formatMessageTime(ts) {
|
|
177
|
+
if (!ts) return "";
|
|
178
|
+
const d = new Date(ts);
|
|
179
|
+
return `${d.getHours()}:${d.getMinutes().toString().padStart(2, "0")}`;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function appendUserMessage(text, timestamp) {
|
|
183
|
+
const time = formatMessageTime(timestamp || Date.now());
|
|
171
184
|
const div = document.createElement("div");
|
|
172
185
|
div.className = "chat-msg chat-msg--user";
|
|
173
|
-
div.innerHTML =
|
|
186
|
+
div.innerHTML = `
|
|
187
|
+
<div class="chat-msg__content">
|
|
188
|
+
<div class="chat-msg__header">
|
|
189
|
+
<span class="chat-msg__sender">You</span>
|
|
190
|
+
<span class="chat-msg__time">${time}</span>
|
|
191
|
+
</div>
|
|
192
|
+
<div class="chat-msg__bubble">${escapeHtml(text)}</div>
|
|
193
|
+
</div>
|
|
194
|
+
<div class="chat-msg__avatar chat-msg__avatar--user">Y</div>`;
|
|
174
195
|
messagesEl.appendChild(div);
|
|
175
196
|
scrollToBottom();
|
|
176
197
|
}
|
|
@@ -186,9 +207,18 @@ function startStreaming() {
|
|
|
186
207
|
showGeneratingPreview();
|
|
187
208
|
}
|
|
188
209
|
|
|
210
|
+
const time = formatMessageTime(streamStartTime);
|
|
189
211
|
const div = document.createElement("div");
|
|
190
212
|
div.className = "chat-msg chat-msg--assistant chat-msg--streaming";
|
|
191
|
-
div.innerHTML =
|
|
213
|
+
div.innerHTML = `
|
|
214
|
+
<div class="chat-msg__avatar chat-msg__avatar--ai">AI</div>
|
|
215
|
+
<div class="chat-msg__content">
|
|
216
|
+
<div class="chat-msg__header">
|
|
217
|
+
<span class="chat-msg__sender">vibeSpot AI</span>
|
|
218
|
+
<span class="chat-msg__time">${time}</span>
|
|
219
|
+
</div>
|
|
220
|
+
<div class="chat-msg__bubble"></div>
|
|
221
|
+
</div>`;
|
|
192
222
|
messagesEl.appendChild(div);
|
|
193
223
|
streamingMsgEl = div.querySelector(".chat-msg__bubble");
|
|
194
224
|
scrollToBottom();
|
|
@@ -271,11 +301,12 @@ function finishStreaming() {
|
|
|
271
301
|
if (streamingEl) {
|
|
272
302
|
streamingEl.classList.remove("chat-msg--streaming");
|
|
273
303
|
|
|
274
|
-
// Add duration metadata beneath the bubble
|
|
304
|
+
// Add duration metadata beneath the bubble (inside .chat-msg__content)
|
|
275
305
|
const meta = document.createElement("div");
|
|
276
306
|
meta.className = "chat-msg__meta";
|
|
277
307
|
meta.textContent = durationStr;
|
|
278
|
-
streamingEl.
|
|
308
|
+
const contentEl = streamingEl.querySelector(".chat-msg__content") || streamingEl;
|
|
309
|
+
contentEl.appendChild(meta);
|
|
279
310
|
}
|
|
280
311
|
|
|
281
312
|
// Final render of the full response
|
|
@@ -290,11 +321,20 @@ function finishStreaming() {
|
|
|
290
321
|
}
|
|
291
322
|
|
|
292
323
|
function appendAssistantError(message) {
|
|
324
|
+
const time = formatMessageTime(Date.now());
|
|
293
325
|
const div = document.createElement("div");
|
|
294
326
|
div.className = "chat-msg chat-msg--assistant";
|
|
295
|
-
div.innerHTML =
|
|
296
|
-
<
|
|
297
|
-
|
|
327
|
+
div.innerHTML = `
|
|
328
|
+
<div class="chat-msg__avatar chat-msg__avatar--ai">AI</div>
|
|
329
|
+
<div class="chat-msg__content">
|
|
330
|
+
<div class="chat-msg__header">
|
|
331
|
+
<span class="chat-msg__sender">vibeSpot AI</span>
|
|
332
|
+
<span class="chat-msg__time">${time}</span>
|
|
333
|
+
</div>
|
|
334
|
+
<div class="chat-msg__bubble" style="border-left: 3px solid var(--error);">
|
|
335
|
+
<strong>Error:</strong> ${escapeHtml(message)}
|
|
336
|
+
</div>
|
|
337
|
+
</div>`;
|
|
298
338
|
messagesEl.appendChild(div);
|
|
299
339
|
scrollToBottom();
|
|
300
340
|
}
|
|
@@ -359,10 +399,16 @@ function setStatus(text) {
|
|
|
359
399
|
// Restored / system messages
|
|
360
400
|
// ---------------------------------------------------------------------------
|
|
361
401
|
|
|
362
|
-
function appendRestoredAssistantMessage(text) {
|
|
402
|
+
function appendRestoredAssistantMessage(text, timestamp) {
|
|
403
|
+
const time = formatMessageTime(timestamp);
|
|
363
404
|
const div = document.createElement("div");
|
|
364
405
|
div.className = "chat-msg chat-msg--assistant";
|
|
365
|
-
div.innerHTML =
|
|
406
|
+
div.innerHTML = `
|
|
407
|
+
<div class="chat-msg__avatar chat-msg__avatar--ai">AI</div>
|
|
408
|
+
<div class="chat-msg__content">
|
|
409
|
+
${time ? `<div class="chat-msg__header"><span class="chat-msg__sender">vibeSpot AI</span><span class="chat-msg__time">${time}</span></div>` : ""}
|
|
410
|
+
<div class="chat-msg__bubble">${renderMarkdown(text)}</div>
|
|
411
|
+
</div>`;
|
|
366
412
|
messagesEl.appendChild(div);
|
|
367
413
|
}
|
|
368
414
|
|
|
@@ -713,6 +759,12 @@ document.getElementById("starter-templates").addEventListener("click", (e) => {
|
|
|
713
759
|
if (btn) sendMessage(btn.dataset.prompt);
|
|
714
760
|
});
|
|
715
761
|
|
|
762
|
+
// Templates icon in input area — toggle welcome section visibility
|
|
763
|
+
document.getElementById("btn-starter-templates")?.addEventListener("click", () => {
|
|
764
|
+
const welcome = document.getElementById("chat-welcome");
|
|
765
|
+
if (welcome) welcome.classList.toggle("hidden");
|
|
766
|
+
});
|
|
767
|
+
|
|
716
768
|
// Version history
|
|
717
769
|
document.getElementById("btn-history")?.addEventListener("click", toggleHistoryPanel);
|
|
718
770
|
document.getElementById("history-panel-close")?.addEventListener("click", () => {
|
package/ui/index.html
CHANGED
|
@@ -288,6 +288,10 @@
|
|
|
288
288
|
</div>
|
|
289
289
|
|
|
290
290
|
<div class="chat">
|
|
291
|
+
<div class="chat__header" id="chat-header">
|
|
292
|
+
<span class="chat__header-title" id="chat-header-title">Chat</span>
|
|
293
|
+
<span class="chat__header-context" id="chat-header-context"></span>
|
|
294
|
+
</div>
|
|
291
295
|
<div class="chat__messages" id="chat-messages">
|
|
292
296
|
<div class="chat__welcome" id="chat-welcome">
|
|
293
297
|
<p>Describe what you want or pick a template to get started.</p>
|
|
@@ -302,10 +306,17 @@
|
|
|
302
306
|
</div>
|
|
303
307
|
</div>
|
|
304
308
|
<div class="chat__input-area">
|
|
305
|
-
<
|
|
306
|
-
|
|
307
|
-
<
|
|
308
|
-
|
|
309
|
+
<div class="chat__input-wrapper">
|
|
310
|
+
<textarea class="chat__input" id="chat-input" placeholder="Describe your landing page..." rows="1"></textarea>
|
|
311
|
+
<div class="chat__input-actions">
|
|
312
|
+
<button class="chat__input-icon" id="btn-starter-templates" title="Templates">
|
|
313
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/><path d="M9 21V9"/></svg>
|
|
314
|
+
</button>
|
|
315
|
+
<button class="chat__send" id="chat-send" title="Send (Enter)">
|
|
316
|
+
<svg width="18" height="18" viewBox="0 0 20 20" fill="none"><path d="M3 10L17 3L10 17L9 11L3 10Z" fill="currentColor"/></svg>
|
|
317
|
+
</button>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
309
320
|
</div>
|
|
310
321
|
</div>
|
|
311
322
|
</aside>
|
package/ui/styles.css
CHANGED
|
@@ -1221,6 +1221,26 @@ html, body {
|
|
|
1221
1221
|
overflow: hidden;
|
|
1222
1222
|
}
|
|
1223
1223
|
|
|
1224
|
+
.chat__header {
|
|
1225
|
+
display: flex;
|
|
1226
|
+
align-items: baseline;
|
|
1227
|
+
gap: 8px;
|
|
1228
|
+
padding: 12px 16px;
|
|
1229
|
+
border-bottom: 1px solid var(--border);
|
|
1230
|
+
background: var(--bg-panel-solid);
|
|
1231
|
+
flex-shrink: 0;
|
|
1232
|
+
}
|
|
1233
|
+
.chat__header-title {
|
|
1234
|
+
font-family: var(--font-display);
|
|
1235
|
+
font-size: 15px;
|
|
1236
|
+
font-weight: 600;
|
|
1237
|
+
color: var(--text);
|
|
1238
|
+
}
|
|
1239
|
+
.chat__header-context {
|
|
1240
|
+
font-size: 12px;
|
|
1241
|
+
color: var(--text-dim);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1224
1244
|
.chat__messages {
|
|
1225
1245
|
flex: 1;
|
|
1226
1246
|
overflow-y: auto;
|
|
@@ -1310,6 +1330,9 @@ html, body {
|
|
|
1310
1330
|
|
|
1311
1331
|
/* Chat messages */
|
|
1312
1332
|
.chat-msg {
|
|
1333
|
+
display: flex;
|
|
1334
|
+
align-items: flex-start;
|
|
1335
|
+
gap: 10px;
|
|
1313
1336
|
margin-bottom: 16px;
|
|
1314
1337
|
animation: fadeIn 0.2s ease;
|
|
1315
1338
|
}
|
|
@@ -1320,32 +1343,100 @@ html, body {
|
|
|
1320
1343
|
}
|
|
1321
1344
|
|
|
1322
1345
|
.chat-msg--user {
|
|
1323
|
-
|
|
1324
|
-
|
|
1346
|
+
flex-direction: row-reverse;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
.chat-msg--user .chat-msg__header {
|
|
1350
|
+
flex-direction: row-reverse;
|
|
1325
1351
|
}
|
|
1326
1352
|
|
|
1327
1353
|
.chat-msg--user .chat-msg__bubble {
|
|
1328
1354
|
background: var(--accent-gradient);
|
|
1329
1355
|
color: white;
|
|
1330
|
-
border-radius:
|
|
1356
|
+
border-radius: 16px 16px 4px 16px;
|
|
1331
1357
|
max-width: 85%;
|
|
1332
1358
|
}
|
|
1333
1359
|
|
|
1334
1360
|
.chat-msg--assistant .chat-msg__bubble {
|
|
1335
1361
|
background: var(--bg-input);
|
|
1336
1362
|
color: var(--text);
|
|
1337
|
-
border-radius:
|
|
1363
|
+
border-radius: 16px 16px 16px 4px;
|
|
1338
1364
|
max-width: 95%;
|
|
1339
1365
|
border: 1px solid var(--border);
|
|
1340
1366
|
}
|
|
1341
1367
|
|
|
1368
|
+
/* Avatar */
|
|
1369
|
+
.chat-msg__avatar {
|
|
1370
|
+
width: 32px;
|
|
1371
|
+
height: 32px;
|
|
1372
|
+
border-radius: 50%;
|
|
1373
|
+
display: flex;
|
|
1374
|
+
align-items: center;
|
|
1375
|
+
justify-content: center;
|
|
1376
|
+
font-size: 12px;
|
|
1377
|
+
font-weight: 600;
|
|
1378
|
+
flex-shrink: 0;
|
|
1379
|
+
font-family: var(--font-display);
|
|
1380
|
+
}
|
|
1381
|
+
.chat-msg__avatar--user {
|
|
1382
|
+
background: var(--accent-gradient);
|
|
1383
|
+
color: white;
|
|
1384
|
+
}
|
|
1385
|
+
.chat-msg__avatar--ai {
|
|
1386
|
+
background: var(--accent-dim);
|
|
1387
|
+
color: var(--accent);
|
|
1388
|
+
border: 1px solid var(--accent-glow);
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
/* Content wrapper */
|
|
1392
|
+
.chat-msg__content {
|
|
1393
|
+
flex: 1;
|
|
1394
|
+
min-width: 0;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
/* Header (sender + time) */
|
|
1398
|
+
.chat-msg__header {
|
|
1399
|
+
display: flex;
|
|
1400
|
+
align-items: baseline;
|
|
1401
|
+
gap: 8px;
|
|
1402
|
+
margin-bottom: 4px;
|
|
1403
|
+
padding: 0 2px;
|
|
1404
|
+
}
|
|
1405
|
+
.chat-msg__sender {
|
|
1406
|
+
font-size: 12px;
|
|
1407
|
+
font-weight: 600;
|
|
1408
|
+
color: var(--text-dim);
|
|
1409
|
+
}
|
|
1410
|
+
.chat-msg__time {
|
|
1411
|
+
font-size: 11px;
|
|
1412
|
+
color: var(--text-muted);
|
|
1413
|
+
font-variant-numeric: tabular-nums;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1342
1416
|
.chat-msg__bubble {
|
|
1343
|
-
padding:
|
|
1417
|
+
padding: 12px 16px;
|
|
1344
1418
|
font-size: 13.5px;
|
|
1345
1419
|
line-height: 1.6;
|
|
1346
1420
|
word-wrap: break-word;
|
|
1347
1421
|
}
|
|
1348
1422
|
|
|
1423
|
+
/* Streaming cursor */
|
|
1424
|
+
.chat-msg--streaming .chat-msg__bubble::after {
|
|
1425
|
+
content: "";
|
|
1426
|
+
display: inline-block;
|
|
1427
|
+
width: 6px;
|
|
1428
|
+
height: 14px;
|
|
1429
|
+
background: var(--accent);
|
|
1430
|
+
border-radius: 1px;
|
|
1431
|
+
margin-left: 2px;
|
|
1432
|
+
vertical-align: text-bottom;
|
|
1433
|
+
animation: cursorBlink 0.8s ease infinite;
|
|
1434
|
+
}
|
|
1435
|
+
@keyframes cursorBlink {
|
|
1436
|
+
0%, 100% { opacity: 1; }
|
|
1437
|
+
50% { opacity: 0.2; }
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1349
1440
|
.chat-msg__bubble p { margin-bottom: 8px; }
|
|
1350
1441
|
.chat-msg__bubble p:last-child { margin-bottom: 0; }
|
|
1351
1442
|
|
|
@@ -1419,41 +1510,74 @@ html, body {
|
|
|
1419
1510
|
|
|
1420
1511
|
/* Chat input */
|
|
1421
1512
|
.chat__input-area {
|
|
1422
|
-
display: flex;
|
|
1423
|
-
align-items: flex-end;
|
|
1424
|
-
gap: 8px;
|
|
1425
1513
|
padding: 12px 16px;
|
|
1426
1514
|
border-top: 1px solid var(--border);
|
|
1427
1515
|
background: var(--bg-panel-solid);
|
|
1428
1516
|
}
|
|
1429
1517
|
|
|
1518
|
+
.chat__input-wrapper {
|
|
1519
|
+
display: flex;
|
|
1520
|
+
align-items: flex-end;
|
|
1521
|
+
gap: 8px;
|
|
1522
|
+
background: var(--bg-input);
|
|
1523
|
+
border: 1px solid var(--border);
|
|
1524
|
+
border-radius: 12px;
|
|
1525
|
+
padding: 6px 6px 6px 14px;
|
|
1526
|
+
transition: border-color 0.2s;
|
|
1527
|
+
}
|
|
1528
|
+
.chat__input-wrapper:focus-within {
|
|
1529
|
+
border-color: var(--accent-glow);
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1430
1532
|
.chat__input {
|
|
1431
1533
|
flex: 1;
|
|
1432
1534
|
resize: none;
|
|
1433
|
-
border:
|
|
1434
|
-
|
|
1435
|
-
padding: 10px 14px;
|
|
1436
|
-
background: var(--bg-input);
|
|
1535
|
+
border: none;
|
|
1536
|
+
background: transparent;
|
|
1437
1537
|
color: var(--text);
|
|
1438
1538
|
font-family: var(--font);
|
|
1439
1539
|
font-size: 14px;
|
|
1440
1540
|
line-height: 1.5;
|
|
1441
1541
|
max-height: 150px;
|
|
1442
1542
|
outline: none;
|
|
1443
|
-
|
|
1543
|
+
padding: 6px 0;
|
|
1444
1544
|
}
|
|
1445
|
-
.chat__input:focus { border-color: var(--accent-glow); }
|
|
1446
1545
|
.chat__input::placeholder { color: var(--text-muted); }
|
|
1447
1546
|
|
|
1547
|
+
.chat__input-actions {
|
|
1548
|
+
display: flex;
|
|
1549
|
+
align-items: center;
|
|
1550
|
+
gap: 4px;
|
|
1551
|
+
flex-shrink: 0;
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
.chat__input-icon {
|
|
1555
|
+
width: 32px;
|
|
1556
|
+
height: 32px;
|
|
1557
|
+
display: flex;
|
|
1558
|
+
align-items: center;
|
|
1559
|
+
justify-content: center;
|
|
1560
|
+
background: none;
|
|
1561
|
+
border: none;
|
|
1562
|
+
color: var(--text-muted);
|
|
1563
|
+
cursor: pointer;
|
|
1564
|
+
border-radius: 8px;
|
|
1565
|
+
transition: all 0.15s;
|
|
1566
|
+
}
|
|
1567
|
+
.chat__input-icon:hover {
|
|
1568
|
+
color: var(--accent);
|
|
1569
|
+
background: var(--accent-tint);
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1448
1572
|
.chat__send {
|
|
1449
|
-
width:
|
|
1450
|
-
height:
|
|
1573
|
+
width: 32px;
|
|
1574
|
+
height: 32px;
|
|
1451
1575
|
display: flex;
|
|
1452
1576
|
align-items: center;
|
|
1453
1577
|
justify-content: center;
|
|
1454
1578
|
background: var(--accent-gradient);
|
|
1455
1579
|
border: none;
|
|
1456
|
-
border-radius:
|
|
1580
|
+
border-radius: 8px;
|
|
1457
1581
|
color: white;
|
|
1458
1582
|
cursor: pointer;
|
|
1459
1583
|
transition: filter 0.15s;
|