From 901798055b7a54459be8dffa3e7fa2e444627ac4 Mon Sep 17 00:00:00 2001 From: Aimsucks Date: Tue, 7 Jun 2022 16:53:51 +0000 Subject: [PATCH 01/23] :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 }) { Date: Tue, 7 Jun 2022 17:36:05 +0000 Subject: [PATCH 02/23] :sparkles: Added a background image input Added an input in the advanced options for a background image. Also removed an unused import from my previous commit and changed the margin on the header bar to padding instead. --- src/components/Settings/AdvancedSettings.tsx | 10 +++++++++- src/components/Settings/CommonSettings.tsx | 1 - src/components/layout/Aside.tsx | 1 + src/components/layout/Background.tsx | 19 +++++++++++++++++++ src/components/layout/Header.tsx | 2 +- src/components/layout/Layout.tsx | 2 ++ src/tools/types.ts | 1 + 7 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 src/components/layout/Background.tsx diff --git a/src/components/Settings/AdvancedSettings.tsx b/src/components/Settings/AdvancedSettings.tsx index 4c06cdd7d..0840517fd 100644 --- a/src/components/Settings/AdvancedSettings.tsx +++ b/src/components/Settings/AdvancedSettings.tsx @@ -10,10 +10,16 @@ export default function TitleChanger() { title: config.settings.title, logo: config.settings.logo, favicon: config.settings.favicon, + background: config.settings.background, }, }); - const saveChanges = (values: { title?: string; logo?: string; favicon?: string }) => { + const saveChanges = (values: { + title?: string; + logo?: string; + favicon?: string; + background?: string; + }) => { setConfig({ ...config, settings: { @@ -21,6 +27,7 @@ export default function TitleChanger() { title: values.title, logo: values.logo, favicon: values.favicon, + background: values.background, }, }); }; @@ -36,6 +43,7 @@ export default function TitleChanger() { placeholder="/favicon.svg" {...form.getInputProps('favicon')} /> + diff --git a/src/components/Settings/CommonSettings.tsx b/src/components/Settings/CommonSettings.tsx index 02cb8e84c..5f347fe0a 100644 --- a/src/components/Settings/CommonSettings.tsx +++ b/src/components/Settings/CommonSettings.tsx @@ -5,7 +5,6 @@ import { SegmentedControl, TextInput, Anchor, - ColorPicker, useMantineTheme, } from '@mantine/core'; import { useState } from 'react'; diff --git a/src/components/layout/Aside.tsx b/src/components/layout/Aside.tsx index 8fafc5708..2a12a98e1 100644 --- a/src/components/layout/Aside.tsx +++ b/src/components/layout/Aside.tsx @@ -28,6 +28,7 @@ export default function Aside(props: any) { className={cx(classes.hide)} style={{ border: 'none', + background: 'none', }} width={{ base: 'auto', diff --git a/src/components/layout/Background.tsx b/src/components/layout/Background.tsx new file mode 100644 index 000000000..0c17374d4 --- /dev/null +++ b/src/components/layout/Background.tsx @@ -0,0 +1,19 @@ +import { Global } from '@mantine/core'; +import { useConfig } from '../../tools/state'; + +export function Background() { + const { config } = useConfig(); + + return ( + + ); +} diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 1cfb218a5..20374f609 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -41,7 +41,7 @@ export function Header(props: any) { return ( - + diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx index d9ccbccb7..975e51776 100644 --- a/src/components/layout/Layout.tsx +++ b/src/components/layout/Layout.tsx @@ -3,6 +3,7 @@ import { Header } from './Header'; import { Footer } from './Footer'; import Aside from './Aside'; import { HeaderConfig } from './HeaderConfig'; +import { Background } from './Background'; const useStyles = createStyles((theme) => ({ main: {}, @@ -13,6 +14,7 @@ export default function Layout({ children, style }: any) { return ( } header={
} footer={