API-KA — plateforme centrale : collecte quotidienne des 8 services KA, historisation append-only et API publique sur www.api-ka.com
1/* ============================================2 Projet : API-KA3 Fichier : src/api/web/ka/ka-shell.js4 Node : m3u96b5 Author : Simon-Pierre Boucher6 Contact : contact@spboucher.ai7 Date : 2026-08-178 ============================================9 Coquille commune Groupe KA pour les pages statiques d'API-KA :10 · footer commun .ka-footer (équivalent vanilla de ka-ui/KaFooter.tsx),11 alimenté par /ka/ecosystem.json (source de vérité unique) ;12 · cartes contact (page /contact, conteneur #ka-contacts) ;13 · état de connexion KA ID dans le header (conteneur #ka-auth). */14"use strict";1516const KA_SITE_ID = "api-ka";1718async function kaEco() {19 const r = await fetch("/ka/ecosystem.json");20 return r.json();21}2223function el(tag, cls, html) {24 const e = document.createElement(tag);25 if (cls) e.className = cls;26 if (html !== undefined) e.innerHTML = html;27 return e;28}2930function esc(s) {31 return String(s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");32}3334/* ---------- footer commun (structure .ka-footer de tokens.css) ---------- */35function kaRenderFooter(eco) {36 const root = document.getElementById("ka-footer-root");37 if (!root) return;38 const site = eco.sites.find((s) => s.id === KA_SITE_ID);39 const others = eco.sites.filter((s) => s.id !== KA_SITE_ID);40 const year = new Date().getFullYear();41 root.innerHTML = `42 <a class="wordmark" href="${eco.hub.url}" target="_blank" rel="noopener noreferrer"43 aria-label="Groupe KA — le portail de l'écosystème">Groupe <span class="ka">KA</span></a>44 <p class="desc">${esc(eco.org.tagline)} Des centaines de connecteurs lisent les sites à la45 source, normalisent la donnée et se resynchronisent seuls.46 ${site ? `<b style="color:var(--paper)">${esc(site.wordmark)}</b> — ${esc(site.tagline)} — est un service Groupe KA.` : ""}</p>47 <p class="notice"><b>${esc(eco.org.disclaimer)}</b></p>48 <ul class="sites">49 ${others.map((s) => `<li><a href="https://${s.domain}" target="_blank" rel="noopener noreferrer">${esc(s.wordmark)}</a></li>`).join("")}50 ${(eco.extraFooterLinks || []).map((l) => `<li><a href="${l.href}" target="_blank" rel="noopener noreferrer">${esc(l.label)}</a></li>`).join("")}51 </ul>52 <div class="contacts">53 ${eco.contacts.map((c) => `<p style="margin:0"><a href="mailto:${c.email}">${c.email}</a><span>${esc(c.role)}</span></p>`).join("")}54 </div>55 <p class="legal">© ${year} ${esc(eco.org.copyrightHolder)}56 ${eco.legal.map((l) => ` · <a href="${l.href}" target="_blank" rel="noopener noreferrer">${esc(l.label)}</a>`).join("")}57 </p>`;58}5960/* ---------- cartes contact (page /contact) ---------- */61function kaRenderContacts(eco) {62 const zone = document.getElementById("ka-contacts");63 if (!zone) return;64 zone.innerHTML = eco.contacts65 .map(66 (c) => `<div class="card contact-card">67 <span class="klabel">${esc(c.role)}</span>68 <a class="contact-mail" href="mailto:${c.email}">${c.email}</a>69 </div>`70 )71 .join("");72 const hub = document.getElementById("ka-hub-link");73 if (hub) hub.href = eco.hub.url + eco.hub.loginPath;74}7576/* ---------- connexion KA ID dans le header (#ka-auth) ---------- */77async function kaRenderAuth() {78 const zone = document.getElementById("ka-auth");79 if (!zone) return;80 try {81 const r = await fetch("/api/auth/me", { headers: { Accept: "application/json" } });82 if (r.ok) {83 const u = await r.json();84 zone.innerHTML = `<span class="ka-user" title="${esc(u.email || "")}">85 ${u.picture ? `<img src="${u.picture}" alt="" class="ka-avatar">` : ""}86 <b>${esc(u.name || "membre")}</b></span>87 <button class="btn btn-ghost ka-logout" type="button">Déconnexion</button>`;88 zone.querySelector(".ka-logout").addEventListener("click", async () => {89 await fetch("/api/auth/logout", { method: "POST" });90 location.reload();91 });92 return;93 }94 } catch {}95 zone.innerHTML = `<a class="btn btn-accent ka-login" href="/api/auth/ka/login">Se connecter avec KA</a>`;96}9798(async () => {99 kaRenderAuth();100 try {101 const eco = await kaEco();102 kaRenderFooter(eco);103 kaRenderContacts(eco);104 } catch {}105})();106