Commit completed Torbat Pages admin frontend module, BFF proxy, routes, and validation artifacts for official platform deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
81 lines
2.2 KiB
TypeScript
81 lines
2.2 KiB
TypeScript
"use client";
|
|
|
|
import { createContext, useContext, useEffect, useMemo, type ReactNode } from "react";
|
|
|
|
export type ExperienceBrandTokens = {
|
|
accent?: string;
|
|
accentSoft?: string;
|
|
success?: string;
|
|
warning?: string;
|
|
danger?: string;
|
|
};
|
|
|
|
export type ExperienceDirection = "rtl" | "ltr";
|
|
|
|
type ThemeContextValue = {
|
|
direction: ExperienceDirection;
|
|
brand: ExperienceBrandTokens;
|
|
tenantThemeId?: string | null;
|
|
};
|
|
|
|
const ExperienceThemeContext = createContext<ThemeContextValue>({
|
|
direction: "rtl",
|
|
brand: {},
|
|
tenantThemeId: null,
|
|
});
|
|
|
|
export function useExperienceTheme() {
|
|
return useContext(ExperienceThemeContext);
|
|
}
|
|
|
|
/** Applies tenant/brand CSS variables on a scoped subtree; inherits platform light/dark. */
|
|
export function ExperienceThemeProvider({
|
|
children,
|
|
direction = "rtl",
|
|
brand,
|
|
tenantThemeId,
|
|
className,
|
|
}: {
|
|
children: ReactNode;
|
|
direction?: ExperienceDirection;
|
|
brand?: ExperienceBrandTokens;
|
|
tenantThemeId?: string | null;
|
|
className?: string;
|
|
}) {
|
|
const value = useMemo(
|
|
() => ({
|
|
direction,
|
|
brand: brand ?? {},
|
|
tenantThemeId: tenantThemeId ?? null,
|
|
}),
|
|
[direction, brand, tenantThemeId]
|
|
);
|
|
|
|
useEffect(() => {
|
|
const root = document.documentElement;
|
|
root.setAttribute("data-experience-dir", direction);
|
|
}, [direction]);
|
|
|
|
const style: React.CSSProperties = {
|
|
direction,
|
|
...(brand?.accent ? { ["--experience-accent" as string]: brand.accent } : {}),
|
|
...(brand?.accentSoft ? { ["--experience-accent-soft" as string]: brand.accentSoft } : {}),
|
|
...(brand?.success ? { ["--experience-success" as string]: brand.success } : {}),
|
|
...(brand?.warning ? { ["--experience-warning" as string]: brand.warning } : {}),
|
|
...(brand?.danger ? { ["--experience-danger" as string]: brand.danger } : {}),
|
|
};
|
|
|
|
return (
|
|
<ExperienceThemeContext.Provider value={value}>
|
|
<div
|
|
className={className}
|
|
data-experience-theme={tenantThemeId ?? "default"}
|
|
data-experience-dir={direction}
|
|
style={style}
|
|
>
|
|
{children}
|
|
</div>
|
|
</ExperienceThemeContext.Provider>
|
|
);
|
|
}
|