Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
483af904af | ||
|
|
bfe0c75106 | ||
|
|
2a96ad3b1d |
+1
-66
@@ -47,33 +47,6 @@
|
||||
href="/static/icons/icon-192x192.svg"
|
||||
/>
|
||||
|
||||
<!-- Boot splash CSS — inline so it applies BEFORE /static/style.css is
|
||||
available (desktop: embedded page served from tauri:// has no /static) -->
|
||||
<style id="boot-splash-css">
|
||||
body:not(.app-booted) > *:not(#boot-splash) { display: none !important; }
|
||||
#boot-splash {
|
||||
position: fixed; inset: 0; z-index: 2147483647;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
background: radial-gradient(1200px 600px at 50% -10%, #26272b 0%, #17181a 60%);
|
||||
color: #eceeeb; font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
body.app-booted #boot-splash { display: none; }
|
||||
.bs-card { display: flex; flex-direction: column; align-items: center; gap: 14px; }
|
||||
.bs-logo {
|
||||
width: 72px; height: 72px; display: flex; align-items: center; justify-content: center;
|
||||
font-size: 38px; background: #1f2023; border: 1px solid #33353a; border-radius: 18px;
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
.bs-title { font-size: 22px; font-weight: 600; letter-spacing: 0.3px; }
|
||||
.bs-spinner {
|
||||
width: 34px; height: 34px; border-radius: 50%;
|
||||
border: 3px solid rgba(124, 58, 237, 0.25); border-top-color: #7c3aed;
|
||||
animation: bs-spin 0.9s linear infinite;
|
||||
}
|
||||
@keyframes bs-spin { to { transform: rotate(360deg); } }
|
||||
.bs-status { font-size: 13px; color: #9aa3b2; min-height: 18px; }
|
||||
@media (prefers-reduced-motion: reduce) { .bs-spinner { animation-duration: 1.8s; } }
|
||||
</style>
|
||||
<link rel="stylesheet" href="/static/style.css" />
|
||||
<link rel="stylesheet" href="/static/draco-barre.css" />
|
||||
<link rel="stylesheet" href="/static/draco-alertes.css" />
|
||||
@@ -89,7 +62,7 @@
|
||||
id="hljs-theme-light"
|
||||
disabled
|
||||
/>
|
||||
<!-- defer: ne bloque pas le premier paint (le splash inline s'affiche immédiatement) -->
|
||||
<!-- defer: ne bloque pas le premier paint -->
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||
<!-- Langues highlight.js hors bundle "common" (enregistrement auto apres le core) -->
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/dockerfile.min.js"></script>
|
||||
@@ -226,44 +199,6 @@
|
||||
</script>
|
||||
</head>
|
||||
<body class="has-draco-bar">
|
||||
<!-- Boot splash : visible tant que l'app n'a pas booté avec son CSS.
|
||||
Sur desktop, la page embarquée (tauri://) n'a pas /static/style.css →
|
||||
sans ce splash, le squelette HTML brut serait visible pendant le
|
||||
démarrage du backend (FOUC 3-10 s). Styles 100% inline. -->
|
||||
<div id="boot-splash" role="status" aria-live="polite">
|
||||
<div class="bs-card">
|
||||
<div class="bs-logo">📖</div>
|
||||
<div class="bs-title">ObsiGate</div>
|
||||
<div class="bs-spinner" aria-hidden="true"></div>
|
||||
<div class="bs-status" id="boot-splash-status">Démarrage…</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
var done = false;
|
||||
function bootReady() {
|
||||
if (done) return;
|
||||
done = true;
|
||||
document.body.classList.add("app-booted");
|
||||
var s = document.getElementById("boot-splash");
|
||||
if (s && s.parentNode) s.parentNode.removeChild(s);
|
||||
}
|
||||
window.__obsigateBootReady = bootReady;
|
||||
window.__setBootStatus = function (txt) {
|
||||
var el = document.getElementById("boot-splash-status");
|
||||
if (el) el.textContent = txt;
|
||||
};
|
||||
var poll = setInterval(function () {
|
||||
if (window.__OBSIGATE_BOOTED) { clearInterval(poll); bootReady(); }
|
||||
}, 80);
|
||||
// Filet de sécurité : si le CSS principal a chargé (origine backend réelle)
|
||||
// mais que le JS a échoué, révéler l'app après 10 s au lieu d'un splash infini.
|
||||
setTimeout(function () {
|
||||
var link = document.querySelector('link[href*="style.css"]');
|
||||
if (link && link.sheet) { clearInterval(poll); bootReady(); }
|
||||
}, 10000);
|
||||
})();
|
||||
</script>
|
||||
<div class="search-progress-bar" id="search-progress-bar">
|
||||
<div class="search-progress-bar__fill"></div>
|
||||
</div>
|
||||
|
||||
+2
-10
@@ -120,16 +120,8 @@ async function init() {
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
try {
|
||||
await init();
|
||||
Sync.init();
|
||||
} finally {
|
||||
// Signale au splash de démarrage (index.html #boot-splash) que l'app est
|
||||
// initialisée : le splash est retiré et le squelette stylé révélé.
|
||||
// Set AFTER init() resolves so every handler (search, tabs, …) is bound.
|
||||
window.__OBSIGATE_BOOTED = true;
|
||||
if (typeof window.__obsigateBootReady === "function") window.__obsigateBootReady();
|
||||
}
|
||||
await init();
|
||||
Sync.init();
|
||||
// Show version in header — always visible, fallback before the async fetch
|
||||
populateVersions();
|
||||
fetch('/api/health')
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
"""Tests — démarrage ObsiGate sans écran de chargement plein écran.
|
||||
|
||||
Le splash (``#boot-splash`` dans ``frontend/index.html`` : icône
|
||||
livre, titre, spinner, « Démarrage… ») masquait tout le reste de la
|
||||
page via ``body:not(.app-booted) > * { display: none !important }``
|
||||
jusqu'au signal de ``frontend/js/app.js`` (ou un repli à 10 s).
|
||||
Les autres applications (TikTak, Kanbante, Flowdeck, console Spark)
|
||||
n'affichent aucun splash de ce type au démarrage : le contenu y
|
||||
apparaît dès qu'il est prêt. Le retrait supprime donc l'écran, son
|
||||
CSS de masquage, son script de pilotage et le signal côté ``app.js``,
|
||||
sans toucher aux indicateurs internes aux vues ni à l'écran de
|
||||
connexion.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
FRONTEND = ROOT / "frontend"
|
||||
|
||||
MARQUEURS_SPLASH = (
|
||||
"boot-splash",
|
||||
"app-booted",
|
||||
"__OBSIGATE_BOOTED",
|
||||
"__obsigateBootReady",
|
||||
"__setBootStatus",
|
||||
"bs-card",
|
||||
"bs-logo",
|
||||
"bs-title",
|
||||
"bs-spinner",
|
||||
"bs-status",
|
||||
"bs-spin",
|
||||
"Démarrage…",
|
||||
)
|
||||
|
||||
|
||||
def _index() -> str:
|
||||
return (FRONTEND / "index.html").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def _app_js() -> str:
|
||||
return (FRONTEND / "js" / "app.js").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_aucun_marqueur_splash():
|
||||
index = _index()
|
||||
app_js = _app_js()
|
||||
for marqueur in MARQUEURS_SPLASH:
|
||||
assert marqueur not in index, f"{marqueur} encore dans index.html"
|
||||
assert marqueur not in app_js, f"{marqueur} encore dans js/app.js"
|
||||
|
||||
|
||||
def test_pas_de_masquage_global_au_demarrage():
|
||||
"""Aucune règle ne cache tout le <body> en attendant un signal :
|
||||
sans elle, un chargement lent ne peut plus donner un écran blanc
|
||||
bloqué."""
|
||||
index = _index()
|
||||
assert "body:not(.app-booted)" not in index
|
||||
assert "display: none !important" not in index
|
||||
|
||||
|
||||
def test_boot_js_conserve_et_indicateurs_internes_intacts():
|
||||
"""Le démarrage SPA reste branché ; seuls le splash et son signal
|
||||
disparaissent. L'écran de connexion et la barre de progression
|
||||
de recherche (indicateurs internes aux vues) ne sont PAS visés."""
|
||||
app_js = _app_js()
|
||||
assert 'document.addEventListener("DOMContentLoaded"' in app_js
|
||||
assert "await init();" in app_js
|
||||
assert "Sync.init();" in app_js
|
||||
assert "populateVersions" in app_js
|
||||
index = _index()
|
||||
assert 'id="login-screen"' in index
|
||||
assert 'id="search-progress-bar"' in index
|
||||
assert 'id="app"' in index
|
||||
Reference in New Issue
Block a user