Dashboard: refonte design « instrument 1-bit » (jauges graduées, polices vendorisées, glyphes météo)
- Identité noir & blanc pur (zéro gris, anti-ghosting e-ink) ; hachures pour conso/alarme - Typo vendorisée : Archivo (mots) + JetBrains Mono (nombres tabulaires), @font-face base64 - Jauge signature : noir = restant, repère seuil 20 %, hachures sous le seuil - Météo : glyphes 1-bit en silhouette (weather.kind) au lieu d'emoji couleur - Layout rééquilibré (plus de débordement), états dégradés soignés - dev/preview.py : aperçu hors-ligne du template
This commit is contained in:
@@ -3,180 +3,243 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
/* Dashboard e-ink PAYSAGE 1680x1264 — noir & blanc, fort contraste, sans couleur.
|
||||
Le PNG est pivoté de 90° côté backend pour le panneau portrait de la Kobo. */
|
||||
/* ============================================================================
|
||||
MONITORINK — instrument de mesure 1-bit. Canevas PAYSAGE 1680x1264, pivoté 90°
|
||||
côté backend pour le panneau e-ink portrait de la Kobo.
|
||||
Règles e-ink : NOIR & BLANC purs, aucun gris (le gris fantôme au refresh partiel).
|
||||
La hiérarchie passe par taille/graisse ; le « consommé » par des hachures.
|
||||
Mots = Archivo (grotesque lourd) · Nombres mesurés = JetBrains Mono (tabulaire).
|
||||
========================================================================= */
|
||||
{{ fonts | safe }}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
:root {
|
||||
--ink: #000;
|
||||
--paper: #fff;
|
||||
--muted: #555;
|
||||
--line: #000;
|
||||
--gauge-bg: #d9d9d9;
|
||||
}
|
||||
:root { --ink: #000; --paper: #fff; }
|
||||
|
||||
html, body {
|
||||
width: {{ width }}px; height: {{ height }}px;
|
||||
background: var(--paper); color: var(--ink);
|
||||
font-family: "DejaVu Sans", "Noto Sans", Arial, sans-serif;
|
||||
font-family: "Archivo", "DejaVu Sans", sans-serif;
|
||||
-webkit-font-smoothing: none;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
/* Deux colonnes + pied de page pleine largeur. */
|
||||
.num { font-family: "JetBrains Mono", monospace; font-variant-numeric: tabular-nums; }
|
||||
|
||||
body {
|
||||
padding: 44px 52px;
|
||||
padding: 46px 52px 0;
|
||||
display: grid;
|
||||
grid-template-columns: 600px 1fr;
|
||||
grid-template-columns: 560px 1fr;
|
||||
grid-template-rows: 1fr auto;
|
||||
grid-template-areas: "left right" "footer footer";
|
||||
column-gap: 56px;
|
||||
row-gap: 28px;
|
||||
grid-template-areas: "left right" "foot foot";
|
||||
column-gap: 52px;
|
||||
}
|
||||
.col {
|
||||
display: flex; flex-direction: column; min-width: 0;
|
||||
}
|
||||
.col-left { grid-area: left; }
|
||||
.col-right { grid-area: right; padding-left: 56px; border-left: 5px solid var(--line); }
|
||||
.section { margin-bottom: 40px; }
|
||||
.section:last-child { margin-bottom: 0; }
|
||||
.rule { border: 0; border-top: 4px solid var(--line); margin: 0 0 32px; }
|
||||
.pane { grid-area: left; display: flex; flex-direction: column; min-width: 0; }
|
||||
.deck { grid-area: right; display: flex; flex-direction: column; min-width: 0;
|
||||
padding-left: 52px; border-left: 4px solid var(--ink); }
|
||||
|
||||
/* Météo */
|
||||
.weather .top { display: flex; align-items: center; gap: 32px; }
|
||||
.weather .icon { font-size: 140px; line-height: 1; }
|
||||
.weather .temp { font-size: 130px; font-weight: 800; line-height: 1; }
|
||||
.weather .meta { font-size: 40px; color: var(--muted); margin-top: 18px; }
|
||||
.weather .meta b { color: var(--ink); }
|
||||
/* Étiquette de bloc : barre pleine + mot. Encode "section", pas de déco capitale flottante. */
|
||||
.label { display: flex; align-items: center; gap: 16px; margin-bottom: 26px; }
|
||||
.label::before { content: ""; width: 26px; height: 26px; background: var(--ink); flex: 0 0 auto; }
|
||||
.label .t { font-weight: 800; font-size: 33px; letter-spacing: 1px; text-transform: uppercase; }
|
||||
.label .meta { font-weight: 700; font-size: 24px; letter-spacing: 1px; text-transform: uppercase;
|
||||
margin-left: auto; padding: 4px 12px; border: 3px solid var(--ink); }
|
||||
.label .alarm { background: var(--ink); color: var(--paper); }
|
||||
|
||||
/* Titre de section */
|
||||
.title { font-size: 36px; font-weight: 800; text-transform: uppercase;
|
||||
letter-spacing: 3px; margin-bottom: 24px; }
|
||||
hr.div { border: 0; border-top: 4px solid var(--ink); margin: 30px 0; }
|
||||
|
||||
/* Jauges Claude */
|
||||
.gauge { margin-bottom: 36px; }
|
||||
.gauge .row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 12px; }
|
||||
.gauge .name { font-size: 42px; font-weight: 700; }
|
||||
.gauge .pct { font-size: 66px; font-weight: 800; }
|
||||
.gauge .pct small { font-size: 32px; font-weight: 600; }
|
||||
.bar { position: relative; height: 50px; background: var(--gauge-bg);
|
||||
border: 4px solid var(--ink); border-radius: 6px; overflow: hidden; }
|
||||
.bar .fill { position: absolute; top: 0; left: 0; bottom: 0; background: var(--ink); }
|
||||
.bar.low .fill { background: repeating-linear-gradient(45deg, #000 0 14px, #fff 14px 22px); }
|
||||
.gauge .sub { font-size: 30px; color: var(--muted); margin-top: 10px; }
|
||||
.err { font-size: 40px; font-weight: 700; padding: 24px; border: 4px dashed var(--ink); }
|
||||
/* ---- Météo : silhouette 1-bit + relevé mono ---- */
|
||||
.wx { display: flex; align-items: center; gap: 30px; }
|
||||
.wx svg { width: 150px; height: 150px; flex: 0 0 auto; }
|
||||
.wx .temp { font-size: 144px; font-weight: 800; line-height: .82; }
|
||||
.wx .deg { font-size: 64px; vertical-align: top; }
|
||||
.wx-meta { margin-top: 18px; font-size: 30px; line-height: 1.45; }
|
||||
.wx-meta .k { font-family: "Archivo", sans-serif; font-weight: 700;
|
||||
text-transform: uppercase; letter-spacing: 1px; font-size: 24px; }
|
||||
|
||||
/* Liste NAS (valeurs larges -> une colonne pleine largeur, sans soulignements) */
|
||||
.nas-list { display: flex; flex-direction: column; gap: 18px; }
|
||||
.nas-list .ha-item { border-bottom: 0; padding-bottom: 0; }
|
||||
.bad { font-weight: 800; }
|
||||
/* ---- Lignes de données (NAS, Maison) ---- */
|
||||
.rows { display: flex; flex-direction: column; }
|
||||
.rows.grid2 { display: grid; grid-template-columns: 1fr 1fr; column-gap: 40px; }
|
||||
.row { display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
|
||||
padding: 13px 0; border-bottom: 2px solid var(--ink); }
|
||||
.row .k { font-weight: 700; font-size: 31px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.row .v { font-size: 36px; font-weight: 700; white-space: nowrap; }
|
||||
.rows.grid2 .k { font-size: 28px; } .rows.grid2 .v { font-size: 32px; }
|
||||
.ko { display: inline-block; padding: 0 8px; background: var(--ink); color: var(--paper); }
|
||||
|
||||
/* Grille Home Assistant */
|
||||
.ha-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 44px; }
|
||||
.ha-item { display: flex; justify-content: space-between; align-items: baseline;
|
||||
border-bottom: 3px solid var(--ink); padding-bottom: 12px; }
|
||||
.ha-item .k { font-size: 38px; font-weight: 600; }
|
||||
.ha-item .v { font-size: 44px; font-weight: 800; }
|
||||
/* ============================ JAUGE (signature) ============================
|
||||
Échelle graduée : noir plein = budget RESTANT (le poids visuel colle au "% restant").
|
||||
Repère ▼ = seuil d'alerte 20 %, toujours lisible (au-dessus de la piste).
|
||||
Sous le seuil : zone consommée en hachures + état alarme. */
|
||||
.g { margin-bottom: 34px; }
|
||||
.g:last-child { margin-bottom: 0; }
|
||||
.g .head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 14px; }
|
||||
.g .name { font-weight: 700; font-size: 38px; }
|
||||
.g .pct { font-size: 80px; font-weight: 800; line-height: .8; }
|
||||
.g .pct .u { font-size: 24px; font-weight: 700; letter-spacing: .5px; }
|
||||
|
||||
footer { grid-area: footer; display: flex; justify-content: space-between;
|
||||
font-size: 28px; color: var(--muted); padding-top: 20px; border-top: 3px solid var(--ink); }
|
||||
.stale { font-weight: 800; color: var(--ink); }
|
||||
.meter { position: relative; padding-top: 26px; } /* place pour le repère de seuil */
|
||||
.meter .mark { position: absolute; top: 0; left: 20%; transform: translateX(-50%);
|
||||
width: 0; height: 0; border-left: 11px solid transparent;
|
||||
border-right: 11px solid transparent; border-top: 14px solid var(--ink); }
|
||||
.track { position: relative; height: 58px; border: 4px solid var(--ink); background: var(--paper);
|
||||
overflow: hidden; }
|
||||
.track .fill { position: absolute; top: 0; bottom: 0; left: 0; background: var(--ink); }
|
||||
.track .tick { position: absolute; top: 0; width: 3px; height: 16px; background: var(--ink); }
|
||||
.track .t25 { left: 25%; } .track .t50 { left: 50%; } .track .t75 { left: 75%; }
|
||||
.g.low .track { background: repeating-linear-gradient(-45deg, #000 0 4px, #fff 4px 11px); }
|
||||
.g.low .mark { border-top-width: 18px; border-left-width: 13px; border-right-width: 13px; }
|
||||
|
||||
.g .sub { font-size: 28px; margin-top: 12px; }
|
||||
|
||||
/* Variante compacte (Codex, secondaire). */
|
||||
.g.mini { margin-bottom: 22px; }
|
||||
.g.mini .name { font-size: 30px; }
|
||||
.g.mini .pct { font-size: 52px; }
|
||||
.g.mini .pct .u { font-size: 22px; }
|
||||
.g.mini .meter { padding-top: 22px; }
|
||||
.g.mini .track { height: 38px; }
|
||||
.g.mini .sub { font-size: 24px; margin-top: 9px; }
|
||||
|
||||
.err { font-size: 36px; font-weight: 700; padding: 22px; border: 4px solid var(--ink);
|
||||
background: repeating-linear-gradient(-45deg, #000 0 4px, #fff 4px 11px); }
|
||||
.err span { background: var(--paper); padding: 6px 10px; }
|
||||
|
||||
/* ---- Pied de page ---- */
|
||||
footer { grid-area: foot; display: flex; justify-content: space-between; align-items: center;
|
||||
margin-top: 26px; padding: 18px 0 22px; border-top: 4px solid var(--ink);
|
||||
font-size: 26px; }
|
||||
footer .num { font-weight: 500; }
|
||||
.stale { background: var(--ink); color: var(--paper); padding: 2px 10px; font-weight: 700; }
|
||||
|
||||
.space { flex: 1 1 auto; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
{# ---- Glyphes météo 1-bit (silhouettes pleines, nettes sur e-ink) ---- #}
|
||||
{% macro sun(cx, cy, r) -%}
|
||||
<circle cx="{{cx}}" cy="{{cy}}" r="{{r}}"/>
|
||||
{% for a in [0,45,90,135,180,225,270,315] %}
|
||||
<rect x="{{cx-2.5}}" y="{{cy-r-13}}" width="5" height="11" transform="rotate({{a}} {{cx}} {{cy}})"/>
|
||||
{% endfor %}
|
||||
{%- endmacro %}
|
||||
{% macro cloud(ox, oy, s) -%}
|
||||
<g transform="translate({{ox}},{{oy}}) scale({{s}})">
|
||||
<circle cx="32" cy="42" r="20"/><circle cx="56" cy="34" r="26"/>
|
||||
<circle cx="78" cy="44" r="18"/><rect x="30" y="42" width="50" height="22" rx="11"/>
|
||||
</g>
|
||||
{%- endmacro %}
|
||||
{% macro wxicon(kind) -%}
|
||||
<svg viewBox="0 0 100 100" fill="#000" stroke="#000" stroke-linecap="round">
|
||||
{% if kind == 'clear' %}{{ sun(50, 50, 21) }}
|
||||
{% elif kind == 'partly' %}{{ sun(34, 32, 15) }}{{ cloud(18, 36, 0.78) }}
|
||||
{% elif kind == 'cloudy' %}{{ cloud(8, 22, 0.95) }}
|
||||
{% elif kind == 'fog' %}{{ cloud(8, 12, 0.9) }}
|
||||
{% for y in [76, 86, 96] %}<rect x="14" y="{{y}}" width="72" height="5" rx="2"/>{% endfor %}
|
||||
{% elif kind == 'rain' %}{{ cloud(8, 8, 0.92) }}
|
||||
{% for x in [30, 50, 70] %}<rect x="{{x}}" y="74" width="5" height="20" rx="2" transform="rotate(18 {{x}} 84)"/>{% endfor %}
|
||||
{% elif kind == 'snow' %}{{ cloud(8, 8, 0.92) }}
|
||||
{% for x in [30, 50, 70] %}<circle cx="{{x}}" cy="86" r="5"/>{% endfor %}
|
||||
{% elif kind == 'storm' %}{{ cloud(8, 4, 0.92) }}
|
||||
<polygon points="52,66 38,90 50,90 44,100 66,76 53,76 60,66" stroke="none"/>
|
||||
{% else %}{{ cloud(8, 22, 0.95) }}{% endif %}
|
||||
</svg>
|
||||
{%- endmacro %}
|
||||
|
||||
{# ---- Jauge : la signature ---- #}
|
||||
{% macro gauge(g, mini=False) -%}
|
||||
<div class="g{% if g.remaining < 20 %} low{% endif %}{% if mini %} mini{% endif %}">
|
||||
<div class="head">
|
||||
<span class="name">{{ g.name }}</span>
|
||||
<span class="pct num">{{ g.remaining | round | int }}<span class="u">% restant</span></span>
|
||||
</div>
|
||||
<div class="meter">
|
||||
<span class="mark"></span>
|
||||
<div class="track">
|
||||
<span class="tick t25"></span><span class="tick t50"></span><span class="tick t75"></span>
|
||||
<div class="fill" style="width: {{ g.remaining | round(1) }}%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sub num">reset {{ g.resets_in }} · {{ (100 - g.remaining) | round | int }}% conso{% if g.extra %} · {{ g.extra }}{% endif %}</div>
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
<body>
|
||||
|
||||
<!-- Colonne gauche : météo, NAS -->
|
||||
<div class="col col-left">
|
||||
<div class="section weather">
|
||||
<!-- COLONNE GAUCHE : météo + infra maison -->
|
||||
<div class="pane">
|
||||
<div class="wx">
|
||||
{% if weather.ok %}
|
||||
<div class="top">
|
||||
<div class="icon">{{ weather.icon }}</div>
|
||||
<div class="temp">{{ weather.temp | round | int }}°</div>
|
||||
</div>
|
||||
<div class="meta">
|
||||
{{ weather.label }} · ressenti <b>{{ weather.feels_like | round | int }}°</b>
|
||||
</div>
|
||||
<div class="meta">
|
||||
min <b>{{ weather.temp_min | round | int }}°</b> / max <b>{{ weather.temp_max | round | int }}°</b>{% if weather.precip_prob is not none %} · pluie <b>{{ weather.precip_prob }}%</b>{% endif %}
|
||||
{{ wxicon(weather.kind) }}
|
||||
<div>
|
||||
<div class="temp num">{{ weather.temp | round | int }}<span class="deg">°C</span></div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="meta">Météo indisponible</div>
|
||||
<div class="wx-meta">Météo indisponible</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if nas.ok %}
|
||||
<hr class="rule">
|
||||
<div class="section">
|
||||
<div class="title">NAS</div>
|
||||
<div class="nas-list">
|
||||
{% for d in nas.disks %}
|
||||
<div class="ha-item"><span class="k">{{ d.label }}</span><span class="v">{{ d.percent | round | int }}% · {{ d.free_human }} libre</span></div>
|
||||
{% endfor %}
|
||||
<div class="ha-item"><span class="k">Docker</span><span class="v">{{ nas.docker_running }}/{{ nas.docker_total }}{% if nas.docker_unhealthy %} · <span class="bad">{{ nas.docker_unhealthy }} KO</span>{% else %} ✓{% endif %}</span></div>
|
||||
<div class="ha-item"><span class="k">Port VPN</span><span class="v">{% if nas.vpn_ok %}OK{% if nas.vpn_port %} · {{ nas.vpn_port }}{% endif %}{% else %}<span class="bad">✗ désync</span>{% endif %}</span></div>
|
||||
</div>
|
||||
{% if weather.ok %}
|
||||
<div class="wx-meta num">
|
||||
{{ weather.label }} · ressenti <span class="k">{{ weather.feels_like | round | int }}°</span>
|
||||
· {{ weather.temp_min | round | int }}° / {{ weather.temp_max | round | int }}°{% if weather.precip_prob is not none %} · pluie {{ weather.precip_prob }}%{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Colonne droite : abonnement Claude + maison -->
|
||||
<div class="col col-right">
|
||||
<div class="section">
|
||||
<div class="title">Claude{% if claude.ok %} · Max 5x{% endif %}</div>
|
||||
{% if not claude.ok %}
|
||||
<div class="err">⚠ {{ claude.error }}</div>
|
||||
{% else %}
|
||||
{% for g in gauges %}
|
||||
<div class="gauge">
|
||||
<div class="row">
|
||||
<span class="name">{{ g.name }}</span>
|
||||
<span class="pct">{{ g.remaining | round | int }}<small>% restant</small></span>
|
||||
</div>
|
||||
<div class="bar {% if g.remaining < 20 %}low{% endif %}">
|
||||
<div class="fill" style="width: {{ (100 - g.remaining) | round(1) }}%;"></div>
|
||||
</div>
|
||||
<div class="sub">{{ (100 - g.remaining) | round | int }}% utilisé · reset dans {{ g.resets_in }}{% if g.extra %} · {{ g.extra }}{% endif %}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if claude.extra %}
|
||||
<div class="sub" style="font-size:32px;">{{ claude.extra.label }}</div>
|
||||
{% endif %}
|
||||
{% if claude.burn_rate %}
|
||||
<div class="sub" style="font-size:32px;">Burn rate : {{ claude.burn_rate | round | int }} tok/min</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if codex.ok %}
|
||||
<div class="section">
|
||||
<div class="title">Codex{% if codex.plan_type %} · {{ codex.plan_type | capitalize }}{% endif %}{% if codex.limited %} · <span class="bad">⚠ limite atteinte</span>{% endif %}</div>
|
||||
{% for g in codex.gauges %}
|
||||
<div class="gauge">
|
||||
<div class="row">
|
||||
<span class="name">{{ g.name }}</span>
|
||||
<span class="pct">{{ g.remaining | round | int }}<small>% restant</small></span>
|
||||
</div>
|
||||
<div class="bar {% if g.remaining < 20 %}low{% endif %}">
|
||||
<div class="fill" style="width: {{ (100 - g.remaining) | round(1) }}%;"></div>
|
||||
</div>
|
||||
<div class="sub">{{ (100 - g.remaining) | round | int }}% utilisé · reset dans {{ g.resets_in }}</div>
|
||||
</div>
|
||||
{% if nas.ok %}
|
||||
<hr class="div">
|
||||
<div class="label"><span class="t">NAS</span>
|
||||
{% if nas.docker_unhealthy %}<span class="meta alarm">{{ nas.docker_unhealthy }} KO</span>{% endif %}</div>
|
||||
<div class="rows">
|
||||
{% for d in nas.disks %}
|
||||
<div class="row"><span class="k">{{ d.label }}</span><span class="v num">{{ d.percent | round | int }}% · {{ d.free_human }}</span></div>
|
||||
{% endfor %}
|
||||
<div class="row"><span class="k">Docker</span><span class="v num">{{ nas.docker_running }}/{{ nas.docker_total }}{% if not nas.docker_unhealthy %} ✓{% endif %}</span></div>
|
||||
<div class="row"><span class="k">VPN</span><span class="v num">{% if nas.vpn_ok %}OK{% if nas.vpn_port %} · {{ nas.vpn_port }}{% endif %}{% else %}<span class="ko">DÉSYNC</span>{% endif %}</span></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if ha_states %}
|
||||
<div class="section">
|
||||
<div class="title">Maison</div>
|
||||
<div class="ha-grid">
|
||||
{% for s in ha_states %}
|
||||
<div class="ha-item"><span class="k">{{ s.label }}</span><span class="v">{{ s.display }}</span></div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<hr class="div">
|
||||
<div class="label"><span class="t">Maison</span></div>
|
||||
<div class="rows grid2">
|
||||
{% for s in ha_states %}
|
||||
<div class="row"><span class="k">{{ s.label }}</span><span class="v num">{{ s.display }}</span></div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="space"></div>
|
||||
</div>
|
||||
|
||||
<!-- COLONNE DROITE : budgets (le héros) -->
|
||||
<div class="deck">
|
||||
<div class="label"><span class="t">Claude</span>
|
||||
{% if claude.ok %}<span class="meta">Max 5×</span>{% endif %}</div>
|
||||
{% if not claude.ok %}
|
||||
<div class="err"><span>⚠ {{ claude.error }}</span></div>
|
||||
{% else %}
|
||||
{% for g in gauges %}{{ gauge(g) }}{% endfor %}
|
||||
{% if claude.extra or claude.burn_rate %}
|
||||
<div class="sub num" style="font-size:26px; margin-top:6px;">
|
||||
{% if claude.extra %}{{ claude.extra.label }}{% endif %}{% if claude.extra and claude.burn_rate %} · {% endif %}{% if claude.burn_rate %}burn {{ claude.burn_rate | round | int }} tok/min{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if codex.ok %}
|
||||
<hr class="div">
|
||||
<div class="label"><span class="t">Codex</span>
|
||||
{% if codex.plan_type %}<span class="meta">{{ codex.plan_type | capitalize }}</span>{% endif %}
|
||||
{% if codex.limited %}<span class="meta alarm">Limite</span>{% endif %}</div>
|
||||
{% for g in codex.gauges %}{{ gauge(g, mini=True) }}{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<div class="space"></div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<span>Monitorink · 3 appuis bouton page = redémarrer</span>
|
||||
{% if kobo.ok %}<span class="{% if kobo.low %}stale{% endif %}">{% if kobo.charging %}⚡{% else %}🔋{% endif %} Kobo {{ kobo.percent }}%{% if kobo.stale %} · ?{% endif %}</span>{% endif %}
|
||||
<span class="{% if stale %}stale{% endif %}">maj {{ updated }}{% if stale %} · DONNÉE PÉRIMÉE{% endif %}</span>
|
||||
<span class="num">monitorink · 3× bouton page → reboot</span>
|
||||
<span class="space"></span>
|
||||
{% if kobo.ok %}<span class="num">{% if kobo.charging %}⚡{% else %}batt{% endif %} {{ kobo.percent }}%{% if kobo.stale %} ?{% endif %}</span>{% endif %}
|
||||
<span class="num" style="margin-left:28px;">maj {{ updated }}{% if stale %} <span class="stale">PÉRIMÉ</span>{% endif %}</span>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user