feat: en-tete allege, compte utilisateur en sidebar et pellicule d'images defilable (molette + fleches) #112
CI / lint (push) Successful in 1m59s
CI / security (push) Successful in 1m29s
CI / test (push) Successful in 4m59s
CI / build (push) Successful in 1m48s
CI / e2e (push) Successful in 13m49s

This commit is contained in:
2026-09-23 21:06:41 -04:00
parent b926f01b85
commit a726ad8511
21 changed files with 563 additions and 53 deletions
+45 -9
View File
@@ -1,7 +1,7 @@
/* ObsiGate — Authentication: API helper, AuthManager, login form, AdminPanel */
import { state } from './state.js';
import { safeCreateIcons, escapeHtml } from './utils.js';
import { showToast, closeHeaderMenu } from './ui.js';
import { showToast, closeHeaderMenu, closeMobileSidebar } from './ui.js';
import { t, getLocale, setLocale } from './i18n.js';
import { showWelcome } from './viewer.js';
@@ -13,6 +13,15 @@ window.handleLogout = () => {
AuthManager.logout();
};
/** Two-letter initials for the sidebar account avatar (#112). */
function userInitials(name) {
const parts = String(name || "").trim().split(/\s+/).filter(Boolean);
if (!parts.length) return "?";
const first = parts[0][0] || "";
const last = parts.length > 1 ? parts[parts.length - 1][0] : "";
return (first + last).toUpperCase() || "?";
}
// ---------------------------------------------------------------------------
// API helpers
// ---------------------------------------------------------------------------
@@ -323,22 +332,46 @@ const AuthManager = {
const app = document.getElementById("app");
if (login) login.classList.add("hidden");
if (app) app.classList.remove("hidden");
this.renderUserMenu();
this.renderUserSection();
},
renderUserMenu() {
/**
* Render the account block pinned at the bottom of the sidebar (#112) —
* the user identity/logout no longer live in the header.
*/
renderUserSection() {
const user = this.getUser();
const userMenu = document.getElementById("user-menu");
if (!userMenu) return;
const section = document.getElementById("sidebar-user");
if (!user || !this._authEnabled) {
userMenu.innerHTML = "";
if (section) section.hidden = true;
return;
}
userMenu.innerHTML = '<span class="user-display-name">' + (user.display_name || user.username) + "</span>" + '<button class="btn-logout" id="logout-btn" title="' + t('auth.logout_title') + '" onclick="window.handleLogout()"><i data-lucide="log-out" style="width:14px;height:14px"></i></button>';
if (!section) return;
const name = user.display_name || user.username || "";
const nameEl = document.getElementById("sidebar-user-name");
if (nameEl) nameEl.textContent = name;
const roleEl = document.getElementById("sidebar-user-role");
if (roleEl) roleEl.textContent = user.role === "admin" ? t("sidebar.user_role_admin") : t("sidebar.user_role_user");
const avatarEl = document.getElementById("sidebar-user-avatar");
if (avatarEl) avatarEl.textContent = userInitials(name);
section.hidden = false;
safeCreateIcons();
const logoutBtn = document.getElementById("logout-btn");
if (logoutBtn) logoutBtn.addEventListener("click", () => AuthManager.logout());
const logoutBtn = document.getElementById("sidebar-user-logout");
if (logoutBtn && !logoutBtn._obsigateBound) {
logoutBtn._obsigateBound = true;
logoutBtn.addEventListener("click", () => this.logout());
}
const profileBtn = document.getElementById("sidebar-user-profile");
if (profileBtn && !profileBtn._obsigateBound) {
profileBtn._obsigateBound = true;
profileBtn.addEventListener("click", () => {
closeMobileSidebar();
const trigger = document.getElementById("profile-open-btn");
if (trigger) trigger.click();
});
}
const adminRow = document.getElementById("admin-menu-row");
if (adminRow) {
@@ -355,6 +388,9 @@ const AuthManager = {
}
},
// Backwards-compatible alias (older callers/tests may use this name).
renderUserMenu() { this.renderUserSection(); },
// ── Initialization ──────────────────────────────────────────────
async checkAuthStatus() {