// App state store
const STORE = {
currentDocId: null,
currentSessionId: null,
currentPage: 0,
totalPages: 0,
documents: [],
sessions: [],
polygons: [],
viewerDoc: null,
chunkCache: {},
chatMessages: [],
};
// API helpers
const API = {
async get(url) {
const r = await fetch(url);
if (!r.ok) throw new Error(`API ${r.status}: ${r.statusText}`);
return r.json();
},
async post(url, body) {
const r = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
if (!r.ok) throw new Error(`API ${r.status}: ${r.statusText}`);
return r.json();
},
};
// DOM helpers
const $ = (sel) => document.querySelector(sel);
const $$ = (sel) => document.querySelectorAll(sel);
// Render markdown-style content
function renderContent(text) {
if (!text) return "
No content
";
let html = text
.replace(/&/g, "&")
.replace(//g, ">");
// Headers
html = html.replace(/^### (.+)$/gm, '$1
');
html = html.replace(/^## (.+)$/gm, '$1
');
html = html.replace(/^# (.+)$/gm, '$1
');
// Bold
html = html.replace(/\*\*(.+?)\*\*/g, '$1');
// Italic
html = html.replace(/\*(.+?)\*/g, '$1');
// Code blocks
html = html.replace(/```([\s\S]*?)```/g, '$1
');
// Inline code
html = html.replace(/`(.+?)`/g, '$1');
// Unordered lists
html = html.replace(/^- (.+)$/gm, '$1');
html = html.replace(/(.*<\/li>\n?)+/g, '');
// Ordered lists
html = html.replace(/^\d+\. (.+)$/gm, '$1');
// Horizontal rules
html = html.replace(/^---$/gm, '
');
// Blockquotes
html = html.replace(/^> (.+)$/gm, '$1
');
// Tables
html = html.replace(/^\|(.+)\|$/gm, (match, content) => {
const cells = content.split('|').map(c => c.trim());
if (cells.every(c => /^[-:]+$/.test(c))) {
return '';
}
if (cells.every(c => c.length < 30 && !c.includes(' '))) {
return '' + cells.map(c => `| ${c} | `).join('') + '
';
}
return `| ${cells.join(' | ')} |
`;
});
// Wrap rows in table
let inTable = false;
const lines = html.split('\n');
let result = [];
let tableBuffer = [];
for (let line of lines) {
if (line.includes('')) {
if (tableBuffer.length > 0) {
result.push('' + tableBuffer.join('') + '
');
tableBuffer = [];
}
continue;
}
if (line.startsWith('')) {
tableBuffer.push(line);
} else {
if (tableBuffer.length > 0) {
result.push('' + tableBuffer.join('') + '
');
tableBuffer = [];
}
result.push(line);
}
}
if (tableBuffer.length > 0) {
result.push('' + tableBuffer.join('') + '
');
}
html = result.join('\n');
// Paragraphs
html = html.replace(/^(?!<[huldtbr]|