forked from baron/baron-sso
125 lines
3.4 KiB
TypeScript
125 lines
3.4 KiB
TypeScript
export type ShellTheme = "light" | "dark";
|
|
|
|
export type ShellTranslator = (
|
|
key: string,
|
|
fallback: string,
|
|
vars?: Record<string, string | number>,
|
|
) => string;
|
|
|
|
type ShellSessionStatusParams = {
|
|
expiresAtSec?: number | null;
|
|
nowMs: number;
|
|
t: ShellTranslator;
|
|
};
|
|
|
|
type ShellProfileSummaryParams = {
|
|
profileName?: string | null;
|
|
profileEmail?: string | null;
|
|
fallbackName: string;
|
|
fallbackEmail: string;
|
|
};
|
|
|
|
export const SHELL_THEME_STORAGE_KEY = "admin_theme";
|
|
export const SHELL_SESSION_EXPIRY_STORAGE_KEY =
|
|
"baron_session_expiry_enabled";
|
|
export { AppSidebar } from "./AppSidebar";
|
|
export type { ShellSidebarNavItem } from "./AppSidebar";
|
|
export { shellLayoutClasses } from "./layout";
|
|
|
|
export function readShellTheme(): ShellTheme {
|
|
return window.localStorage.getItem(SHELL_THEME_STORAGE_KEY) === "dark"
|
|
? "dark"
|
|
: "light";
|
|
}
|
|
|
|
export function applyShellTheme(theme: ShellTheme) {
|
|
const root = document.documentElement;
|
|
root.classList.remove("light", "dark");
|
|
root.classList.add(theme);
|
|
window.localStorage.setItem(SHELL_THEME_STORAGE_KEY, theme);
|
|
}
|
|
|
|
export function readShellSessionExpiryEnabled() {
|
|
return window.localStorage.getItem(SHELL_SESSION_EXPIRY_STORAGE_KEY) !== "false";
|
|
}
|
|
|
|
export function writeShellSessionExpiryEnabled(isEnabled: boolean) {
|
|
window.localStorage.setItem(
|
|
SHELL_SESSION_EXPIRY_STORAGE_KEY,
|
|
String(isEnabled),
|
|
);
|
|
}
|
|
|
|
export function buildShellProfileSummary({
|
|
profileName,
|
|
profileEmail,
|
|
fallbackName,
|
|
fallbackEmail,
|
|
}: ShellProfileSummaryParams) {
|
|
const resolvedName = profileName?.trim() || fallbackName;
|
|
const resolvedEmail = profileEmail?.trim() || fallbackEmail;
|
|
|
|
return {
|
|
name: resolvedName,
|
|
email: resolvedEmail,
|
|
initial: resolvedName.charAt(0).toUpperCase(),
|
|
};
|
|
}
|
|
|
|
export function buildShellSessionStatus({
|
|
expiresAtSec,
|
|
nowMs,
|
|
t,
|
|
}: ShellSessionStatusParams) {
|
|
const remainingMs =
|
|
typeof expiresAtSec === "number" ? expiresAtSec * 1000 - nowMs : null;
|
|
const remainingTotalSec =
|
|
remainingMs !== null ? Math.max(0, Math.floor(remainingMs / 1000)) : null;
|
|
const remainingMinutes =
|
|
remainingTotalSec !== null ? Math.floor(remainingTotalSec / 60) : null;
|
|
const remainingSeconds =
|
|
remainingTotalSec !== null ? remainingTotalSec % 60 : null;
|
|
|
|
let toneClass =
|
|
"border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300";
|
|
let text = t("ui.dev.session.active", "세션 활성");
|
|
|
|
if (remainingMs === null) {
|
|
toneClass = "border-border bg-card text-muted-foreground";
|
|
text = t("ui.dev.session.unknown", "알 수 없음");
|
|
} else if (remainingMs <= 0) {
|
|
toneClass =
|
|
"border-rose-500/30 bg-rose-500/10 text-rose-700 dark:text-rose-300";
|
|
text = t("ui.dev.session.expired", "세션 만료");
|
|
} else if (
|
|
remainingMinutes !== null &&
|
|
remainingSeconds !== null &&
|
|
remainingMinutes <= 5
|
|
) {
|
|
toneClass =
|
|
"border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300";
|
|
text = t(
|
|
"ui.dev.session.expiring",
|
|
"만료 임박: {{minutes}}분 {{seconds}}초 남음",
|
|
{
|
|
minutes: remainingMinutes,
|
|
seconds: remainingSeconds,
|
|
},
|
|
);
|
|
} else {
|
|
text = t(
|
|
"ui.dev.session.remaining",
|
|
"만료 예정: {{minutes}}분 {{seconds}}초 남음",
|
|
{
|
|
minutes: remainingMinutes ?? 0,
|
|
seconds: remainingSeconds ?? 0,
|
|
},
|
|
);
|
|
}
|
|
|
|
return {
|
|
toneClass,
|
|
text,
|
|
};
|
|
}
|