173 lines
6.1 KiB
TypeScript
173 lines
6.1 KiB
TypeScript
import { useTheme } from '@tamagui/core';
|
|
|
|
export const ADMIN_COLORS = {
|
|
primary: '#4F46E5', // Indigo 600
|
|
primaryStrong: '#4338CA', // Indigo 700
|
|
accent: '#F43F5E', // Rose 500
|
|
accentSoft: '#E0E7FF', // Indigo 100
|
|
accentWarm: '#FFE4E6', // Rose 100
|
|
warning: '#F59E0B', // Amber 500
|
|
success: '#10B981', // Emerald 500
|
|
danger: '#EF4444', // Red 500
|
|
text: '#0F172A', // Slate 900
|
|
textMuted: '#64748B', // Slate 500
|
|
textSubtle: '#94A3B8', // Slate 400
|
|
border: '#E2E8F0', // Slate 200
|
|
surface: '#FFFFFF',
|
|
surfaceMuted: '#F8FAFC', // Slate 50
|
|
backdrop: '#0F172A',
|
|
};
|
|
|
|
export const ADMIN_ACTION_COLORS = {
|
|
settings: '#64748B', // Slate 500
|
|
tasks: '#F43F5E', // Rose 500 (Accent)
|
|
qr: '#10B981', // Emerald 500
|
|
images: '#4F46E5', // Indigo 600 (Primary)
|
|
liveShow: '#F59E0B', // Amber 500
|
|
liveShowSettings: '#6366F1', // Indigo 500
|
|
guests: '#334155', // Slate 700
|
|
guestMessages: '#4F46E5',
|
|
branding: '#6366F1',
|
|
photobooth: '#8B5CF6', // Violet 500
|
|
recap: '#94A3B8',
|
|
packages: '#4F46E5',
|
|
analytics: '#10B981',
|
|
invites: '#10B981',
|
|
};
|
|
|
|
export const ADMIN_GRADIENTS = {
|
|
primaryCta: `linear-gradient(135deg, ${ADMIN_COLORS.primary}, ${ADMIN_COLORS.primaryStrong})`,
|
|
softCard: 'linear-gradient(145deg, rgba(255,255,255,1), rgba(248,250,252,0.95))',
|
|
loginBackground: 'linear-gradient(135deg, #0F172A, #1E293B, #0F172A)',
|
|
appBackground: 'linear-gradient(180deg, #F1F5F9 0%, #F1F5F9 100%)',
|
|
appBackgroundDark: 'linear-gradient(180deg, #0F172A 0%, #1E293B 100%)',
|
|
};
|
|
|
|
export const ADMIN_MOTION = {
|
|
tileStaggerMs: 40,
|
|
};
|
|
|
|
type Rgb = { r: number; g: number; b: number };
|
|
|
|
function parseRgb(color: string): Rgb | null {
|
|
const trimmed = color.trim();
|
|
if (trimmed.startsWith('#')) {
|
|
const hex = trimmed.slice(1);
|
|
const normalized = hex.length === 3 ? hex.split('').map((ch) => ch + ch).join('') : hex;
|
|
if (normalized.length === 6) {
|
|
return {
|
|
r: Number.parseInt(normalized.slice(0, 2), 16),
|
|
g: Number.parseInt(normalized.slice(2, 4), 16),
|
|
b: Number.parseInt(normalized.slice(4, 6), 16),
|
|
};
|
|
}
|
|
}
|
|
|
|
const rgb = trimmed.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/i);
|
|
if (rgb) {
|
|
return { r: Number(rgb[1]), g: Number(rgb[2]), b: Number(rgb[3]) };
|
|
}
|
|
|
|
const rgba = trimmed.match(/^rgba\((\d+),\s*(\d+),\s*(\d+),\s*([0-9.]+)\)$/i);
|
|
if (rgba) {
|
|
return { r: Number(rgba[1]), g: Number(rgba[2]), b: Number(rgba[3]) };
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function withAlpha(color: string, alpha: number): string {
|
|
const rgb = parseRgb(color);
|
|
if (! rgb) {
|
|
return color;
|
|
}
|
|
|
|
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`;
|
|
}
|
|
|
|
function isDarkColor(color: string): boolean {
|
|
const rgb = parseRgb(color);
|
|
if (! rgb) {
|
|
return false;
|
|
}
|
|
|
|
const luminance = (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255;
|
|
return luminance < 0.5;
|
|
}
|
|
|
|
export function useAdminTheme() {
|
|
const theme = useTheme();
|
|
|
|
const cssValue = (name: string): string => {
|
|
if (typeof document === 'undefined') {
|
|
return '';
|
|
}
|
|
|
|
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
};
|
|
|
|
const cssBackground = cssValue('--background');
|
|
const cssSurface = cssValue('--surface');
|
|
const cssMuted = cssValue('--muted');
|
|
const cssBorder = cssValue('--borderColor');
|
|
const cssText = cssValue('--color');
|
|
|
|
const background = cssBackground || String(theme.background?.val ?? ADMIN_COLORS.surfaceMuted);
|
|
const isDark = isDarkColor(background);
|
|
|
|
// Resolve core colors
|
|
const primary = String(theme.primary?.val ?? ADMIN_COLORS.primary);
|
|
const surface = cssSurface || String(theme.surface?.val ?? (isDark ? '#0F1B36' : ADMIN_COLORS.surface));
|
|
const border = cssBorder || String(theme.borderColor?.val ?? (isDark ? '#1F2A4A' : ADMIN_COLORS.border));
|
|
const text = cssText || String(theme.color?.val ?? (isDark ? '#F8FAFF' : ADMIN_COLORS.text));
|
|
|
|
// Muted/Subtle should NOT use theme.muted (which is a background color in Tamagui standard)
|
|
// Instead, we derive them from Text with opacity or use specific palette values if available
|
|
// But safer is Alpha since it works in both Light (Dark Text) and Dark (Light Text) modes.
|
|
const muted = withAlpha(text, 0.65);
|
|
const subtle = withAlpha(text, 0.45);
|
|
const surfaceMuted = cssMuted || String(theme.muted?.val ?? (isDark ? '#121F3D' : ADMIN_COLORS.surfaceMuted));
|
|
|
|
const glassSurface = withAlpha(surface, isDark ? 0.90 : 0.85);
|
|
const glassSurfaceStrong = withAlpha(surface, isDark ? 0.96 : 0.95);
|
|
const glassBorder = withAlpha(border, 0.5);
|
|
const glassShadow = isDark ? 'rgba(0, 0, 0, 0.55)' : 'rgba(15, 23, 42, 0.08)';
|
|
const appBackground = isDark ? ADMIN_GRADIENTS.appBackgroundDark : ADMIN_GRADIENTS.appBackground;
|
|
|
|
return {
|
|
theme,
|
|
background,
|
|
surface,
|
|
surfaceMuted,
|
|
border,
|
|
text,
|
|
textStrong: text, // Alias
|
|
textMuted: muted, // Alias for legacy usage
|
|
textSubtle: subtle, // Alias for legacy usage
|
|
muted, // Now properly derived from text color
|
|
subtle, // Now properly derived from text color
|
|
primary,
|
|
accent: String(theme.accent?.val ?? ADMIN_COLORS.accent),
|
|
accentSoft: String(theme.blue3?.val ?? ADMIN_COLORS.accentSoft),
|
|
accentStrong: String(theme.blue11?.val ?? ADMIN_COLORS.primaryStrong),
|
|
successBg: String(theme.backgroundStrong?.val ?? '#DCFCE7'),
|
|
successText: String(theme.green10?.val ?? ADMIN_COLORS.success),
|
|
dangerBg: String(theme.red3?.val ?? '#FEE2E2'),
|
|
dangerText: String(theme.red11?.val ?? ADMIN_COLORS.danger),
|
|
warningBg: String(theme.yellow3?.val ?? '#FEF3C7'),
|
|
warningBorder: String(theme.yellow6?.val ?? '#FCD34D'),
|
|
warningText: String(theme.yellow11?.val ?? ADMIN_COLORS.warning),
|
|
infoBg: String(theme.blue3?.val ?? ADMIN_COLORS.accentSoft),
|
|
infoText: String(theme.blue10?.val ?? ADMIN_COLORS.primaryStrong),
|
|
danger: String(theme.danger?.val ?? ADMIN_COLORS.danger),
|
|
backdrop: String(theme.backgroundStrong?.val ?? ADMIN_COLORS.backdrop),
|
|
overlay: withAlpha(String(theme.backgroundStrong?.val ?? ADMIN_COLORS.backdrop), 0.6),
|
|
shadow: String(theme.shadowColor?.val ?? 'rgba(15, 23, 42, 0.08)'),
|
|
glassSurface,
|
|
glassSurfaceStrong,
|
|
glassBorder,
|
|
glassShadow,
|
|
appBackground,
|
|
};
|
|
}
|