Deploy v2: Supply headroom bar + View buttons (760895 bytes)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Dockerfile.inline
|
||||
deploy-nogit.sh
|
||||
53
index.html
53
index.html
@@ -342,12 +342,19 @@ Check your Browserslist config to be sure that your targets are set up correctly
|
||||
<span class="font-mono text-[11px] uppercase tracking-[.04em] text-muted-2" x-text="s.loc"></span>
|
||||
<h3 class="mt-0.5 text-[17px] font-bold text-ink" x-text="s.name"></h3>
|
||||
<span class="mt-0.5 text-[12.5px] text-muted" x-text="s.load"></span>
|
||||
<span class="mt-auto flex items-start gap-2 pt-3.5 text-[13px]">
|
||||
<span class="block" x-html="headroomMini(s)"></span>
|
||||
<span class="mt-auto flex items-end justify-between gap-2 pt-3.5 text-[13px]">
|
||||
<span class="flex min-w-0 items-start gap-2">
|
||||
<span class="mt-px flex-none rounded-md border px-1.5 py-[3px] font-mono text-[10px] font-bold uppercase tracking-[.06em]"
|
||||
:class="{'border-[#F1C7C3] bg-[#FBEAE8] text-red-ink':s.cardStatus.cls==='red','border-[#EED9B4] bg-brandamber-tint text-amber-ink':s.cardStatus.cls==='amber','border-[#BADFCB] bg-[#EAF6EF] text-green-ink':s.cardStatus.cls==='green'}"
|
||||
x-text="s.cardStatus.chip"></span>
|
||||
<span class="leading-snug text-ink/80" x-text="s.cardStatus.txt"></span>
|
||||
</span>
|
||||
<span class="viewpill flex-none inline-flex items-center gap-1 rounded-full border border-line bg-card px-2.5 py-1 text-[11px] font-semibold text-muted transition group-hover:border-teal group-hover:bg-teal group-hover:text-white" aria-hidden="true">
|
||||
<svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M1.5 8s2.4-4.5 6.5-4.5S14.5 8 14.5 8s-2.4 4.5-6.5 4.5S1.5 8 1.5 8Z"/><circle cx="8" cy="8" r="2.2"/></svg>
|
||||
View
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
@@ -410,6 +417,9 @@ Check your Browserslist config to be sure that your targets are set up correctly
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SUPPLY HEADROOM -->
|
||||
<div class="mt-4" x-html="headroomB()"></div>
|
||||
|
||||
<!-- LOAD BY PHASE -->
|
||||
<div class="mt-4 rounded-lg border border-line bg-card p-[18px] shadow-card">
|
||||
<h2 class="mb-3.5 text-[11px] font-bold uppercase tracking-[.13em] text-muted">Load by phase <span id="phase-unitnote" class="text-[11px] font-medium normal-case tracking-normal text-muted-2">(Mean kW per hour)</span></h2>
|
||||
@@ -1242,6 +1252,45 @@ Object.entries(phaseMeta).forEach(([id,m])=>{
|
||||
rebalance_kva:d.rebalance_kva, phase_note:m.note(d),
|
||||
aggNote:PHASE_AGGNOTE[id]});
|
||||
});
|
||||
|
||||
/* ---------- supply headroom (peak demand vs supply capacity, kVA) ---------- */
|
||||
const HEADROOM={
|
||||
kaimana:{supply:60,peak:44,flag:"Peaks near three-quarters of supply at the afternoon milking."},
|
||||
coolstore:{supply:50,peak:41,flag:"Running at 82% of supply on peak — little room left for another load."},
|
||||
riverside:{supply:40,peak:26,flag:"Comfortable — about a third of supply spare at peak."},
|
||||
tikipunga:{supply:60,peak:22,flag:"Plenty of headroom — well under supply capacity."},
|
||||
cookham:{supply:45,peak:28,flag:"Steady — around 60% of supply at the daytime peak."},
|
||||
kamo:{supply:30,peak:12,flag:"Light load — large headroom on the supply."}
|
||||
};
|
||||
Object.entries(HEADROOM).forEach(([id,h])=>{ if(siteById[id]) Object.assign(siteById[id],h); });
|
||||
function headroomTone(pct){ return pct>85?"#E23B34":(pct>=70?"#F59E0B":"#1F9E70"); }
|
||||
function headroomBar(s,variant){
|
||||
if(!s||!s.supply) return "";
|
||||
const pct=Math.round(s.peak/s.supply*100), w=Math.min(100,pct), c=headroomTone(pct);
|
||||
if(variant==="mini"){
|
||||
return `<div class="mt-3" role="img" aria-label="Supply headroom: peak demand is ${pct} percent of the ${s.supply} kVA supply">
|
||||
<div class="flex items-center justify-between text-[10.5px] text-muted">
|
||||
<span class="uppercase tracking-[.06em] font-semibold">Supply headroom</span>
|
||||
<b class="font-mono text-ink/80">${s.peak}/${s.supply} kVA · ${pct}%</b>
|
||||
</div>
|
||||
<div class="mt-1 h-1.5 w-full overflow-hidden rounded-full bg-surface2">
|
||||
<i class="block h-full rounded-full" style="width:${w}%;background:${c}"></i>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
return `<div class="rounded-lg border border-line bg-card p-[18px] shadow-card">
|
||||
<h2 class="mb-3 text-[11px] font-bold uppercase tracking-[.13em] text-muted">Supply headroom</h2>
|
||||
<div class="flex items-baseline justify-between gap-3">
|
||||
<span class="text-[13px] text-muted">Peak demand vs supply capacity</span>
|
||||
<b class="font-mono text-[15px] text-ink">${s.peak} / ${s.supply} kVA · ${pct}%</b>
|
||||
</div>
|
||||
<div class="mt-2.5 h-3 w-full overflow-hidden rounded-full bg-surface2" role="img" aria-label="Peak demand is ${pct} percent of the ${s.supply} kVA supply capacity">
|
||||
<i class="block h-full rounded-full" style="width:${w}%;background:${c}"></i>
|
||||
</div>
|
||||
<p class="mt-3 text-[13px] text-ink/80">${s.flag}</p>
|
||||
<p class="mt-2 text-[11.5px] italic text-muted-2">Peak demand from the meter’s per-phase apparent power; supply capacity is the site’s connection rating. Illustrative sample data.</p>
|
||||
</div>`;
|
||||
}
|
||||
const STATUS_LABEL={red:"Action needed",amber:"Opportunity",green:"Normal"};
|
||||
const STATUS_RANK={red:0,amber:1,green:2};
|
||||
|
||||
@@ -1358,6 +1407,8 @@ window.dashboard=function(){
|
||||
healthB(){ const s=this.currentSite; return s?healthBlock(s):""; },
|
||||
watchB(){ const s=this.currentSite; return s?watchingList(s):""; },
|
||||
actionB(){ const s=this.currentSite; return s?actionHtml(s):""; },
|
||||
headroomMini(s){ return headroomBar(s,"mini"); },
|
||||
headroomB(){ const s=this.currentSite; return s?headroomBar(s,"full"):""; },
|
||||
sankeyB(){ const s=this.currentSite; return s?sankeySVG(energyData[s.id].sankey):""; },
|
||||
sankeyLeg(){ const s=this.currentSite; return s?sankeyLegend(energyData[s.id].sankey):""; },
|
||||
sankeyNote(){ const s=this.currentSite; return s?energyData[s.id].sankey.note:""; },
|
||||
|
||||
Reference in New Issue
Block a user