67 lines
2.1 KiB
TypeScript
67 lines
2.1 KiB
TypeScript
import { Theme } from '@tamagui/core';
|
|
import React from 'react';
|
|
import type { Appearance } from '@/hooks/use-appearance';
|
|
import { useAppearance } from '@/hooks/use-appearance';
|
|
import { useEventBranding } from '@/guest/context/EventBrandingContext';
|
|
import { relativeLuminance } from '@/guest/lib/color';
|
|
import type { EventBranding } from '@/guest/types/event-branding';
|
|
|
|
const LIGHT_LUMINANCE_THRESHOLD = 0.65;
|
|
const DARK_LUMINANCE_THRESHOLD = 0.35;
|
|
|
|
type ThemeVariant = 'light' | 'dark';
|
|
|
|
function resolveThemeVariant(
|
|
mode: EventBranding['mode'],
|
|
backgroundColor: string,
|
|
appearanceOverride: 'light' | 'dark' | null
|
|
): ThemeVariant {
|
|
const prefersDark =
|
|
typeof window !== 'undefined' && typeof window.matchMedia === 'function'
|
|
? window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
: false;
|
|
const backgroundLuminance = relativeLuminance(backgroundColor);
|
|
const backgroundPrefers =
|
|
backgroundLuminance >= LIGHT_LUMINANCE_THRESHOLD
|
|
? 'light'
|
|
: backgroundLuminance <= DARK_LUMINANCE_THRESHOLD
|
|
? 'dark'
|
|
: null;
|
|
|
|
if (appearanceOverride) {
|
|
return appearanceOverride;
|
|
}
|
|
|
|
if (mode === 'dark') {
|
|
return 'dark';
|
|
}
|
|
|
|
if (mode === 'light') {
|
|
return 'light';
|
|
}
|
|
|
|
if (backgroundPrefers) {
|
|
return backgroundPrefers;
|
|
}
|
|
|
|
return prefersDark ? 'dark' : 'light';
|
|
}
|
|
|
|
export function resolveGuestThemeName(
|
|
branding: EventBranding,
|
|
appearance: Appearance
|
|
): 'guestLight' | 'guestNight' {
|
|
const appearanceOverride = appearance === 'light' || appearance === 'dark' ? appearance : null;
|
|
const background = branding.backgroundColor || branding.palette?.background || '#ffffff';
|
|
const variant = resolveThemeVariant(branding.mode ?? 'auto', background, appearanceOverride);
|
|
return variant === 'dark' ? 'guestNight' : 'guestLight';
|
|
}
|
|
|
|
export function BrandingTheme({ children }: { children: React.ReactNode }) {
|
|
const { branding } = useEventBranding();
|
|
const { appearance } = useAppearance();
|
|
const themeName = resolveGuestThemeName(branding, appearance);
|
|
|
|
return <Theme name={themeName}>{children}</Theme>;
|
|
}
|