ERP-node/frontend/lib/contexts/ThemeContext.tsx

168 lines
3.8 KiB
TypeScript

"use client";
import React, { createContext, useContext, useState, useEffect } from "react";
export type ThemeMode = "light" | "dark" | "system";
export type ColorScheme = "orange" | "blue" | "green" | "purple" | "red";
export interface ThemeConfig {
mode: ThemeMode;
colorScheme: ColorScheme;
customColors?: {
primary?: string;
secondary?: string;
accent?: string;
};
}
interface ThemeContextType {
theme: ThemeConfig;
setTheme: (theme: Partial<ThemeConfig>) => void;
toggleMode: () => void;
isDark: boolean;
colors: {
primary: string;
secondary: string;
accent: string;
background: string;
surface: string;
text: string;
textSecondary: string;
border: string;
hover: string;
};
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
const colorSchemes = {
orange: {
primary: "#f97316",
secondary: "#ea580c",
accent: "#fb923c",
},
blue: {
primary: "#3b82f6",
secondary: "#2563eb",
accent: "#60a5fa",
},
green: {
primary: "#10b981",
secondary: "#059669",
accent: "#34d399",
},
purple: {
primary: "#8b5cf6",
secondary: "#7c3aed",
accent: "#a78bfa",
},
red: {
primary: "#ef4444",
secondary: "#dc2626",
accent: "#f87171",
},
};
const lightColors = {
background: "#ffffff",
surface: "#f8fafc",
text: "#1f2937",
textSecondary: "#6b7280",
border: "#e5e7eb",
hover: "#f3f4f6",
};
const darkColors = {
background: "#0f172a",
surface: "#1e293b",
text: "#f1f5f9",
textSecondary: "#94a3b8",
border: "#334155",
hover: "#334155",
};
export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [theme, setThemeState] = useState<ThemeConfig>({
mode: "system",
colorScheme: "orange",
});
const [isDark, setIsDark] = useState(false);
// 시스템 테마 감지
useEffect(() => {
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleChange = () => {
if (theme.mode === "system") {
setIsDark(mediaQuery.matches);
}
};
handleChange();
mediaQuery.addEventListener("change", handleChange);
return () => mediaQuery.removeEventListener("change", handleChange);
}, [theme.mode]);
// 테마 모드에 따른 다크모드 설정
useEffect(() => {
switch (theme.mode) {
case "light":
setIsDark(false);
break;
case "dark":
setIsDark(true);
break;
case "system":
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
setIsDark(mediaQuery.matches);
break;
}
}, [theme.mode]);
const setTheme = (newTheme: Partial<ThemeConfig>) => {
setThemeState(prev => ({ ...prev, ...newTheme }));
};
const toggleMode = () => {
setThemeState(prev => ({
...prev,
mode: prev.mode === "light" ? "dark" : "light"
}));
};
const baseColors = colorSchemes[theme.colorScheme];
const themeColors = isDark ? darkColors : lightColors;
const colors = {
primary: theme.customColors?.primary || baseColors.primary,
secondary: theme.customColors?.secondary || baseColors.secondary,
accent: theme.customColors?.accent || baseColors.accent,
background: themeColors.background,
surface: themeColors.surface,
text: themeColors.text,
textSecondary: themeColors.textSecondary,
border: themeColors.border,
hover: themeColors.hover,
};
return (
<ThemeContext.Provider value={{
theme,
setTheme,
toggleMode,
isDark,
colors,
}}>
{children}
</ThemeContext.Provider>
);
};
export const useTheme = () => {
const context = useContext(ThemeContext);
if (context === undefined) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
};