Thème Keycloak : console de compte (account) à l'identité Alliance
Thème account (parent=keycloak.v3) : overlay CSS surchargeant les variables PatternFly 5 (fond aurore, cartes en verre, accent aurore, bouton dégradé) + la même constellation animée. Appliqué via kcadm -s accountTheme. Prouvé : console charge (200, keycloak.v3 intact), account.css servi (200), constellation.js référencé. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
53acf1e209
commit
987ba88644
6 changed files with 188 additions and 1 deletions
|
|
@ -16,6 +16,10 @@
|
||||||
(canvas + aurore, le template n'en ayant pas) — étoiles scintillantes qui dérivent, liens de
|
(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 cyan, blob d'aurore ondulant ; respecte `prefers-reduced-motion`. Prouvé :
|
||||||
`constellation.js` référencé + servi (200).
|
`constellation.js` référencé + servi (200).
|
||||||
|
**Console de compte thémée aussi** (thème `account`, `parent=keycloak.v3`) : overlay CSS
|
||||||
|
surchargeant les variables PatternFly 5 (fond aurore, cartes en verre, accent aurore) + la même
|
||||||
|
constellation animée. Var `serveur_keycloak_account_theme` via `kcadm -s accountTheme`. Prouvé :
|
||||||
|
console charge (HTTP 200, `keycloak.v3` intact), `account.css` 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
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,9 @@ serveur_keycloak_admin_password: "{{ vault_keycloak_admin | default('') }}" # r
|
||||||
# Requiert client_pki sur ce nœud (racine step_ca dans le bundle système pour LDAPS).
|
# Requiert client_pki sur ce nœud (racine step_ca dans le bundle système pour LDAPS).
|
||||||
serveur_keycloak_ldap_federation: true
|
serveur_keycloak_ldap_federation: true
|
||||||
serveur_keycloak_realm: "chezlepro"
|
serveur_keycloak_realm: "chezlepro"
|
||||||
# Thème de login du realm (déployé depuis files/themes/). Vide = thème Keycloak par défaut.
|
# Thèmes du realm (déployés depuis files/themes/). Vide = thème Keycloak par défaut.
|
||||||
serveur_keycloak_login_theme: ""
|
serveur_keycloak_login_theme: ""
|
||||||
|
serveur_keycloak_account_theme: ""
|
||||||
serveur_keycloak_ldap_nom: "openldap"
|
serveur_keycloak_ldap_nom: "openldap"
|
||||||
# Connexion à l'annuaire (url, users_dn, bind_dn, bind_password) : fournie par le rôle
|
# Connexion à l'annuaire (url, users_dn, bind_dn, bind_password) : fournie par le rôle
|
||||||
# partagé resoudre_annuaire (voir tasks/main.yml « Adopter la connexion annuaire »).
|
# partagé resoudre_annuaire (voir tasks/main.yml « Adopter la connexion annuaire »).
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* =========================================================================
|
||||||
|
Alliance Boréale — console de compte Keycloak (SPA PatternFly 5)
|
||||||
|
Overlay : ciel nocturne aurore, cartes en verre, accent aurore.
|
||||||
|
========================================================================= */
|
||||||
|
:root,
|
||||||
|
.pf-v5-theme-dark,
|
||||||
|
html {
|
||||||
|
--pf-v5-global--Color--100: #e9ecff;
|
||||||
|
--pf-v5-global--Color--200: #99a1c9;
|
||||||
|
--pf-v5-global--link--Color: #56c2ff;
|
||||||
|
--pf-v5-global--link--Color--hover: #a98bff;
|
||||||
|
--pf-v5-global--primary-color--100: #56c2ff;
|
||||||
|
--pf-v5-global--primary-color--200: #4fe3c1;
|
||||||
|
--pf-v5-global--BorderColor--100: rgba(255, 255, 255, 0.12);
|
||||||
|
--pf-v5-global--BackgroundColor--100: rgba(255, 255, 255, 0.05);
|
||||||
|
--pf-v5-global--BackgroundColor--200: #0a0d24;
|
||||||
|
--pf-v5-global--FontFamily--text: -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
|
Roboto, Oxygen, Ubuntu, Cantarell, "Noto Sans", "Helvetica Neue", Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body, #app, .pf-v5-c-page, .pf-v5-c-page__main {
|
||||||
|
background: transparent !important;
|
||||||
|
color: #e9ecff;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background:
|
||||||
|
radial-gradient(1200px 700px at 80% -10%, #131a44 0%, transparent 60%),
|
||||||
|
radial-gradient(900px 600px at 10% 0%, #0e1640 0%, transparent 55%),
|
||||||
|
linear-gradient(180deg, #0a0d24 0%, #05060f 70%) fixed !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* En-tête / masthead + cartes : verre */
|
||||||
|
.pf-v5-c-masthead,
|
||||||
|
.pf-v5-c-card,
|
||||||
|
.pf-v5-c-page__sidebar,
|
||||||
|
.pf-v5-c-nav {
|
||||||
|
background: rgba(255, 255, 255, 0.05) !important;
|
||||||
|
border-color: rgba(255, 255, 255, 0.10) !important;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
.pf-v5-c-card { border-radius: 16px; box-shadow: 0 18px 50px rgba(0, 0, 0, 0.4); }
|
||||||
|
|
||||||
|
/* Textes, titres */
|
||||||
|
.pf-v5-c-title, .pf-v5-c-content, h1, h2, h3, label { color: #e9ecff !important; }
|
||||||
|
a, .pf-v5-c-button.pf-m-link { color: #56c2ff; }
|
||||||
|
|
||||||
|
/* Champs */
|
||||||
|
.pf-v5-c-form-control, input, select, textarea {
|
||||||
|
background: rgba(255, 255, 255, 0.06) !important;
|
||||||
|
color: #e9ecff !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.14) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bouton primaire : ruban d'aurore */
|
||||||
|
.pf-v5-c-button.pf-m-primary {
|
||||||
|
background: linear-gradient(100deg, #4fe3c1, #56c2ff) !important;
|
||||||
|
color: #04121a !important;
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 999px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
})();
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
parent=keycloak.v3
|
||||||
|
styles=css/account.css
|
||||||
|
scripts=js/constellation.js
|
||||||
|
|
@ -169,3 +169,27 @@
|
||||||
when:
|
when:
|
||||||
- serveur_keycloak_login_theme | length > 0
|
- serveur_keycloak_login_theme | length > 0
|
||||||
- not ansible_check_mode
|
- not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Definir le theme de la console de compte (identite Alliance Boreale)
|
||||||
|
ansible.builtin.shell:
|
||||||
|
executable: /bin/bash
|
||||||
|
cmd: |
|
||||||
|
set -euo pipefail
|
||||||
|
KC={{ serveur_keycloak_home }}/bin/kcadm.sh
|
||||||
|
"$KC" config credentials --server http://localhost:8080 --realm master \
|
||||||
|
--user {{ serveur_keycloak_admin_user }} --password "$KC_ADMIN_PW" >/dev/null
|
||||||
|
if "$KC" get realms/{{ serveur_keycloak_realm }} --fields accountTheme 2>/dev/null \
|
||||||
|
| grep -q '"{{ serveur_keycloak_account_theme }}"'; then
|
||||||
|
echo SETOPS_OK
|
||||||
|
else
|
||||||
|
"$KC" update realms/{{ serveur_keycloak_realm }} \
|
||||||
|
-s accountTheme={{ serveur_keycloak_account_theme }} >/dev/null
|
||||||
|
echo SETOPS_CHANGED
|
||||||
|
fi
|
||||||
|
environment:
|
||||||
|
KC_ADMIN_PW: "{{ serveur_keycloak_admin_password }}"
|
||||||
|
register: serveur_keycloak_account_res
|
||||||
|
changed_when: "'SETOPS_CHANGED' in serveur_keycloak_account_res.stdout"
|
||||||
|
when:
|
||||||
|
- serveur_keycloak_account_theme | length > 0
|
||||||
|
- not ansible_check_mode
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue