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) {
- } variant="outline" onClick={onClick}>
+ }
+ variant="outline"
+ color={config.settings.primary_color || 'red'}
+ onClick={onClick}
+ >
Download config
}
variant="outline"
+ color={config.settings.primary_color || 'red'}
onClick={() => {
axios
.delete(`/api/configs/${config.name}`)
@@ -94,7 +101,13 @@ export default function SaveConfigComponent(props: any) {
>
Delete config
- } variant="outline" onClick={() => setOpened(true)}>
+ }
+ variant="outline"
+ color={config.settings.primary_color || 'red'}
+ onClick={() => setOpened(true)}
+ >
Save a copy
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 }) {