Skip to content

Commit 07e138d

Browse files
ferr079claude
andcommitted
tweak(status): align 4 PVE nodes in one row + on-demand sky style + split footer note
- .nodes-grid: repeat(3, 1fr) → repeat(auto-fit, minmax(180px, 1fr)) Now the 4 PVE nodes line up on a single row (matching the service cards rhythm). Previously pve4 was orphaned on a 2nd line. - Handle 'on-demand' node state (v2 kv-push) — renders a sky-accent dashed card ('on-demand · WOL · powered on when needed') instead of the red-tinted 'offline'. pve3 no longer looks broken on the page; it looks intentionally asleep. - Footer status-note split across 2 lines with <br/> + line-height 1.8, for visual rhythm with the rest of the page (was a single long line). EN+FR both updated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f64f16f commit 07e138d

2 files changed

Lines changed: 88 additions & 31 deletions

File tree

src/pages/fr/status.astro

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ import Base from '../../layouts/Base.astro';
9898
<!-- Note de bas de page -->
9999
<section class="status-footer reveal">
100100
<div class="container">
101-
<p class="status-note">Données poussées depuis le homelab par <strong>OpenFang</strong> (agent IA, CT 192) via l'API Cloudflare KV. Zéro port exposé — push HTTPS sortant uniquement.</p>
101+
<p class="status-note">
102+
Données poussées depuis le homelab par <strong>OpenFang</strong> (agent IA, CT 192) via l'API Cloudflare KV.<br/>
103+
Zéro port exposé — push HTTPS sortant uniquement.
104+
</p>
102105
</div>
103106
</section>
104107
</main>
@@ -209,11 +212,12 @@ import Base from '../../layouts/Base.astro';
209212

210213
for (const node of data.nodes) {
211214
const card = el('div', 'node-card');
215+
const nodeState = (node.state || node.status || (node.cpu != null ? 'up' : 'offline')) as string;
216+
card.classList.add('node-' + nodeState);
217+
212218
card.appendChild(el('h4', 'node-name', node.name));
213219

214-
if (node.status === 'offline') {
215-
card.appendChild(el('span', 'node-offline', 'offline'));
216-
} else {
220+
if (nodeState === 'up' && node.cpu != null) {
217221
for (const [metric, value] of [['CPU', node.cpu], ['RAM', node.ram]] as [string, number][]) {
218222
const row = el('div', 'node-metric');
219223
row.appendChild(el('span', 'metric-label', metric));
@@ -226,7 +230,12 @@ import Base from '../../layouts/Base.astro';
226230
row.appendChild(el('span', 'metric-value', value + '%'));
227231
card.appendChild(row);
228232
}
229-
card.appendChild(el('div', 'node-uptime', node.uptime_days + 'd uptime'));
233+
card.appendChild(el('div', 'node-uptime', node.uptime_days + 'j d\'uptime'));
234+
} else if (nodeState === 'on-demand') {
235+
card.appendChild(el('span', 'node-ondemand', 'on-demand · WOL'));
236+
card.appendChild(el('div', 'node-sub', 'allumé à la demande'));
237+
} else {
238+
card.appendChild(el('span', 'node-offline', 'hors ligne'));
230239
}
231240

232241
nodesContainer.appendChild(card);
@@ -340,12 +349,12 @@ import Base from '../../layouts/Base.astro';
340349

341350
.skeleton-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.75rem; }
342351
.skeleton-card { height: 2.5rem; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 6px; animation: skeleton-pulse 1.5s ease-in-out infinite; }
343-
.skeleton-nodes { grid-template-columns: repeat(3, 1fr); }
352+
.skeleton-nodes { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
344353
.skeleton-node { height: 8rem; }
345354
.status-waiting { text-align: center; color: var(--color-text-muted); font-family: var(--font-mono); font-size: 0.85rem; margin-top: 1.5rem; }
346355
.status-loading { padding: 1rem 0; }
347356
.status-footer { padding: 2rem 0; }
348-
.status-note { font-size: 0.8rem; color: var(--color-text-muted); text-align: center; font-family: var(--font-mono); }
357+
.status-note { font-size: 0.8rem; color: var(--color-text-muted); text-align: center; font-family: var(--font-mono); line-height: 1.8; }
349358

350359
@media (max-width: 640px) {
351360
.summary-grid { gap: 1.5rem; }
@@ -381,19 +390,38 @@ import Base from '../../layouts/Base.astro';
381390
.svc-name { font-family: var(--font-mono); font-size: 0.85rem; color: var(--color-text); flex: 1; }
382391
.svc-latency { font-family: var(--font-mono); font-size: 0.75rem; color: var(--color-text-muted); }
383392

384-
.nodes-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
385-
.node-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; padding: 1.25rem; transition: border-color 0.2s; }
393+
.nodes-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0.75rem; }
394+
.node-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 6px; padding: 1rem 1.1rem; transition: border-color 0.2s; display: flex; flex-direction: column; min-height: 7.5rem; }
386395
.node-card:hover { border-color: var(--color-accent); }
387-
.node-name { font-family: var(--font-mono); font-size: 1rem; font-weight: 700; color: var(--color-text); margin: 0 0 1rem; }
388-
.node-metric { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.5rem; }
389-
.metric-label { font-family: var(--font-mono); font-size: 0.75rem; color: var(--color-text-muted); width: 2.5rem; }
396+
.node-name { font-family: var(--font-mono); font-size: 0.95rem; font-weight: 700; color: var(--color-text); margin: 0 0 0.85rem; }
397+
.node-metric { display: flex; align-items: center; gap: 0.55rem; margin-bottom: 0.45rem; }
398+
.metric-label { font-family: var(--font-mono); font-size: 0.72rem; color: var(--color-text-muted); width: 2.3rem; }
390399
.bar { flex: 1; height: 6px; background: var(--color-border); border-radius: 3px; overflow: hidden; }
391400
.bar-fill { height: 100%; border-radius: 3px; transition: width 0.8s ease-out; }
392-
.metric-value { font-family: var(--font-mono); font-size: 0.8rem; color: var(--color-text); width: 3rem; text-align: right; }
393-
.node-uptime { font-family: var(--font-mono); font-size: 0.75rem; color: var(--color-text-muted); margin-top: 0.5rem; }
394-
.node-offline { font-family: var(--font-mono); font-size: 0.85rem; color: var(--color-text-muted); font-style: italic; }
401+
.metric-value { font-family: var(--font-mono); font-size: 0.75rem; color: var(--color-text); width: 2.75rem; text-align: right; }
402+
.node-uptime { font-family: var(--font-mono); font-size: 0.72rem; color: var(--color-text-muted); margin-top: auto; padding-top: 0.5rem; }
403+
.node-offline { font-family: var(--font-mono); font-size: 0.82rem; color: var(--color-text-muted); font-style: italic; }
395404

396-
@media (max-width: 640px) {
405+
/* on-demand nodes (pve3 WOL) — sky accent, pas rouge */
406+
.node-ondemand {
407+
display: inline-block;
408+
font-family: var(--font-mono);
409+
font-size: 0.72rem;
410+
color: var(--color-accent);
411+
background: rgba(56, 189, 248, 0.08);
412+
border: 1px solid rgba(56, 189, 248, 0.25);
413+
padding: 0.15rem 0.5rem;
414+
border-radius: 3px;
415+
letter-spacing: 0.04em;
416+
width: fit-content;
417+
}
418+
.node-card.node-on-demand { border-style: dashed; border-color: rgba(56, 189, 248, 0.25); }
419+
.node-sub { font-family: var(--font-mono); font-size: 0.7rem; color: var(--color-text-muted); margin-top: 0.5rem; opacity: 0.75; }
420+
421+
@media (max-width: 700px) {
422+
.nodes-grid { grid-template-columns: repeat(2, 1fr); }
423+
}
424+
@media (max-width: 480px) {
397425
.nodes-grid { grid-template-columns: 1fr; }
398426
.service-grid { grid-template-columns: 1fr; }
399427
}

src/pages/status.astro

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ import Base from '../layouts/Base.astro';
9898
<!-- Footer note -->
9999
<section class="status-footer reveal">
100100
<div class="container">
101-
<p class="status-note">Data pushed from the homelab by <strong>OpenFang</strong> (AI agent, CT 192) via Cloudflare KV API. Zero ports exposed — all outbound HTTPS push.</p>
101+
<p class="status-note">
102+
Data pushed from the homelab by <strong>OpenFang</strong> (AI agent, CT 192) via Cloudflare KV API.<br/>
103+
Zero ports exposed — all outbound HTTPS push.
104+
</p>
102105
</div>
103106
</section>
104107
</main>
@@ -209,11 +212,13 @@ import Base from '../layouts/Base.astro';
209212

210213
for (const node of data.nodes) {
211214
const card = el('div', 'node-card');
215+
// derive normalized state — tolerate both 'state' (v2) and 'status' (legacy)
216+
const nodeState = (node.state || node.status || (node.cpu != null ? 'up' : 'offline')) as string;
217+
card.classList.add('node-' + nodeState);
218+
212219
card.appendChild(el('h4', 'node-name', node.name));
213220

214-
if (node.status === 'offline') {
215-
card.appendChild(el('span', 'node-offline', 'offline'));
216-
} else {
221+
if (nodeState === 'up' && node.cpu != null) {
217222
for (const [metric, value] of [['CPU', node.cpu], ['RAM', node.ram]] as [string, number][]) {
218223
const row = el('div', 'node-metric');
219224
row.appendChild(el('span', 'metric-label', metric));
@@ -227,6 +232,11 @@ import Base from '../layouts/Base.astro';
227232
card.appendChild(row);
228233
}
229234
card.appendChild(el('div', 'node-uptime', node.uptime_days + 'd uptime'));
235+
} else if (nodeState === 'on-demand') {
236+
card.appendChild(el('span', 'node-ondemand', 'on-demand · WOL'));
237+
card.appendChild(el('div', 'node-sub', 'powered on when needed'));
238+
} else {
239+
card.appendChild(el('span', 'node-offline', 'offline'));
230240
}
231241

232242
nodesContainer.appendChild(card);
@@ -341,12 +351,12 @@ import Base from '../layouts/Base.astro';
341351

342352
.skeleton-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.75rem; }
343353
.skeleton-card { height: 2.5rem; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 6px; animation: skeleton-pulse 1.5s ease-in-out infinite; }
344-
.skeleton-nodes { grid-template-columns: repeat(3, 1fr); }
354+
.skeleton-nodes { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
345355
.skeleton-node { height: 8rem; }
346356
.status-waiting { text-align: center; color: var(--color-text-muted); font-family: var(--font-mono); font-size: 0.85rem; margin-top: 1.5rem; }
347357
.status-loading { padding: 1rem 0; }
348358
.status-footer { padding: 2rem 0; }
349-
.status-note { font-size: 0.8rem; color: var(--color-text-muted); text-align: center; font-family: var(--font-mono); }
359+
.status-note { font-size: 0.8rem; color: var(--color-text-muted); text-align: center; font-family: var(--font-mono); line-height: 1.8; }
350360

351361
@media (max-width: 640px) {
352362
.summary-grid { gap: 1.5rem; }
@@ -383,19 +393,38 @@ import Base from '../layouts/Base.astro';
383393
.svc-name { font-family: var(--font-mono); font-size: 0.85rem; color: var(--color-text); flex: 1; }
384394
.svc-latency { font-family: var(--font-mono); font-size: 0.75rem; color: var(--color-text-muted); }
385395

386-
.nodes-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
387-
.node-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; padding: 1.25rem; transition: border-color 0.2s; }
396+
.nodes-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0.75rem; }
397+
.node-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 6px; padding: 1rem 1.1rem; transition: border-color 0.2s; display: flex; flex-direction: column; min-height: 7.5rem; }
388398
.node-card:hover { border-color: var(--color-accent); }
389-
.node-name { font-family: var(--font-mono); font-size: 1rem; font-weight: 700; color: var(--color-text); margin: 0 0 1rem; }
390-
.node-metric { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.5rem; }
391-
.metric-label { font-family: var(--font-mono); font-size: 0.75rem; color: var(--color-text-muted); width: 2.5rem; }
399+
.node-name { font-family: var(--font-mono); font-size: 0.95rem; font-weight: 700; color: var(--color-text); margin: 0 0 0.85rem; }
400+
.node-metric { display: flex; align-items: center; gap: 0.55rem; margin-bottom: 0.45rem; }
401+
.metric-label { font-family: var(--font-mono); font-size: 0.72rem; color: var(--color-text-muted); width: 2.3rem; }
392402
.bar { flex: 1; height: 6px; background: var(--color-border); border-radius: 3px; overflow: hidden; }
393403
.bar-fill { height: 100%; border-radius: 3px; transition: width 0.8s ease-out; }
394-
.metric-value { font-family: var(--font-mono); font-size: 0.8rem; color: var(--color-text); width: 3rem; text-align: right; }
395-
.node-uptime { font-family: var(--font-mono); font-size: 0.75rem; color: var(--color-text-muted); margin-top: 0.5rem; }
396-
.node-offline { font-family: var(--font-mono); font-size: 0.85rem; color: var(--color-text-muted); font-style: italic; }
404+
.metric-value { font-family: var(--font-mono); font-size: 0.75rem; color: var(--color-text); width: 2.75rem; text-align: right; }
405+
.node-uptime { font-family: var(--font-mono); font-size: 0.72rem; color: var(--color-text-muted); margin-top: auto; padding-top: 0.5rem; }
406+
.node-offline { font-family: var(--font-mono); font-size: 0.82rem; color: var(--color-text-muted); font-style: italic; }
397407

398-
@media (max-width: 640px) {
408+
/* on-demand nodes (pve3 WOL) — intentionally sleeping, sky accent not red */
409+
.node-ondemand {
410+
display: inline-block;
411+
font-family: var(--font-mono);
412+
font-size: 0.72rem;
413+
color: var(--color-accent);
414+
background: rgba(56, 189, 248, 0.08);
415+
border: 1px solid rgba(56, 189, 248, 0.25);
416+
padding: 0.15rem 0.5rem;
417+
border-radius: 3px;
418+
letter-spacing: 0.04em;
419+
width: fit-content;
420+
}
421+
.node-card.node-on-demand { border-style: dashed; border-color: rgba(56, 189, 248, 0.25); }
422+
.node-sub { font-family: var(--font-mono); font-size: 0.7rem; color: var(--color-text-muted); margin-top: 0.5rem; opacity: 0.75; }
423+
424+
@media (max-width: 700px) {
425+
.nodes-grid { grid-template-columns: repeat(2, 1fr); }
426+
}
427+
@media (max-width: 480px) {
399428
.nodes-grid { grid-template-columns: 1fr; }
400429
.service-grid { grid-template-columns: 1fr; }
401430
}

0 commit comments

Comments
 (0)