diff --git a/frontend/index.html b/frontend/index.html index fb8b0f3..6c87cd8 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -9,6 +9,10 @@ // hidden — force light regardless of stored/OS preference. To re-enable, // restore the localStorage/prefers-color-scheme logic and unhide the toggle. document.documentElement.setAttribute('data-theme', 'light'); + // Role is unknown until Keycloak check-sso resolves (async). Start in the + // "pending" state that hides manager-only controls, so anonymous visitors + // never see a flash of them before applyRoleUi() runs. + document.documentElement.classList.add('role-pending'); @@ -47,7 +51,7 @@ -
+
-
+
-
+
-
+
@@ -128,7 +132,7 @@
-
+
diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 6a49ba8..bb66ed2 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -59,6 +59,9 @@ const el = { // sense for the full-data (manager) tier so the anonymous view stays clean. function applyRoleUi(): void { const manager = isManager(); + // Role resolved — leave the pre-paint "pending" state; from here explicit + // per-element display below is the source of truth. + document.documentElement.classList.remove('role-pending'); const hideField = (node: Element | null): void => { const f = node?.closest('.field') as HTMLElement | null; if (f) f.style.display = manager ? '' : 'none'; diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 8a0295e..d802aa1 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -313,6 +313,11 @@ input::placeholder { color: var(--text-muted); } } .theme-toggle:hover { border-color: var(--border-strong); background: var(--surface); } +/* Anti-flash: until the role is resolved (Keycloak check-sso), hide every + manager-only control so anonymous visitors never see them flash on load. + applyRoleUi() drops .role-pending and then sets each element's final state. */ +html.role-pending .manager-only { display: none !important; } + /* Login / logout button — pinned to the header's top-right corner */ .auth-wrap { position: absolute; right: 18px; top: 12px; z-index: 3; }