From d570ca6887023ddcc278a01bdd46712cd2f5bb51 Mon Sep 17 00:00:00 2001 From: calesthio Date: Wed, 18 Mar 2026 10:52:04 -0700 Subject: [PATCH] Improve mobile dashboard layout and map defaults --- dashboard/public/jarvis.html | 170 +++++++++++++++++++++++++---------- 1 file changed, 124 insertions(+), 46 deletions(-) diff --git a/dashboard/public/jarvis.html b/dashboard/public/jarvis.html index 45b5b8e..9349549 100644 --- a/dashboard/public/jarvis.html +++ b/dashboard/public/jarvis.html @@ -226,7 +226,25 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:var(--s /* RESPONSIVE */ @media(max-width:1400px){.grid{grid-template-columns:240px 1fr 320px}.metrics-row{grid-template-columns:repeat(3,1fr)}.src-grid{grid-template-columns:repeat(3,1fr)}} -@media(max-width:1100px){.grid{grid-template-columns:1fr}.lower .lp-ticker,.lower .lp-delta,.lower .lp-macro,.lower .lp-ideas{flex:1 1 100%;max-width:none}.metrics-row{grid-template-columns:repeat(2,1fr)}.src-grid{grid-template-columns:repeat(2,1fr)}} +@media(max-width:1100px){ + #main{padding:8px} + .topbar{padding:10px 12px} + .top-left,.top-center,.top-right{width:100%} + .top-center{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px} + .top-right{gap:6px} + .region-btn,.meta-pill,.alert-badge{font-size:10px} + .grid{display:flex;flex-direction:column} + #centerCol{order:1} + #rightRail{order:2} + #leftRail{order:3} + .map-container{min-height:420px} + .map-hint{font-size:8px;right:8px} + .map-legend{left:8px;right:8px;bottom:8px;gap:4px} + .leg-item{font-size:8px} + .lower .lp-ticker,.lower .lp-osint,.lower .lp-delta,.lower .lp-macro,.lower .lp-ideas{flex:1 1 100%;max-width:none} + .metrics-row{grid-template-columns:repeat(2,1fr)} + .src-grid{grid-template-columns:repeat(2,1fr)} +} /* CONFLICT LAYER */ @keyframes pulse-conflict{0%,100%{opacity:0.5;stroke-width:1.5}50%{opacity:0.9;stroke-width:2.5}} @@ -295,7 +313,7 @@ let D = null; // === GLOBALS === let globe = null; let flightsVisible = true; -let isFlat = true; +let isFlat = !isMobileLayout(); let flatSvg, flatProjection, flatPath, flatG, flatZoom, flatW, flatH; const regionPOV = { world: { lat: 20, lng: 20, altitude: 1.8 }, @@ -486,18 +504,27 @@ function initMap(){ }); // Resize handler - window.addEventListener('resize', () => { - const c = document.getElementById('mapContainer'); - globe.width(c.clientWidth).height(c.clientHeight || 560); + window.addEventListener('resize', () => syncResponsiveLayout()); + window.addEventListener('orientationchange', () => setTimeout(() => syncResponsiveLayout(true), 150)); + document.addEventListener('visibilitychange', () => { + if(!document.hidden) setTimeout(() => syncResponsiveLayout(true), 150); }); + window.addEventListener('pageshow', () => setTimeout(() => syncResponsiveLayout(true), 150)); // Plot globe markers (preloaded but hidden) plotMarkers(); // Start in flat mode โ€” hide globe, show flat map - document.getElementById('globeViz').style.display = 'none'; - document.getElementById('flatMapSvg').style.display = 'block'; - initFlatMap(); + if(isFlat){ + document.getElementById('globeViz').style.display = 'none'; + document.getElementById('flatMapSvg').style.display = 'block'; + initFlatMap(); + } else { + document.getElementById('globeViz').style.display = 'block'; + document.getElementById('flatMapSvg').style.display = 'none'; + document.getElementById('projToggle').textContent = 'FLAT MODE'; + document.getElementById('mapHint').textContent = 'DRAG TO ROTATE ยท SCROLL TO ZOOM'; + } // Legend document.getElementById('mapLegend').innerHTML= @@ -976,6 +1003,7 @@ function mkSparkSvg(values, isGood){ // === LOWER GRID === function renderLower(){ + const mobile = isMobileLayout(); const spread=D.fred.find(f=>f.id==='T10Y2Y'); const ff=D.fred.find(f=>f.id==='DFF'); const ue=D.bls.find(b=>b.id==='LNS14000000'); @@ -1092,23 +1120,14 @@ function renderLower(){ } const deltaHtml = hasDelta ? deltaRows.join('') : '
No changes since last sweep
'; - document.getElementById('lowerGrid').innerHTML=` -
+ const tickerPanel = `

Live News Ticker

${feed.length} ITEMS
${tickerCards}${tickerCards}
-
-
-

Sweep Delta

${dirEmoji} ${ds.direction?ds.direction.toUpperCase():'BASELINE'}
- ${hasDelta?`
- Changes: ${ds.totalChanges} - Critical: ${ds.criticalChanges||0} - ${ds.signalBreakdown?`New: ${ds.signalBreakdown.new} ↑${ds.signalBreakdown.escalated} ↓${ds.signalBreakdown.deescalated}`:''} -
`:''} -
${deltaHtml}
-
-
+
`; + const osintPanel = mobile ? buildOsintPanel('lp-osint', 240) : ''; + const macroPanel = `

Macro + Markets

${mkt.timestamp?'LIVE':'DELAYED'}
${hasMarkets?`
INDEXES
@@ -1129,33 +1148,32 @@ function renderLower(){
WTI 5-DAY
${sparkHtml}
-
-
+
`; + const ideasPanel = `

Leverageable Ideas

${D.ideasSource==='llm'?'AI ENHANCED':D.ideasSource==='disabled'?'LLM OFF':'PENDING'}
${ideasHtml}
FOR INFORMATIONAL PURPOSES ONLY. This is not financial advice, a recommendation to buy or sell any security, or a solicitation of any kind. All signal-based observations are derived from publicly available OSINT data and should not be relied upon for investment decisions. Consult a licensed financial advisor before making any investment. Past performance does not guarantee future results.
`; + const deltaPanel = `
+

Sweep Delta

${dirEmoji} ${ds.direction?ds.direction.toUpperCase():'BASELINE'}
+ ${hasDelta?`
+ Changes: ${ds.totalChanges} + Critical: ${ds.criticalChanges||0} + ${ds.signalBreakdown?`New: ${ds.signalBreakdown.new} ↑${ds.signalBreakdown.escalated} ↓${ds.signalBreakdown.deescalated}`:''} +
`:''} +
${deltaHtml}
+
`; + + document.getElementById('lowerGrid').innerHTML=`${tickerPanel}${osintPanel}${macroPanel}${ideasPanel}${deltaPanel}`; } // === RIGHT RAIL === function renderRight(){ + const mobile = isMobileLayout(); // CROSS-SOURCE SIGNALS โ€” moved from lower grid to right rail const signals=D.tSignals.slice(0,6).map((s,i)=>`
Signal ${i+1}

${s}

`).join(''); // OSINT TICKER โ€” Telegram + WHO as flowing cards - const allPosts=[...D.tg.urgent,...D.tg.topPosts].sort((a,b)=>new Date(b.date||0)-new Date(a.date||0)); - const whoItems=D.who.slice(0,4).map(w=>({channel:'WHO ALERT',text:w.title,date:w.date,isWho:true})); - const osintItems=[...allPosts.slice(0,15),...whoItems]; - const osintCards=osintItems.map(p=>{ - const isU=p.urgentFlags&&p.urgentFlags.length>0; - const views=p.views?p.views>=1000?`${(p.views/1000).toFixed(0)}K`:p.views:''; - const age=p.date?getAge(p.date):''; - const flags=(p.urgentFlags||[]).map(f=>`${f}`).join(''); - const srcCls=p.isWho?'style="color:#69f0ae;border-color:rgba(105,240,174,0.4)"':'class="tk-src tg"'; - return `
${(p.channel||'OSINT').toUpperCase().substring(0,14)}${views?`${views}`:''}${age}${flags}
${cleanText((p.text||'').substring(0,160))}
`; - }).join(''); - const osintDuration=Math.max(25,osintItems.length*3); - const signalMetrics=[ {l:'Incident Tempo',v:D.tg.urgent.length,p:70}, {l:'Air Theaters',v:D.air.length,p:60}, @@ -1166,17 +1184,12 @@ function renderRight(){ ]; document.getElementById('rightRail').innerHTML=` -
+

Cross-Source Signals

WORLDVIEW
${signals}
-
-

OSINT Stream

${D.tg.urgent.length} URGENT
-
-
${osintCards}${osintCards}
-
-
-
+ ${mobile ? '' : buildOsintPanel('right-osint', 260)} +

Signal Core

HOT METRICS
${signalMetrics.map(s=>`
${s.l}
${s.v}
`).join('')}
`; @@ -1210,8 +1223,8 @@ function runBoot(){ tl.call(()=>{ const div=document.createElement('div');div.innerHTML=line.text;div.style.opacity='0'; container.appendChild(div);gsap.to(div,{opacity:1,duration:0.2}); - },null,line.delay/1000+0.5); - }); + },[],line.delay/1000+0.5); + }); tl.to('#bootFinal',{opacity:1,duration:0.4},3.1); tl.to('#boot',{opacity:0,duration:0.5,ease:'power2.in'},3.7); tl.set('#boot',{display:'none'},4.2); @@ -1232,6 +1245,70 @@ function runBoot(){ },4.0); } +function isMobileLayout(){ return window.innerWidth <= 1100; } + +function buildOsintPanel(panelClass='', maxHeight=260){ + const allPosts=[...D.tg.urgent,...D.tg.topPosts].sort((a,b)=>new Date(b.date||0)-new Date(a.date||0)); + const whoItems=D.who.slice(0,4).map(w=>({channel:'WHO ALERT',text:w.title,date:w.date,isWho:true})); + const osintItems=[...allPosts.slice(0,15),...whoItems]; + const osintCards=osintItems.map(p=>{ + const isU=p.urgentFlags&&p.urgentFlags.length>0; + const views=p.views?p.views>=1000?`${(p.views/1000).toFixed(0)}K`:p.views:''; + const age=p.date?getAge(p.date):''; + const flags=(p.urgentFlags||[]).map(f=>`${f}`).join(''); + const srcCls=p.isWho?'style="color:#69f0ae;border-color:rgba(105,240,174,0.4)"':'class="tk-src tg"'; + return `
${(p.channel||'OSINT').toUpperCase().substring(0,14)}${views?`${views}`:''}${age}${flags}
${cleanText((p.text||'').substring(0,160))}
`; + }).join(''); + const osintDuration=Math.max(25,osintItems.length*3); + return `
+

OSINT Stream

${D.tg.urgent.length} URGENT
+
+
${osintCards}${osintCards}
+
+
`; +} + +function refreshMapViewport(forceGlobeReflow=false){ + const container = document.getElementById('mapContainer'); + if(!container) return; + const width = container.clientWidth; + const height = container.clientHeight || (isMobileLayout() ? 420 : 560); + if(globe){ + globe.width(width).height(height); + if(forceGlobeReflow && !isFlat){ + const globeEl = document.getElementById('globeViz'); + globeEl.style.display = 'none'; + requestAnimationFrame(() => { + globeEl.style.display = 'block'; + globe.width(width).height(height); + }); + } + } + if(flatSvg){ + flatW = width; + flatH = height; + flatSvg.attr('viewBox',`0 0 ${flatW} ${flatH}`).attr('preserveAspectRatio','xMidYMid meet'); + if(flatProjection && flatG){ + flatProjection = d3.geoNaturalEarth1().fitSize([flatW-20,flatH-20],{type:'Sphere'}).translate([flatW/2,flatH/2]); + flatPath = d3.geoPath(flatProjection); + flatG.selectAll('*').remove(); + drawFlatMap(); + } + } +} + +let lastResponsiveMobile = null; +function syncResponsiveLayout(force=false){ + const mobileNow = isMobileLayout(); + if(force || lastResponsiveMobile === null || mobileNow !== lastResponsiveMobile){ + lastResponsiveMobile = mobileNow; + renderLeftRail(); + renderLower(); + renderRight(); + } + refreshMapViewport(force && !isFlat); +} + // === REINIT (for live updates without boot sequence) === function reinit(){ renderTopbar();renderLeftRail();renderLower();renderRight(); @@ -1288,6 +1365,7 @@ function init(){ if(url) window.open(url,'_blank','noopener'); } }); + syncResponsiveLayout(true); } document.addEventListener('DOMContentLoaded', () => {