Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- frontend/app.js +56 -5
- frontend/style.css +68 -1
frontend/app.js
CHANGED
|
@@ -288,11 +288,62 @@ function escAttr(str) {
|
|
| 288 |
}
|
| 289 |
|
| 290 |
function formatAnswer(text) {
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
}
|
| 297 |
|
| 298 |
function showToast(msg) {
|
|
|
|
| 288 |
}
|
| 289 |
|
| 290 |
function formatAnswer(text) {
|
| 291 |
+
if (!text) return "";
|
| 292 |
+
|
| 293 |
+
let html = text
|
| 294 |
+
// Headers
|
| 295 |
+
.replace(/^### (.+)$/gm, '<h3>$1</h3>')
|
| 296 |
+
.replace(/^## (.+)$/gm, '<h2>$1</h2>')
|
| 297 |
+
.replace(/^# (.+)$/gm, '<h1>$1</h1>')
|
| 298 |
+
|
| 299 |
+
// Bold and italic
|
| 300 |
+
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
| 301 |
+
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
| 302 |
+
|
| 303 |
+
// Numbered lists
|
| 304 |
+
.replace(/^\d+\.\s+(.+)$/gm, '<li class="numbered">$1</li>')
|
| 305 |
+
|
| 306 |
+
// Bullet lists
|
| 307 |
+
.replace(/^[-•]\s+(.+)$/gm, '<li class="bullet">$1</li>')
|
| 308 |
+
|
| 309 |
+
// Tables — | col | col |
|
| 310 |
+
.replace(/\|(.+)\|/g, (match) => {
|
| 311 |
+
const cells = match.split('|').filter(c => c.trim());
|
| 312 |
+
return '<tr>' + cells.map(c =>
|
| 313 |
+
c.trim().match(/^[-]+$/)
|
| 314 |
+
? ''
|
| 315 |
+
: `<td>${c.trim()}</td>`
|
| 316 |
+
).join('') + '</tr>';
|
| 317 |
+
})
|
| 318 |
+
|
| 319 |
+
// Inline code
|
| 320 |
+
.replace(/`(.+?)`/g, '<code>$1</code>')
|
| 321 |
+
|
| 322 |
+
// Double newline = paragraph break
|
| 323 |
+
.replace(/\n\n/g, '</p><p>')
|
| 324 |
+
|
| 325 |
+
// Single newline = line break
|
| 326 |
+
.replace(/\n/g, '<br>');
|
| 327 |
+
|
| 328 |
+
// Wrap consecutive <li class="numbered"> in <ol>
|
| 329 |
+
html = html.replace(
|
| 330 |
+
/(<li class="numbered">.*?<\/li>)+/gs,
|
| 331 |
+
(match) => `<ol>${match.replace(/class="numbered"/g, '')}</ol>`
|
| 332 |
+
);
|
| 333 |
+
|
| 334 |
+
// Wrap consecutive <li class="bullet"> in <ul>
|
| 335 |
+
html = html.replace(
|
| 336 |
+
/(<li class="bullet">.*?<\/li>)+/gs,
|
| 337 |
+
(match) => `<ul>${match.replace(/class="bullet"/g, '')}</ul>`
|
| 338 |
+
);
|
| 339 |
+
|
| 340 |
+
// Wrap table rows in <table>
|
| 341 |
+
html = html.replace(
|
| 342 |
+
/(<tr>.*?<\/tr>)+/gs,
|
| 343 |
+
(match) => `<table class="answer-table">${match}</table>`
|
| 344 |
+
);
|
| 345 |
+
|
| 346 |
+
return `<p>${html}</p>`;
|
| 347 |
}
|
| 348 |
|
| 349 |
function showToast(msg) {
|
frontend/style.css
CHANGED
|
@@ -683,4 +683,71 @@ body {
|
|
| 683 |
font-size: 11px;
|
| 684 |
color: var(--text-3);
|
| 685 |
margin-top: 8px;
|
| 686 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 683 |
font-size: 11px;
|
| 684 |
color: var(--text-3);
|
| 685 |
margin-top: 8px;
|
| 686 |
+
}
|
| 687 |
+
|
| 688 |
+
/* ── Answer formatting ── */
|
| 689 |
+
.bubble-ai ol, .bubble-ai ul {
|
| 690 |
+
margin: 10px 0 10px 20px;
|
| 691 |
+
display: flex;
|
| 692 |
+
flex-direction: column;
|
| 693 |
+
gap: 6px;
|
| 694 |
+
}
|
| 695 |
+
|
| 696 |
+
.bubble-ai ol { list-style: decimal; }
|
| 697 |
+
.bubble-ai ul { list-style: disc; }
|
| 698 |
+
|
| 699 |
+
.bubble-ai li {
|
| 700 |
+
color: var(--text-1);
|
| 701 |
+
line-height: 1.6;
|
| 702 |
+
padding-left: 4px;
|
| 703 |
+
}
|
| 704 |
+
|
| 705 |
+
.bubble-ai h1, .bubble-ai h2, .bubble-ai h3 {
|
| 706 |
+
font-family: 'Cormorant Garamond', serif;
|
| 707 |
+
color: var(--gold);
|
| 708 |
+
margin: 16px 0 8px;
|
| 709 |
+
}
|
| 710 |
+
|
| 711 |
+
.bubble-ai h1 { font-size: 20px; }
|
| 712 |
+
.bubble-ai h2 { font-size: 17px; }
|
| 713 |
+
.bubble-ai h3 { font-size: 15px; }
|
| 714 |
+
|
| 715 |
+
.bubble-ai strong { color: var(--text-1); font-weight: 600; }
|
| 716 |
+
.bubble-ai em { color: var(--text-2); font-style: italic; }
|
| 717 |
+
|
| 718 |
+
.bubble-ai code {
|
| 719 |
+
background: var(--navy-4);
|
| 720 |
+
padding: 2px 6px;
|
| 721 |
+
border-radius: 4px;
|
| 722 |
+
font-family: monospace;
|
| 723 |
+
font-size: 12px;
|
| 724 |
+
color: var(--gold);
|
| 725 |
+
}
|
| 726 |
+
|
| 727 |
+
.answer-table {
|
| 728 |
+
width: 100%;
|
| 729 |
+
border-collapse: collapse;
|
| 730 |
+
margin: 12px 0;
|
| 731 |
+
font-size: 13px;
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
.answer-table td {
|
| 735 |
+
padding: 8px 12px;
|
| 736 |
+
border: 1px solid var(--border);
|
| 737 |
+
color: var(--text-2);
|
| 738 |
+
line-height: 1.5;
|
| 739 |
+
}
|
| 740 |
+
|
| 741 |
+
.answer-table tr:first-child td {
|
| 742 |
+
background: var(--navy-3);
|
| 743 |
+
color: var(--text-1);
|
| 744 |
+
font-weight: 600;
|
| 745 |
+
}
|
| 746 |
+
|
| 747 |
+
.answer-table tr:hover td { background: var(--navy-3); }
|
| 748 |
+
|
| 749 |
+
.bubble-ai p {
|
| 750 |
+
margin-bottom: 10px;
|
| 751 |
+
}
|
| 752 |
+
|
| 753 |
+
.bubble-ai p:last-child { margin-bottom: 0; }
|