Live video on the AT Protocol
1import { useMemo, type ReactNode } from "react";
2import {
3 useAccentColor,
4 usePrimaryColor,
5 useStreamplaceStore,
6} from "../../streamplace-store";
7import { ThemeProvider, type Theme } from "./theme";
8
9interface BrandedThemeProviderProps {
10 children: ReactNode;
11 defaultTheme?: "light" | "dark" | "system";
12 forcedTheme?: "light" | "dark";
13}
14
15/**
16 * ThemeProvider wrapper that automatically applies branding colors from the
17 * broadcaster's branding configuration.
18 */
19export function BrandedThemeProvider({
20 children,
21 defaultTheme,
22 forcedTheme,
23}: BrandedThemeProviderProps) {
24 const primaryColor = usePrimaryColor();
25 const accentColor = useAccentColor();
26 const brandingLoading = useStreamplaceStore((state) => state.brandingLoading);
27
28 // Build color theme overrides from branding
29 const colorTheme = useMemo<Partial<Theme["colors"]>>(() => {
30 // don't override until branding is loaded
31 if (brandingLoading) {
32 return {};
33 }
34
35 const overrides: Partial<Theme["colors"]> = {};
36
37 if (primaryColor) {
38 overrides.primary = primaryColor;
39 overrides.ring = primaryColor;
40 }
41
42 if (accentColor) {
43 overrides.accent = accentColor;
44 }
45
46 return overrides;
47 }, [primaryColor, accentColor, brandingLoading]);
48
49 return (
50 <ThemeProvider
51 defaultTheme={defaultTheme}
52 forcedTheme={forcedTheme}
53 colorTheme={colorTheme}
54 >
55 {children}
56 </ThemeProvider>
57 );
58}