Maharshi Alpesh 0250ced3d7
fix: fixing the layout color (#4879)
fix: adding tooltip to show items which are only for the visual purpose

fix: persist the theme across reloads

chore: modifying the mobile styles
2025-02-20 11:31:01 -03:00

357 lines
8.7 KiB
TypeScript

import {useState, createContext, useContext} from "react";
import {useLocalStorage} from "usehooks-ts";
import {configKey, initialConfig} from "./constants";
import {
ConfigColors,
Config,
ConfigLayout,
ThemeType,
Radius,
TemplateType,
FontType,
HeroUIScaling,
Border,
} from "./types";
export interface ThemeBuilderContextProps {
config: Config;
radiusValue: Radius;
borderWidthValue: Border;
templateTheme: TemplateType;
font: FontType | undefined;
scaling: HeroUIScaling;
resetConfig: (theme: ThemeType, sync: boolean) => Config;
setLayoutColor: (
newConfig: Partial<ConfigColors["layoutColor"]>,
theme: ThemeType,
sync: boolean,
) => void;
setContentColor: (newConfig: Partial<ConfigColors["contentColor"]>, theme: ThemeType) => void;
setBorderWidth: (newConfig: Partial<ConfigLayout["borderWidth"]>) => void;
setBaseColor: (
newConfig: Partial<ConfigColors["baseColor"]>,
theme: ThemeType,
sync: boolean,
) => void;
setDefaultColor: (
newConfig: Partial<ConfigColors["defaultColor"]>,
theme: ThemeType,
sync: boolean,
) => void;
setConfiguration: (newConfig: Config, theme: ThemeType, sync: boolean) => void;
setLineHeight: (newConfig: Partial<ConfigLayout["lineHeight"]>) => void;
setFontSize: (newConfig: Partial<ConfigLayout["fontSize"]>) => void;
setOtherParams: (newConfig: Partial<ConfigLayout["otherParams"]>) => void;
setRadius: (newConfig: Partial<ConfigLayout["radius"]>) => void;
setRadiusValue: (radius: Radius) => void;
setBorderWidthValue: (borderWidth: Border) => void;
setTemplateTheme: (theme: TemplateType) => void;
setFont: (font: FontType) => void;
setScaling: (scale: HeroUIScaling) => void;
}
const ThemeBuilderContext = createContext<ThemeBuilderContextProps>({
config: initialConfig,
radiusValue: "md",
borderWidthValue: "thick",
templateTheme: "heroui",
font: "Inter",
scaling: 100,
resetConfig: () => initialConfig,
setLayoutColor: () => {},
setBorderWidth: () => {},
setBaseColor: () => {},
setConfiguration: () => {},
setLineHeight: () => {},
setFontSize: () => {},
setOtherParams: () => {},
setRadius: () => {},
setDefaultColor: () => {},
setContentColor: () => {},
setRadiusValue: () => {},
setBorderWidthValue: () => {},
setTemplateTheme: () => {},
setFont: () => {},
setScaling: () => {},
});
interface ThemeBuilderProviderProps {
children: React.ReactNode;
}
export default function ThemeBuilderProvider({children}: ThemeBuilderProviderProps) {
const [lsConfig] = useLocalStorage<Config>(configKey, initialConfig);
const [config, setConfig] = useState<Config>(lsConfig);
const [radiusValue, setRadiusValue] = useState<Radius>("sm");
const [borderWidthValue, setBorderWidthValue] = useState<Border>("thin");
const [templateTheme, setTemplateTheme] = useState<TemplateType>("heroui");
const [font, setFont] = useState<FontType | undefined>(undefined);
const [scaling, setScaling] = useState<HeroUIScaling>(100);
const setConfiguration = (newConfig: Config, theme: ThemeType, sync: boolean) => {
setConfig((prev) =>
sync
? newConfig
: {
...prev,
[theme]: newConfig[theme],
},
);
};
const setTemplate = (template: TemplateType) => {
setTemplateTheme(template);
setConfig((prev) => {
return {
...prev,
name: template,
};
});
};
const resetConfig = (theme: ThemeType, sync: boolean) => {
let newConfig = initialConfig;
setConfig((prev) => {
newConfig = sync
? newConfig
: {
...prev,
[theme]: newConfig[theme],
layout: newConfig.layout,
};
return newConfig;
});
return newConfig;
};
const setBaseColor = (
newConfig: Partial<ConfigColors["baseColor"]>,
theme: ThemeType,
sync: boolean,
) => {
setConfig((prev) =>
sync
? {
...prev,
light: {
...prev.light,
baseColor: {
...prev.light.baseColor,
...newConfig,
},
},
dark: {
...prev.dark,
baseColor: {
...prev.dark.baseColor,
...newConfig,
},
},
}
: {
...prev,
[theme]: {
...prev[theme],
baseColor: {
...prev[theme].baseColor,
...newConfig,
},
},
},
);
};
const setDefaultColor = (
newConfig: Partial<ConfigColors["defaultColor"]>,
theme: ThemeType,
sync: boolean,
) => {
setConfig((prev) =>
sync
? {
...prev,
light: {
...prev.light,
defaultColor: {
...prev.light.defaultColor,
...newConfig,
},
},
dark: {
...prev.dark,
defaultColor: {
...prev.dark.defaultColor,
...newConfig,
},
},
}
: {
...prev,
[theme]: {
...prev[theme],
defaultColor: {
...prev[theme].defaultColor,
...newConfig,
},
},
},
);
};
const setContentColor = (newConfig: Partial<ConfigColors["contentColor"]>, theme: ThemeType) => {
setConfig((prev) => ({
...prev,
[theme]: {
...prev[theme],
contentColor: {
...prev[theme].contentColor,
...newConfig,
},
},
}));
};
const setLayoutColor = (
newConfig: Partial<ConfigColors["layoutColor"]>,
theme: ThemeType,
sync: boolean,
) => {
setConfig((prev) =>
sync
? {
...prev,
light: {
...prev.light,
layoutColor: {
...prev.light.layoutColor,
...newConfig,
},
},
dark: {
...prev.dark,
layoutColor: {
...prev.dark.layoutColor,
...newConfig,
},
},
}
: {
...prev,
[theme]: {
...prev[theme],
layoutColor: {
...prev[theme].layoutColor,
...newConfig,
},
},
},
);
};
const setBorderWidth = (newBorderWidths: Partial<ConfigLayout["borderWidth"]>) =>
setConfig((prev) => ({
...prev,
layout: {
...prev.layout,
borderWidth: {
...prev.layout.borderWidth,
...newBorderWidths,
},
},
}));
const setLineHeight = (newLineHeights: Partial<ConfigLayout["lineHeight"]>) =>
setConfig((prev) => ({
...prev,
layout: {
...prev.layout,
lineHeight: {
...prev.layout.lineHeight,
...newLineHeights,
},
},
}));
const setFontSize = (newFontSizes: Partial<ConfigLayout["fontSize"]>) =>
setConfig((prev) => ({
...prev,
layout: {
...prev.layout,
fontSize: {
...prev.layout.fontSize,
...newFontSizes,
},
},
}));
const setRadius = (newRadius: Partial<ConfigLayout["radius"]>) =>
setConfig((prev) => ({
...prev,
layout: {
...prev.layout,
radius: {
...prev.layout.radius,
...newRadius,
},
},
}));
const setOtherParams = (newOtherParams: Partial<ConfigLayout["otherParams"]>) =>
setConfig((prev) => ({
...prev,
layout: {
...prev.layout,
otherParams: {
...prev.layout.otherParams,
...newOtherParams,
},
},
}));
return (
<ThemeBuilderContext.Provider
value={{
config,
radiusValue,
borderWidthValue,
templateTheme,
font,
scaling,
resetConfig,
setLayoutColor,
setBorderWidth,
setBaseColor,
setConfiguration,
setLineHeight,
setFontSize,
setOtherParams,
setRadius,
setDefaultColor,
setContentColor,
setRadiusValue,
setBorderWidthValue,
setTemplateTheme: setTemplate,
setFont,
setScaling,
}}
>
{children}
</ThemeBuilderContext.Provider>
);
}
// Create a custom hook to use the ThemeBuilderContext
export function useThemeBuilder(): ThemeBuilderContextProps {
const context = useContext(ThemeBuilderContext);
if (!context) {
throw new Error("useThemeBuilder must be used within a ThemeBuilderProvider");
}
return context;
}