Thème Keycloak : constellation animée en fond du login
Le JS (scripts=js/constellation.js) crée son propre ciel (canvas + aurore, le template Keycloak n'en ayant pas) : champ d'étoiles scintillantes qui dérivent, liens de constellation cyan, blob d'aurore ondulant. Respecte prefers-reduced-motion. Reprend l'animation du site de l'Alliance. Prouvé : constellation.js référencé + servi (200). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
dd10ae8010
commit
53acf1e209
4 changed files with 135 additions and 1 deletions
|
|
@ -12,6 +12,10 @@
|
||||||
`kcadm ... -s loginTheme` (var `serveur_keycloak_login_theme`, idempotent), Keycloak rechargé
|
`kcadm ... -s loginTheme` (var `serveur_keycloak_login_theme`, idempotent), Keycloak rechargé
|
||||||
(`flush_handlers` avant la config realm). **Prouvé** : la page de login charge `alliance.css`
|
(`flush_handlers` avant la config realm). **Prouvé** : la page de login charge `alliance.css`
|
||||||
(HTTP 200) + le `logo.svg` (200), `loginTheme=alliance-boreale` actif sur `chezlepro`.
|
(HTTP 200) + le `logo.svg` (200), `loginTheme=alliance-boreale` actif sur `chezlepro`.
|
||||||
|
**Constellation animée en fond** (`scripts=js/constellation.js`) : le JS crée son propre ciel
|
||||||
|
(canvas + aurore, le template n'en ayant pas) — étoiles scintillantes qui dérivent, liens de
|
||||||
|
constellation cyan, blob d'aurore ondulant ; respecte `prefers-reduced-motion`. Prouvé :
|
||||||
|
`constellation.js` référencé + servi (200).
|
||||||
- **Soumission courriel `:587` interne (authentifiée) — la boucle souveraine est bouclée.**
|
- **Soumission courriel `:587` interne (authentifiée) — la boucle souveraine est bouclée.**
|
||||||
Postfix (`edge-mta`) sert la **soumission `:587`** (bloc `master.cf` : STARTTLS requis, `SMTP AUTH`,
|
Postfix (`edge-mta`) sert la **soumission `:587`** (bloc `master.cf` : STARTTLS requis, `SMTP AUTH`,
|
||||||
seuls les authentifiés relaient) ; l'auth SASL est **déléguée à Dovecot** (`infra-mail`, passdb LDAP
|
seuls les authentifiés relaient) ; l'auth SASL est **déléguée à Dovecot** (`infra-mail`, passdb LDAP
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,43 @@ body {
|
||||||
radial-gradient(900px 600px at 10% 0%, #0e1640 0%, transparent 55%),
|
radial-gradient(900px 600px at 10% 0%, #0e1640 0%, transparent 55%),
|
||||||
linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 70%) fixed;
|
linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 70%) fixed;
|
||||||
}
|
}
|
||||||
.login-pf-page { padding-top: 40px; }
|
.login-pf-page { padding-top: 40px; background: transparent; }
|
||||||
|
#kc-container, #kc-container-wrapper, .login-pf-page .card-pf { position: relative; }
|
||||||
|
|
||||||
|
/* ---------- Ciel animé : constellation + aurore (injecté par constellation.js) ---------- */
|
||||||
|
.ab-sky {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: -1;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.ab-sky canvas {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.ab-aurora {
|
||||||
|
position: absolute;
|
||||||
|
inset: -20% -10% auto -10%;
|
||||||
|
height: 70vh;
|
||||||
|
filter: blur(60px) saturate(140%);
|
||||||
|
opacity: 0.5;
|
||||||
|
background:
|
||||||
|
radial-gradient(40% 60% at 20% 30%, var(--aurora-teal) 0%, transparent 70%),
|
||||||
|
radial-gradient(45% 70% at 55% 20%, var(--aurora-cyan) 0%, transparent 70%),
|
||||||
|
radial-gradient(40% 65% at 80% 35%, var(--aurora-violet) 0%, transparent 70%);
|
||||||
|
animation: aurora-drift 22s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
@keyframes aurora-drift {
|
||||||
|
from { transform: translateX(-3%) translateY(0) scale(1); }
|
||||||
|
to { transform: translateX(3%) translateY(2%) scale(1.08); }
|
||||||
|
}
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.ab-aurora { animation: none; }
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- En-tête + logo étoile aurore ---------- */
|
/* ---------- En-tête + logo étoile aurore ---------- */
|
||||||
#kc-header,
|
#kc-header,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* Alliance Boréale — champ d'étoiles + constellation, adapté au login Keycloak.
|
||||||
|
Vanilla JS, aucune dépendance. Crée son propre ciel en fond (le template
|
||||||
|
Keycloak n'a pas de <canvas>). Respecte prefers-reduced-motion.
|
||||||
|
Métaphore : chaque artisan est une étoile ; reliés, ils forment la constellation. */
|
||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
if (document.querySelector(".ab-sky")) return;
|
||||||
|
|
||||||
|
var sky = document.createElement("div");
|
||||||
|
sky.className = "ab-sky";
|
||||||
|
sky.setAttribute("aria-hidden", "true");
|
||||||
|
var canvas = document.createElement("canvas");
|
||||||
|
canvas.id = "ab-constellation";
|
||||||
|
var aurora = document.createElement("div");
|
||||||
|
aurora.className = "ab-aurora";
|
||||||
|
sky.appendChild(canvas);
|
||||||
|
sky.appendChild(aurora);
|
||||||
|
document.body.insertBefore(sky, document.body.firstChild);
|
||||||
|
|
||||||
|
var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||||
|
var ctx = canvas.getContext("2d");
|
||||||
|
var stars = [];
|
||||||
|
var w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
|
||||||
|
var LINK_DIST = 130;
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
w = canvas.clientWidth;
|
||||||
|
h = canvas.clientHeight;
|
||||||
|
canvas.width = w * dpr;
|
||||||
|
canvas.height = h * dpr;
|
||||||
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||||
|
seed();
|
||||||
|
}
|
||||||
|
|
||||||
|
function seed() {
|
||||||
|
var count = Math.round((w * h) / 14000);
|
||||||
|
count = Math.max(40, Math.min(160, count));
|
||||||
|
stars = [];
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
stars.push({
|
||||||
|
x: Math.random() * w,
|
||||||
|
y: Math.random() * h,
|
||||||
|
r: Math.random() * 1.3 + 0.4,
|
||||||
|
vx: (Math.random() - 0.5) * 0.12,
|
||||||
|
vy: (Math.random() - 0.5) * 0.12,
|
||||||
|
tw: Math.random() * Math.PI * 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
ctx.clearRect(0, 0, w, h);
|
||||||
|
for (var i = 0; i < stars.length; i++) {
|
||||||
|
for (var j = i + 1; j < stars.length; j++) {
|
||||||
|
var dx = stars[i].x - stars[j].x;
|
||||||
|
var dy = stars[i].y - stars[j].y;
|
||||||
|
var d = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
if (d < LINK_DIST) {
|
||||||
|
var a = (1 - d / LINK_DIST) * 0.22;
|
||||||
|
ctx.strokeStyle = "rgba(120, 200, 255," + a + ")";
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(stars[i].x, stars[i].y);
|
||||||
|
ctx.lineTo(stars[j].x, stars[j].y);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var k = 0; k < stars.length; k++) {
|
||||||
|
var s = stars[k];
|
||||||
|
s.tw += 0.02;
|
||||||
|
var glow = 0.6 + Math.sin(s.tw) * 0.4;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
|
||||||
|
ctx.fillStyle = "rgba(255,255,255," + glow + ")";
|
||||||
|
ctx.shadowColor = "rgba(160,220,255,0.9)";
|
||||||
|
ctx.shadowBlur = 6;
|
||||||
|
ctx.fill();
|
||||||
|
ctx.shadowBlur = 0;
|
||||||
|
if (!reduce) {
|
||||||
|
s.x += s.vx;
|
||||||
|
s.y += s.vy;
|
||||||
|
if (s.x < 0 || s.x > w) s.vx *= -1;
|
||||||
|
if (s.y < 0 || s.y > h) s.vy *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!reduce) requestAnimationFrame(draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("resize", resize);
|
||||||
|
resize();
|
||||||
|
draw();
|
||||||
|
})();
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
parent=keycloak
|
parent=keycloak
|
||||||
import=common/keycloak
|
import=common/keycloak
|
||||||
styles=css/login.css css/alliance.css
|
styles=css/login.css css/alliance.css
|
||||||
|
scripts=js/constellation.js
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue