No documents match your search.
';
} else {
const _impIco = '
All active chat sessions. Click to open.
Archived sessions. Restore to make active again.
Completed deep research reports. Click to view.
`;
document.body.appendChild(modal);
modal.querySelectorAll('#doclib-chats-sort, #doclib-arc-sort, #doclib-research-sort, #doclib-sort')
.forEach(_enhanceLibrarySortSelect);
modal.addEventListener('click', (event) => {
if (event.target.closest('.library-sort-picker')) return;
modal.querySelectorAll('.library-sort-menu:not([hidden])').forEach(menu => { menu.hidden = true; });
modal.querySelectorAll('.library-sort-btn[aria-expanded="true"]').forEach(button => { button.setAttribute('aria-expanded', 'false'); });
});
// Make modal draggable (same logic as other modals)
{
const content = modal.querySelector('.modal-content');
const header = modal.querySelector('.modal-header');
if (content && header) {
// Restore saved position / fullscreen state
try {
const saved = JSON.parse(localStorage.getItem('doclib-pos'));
if (saved && saved.fullscreen) {
localStorage.removeItem('doclib-pos');
} else if (saved && saved.left && saved.top) {
content.style.position = 'fixed';
content.style.left = saved.left;
content.style.top = saved.top;
content.style.margin = '0';
// Clamp to viewport in case window was resized
requestAnimationFrame(() => {
const r = content.getBoundingClientRect();
if (r.right > window.innerWidth) content.style.left = Math.max(0, window.innerWidth - r.width - 8) + 'px';
if (r.bottom > window.innerHeight) content.style.top = Math.max(0, window.innerHeight - r.height - 8) + 'px';
if (r.left < 0) content.style.left = '8px';
if (r.top < 0) content.style.top = '8px';
});
}
} catch {}
// Replaced ~150 lines of inline drag/snap/dock with one helper call.
// Library intentionally disables top-edge fullscreen snap: that layout
// breaks dense icon/tool rows. Side docking still works.
const FS_CLASS = 'doclib-fullscreen';
const enterFullscreen = () => {
if (modal.classList.contains(FS_CLASS)) return;
modal.classList.add(FS_CLASS);
content.style.position = 'fixed';
content.style.left = '0';
content.style.top = '0';
content.style.right = '0';
content.style.bottom = '0';
content.style.width = '100vw';
content.style.maxWidth = '100vw';
content.style.height = '100vh';
content.style.maxHeight = '100vh';
content.style.borderRadius = '0';
content.style.margin = '0';
content.style.transform = 'none';
try { localStorage.setItem('doclib-pos', JSON.stringify({ fullscreen: true })); } catch {}
};
const exitFullscreen = (cx, cy) => {
if (!modal.classList.contains(FS_CLASS)) return;
modal.classList.remove(FS_CLASS);
content.style.width = '';
content.style.maxWidth = '';
content.style.height = '';
content.style.maxHeight = '';
content.style.borderRadius = '';
content.style.right = '';
content.style.bottom = '';
const r0 = content.getBoundingClientRect();
const w = r0.width || Math.min(900, window.innerWidth * 0.92);
content.style.left = Math.max(8, cx - w / 2) + 'px';
content.style.top = Math.max(8, cy - 20) + 'px';
};
makeWindowDraggable(modal, {
content,
header,
fsClass: FS_CLASS,
skipSelector: '.modal-close',
onEnterFullscreen: enterFullscreen,
onExitFullscreen: exitFullscreen,
enableFullscreen: false,
onDragEnd: () => {
try { localStorage.setItem('doclib-pos', JSON.stringify({ left: content.style.left, top: content.style.top })); } catch {}
},
});
}
}
// Wire events
document.getElementById('doclib-close').addEventListener('click', closeLibrary);
// Tab switching — Chats / Documents / Archive / Research
let _activeLibTab = (opts && opts.tab) || 'documents';
const _tabBtns = modal.querySelectorAll('[data-doclib-tab]');
const _tabPanels = modal.querySelectorAll('[data-doclib-panel]');
// Client-side pagination for tabs whose API returns everything at once
// (chats/archive/research). Render only this many initially; the
// load-more button reveals more in chunks.
const _LIB_PAGE_SIZE = 20;
let _chatsVisibleLimit = _LIB_PAGE_SIZE;
let _arcVisibleLimit = _LIB_PAGE_SIZE;
let _researchVisibleLimit = _LIB_PAGE_SIZE;
function _appendInlineLoadMore(grid, totalCount, currentLimit, onClick) {
if (!grid || !grid.parentElement) return;
// Drop the previous instance (if any) — we re-render the list from
// scratch each pass, so the button is regenerated alongside it.
grid.parentElement.querySelectorAll(':scope > .doclib-inline-load-more').forEach(b => b.remove());
if (totalCount <= currentLimit) return;
const btn = document.createElement('button');
btn.className = 'doclib-load-more doclib-inline-load-more';
btn.textContent = `Load more (${currentLimit} of ${totalCount})`;
btn.addEventListener('click', onClick);
grid.parentElement.appendChild(btn);
}
// SVG markup + label for each tab — used to keep the modal header
// in sync with whichever sub-tab the user is on.
const _TAB_HEADERS = {
chats: {
label: 'Chats',
svg: '