fix: market cards fixed order; collapsible with arrow indicator
This commit is contained in:
parent
5bdf7fbffe
commit
8564dcb8b2
1 changed files with 24 additions and 10 deletions
|
|
@ -86,12 +86,16 @@
|
||||||
.btn-save:hover{background:#e55a3a;transform:translateY(-1px)}
|
.btn-save:hover{background:#e55a3a;transform:translateY(-1px)}
|
||||||
.save-msg{font-size:.72rem;color:var(--green);display:none;margin-left:10px}
|
.save-msg{font-size:.72rem;color:var(--green);display:none;margin-left:10px}
|
||||||
|
|
||||||
.collapsible .card-head{cursor:pointer;user-select:none}
|
|
||||||
.collapsible .card-head::after{content:"\u2303";font-size:.8rem;color:var(--text3);transition:transform .2s;margin-left:8px}
|
|
||||||
.collapsible.collapsed .card-head::after{transform:rotate(180deg)}
|
/* ── Collapsible ── */
|
||||||
.collapse-body{overflow:hidden;transition:max-height .35s cubic-bezier(.4,0,.2,1);max-height:4000px}
|
.collapsible > .card-head { cursor:pointer; user-select:none; }
|
||||||
.collapsible.collapsed .collapse-body{max-height:0}
|
.collapse-arrow { margin-left:auto; font-size:.75rem; color:var(--text3); transition:transform .25s ease; display:inline-block; }
|
||||||
</style>
|
.collapsible.collapsed .collapse-arrow { transform:rotate(-90deg); }
|
||||||
|
.collapse-body { overflow:hidden; transition:max-height .35s cubic-bezier(.4,0,.2,1); max-height:5000px; }
|
||||||
|
.collapsible.collapsed .collapse-body { max-height:0 !important; }
|
||||||
|
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
|
|
@ -210,7 +214,12 @@ async function loadMarket(){
|
||||||
const {ok,data=[]}=await fetch('/api/market').then(r=>r.json()).catch(()=>({ok:false,data:[]}));
|
const {ok,data=[]}=await fetch('/api/market').then(r=>r.json()).catch(()=>({ok:false,data:[]}));
|
||||||
const grid=document.getElementById('market-grid');
|
const grid=document.getElementById('market-grid');
|
||||||
if(!ok||!data.length){grid.innerHTML='<div class="card mcard" style="grid-column:1/-1;text-align:center;padding:14px;color:var(--text3)">Market data unavailable</div>';return;}
|
if(!ok||!data.length){grid.innerHTML='<div class="card mcard" style="grid-column:1/-1;text-align:center;padding:14px;color:var(--text3)">Market data unavailable</div>';return;}
|
||||||
grid.innerHTML=data.map(q=>{const up=q.changePct>=0,cl=up?'up':'dn',arrow=up?'\u25b2':'\u25bc';const price=q.price>10000?q.price.toLocaleString('en-IN',{maximumFractionDigits:0}):q.price.toFixed(2);return'<div class="card mcard"><div class="mlbl">'+q.label+'</div><div class="mprice">'+price+' <span style="font-size:.62rem;color:var(--text2)">'+q.unit+'</span></div><div class="mchg '+cl+'">'+arrow+' '+Math.abs(q.changePct).toFixed(2)+'% <span style="opacity:.6">'+(q.change>=0?'+':'')+q.change.toFixed(0)+'</span></div>'+(q.stale?'<div class="mstale">prev close</div>':'')+'</div>';}).join('');
|
const ORDER=['SENSEX','NIFTY50','BANKNIFTY','INDIAVIX','CRUDEOIL','USDINR'];
|
||||||
|
const map=Object.fromEntries(data.map(q=>[q.key,q]));
|
||||||
|
const sorted=ORDER.map(k=>map[k]).filter(Boolean);
|
||||||
|
// append any keys not in ORDER
|
||||||
|
data.forEach(q=>{if(!ORDER.includes(q.key))sorted.push(q);});
|
||||||
|
grid.innerHTML=sorted.map(q=>{const up=q.changePct>=0,cl=up?'up':'dn',arrow=up?'\u25b2':'\u25bc';const price=q.price>10000?q.price.toLocaleString('en-IN',{maximumFractionDigits:0}):q.price.toFixed(2);return'<div class="card mcard"><div class="mlbl">'+q.label+'</div><div class="mprice">'+price+' <span style="font-size:.62rem;color:var(--text2)">'+q.unit+'</span></div><div class="mchg '+cl+'">'+arrow+' '+Math.abs(q.changePct).toFixed(2)+'% <span style="opacity:.6">'+(q.change>=0?'+':'')+q.change.toFixed(0)+'</span></div>'+(q.stale?'<div class="mstale">prev close'+(q.cachedAt?' \u00b7 '+q.cachedAt.slice(11,16)+' UTC':'')+'</div>':'')+'</div>';}).join('');
|
||||||
}
|
}
|
||||||
async function loadPositions(){
|
async function loadPositions(){
|
||||||
const {data}=await fetch('/api/positions').then(r=>r.json());
|
const {data}=await fetch('/api/positions').then(r=>r.json());
|
||||||
|
|
@ -260,16 +269,21 @@ async function saveOverride(key){
|
||||||
}
|
}
|
||||||
async function refresh(){await Promise.all([loadPositions(),loadAlerts(),loadHealth(),loadChart(curH),loadMarket()]);}
|
async function refresh(){await Promise.all([loadPositions(),loadAlerts(),loadHealth(),loadChart(curH),loadMarket()]);}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function toggleCard(id){
|
function toggleCard(id){
|
||||||
const el=document.getElementById(id);
|
const el=document.getElementById(id);
|
||||||
|
if(!el)return;
|
||||||
el.classList.toggle('collapsed');
|
el.classList.toggle('collapsed');
|
||||||
const s=JSON.parse(localStorage.getItem('collapse')||'{}');
|
const s=JSON.parse(localStorage.getItem('collapse')||'{}');
|
||||||
s[id]=el.classList.contains('collapsed');
|
s[id]=el.classList.contains('collapsed');
|
||||||
localStorage.setItem('collapse',JSON.stringify(s));
|
localStorage.setItem('collapse',JSON.stringify(s));
|
||||||
}
|
}
|
||||||
(function(){
|
(function restoreCollapse(){
|
||||||
|
try{
|
||||||
const s=JSON.parse(localStorage.getItem('collapse')||'{}');
|
const s=JSON.parse(localStorage.getItem('collapse')||'{}');
|
||||||
Object.entries(s).forEach(([id,c])=>{if(c)document.getElementById(id)?.classList.add('collapsed')});
|
Object.entries(s).forEach(([id,c])=>{if(c){const el=document.getElementById(id);if(el)el.classList.add('collapsed');}});
|
||||||
|
}catch(e){}
|
||||||
})();
|
})();
|
||||||
loadConfig();refresh();
|
loadConfig();refresh();
|
||||||
setInterval(refresh,60000);
|
setInterval(refresh,60000);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue