From 901798055b7a54459be8dffa3e7fa2e444627ac4 Mon Sep 17 00:00:00 2001 From: Aimsucks Date: Tue, 7 Jun 2022 16:53:51 +0000 Subject: [PATCH] :sparkles: Added primary/secondary color selection Added two new inputs to the options menu: primary and secondary color selectors. --- .../ColorSchemeToggle/ColorSchemeSwitch.tsx | 9 +- src/components/Config/SaveConfig.tsx | 17 +++- src/components/Settings/AdvancedSettings.tsx | 4 +- src/components/Settings/ColorSelector.tsx | 93 +++++++++++++++++++ src/components/Settings/CommonSettings.tsx | 23 +++++ src/components/Settings/ModuleEnabler.tsx | 1 + src/components/layout/Logo.tsx | 6 +- src/pages/_app.tsx | 4 +- src/tools/theme.ts | 1 - src/tools/types.ts | 2 + 10 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 src/components/Settings/ColorSelector.tsx diff --git a/src/components/ColorSchemeToggle/ColorSchemeSwitch.tsx b/src/components/ColorSchemeToggle/ColorSchemeSwitch.tsx index 0da7ae998..9e43a3500 100644 --- a/src/components/ColorSchemeToggle/ColorSchemeSwitch.tsx +++ b/src/components/ColorSchemeToggle/ColorSchemeSwitch.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { createStyles, Switch, Group, useMantineColorScheme, Kbd } from '@mantine/core'; import { IconSun as Sun, IconMoonStars as MoonStars } from '@tabler/icons'; +import { useConfig } from '../../tools/state'; const useStyles = createStyles((theme) => ({ root: { @@ -29,6 +30,7 @@ const useStyles = createStyles((theme) => ({ })); export function ColorSchemeSwitch() { + const { config } = useConfig(); const { colorScheme, toggleColorScheme } = useMantineColorScheme(); const { classes, cx } = useStyles(); @@ -37,7 +39,12 @@ export function ColorSchemeSwitch() {
- toggleColorScheme()} size="md" /> + toggleColorScheme()} + size="md" + />
Switch to {colorScheme === 'dark' ? 'light' : 'dark'} mode diff --git a/src/components/Config/SaveConfig.tsx b/src/components/Config/SaveConfig.tsx index d18b38ae2..79bff863d 100644 --- a/src/components/Config/SaveConfig.tsx +++ b/src/components/Config/SaveConfig.tsx @@ -59,13 +59,20 @@ export default function SaveConfigComponent(props: any) { - - diff --git a/src/components/Settings/AdvancedSettings.tsx b/src/components/Settings/AdvancedSettings.tsx index 7b678f10f..4c06cdd7d 100644 --- a/src/components/Settings/AdvancedSettings.tsx +++ b/src/components/Settings/AdvancedSettings.tsx @@ -36,7 +36,9 @@ export default function TitleChanger() { placeholder="/favicon.svg" {...form.getInputProps('favicon')} /> - + diff --git a/src/components/Settings/ColorSelector.tsx b/src/components/Settings/ColorSelector.tsx new file mode 100644 index 000000000..c54d2dae4 --- /dev/null +++ b/src/components/Settings/ColorSelector.tsx @@ -0,0 +1,93 @@ +import React, { useState } from 'react'; +import { ColorSwatch, Group, Popover, Text, useMantineTheme } from '@mantine/core'; +import { useConfig } from '../../tools/state'; + +interface ColorControlProps { + type: string; +} + +export function ColorSelector({ type }: ColorControlProps) { + const { config, setConfig } = useConfig(); + const [opened, setOpened] = useState(false); + const theme = useMantineTheme(); + const colors = Object.keys(theme.colors).map((color) => ({ + swatch: theme.colors[color][6], + color, + })); + + const configColor = + type === 'primary' + ? config.settings.primary_color || 'red' + : config.settings.secondary_color || 'orange'; + + const setConfigColor = (color: string) => { + if (type === 'primary') { + setConfig({ + ...config, + settings: { + ...config.settings, + primary_color: color, + }, + }); + } else { + setConfig({ + ...config, + settings: { + ...config.settings, + secondary_color: color, + }, + }); + } + }; + + const swatches = colors.map(({ color, swatch }) => ( + setConfigColor(color)} + key={color} + color={swatch} + size={22} + style={{ color: theme.white, cursor: 'pointer' }} + /> + )); + + return ( + + setOpened(false)} + transitionDuration={0} + target={ + setOpened((o) => !o)} + size={22} + style={{ display: 'block', cursor: 'pointer' }} + /> + } + styles={{ + root: { + marginRight: theme.spacing.xs, + }, + body: { + width: 152, + backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[8] : theme.white, + }, + arrow: { + backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[8] : theme.white, + }, + }} + position="bottom" + placement="end" + withArrow + arrowSize={3} + > + {swatches} + + {type[0].toUpperCase() + type.slice(1)} color + + ); +} diff --git a/src/components/Settings/CommonSettings.tsx b/src/components/Settings/CommonSettings.tsx index 3f244c0b6..02cb8e84c 100644 --- a/src/components/Settings/CommonSettings.tsx +++ b/src/components/Settings/CommonSettings.tsx @@ -5,6 +5,8 @@ import { SegmentedControl, TextInput, Anchor, + ColorPicker, + useMantineTheme, } from '@mantine/core'; import { useState } from 'react'; import { IconBrandGithub as BrandGithub } from '@tabler/icons'; @@ -14,6 +16,7 @@ import { ColorSchemeSwitch } from '../ColorSchemeToggle/ColorSchemeSwitch'; import ConfigChanger from '../Config/ConfigChanger'; import SaveConfigComponent from '../Config/SaveConfig'; import ModuleEnabler from './ModuleEnabler'; +import { ColorSelector } from './ColorSelector'; export default function CommonSettings(args: any) { const { config, setConfig } = useConfig(); @@ -30,6 +33,24 @@ export default function CommonSettings(args: any) { matches.find((match) => match.value === config.settings.searchUrl)?.value ?? 'Custom' ); + const theme = useMantineTheme(); + const colors = Object.keys(theme.colors).map((color) => theme.colors[color][6]); + + const [primaryColor, setPrimaryColor] = useState(config.settings.primary_color); + const [secondaryColor, setSecondaryColor] = useState(config.settings.secondary_color); + + // const convertColorHexToNames = (hex: string) => { + // // Have to add some exceptions here because it's not converting cleanly + // let colorName = Object.keys(theme.colors).find((key) => theme.colors[key].includes(hex)); + // if (!colorName) { + // if (hex === '#228ae6') colorName = 'blue'; + // else if (hex === '#15abbf') colorName = 'cyan'; + // else if (hex === '#3fbf57') colorName = 'green'; + // else if (hex === '#fc7d14') colorName = 'orange'; + // } + // return colorName; + // }; + return ( @@ -76,6 +97,8 @@ export default function CommonSettings(args: any) { + + { setConfig({ ...config, diff --git a/src/components/layout/Logo.tsx b/src/components/layout/Logo.tsx index 80097fdb6..48ff1eb0a 100644 --- a/src/components/layout/Logo.tsx +++ b/src/components/layout/Logo.tsx @@ -26,7 +26,11 @@ export function Logo({ style }: any) { sx={style} weight="bold" variant="gradient" - gradient={{ from: 'red', to: 'orange', deg: 145 }} + gradient={{ + from: config.settings.primary_color || 'red', + to: config.settings.secondary_color || 'orange', + deg: 145, + }} > {config.settings.title || 'Homarr'} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 83bcf9c98..939ec0175 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -6,12 +6,13 @@ import Head from 'next/head'; import { MantineProvider, ColorScheme, ColorSchemeProvider } from '@mantine/core'; import { NotificationsProvider } from '@mantine/notifications'; import { useHotkeys } from '@mantine/hooks'; -import { ConfigProvider } from '../tools/state'; +import { ConfigProvider, useConfig } from '../tools/state'; import { theme } from '../tools/theme'; import { styles } from '../tools/styles'; export default function App(props: AppProps & { colorScheme: ColorScheme }) { const { Component, pageProps } = props; + const { config } = useConfig(); const [colorScheme, setColorScheme] = useState(props.colorScheme); const toggleColorScheme = (value?: ColorScheme) => { @@ -33,6 +34,7 @@ export default function App(props: AppProps & { colorScheme: ColorScheme }) {