diff --git a/app/static/index.html b/app/static/index.html index 0e05168..e3f987b 100644 --- a/app/static/index.html +++ b/app/static/index.html @@ -539,11 +539,14 @@ .tick-item .dom { font-family: 'Share Tech Mono', monospace; font-size: 0.64rem; color: var(--cyan); background: rgba(53,224,255,0.08); border: 1px solid rgba(53,224,255,0.22); border-radius: 3px; padding: 0.05rem 0.4rem; } .tick-item .tt { font-family: 'Share Tech Mono', monospace; font-size: 0.66rem; color: var(--muted); } .tick-item .sep { color: var(--line-hi); } + button.tick-item { cursor: pointer; background: transparent; border: 0; font: inherit; color: inherit; } .tick-item.brief { cursor: pointer; background: linear-gradient(90deg, rgba(255,46,151,0.12), transparent 70%); border-left: 2px solid var(--magenta); font-weight: 600; } - .tick-item.brief .b-tag { font-family: 'Share Tech Mono', monospace; font-size: 0.6rem; color: #1c0311; background: var(--magenta); border-radius: 2px; padding: 0.08rem 0.4rem; letter-spacing: 0.1em; } + .tick-item .b-tag { font-family: 'Share Tech Mono', monospace; font-size: 0.6rem; color: #1c0311; background: var(--magenta); border-radius: 2px; padding: 0.08rem 0.4rem; letter-spacing: 0.1em; } + .tick-item .b-tag.critical { background: var(--red); } + .tick-item .b-tag.high { background: var(--amber); } .tick-item.brief:hover { color: var(--magenta); } .tick-item.standby { color: var(--muted); opacity: 0.75; } .tick-item.standby .price { color: var(--muted); } @@ -827,7 +830,7 @@
Executive Summary WAITING
-
No executive summary yet — the Gemini summarizer is idle until GEMINI_API_KEY is set on the Pi.
+
No executive summary yet — the Nous summarizer is idle until NOUS_API_KEY is set on the Pi and a model is chosen in Settings.
@@ -1323,13 +1326,16 @@ async function loadNews(force) { if (upd) upd.textContent = 'updating…'; let articles = []; let summaries = []; + let tickerItems = []; try { - const [rArticles, rSumm] = await Promise.all([ + const [rArticles, rSumm, rTick] = await Promise.all([ fetch(`${API}/api/news?limit=100`), - fetch(`${API}/api/news/summaries?limit=1`) + fetch(`${API}/api/news/summaries?limit=1`), + fetch(`${API}/api/news/ticker?limit=20`), ]); if (rArticles.ok) articles = await rArticles.json(); if (rSumm.ok) summaries = await rSumm.json(); + if (rTick.ok) tickerItems = await rTick.json(); } catch (e) { const list = document.getElementById('news-list'); const body = document.getElementById('ns-body'); @@ -1341,7 +1347,7 @@ async function loadNews(force) { } renderNewsSummary(summaries); renderNewsList(articles); - renderNewsTicker(articles, summaries); + renderNewsTicker(articles, summaries, tickerItems); if (upd) upd.textContent = 'updated ' + new Date().toLocaleTimeString(); if (!newsInterval) { newsInterval = setInterval(() => loadNews(false), NEWS_REFRESH_MS); @@ -1353,7 +1359,7 @@ function renderNewsSummary(summaries) { const badgeEl = document.getElementById('ns-badge'); if (!bodyEl) return; if (!summaries || !summaries.length) { - bodyEl.innerHTML = '
No executive summary yet — the Gemini summarizer is idle until GEMINI_API_KEY is set on the Pi.
'; + bodyEl.innerHTML = '
No executive summary yet — the Nous summarizer is idle until NOUS_API_KEY is set on the Pi and a model is chosen in Settings.
'; timeEl.textContent = '—'; badgeEl.textContent = 'WAITING'; return; @@ -1381,25 +1387,45 @@ function renderNewsList(articles) { ''; }).join(''); } -function renderNewsTicker(articles, summaries) { +function renderNewsTicker(articles, summaries, tickerItems) { const track = document.getElementById('nt-track'); if (!track) return; let items = ''; - // LLM executive summary flash first (click → News view) - const summ = summaries && summaries.length ? summaries[0] : null; - if (summ && summ.summary_text) { - const brief = summ.summary_text.replace(/\s+/g, ' ').trim(); - items += ``; + const ticks = Array.isArray(tickerItems) ? tickerItems : []; + if (ticks.length) { + ticks.forEach(t => { + const imp = String(t.importance || '').toLowerCase(); + const tag = imp === 'critical' ? 'CRITICAL' : 'HIGH'; + const loc = (t.location_name || '').trim(); + const inner = + `${tag}` + + `${newsEsc((t.headline || '').trim())}` + + (loc ? `${newsEsc(loc)}` : '') + + `${newsTimeAgo(t.created_at)}`; + const url = (t.url || '').trim(); + if (url) { + items += `${inner}`; + } else { + items += ``; + } + }); + } else { + // Quiet hour: brief chip + article titles so the dock is never blank. + const summ = summaries && summaries.length ? summaries[0] : null; + const briefSrc = summ && (summ.summary_en || summ.summary_text); + if (briefSrc) { + const brief = String(briefSrc).replace(/\s+/g, ' ').trim(); + items += ``; + } + (articles || []).slice(0, 10).forEach(a => { + items += `` + + `${newsEsc(a.domain || '?')}` + + `${newsEsc((a.title || '').trim())}` + + `${newsTimeAgo(a.timestamp)}`; + }); } - // Top headlines - (articles || []).slice(0, 30).forEach(a => { - items += `` + - `${newsEsc(a.domain || '?')}` + - `${newsEsc((a.title || '').trim())}` + - `${newsTimeAgo(a.timestamp)}`; - }); if (!items) { items = `No headlines yet — scraper idle`; }