From e81e8ead788ed71ab3cc0e3b22f1df5d1ea4f4e5 Mon Sep 17 00:00:00 2001 From: Nikki Sharpley Date: Tue, 8 Aug 2023 18:00:02 -0400 Subject: [PATCH] adjust hex values --- .../ThemeBuilder/ThemeBuilder.tsx | 60 +++++++++++++++---- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/admin/src/react-components/ThemeBuilder/ThemeBuilder.tsx b/admin/src/react-components/ThemeBuilder/ThemeBuilder.tsx index 7e5795ba76..0fbbd3d2b4 100644 --- a/admin/src/react-components/ThemeBuilder/ThemeBuilder.tsx +++ b/admin/src/react-components/ThemeBuilder/ThemeBuilder.tsx @@ -6,6 +6,22 @@ import { CategoryE } from '@mozilla/lilypad-ui'; import { NotificationTypesE } from '@mozilla/lilypad-ui'; import { NotificationLocationE } from '@mozilla/lilypad-ui'; +type themeT = { + name: string, + variables: Record, + id: string; + default?: boolean +} + +type ThemeBuilderP = { + config: Record, + onGlobalChange: (path:string, val: string) => void, + onSave: (e:React.SyntheticEvent) => void, + setState: (state:Record) => void, + path: string, + disableSave: boolean, +} + const success: NewNotificationT = { title: "", description: "Copied them JSON to clipboard!", @@ -16,9 +32,9 @@ const success: NewNotificationT = { }; const error: NewNotificationT = {...success, type: NotificationTypesE.ERROR, description: "Unable to copy JSON to clipboard."} -const ThemeBuilder = ({config, onGlobalChange, onSave, path, setState, disableSave}) => { - const [themes, setThemes] =useState(JSON.parse(config?.hubs?.theme?.themes)) - const [selectedTheme, setSelectedTheme] = useState(themes.find(theme => !!theme?.default) || themes[0]) +const ThemeBuilder = ({config, onGlobalChange, onSave, path, setState, disableSave}:ThemeBuilderP) => { + const [themes, setThemes] =useState(JSON.parse(config?.hubs?.theme?.themes)) + const [selectedTheme, setSelectedTheme] = useState(themes.find(theme => !!theme?.default) || themes[0]) const [jsonInput, setJsonInput] = useState("") const [jsonError, setJsonError] = useState("") const formattedThemes = useMemo(() => themes.map(theme => ({title: theme.name, value: theme.id})), [themes, config]); @@ -28,24 +44,24 @@ const ThemeBuilder = ({config, onGlobalChange, onSave, path, setState, disableSa console.log(config) }, [config]) - const onThemeSelect = e => { + const onThemeSelect = (e: React.SyntheticEvent) => { e.preventDefault() setSelectedTheme(themes.find(theme => theme.id === e.target.value)) } - const onSubmit = e => { + const onSubmit = (e: React.SyntheticEvent) => { onSave(e) setThemes(prevState => [...prevState.filter(theme => theme.id !== selectedTheme.id), selectedTheme]) } - const onVariableChange = (e, key )=> { + const onVariableChange = (e:React.ChangeEvent, key:string )=> { e.preventDefault() e.persist() setSelectedTheme(prevState => ({...prevState, variables: {...prevState.variables, [key]: e.target.value}})) onGlobalChange(path, JSON.stringify([...themes.filter(theme => theme.id !== selectedTheme.id), {...selectedTheme, variables: {...selectedTheme.variables, [key]: e.target.value}}])) } - const onNameChange = (e )=> { + const onNameChange = (e:React.ChangeEvent )=> { e.preventDefault() e.persist() setSelectedTheme(prevState => ({...prevState, name: e.target.value})) @@ -70,7 +86,7 @@ const ThemeBuilder = ({config, onGlobalChange, onSave, path, setState, disableSa setSelectedTheme(newTheme) } - const deleteTheme = e => { + const deleteTheme = (e:React.SyntheticEvent) => { onGlobalChange(path, JSON.stringify(themes.filter(theme => theme.id !== selectedTheme.id))) setThemes(prevState => prevState.filter(theme => theme.id !== selectedTheme.id)) setSelectedTheme(themes[0]) @@ -87,7 +103,7 @@ const ThemeBuilder = ({config, onGlobalChange, onSave, path, setState, disableSa }); } - const importThemeFromJson = e => { + const importThemeFromJson = (e:React.SyntheticEvent) => { e.preventDefault() const newTheme = e.target[0].value; setSelectedTheme(JSON.parse(newTheme)) @@ -124,6 +140,28 @@ const ThemeBuilder = ({config, onGlobalChange, onSave, path, setState, disableSa return true } + const adjustHexColor = (hex:string, percent:number) => { + // Validate input + if (!/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(hex)) { + throw new Error("Invalid hex color code"); + } + + // Convert hex to RGB + let r = parseInt(hex.slice(1, 3), 16); + let g = parseInt(hex.slice(3, 5), 16); + let b = parseInt(hex.slice(5), 16); + + // Calculate lighten or darken values. A negative percent darkens. + r = Math.min(255, r + Math.round(255 * (percent / 100))); + g = Math.min(255, g + Math.round(255 * (percent / 100))); + b = Math.min(255, b + Math.round(255 * (percent / 100))); + + // Convert back to hex + const newHex = `#${(r << 16 | g << 8 | b).toString(16).padStart(6, '0')}`; + + return newHex; + } + // edit name and validate no duplicates // add new theme // duplicate theme @@ -131,11 +169,11 @@ const ThemeBuilder = ({config, onGlobalChange, onSave, path, setState, disableSa // copy json // import theme from json - validate and populate missing variables // delete theme + // calculate darkness or lightness from states // import theme from web url?? - validate and populate missing variables // select from github themes // populate with defaults - // calculate darkness or lightness from states return (
@@ -151,7 +189,7 @@ const ThemeBuilder = ({config, onGlobalChange, onSave, path, setState, disableSa
{Object.entries(selectedTheme.variables).map(([key, value]) => { - return onVariableChange(e, key)}/> + return onVariableChange(e, key)} placeholder={''}/> })}