323 lines
14 KiB
JavaScript
323 lines
14 KiB
JavaScript
// ─── Agent data ───
|
|
const agentInfo = {
|
|
cr: { name: 'Company Research Agent', status: 'Completed · 100%', action: 'Company overview complete' },
|
|
fm: { name: 'Financial Modeling Agent', status: 'Running · 62% complete', action: 'Building revenue schedule…' },
|
|
sf: { name: 'SEC Filings Agent', status: 'Running · 45% complete', action: 'Extracting segment data from 10-K…' },
|
|
ec: { name: 'Earnings Call Agent', status: 'Running · 78% complete', action: 'Summarizing Q2 FY25 call…' },
|
|
ci: { name: 'Competitive Intel Agent', status: 'Queued · Waiting for SEC Filings', action: 'Queued' },
|
|
va: { name: 'Valuation Agent', status: 'Queued · Waiting for Financial Modeling', action: 'Queued' },
|
|
rk: { name: 'Risk Agent', status: 'Idle', action: 'Idle' },
|
|
mw: { name: 'Memo Writing Agent', status: 'Idle', action: 'Idle' },
|
|
pa: { name: 'Presentation Agent', status: 'Idle', action: 'Idle' },
|
|
mn: { name: 'Monitoring Agent', status: 'Idle', action: 'Idle' },
|
|
sv: { name: 'Source Verification Agent', status: 'Idle', action: 'Idle' },
|
|
rt: { name: 'Red Team Agent', status: 'Idle', action: 'Idle' },
|
|
ex: { name: 'Export Agent', status: 'Idle', action: 'Idle' },
|
|
qa: { name: 'Model QA Agent', status: 'Idle', action: 'Idle' },
|
|
};
|
|
|
|
const activeAgents = ['sf', 'fm', 'ec'];
|
|
let carouselIdx = 0;
|
|
|
|
// ─── Screen switching ───
|
|
function switchScreen(id, btn) {
|
|
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
|
|
document.getElementById('screen-' + id).classList.add('active');
|
|
document.querySelectorAll('.screen-tabs button').forEach(b => b.classList.remove('active'));
|
|
if (btn && btn.classList) btn.classList.add('active');
|
|
// Show/hide ticker group on home vs other screens
|
|
const tickerGroup = document.getElementById('tickerGroup');
|
|
const navBtn = document.getElementById('navOpenBtn');
|
|
if (id === 'home') {
|
|
if (tickerGroup) tickerGroup.style.display = 'none';
|
|
} else {
|
|
if (tickerGroup) tickerGroup.style.display = 'flex';
|
|
}
|
|
}
|
|
|
|
// ─── Collapsible nav (close completely) ───
|
|
function toggleNav(navId) {
|
|
const nav = document.getElementById(navId);
|
|
nav.classList.toggle('collapsed');
|
|
const btn = nav.querySelector('.collapse-btn');
|
|
if (nav.classList.contains('collapsed')) {
|
|
btn.textContent = '▶';
|
|
} else {
|
|
btn.textContent = '◀';
|
|
}
|
|
}
|
|
function openNav() {
|
|
const wsNav = document.getElementById('ws-nav');
|
|
const memoNav = document.getElementById('memo-nav');
|
|
[wsNav, memoNav].forEach(nav => {
|
|
if (nav && nav.classList.contains('collapsed')) {
|
|
nav.classList.remove('collapsed');
|
|
nav.querySelector('.collapse-btn').textContent = '◀';
|
|
}
|
|
});
|
|
}
|
|
|
|
// ─── Left nav button selection ───
|
|
document.querySelectorAll('#ws-nav button').forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
document.querySelectorAll('#ws-nav button').forEach(b => b.classList.remove('active'));
|
|
this.classList.add('active');
|
|
});
|
|
});
|
|
|
|
// ─── Memo outline selection ───
|
|
document.querySelectorAll('.memo-outline li').forEach(li => {
|
|
li.addEventListener('click', function() {
|
|
document.querySelectorAll('.memo-outline li').forEach(l => l.classList.remove('active'));
|
|
this.classList.add('active');
|
|
});
|
|
});
|
|
|
|
// ─── Agent selection + detail panel ───
|
|
function selectAgent(tile, id) {
|
|
document.querySelectorAll('.agent-tile').forEach(t => t.classList.remove('selected'));
|
|
tile.classList.add('selected');
|
|
const detail = document.getElementById('agentDetail');
|
|
detail.classList.add('open');
|
|
document.getElementById('detailAgentName').textContent = agentInfo[id].name;
|
|
document.getElementById('detailAgentStatus').textContent = agentInfo[id].status;
|
|
}
|
|
function closeAgentDetail() {
|
|
document.getElementById('agentDetail').classList.remove('open');
|
|
document.querySelectorAll('.agent-tile').forEach(t => t.classList.remove('selected'));
|
|
}
|
|
|
|
// ─── Agent carousel ───
|
|
function updateCarousel() {
|
|
const agent = agentInfo[activeAgents[carouselIdx]];
|
|
document.getElementById('carouselName').textContent = agent.name;
|
|
document.getElementById('carouselAction').textContent = agent.action;
|
|
document.getElementById('carouselCounter').textContent = (carouselIdx + 1) + ' / ' + activeAgents.length;
|
|
document.getElementById('carouselPrev').disabled = carouselIdx === 0;
|
|
document.getElementById('carouselNext').disabled = carouselIdx === activeAgents.length - 1;
|
|
}
|
|
function carouselPrev() {
|
|
if (carouselIdx > 0) { carouselIdx--; updateCarousel(); }
|
|
}
|
|
function carouselNext() {
|
|
if (carouselIdx < activeAgents.length - 1) { carouselIdx++; updateCarousel(); }
|
|
}
|
|
updateCarousel();
|
|
|
|
// ─── Agent fullscreen overlay ───
|
|
function openAgentOverlay(agentId) {
|
|
const id = agentId || activeAgents[carouselIdx];
|
|
const agent = agentInfo[id];
|
|
document.getElementById('overlayAgentName').textContent = agent.name;
|
|
document.getElementById('overlayAgentStatus').textContent = agent.status;
|
|
// Activate the matching tab
|
|
document.querySelectorAll('.overlay-agent-tabs .oat-btn').forEach(btn => {
|
|
btn.classList.remove('active');
|
|
if (btn.textContent.trim().includes(agent.name.split(' ')[0])) btn.classList.add('active');
|
|
});
|
|
document.getElementById('agentOverlay').classList.add('open');
|
|
}
|
|
function closeAgentOverlay() {
|
|
document.getElementById('agentOverlay').classList.remove('open');
|
|
}
|
|
|
|
// ─── Settings overlay ───
|
|
function openSettings() { document.getElementById('settingsOverlay').classList.add('open'); }
|
|
function closeSettings() { document.getElementById('settingsOverlay').classList.remove('open'); }
|
|
|
|
// ─── Settings nav ───
|
|
document.querySelectorAll('.settings-nav button').forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
document.querySelectorAll('.settings-nav button').forEach(b => b.classList.remove('active'));
|
|
this.classList.add('active');
|
|
});
|
|
});
|
|
|
|
// ─── Review mode + annotations ───
|
|
let reviewMode = false;
|
|
let annotationMode = null;
|
|
|
|
function toggleReviewMode() {
|
|
reviewMode = !reviewMode;
|
|
const btn = document.getElementById('reviewToggle');
|
|
btn.textContent = reviewMode ? 'Exit Review' : 'Review Mode';
|
|
btn.style.background = reviewMode ? 'var(--accent)' : '';
|
|
btn.style.color = reviewMode ? 'var(--surface)' : '';
|
|
btn.style.borderColor = reviewMode ? 'var(--accent)' : '';
|
|
if (!reviewMode) {
|
|
annotationMode = null;
|
|
document.querySelectorAll('#modeHighlightBtn,#modeCommentBtn,#modeBoxBtn').forEach(b => {
|
|
b.style.background = ''; b.style.color = ''; b.style.borderColor = '';
|
|
});
|
|
}
|
|
}
|
|
|
|
function setAnnotationMode(mode) {
|
|
annotationMode = mode;
|
|
const btns = { highlight: 'modeHighlightBtn', comment: 'modeCommentBtn', box: 'modeBoxBtn' };
|
|
Object.entries(btns).forEach(([m, bid]) => {
|
|
const b = document.getElementById(bid);
|
|
b.style.background = m === mode ? 'var(--accent)' : '';
|
|
b.style.color = m === mode ? 'var(--surface)' : '';
|
|
b.style.borderColor = m === mode ? 'var(--accent)' : '';
|
|
});
|
|
}
|
|
|
|
document.addEventListener('mouseup', function(e) {
|
|
const toolbar = document.getElementById('annotationToolbar');
|
|
if (!reviewMode || !e.target.closest('#screen-memo .center')) {
|
|
toolbar.classList.remove('open'); return;
|
|
}
|
|
const sel = window.getSelection();
|
|
if (sel && sel.toString().trim().length > 0) {
|
|
const range = sel.getRangeAt(0);
|
|
const rect = range.getBoundingClientRect();
|
|
const center = e.target.closest('.center');
|
|
const cRect = center.getBoundingClientRect();
|
|
toolbar.style.top = (rect.top - cRect.top - 36 + center.scrollTop) + 'px';
|
|
toolbar.style.left = (rect.left - cRect.left + center.scrollLeft) + 'px';
|
|
toolbar.classList.add('open');
|
|
} else {
|
|
toolbar.classList.remove('open');
|
|
}
|
|
});
|
|
|
|
function annotateHighlight() {
|
|
const sel = window.getSelection();
|
|
if (!sel || sel.toString().trim().length === 0) return;
|
|
const range = sel.getRangeAt(0);
|
|
const span = document.createElement('span');
|
|
span.className = 'highlight-annotation';
|
|
span.setAttribute('data-comment', 'Highlighted by reviewer');
|
|
try { range.surroundContents(span); } catch(e) { span.textContent = sel.toString(); range.deleteContents(); range.insertNode(span); }
|
|
sel.removeAllRanges();
|
|
document.getElementById('annotationToolbar').classList.remove('open');
|
|
}
|
|
|
|
function annotateComment() {
|
|
const comment = prompt('Add a review comment:');
|
|
if (!comment) return;
|
|
const sel = window.getSelection();
|
|
if (!sel || sel.toString().trim().length === 0) return;
|
|
const range = sel.getRangeAt(0);
|
|
const span = document.createElement('span');
|
|
span.className = 'highlight-annotation';
|
|
span.setAttribute('data-comment', comment);
|
|
try { range.surroundContents(span); } catch(e) { span.textContent = sel.toString(); range.deleteContents(); range.insertNode(span); }
|
|
sel.removeAllRanges();
|
|
document.getElementById('annotationToolbar').classList.remove('open');
|
|
}
|
|
|
|
function annotateStrikethrough() {
|
|
const sel = window.getSelection();
|
|
if (!sel || sel.toString().trim().length === 0) return;
|
|
const range = sel.getRangeAt(0);
|
|
const span = document.createElement('span');
|
|
span.style.textDecoration = 'line-through';
|
|
span.style.color = 'var(--red)';
|
|
span.style.opacity = '0.6';
|
|
try { range.surroundContents(span); } catch(e) { span.textContent = sel.toString(); range.deleteContents(); range.insertNode(span); }
|
|
sel.removeAllRanges();
|
|
document.getElementById('annotationToolbar').classList.remove('open');
|
|
}
|
|
|
|
function annotateBox() {
|
|
document.getElementById('annotationToolbar').classList.remove('open');
|
|
const center = document.querySelector('#screen-memo .center');
|
|
const overlay = document.createElement('div');
|
|
overlay.style.cssText = 'position:absolute;top:0;left:0;right:0;bottom:0;z-index:150;cursor:crosshair;';
|
|
center.style.position = 'relative';
|
|
center.appendChild(overlay);
|
|
let startX, startY;
|
|
overlay.addEventListener('mousedown', function(e) {
|
|
const rect = overlay.getBoundingClientRect();
|
|
startX = e.clientX - rect.left + center.scrollLeft;
|
|
startY = e.clientY - rect.top + center.scrollTop;
|
|
const box = document.createElement('div');
|
|
box.className = 'box-annotation';
|
|
box.style.left = startX + 'px'; box.style.top = startY + 'px';
|
|
box.style.width = '0px'; box.style.height = '0px';
|
|
center.appendChild(box);
|
|
function onMove(ev) {
|
|
const cx = ev.clientX - rect.left + center.scrollLeft;
|
|
const cy = ev.clientY - rect.top + center.scrollTop;
|
|
box.style.width = Math.abs(cx - startX) + 'px';
|
|
box.style.height = Math.abs(cy - startY) + 'px';
|
|
box.style.left = Math.min(cx, startX) + 'px';
|
|
box.style.top = Math.min(cy, startY) + 'px';
|
|
}
|
|
function onUp() {
|
|
overlay.remove();
|
|
const label = document.createElement('div');
|
|
label.className = 'box-label';
|
|
label.textContent = 'Review needed';
|
|
label.onclick = function() { const note = prompt('Add note:', label.textContent); if (note) label.textContent = note; };
|
|
box.appendChild(label);
|
|
document.removeEventListener('mousemove', onMove);
|
|
document.removeEventListener('mouseup', onUp);
|
|
}
|
|
document.addEventListener('mousemove', onMove);
|
|
document.addEventListener('mouseup', onUp);
|
|
});
|
|
}
|
|
|
|
// ─── Model tab switching ───
|
|
function switchModelTab(tab) {
|
|
const spreadsheet = document.querySelector('#screen-model .spreadsheet');
|
|
const spreadsheetInfo = spreadsheet ? spreadsheet.parentElement.querySelector('div:last-of-type') : null;
|
|
const chartsPanel = document.getElementById('chartsPanel');
|
|
const allTables = document.querySelectorAll('#screen-model .center > *');
|
|
|
|
if (tab === 'charts') {
|
|
// Hide spreadsheet area, show charts
|
|
const center = document.querySelector('#screen-model .center');
|
|
if (center) {
|
|
// Hide everything except charts panel
|
|
Array.from(center.children).forEach(child => {
|
|
if (child.id !== 'chartsPanel') child.style.display = 'none';
|
|
});
|
|
}
|
|
if (chartsPanel) chartsPanel.style.display = 'grid';
|
|
} else {
|
|
// Show spreadsheet area, hide charts
|
|
const center = document.querySelector('#screen-model .center');
|
|
if (center) {
|
|
Array.from(center.children).forEach(child => {
|
|
if (child.id !== 'chartsPanel') child.style.display = '';
|
|
});
|
|
}
|
|
if (chartsPanel) chartsPanel.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
// ─── Overlay tab switching (new tab-based layout) ───
|
|
function switchOverlayTab(btn, id) {
|
|
document.querySelectorAll('.overlay-agent-tabs .oat-btn').forEach(b => b.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
const agent = agentInfo[id];
|
|
document.getElementById('overlayAgentName').textContent = agent.name;
|
|
document.getElementById('overlayAgentStatus').textContent = agent.status;
|
|
}
|
|
|
|
// ─── Dep tree tab switching ───
|
|
function switchDepTab(btn, ticker) {
|
|
btn.parentElement.querySelectorAll('button').forEach(b => b.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
// Future: swap dep tree content per ticker
|
|
}
|
|
|
|
// ─── Profile editor ───
|
|
function openProfile() { document.getElementById('profileOverlay').classList.add('open'); }
|
|
function closeProfile() { document.getElementById('profileOverlay').classList.remove('open'); }
|
|
function saveProfile() {
|
|
const name = document.getElementById('profileName').value;
|
|
const initials = name.split(' ').map(w => w[0]).join('').toUpperCase().slice(0, 2);
|
|
document.querySelector('.topbar .avatar').textContent = initials;
|
|
document.getElementById('profileDisplayName').textContent = name;
|
|
document.querySelector('.profile-overlay .profile-avatar').textContent = initials;
|
|
closeProfile();
|
|
}
|
|
|
|
// ─── Init: hide ticker on home screen ───
|
|
document.getElementById('tickerGroup').style.display = 'none';
|