b03441da59
applyAccentColor() forced --sidebar-accent-foreground to the raw accent color regardless of theme. Works in dark mode (bright text on dark-tinted bg) but in light mode the tinted bg is near-white, so full-saturation yellow text on pale-yellow bg was nearly invisible. Now only overrides the foreground in dark mode; light mode keeps the theme's default high-contrast foreground token. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
60 lines
1.9 KiB
TypeScript
60 lines
1.9 KiB
TypeScript
import { create } from 'zustand';
|
|
|
|
export interface AuthUser {
|
|
id: string;
|
|
username: string;
|
|
displayName: string | null;
|
|
role: 'SUPER_ADMIN' | 'ADMIN' | 'USER';
|
|
tenantId: string;
|
|
hasAvatar?: boolean;
|
|
accentColor?: string | null;
|
|
}
|
|
|
|
interface AuthState {
|
|
user: AuthUser | null;
|
|
avatarVersion: number;
|
|
setUser: (user: AuthUser) => void;
|
|
clearUser: () => void;
|
|
bumpAvatarVersion: () => void;
|
|
}
|
|
|
|
function applyAccentColor(color: string | null | undefined) {
|
|
if (typeof document === 'undefined') return;
|
|
const root = document.documentElement;
|
|
if (color) {
|
|
root.style.setProperty('--primary', color);
|
|
root.style.setProperty('--ring', color);
|
|
// Sidebar active state: accent color with 15% opacity (#rrggbbaa, 0x26 ≈ 15%)
|
|
root.style.setProperty('--sidebar-accent', `${color}26`);
|
|
// Full-saturation accent text only reads well against the dark-mode sidebar's
|
|
// tinted-dark background; in light mode it's near-white behind it, so keep
|
|
// the theme's default (dark, high-contrast) foreground there instead.
|
|
if (root.classList.contains('dark')) {
|
|
root.style.setProperty('--sidebar-accent-foreground', color);
|
|
} else {
|
|
root.style.removeProperty('--sidebar-accent-foreground');
|
|
}
|
|
} else {
|
|
root.style.removeProperty('--primary');
|
|
root.style.removeProperty('--ring');
|
|
root.style.removeProperty('--sidebar-accent');
|
|
root.style.removeProperty('--sidebar-accent-foreground');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Zustand store for client-side auth state.
|
|
* No persist middleware -- user state comes from API, not localStorage.
|
|
* Populated on portal load via fetchCurrentUser().
|
|
*/
|
|
export const useAuthStore = create<AuthState>()((set) => ({
|
|
user: null,
|
|
avatarVersion: 0,
|
|
setUser: (user) => {
|
|
applyAccentColor(user.accentColor);
|
|
set({ user });
|
|
},
|
|
clearUser: () => set({ user: null }),
|
|
bumpAvatarVersion: () => set((s) => ({ avatarVersion: s.avatarVersion + 1 })),
|
|
}));
|