mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-09 23:15:46 +01:00
✨ Ability to change title and icons
This commit is contained in:
49
src/components/Settings/AdvancedSettings.tsx
Normal file
49
src/components/Settings/AdvancedSettings.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { TextInput, Group, Button } from '@mantine/core';
|
||||
import { useState } from 'react';
|
||||
import { useConfig } from '../../tools/state';
|
||||
|
||||
export default function TitleChanger() {
|
||||
const { config, loadConfig, setConfig, getConfigs } = useConfig();
|
||||
const [customTitle, setCustomTitle] = useState(config.title);
|
||||
const [customLogo, setCustomLogo] = useState(config.logo);
|
||||
const [customFavicon, setCustomFavicon] = useState(config.favicon);
|
||||
|
||||
const saveChanges = () => {
|
||||
setConfig({
|
||||
...config,
|
||||
title: customTitle || "Homarr 🦞",
|
||||
logo: customLogo || "/imgs/logo.png",
|
||||
favicon: customFavicon || "/favicon.svg",
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Group grow direction="column">
|
||||
<TextInput
|
||||
label="Page title"
|
||||
defaultValue={config.title}
|
||||
value={customTitle}
|
||||
onChange={(event) => setCustomTitle(event.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Logo"
|
||||
defaultValue={config.logo}
|
||||
value={customLogo}
|
||||
onChange={(event) => setCustomLogo(event.currentTarget.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label="Favicon"
|
||||
defaultValue={config.favicon}
|
||||
value={customFavicon}
|
||||
onChange={(event) => setCustomFavicon(event.currentTarget.value)}
|
||||
/>
|
||||
<Button
|
||||
variant="gradient"
|
||||
gradient={{ from: 'red', to: 'orange' }}
|
||||
onClick={() => saveChanges()}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
TextInput,
|
||||
Drawer,
|
||||
Anchor,
|
||||
Tabs
|
||||
} from '@mantine/core';
|
||||
import { useColorScheme, useHotkeys } from '@mantine/hooks';
|
||||
import { useState } from 'react';
|
||||
@@ -18,6 +19,7 @@ import { ColorSchemeSwitch } from '../ColorSchemeToggle/ColorSchemeSwitch';
|
||||
import ConfigChanger from '../Config/ConfigChanger';
|
||||
import SaveConfigComponent from '../Config/SaveConfig';
|
||||
import ModuleEnabler from './ModuleEnabler';
|
||||
import AdvancedSettings from './AdvancedSettings';
|
||||
|
||||
function SettingsMenu(props: any) {
|
||||
const { config, setConfig } = useConfig();
|
||||
@@ -37,95 +39,102 @@ function SettingsMenu(props: any) {
|
||||
);
|
||||
|
||||
return (
|
||||
<Group direction="column" grow>
|
||||
<Group grow direction="column" spacing={0}>
|
||||
<Text>Search engine</Text>
|
||||
<SegmentedControl
|
||||
fullWidth
|
||||
title="Search engine"
|
||||
value={
|
||||
// Match config.settings.searchUrl with a key in the matches array
|
||||
searchUrl
|
||||
}
|
||||
onChange={
|
||||
// Set config.settings.searchUrl to the value of the selected item
|
||||
(e) => {
|
||||
setSearchUrl(e);
|
||||
setConfig({
|
||||
...config,
|
||||
settings: {
|
||||
...config.settings,
|
||||
searchUrl: e,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
data={matches}
|
||||
/>
|
||||
{searchUrl === 'Custom' && (
|
||||
<TextInput
|
||||
label="Query URL"
|
||||
placeholder="Custom query url"
|
||||
value={customSearchUrl}
|
||||
onChange={(event) => {
|
||||
setCustomSearchUrl(event.currentTarget.value);
|
||||
setConfig({
|
||||
...config,
|
||||
settings: {
|
||||
...config.settings,
|
||||
searchUrl: event.currentTarget.value,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
<ModuleEnabler />
|
||||
<ColorSchemeSwitch />
|
||||
<ConfigChanger />
|
||||
<SaveConfigComponent />
|
||||
<Text
|
||||
style={{
|
||||
alignSelf: 'center',
|
||||
fontSize: '0.75rem',
|
||||
textAlign: 'center',
|
||||
color: 'gray',
|
||||
}}
|
||||
>
|
||||
Tip: You can upload your config file by dragging and dropping it onto the page!
|
||||
</Text>
|
||||
<Group position="center" direction="row" mr="xs">
|
||||
<Group spacing={0}>
|
||||
<ActionIcon<'a'> component="a" href="https://github.com/ajnart/homarr" size="lg">
|
||||
<BrandGithub size={18} />
|
||||
</ActionIcon>
|
||||
<Tabs>
|
||||
<Tabs.Tab label="Settings">
|
||||
<Group direction="column" grow>
|
||||
<Group grow direction="column" spacing={0}>
|
||||
<Text>Search engine</Text>
|
||||
<SegmentedControl
|
||||
fullWidth
|
||||
title="Search engine"
|
||||
value={
|
||||
// Match config.settings.searchUrl with a key in the matches array
|
||||
searchUrl
|
||||
}
|
||||
onChange={
|
||||
// Set config.settings.searchUrl to the value of the selected item
|
||||
(e) => {
|
||||
setSearchUrl(e);
|
||||
setConfig({
|
||||
...config,
|
||||
settings: {
|
||||
...config.settings,
|
||||
searchUrl: e,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
data={matches}
|
||||
/>
|
||||
{searchUrl === 'Custom' && (
|
||||
<TextInput
|
||||
label="Query URL"
|
||||
placeholder="Custom query url"
|
||||
value={customSearchUrl}
|
||||
onChange={(event) => {
|
||||
setCustomSearchUrl(event.currentTarget.value);
|
||||
setConfig({
|
||||
...config,
|
||||
settings: {
|
||||
...config.settings,
|
||||
searchUrl: event.currentTarget.value,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
<ModuleEnabler />
|
||||
<ColorSchemeSwitch />
|
||||
<ConfigChanger />
|
||||
<SaveConfigComponent />
|
||||
<Text
|
||||
style={{
|
||||
position: 'relative',
|
||||
fontSize: '0.90rem',
|
||||
alignSelf: 'center',
|
||||
fontSize: '0.75rem',
|
||||
textAlign: 'center',
|
||||
color: 'gray',
|
||||
}}
|
||||
>
|
||||
{CURRENT_VERSION}
|
||||
Tip: You can upload your config file by dragging and dropping it onto the page!
|
||||
</Text>
|
||||
<Group position="center" direction="row" mr="xs">
|
||||
<Group spacing={0}>
|
||||
<ActionIcon<'a'> component="a" href="https://github.com/ajnart/homarr" size="lg">
|
||||
<BrandGithub size={18} />
|
||||
</ActionIcon>
|
||||
<Text
|
||||
style={{
|
||||
position: 'relative',
|
||||
fontSize: '0.90rem',
|
||||
color: 'gray',
|
||||
}}
|
||||
>
|
||||
{CURRENT_VERSION}
|
||||
</Text>
|
||||
</Group>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: '0.90rem',
|
||||
textAlign: 'center',
|
||||
color: 'gray',
|
||||
}}
|
||||
>
|
||||
Made with ❤️ by @
|
||||
<Anchor
|
||||
href="https://github.com/ajnart"
|
||||
style={{ color: 'inherit', fontStyle: 'inherit', fontSize: 'inherit' }}
|
||||
>
|
||||
ajnart
|
||||
</Anchor>
|
||||
</Text>
|
||||
</Group>
|
||||
</Group>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: '0.90rem',
|
||||
textAlign: 'center',
|
||||
color: 'gray',
|
||||
}}
|
||||
>
|
||||
Made with ❤️ by @
|
||||
<Anchor
|
||||
href="https://github.com/ajnart"
|
||||
style={{ color: 'inherit', fontStyle: 'inherit', fontSize: 'inherit' }}
|
||||
>
|
||||
ajnart
|
||||
</Anchor>
|
||||
</Text>
|
||||
</Group>
|
||||
</Group>
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab label="Advanced">
|
||||
<AdvancedSettings />
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
14
src/components/layout/HeaderConfig.tsx
Normal file
14
src/components/layout/HeaderConfig.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import Head from 'next/head';
|
||||
import { useConfig } from '../../tools/state';
|
||||
|
||||
export function HeaderConfig(props: any) {
|
||||
const { config } = useConfig();
|
||||
|
||||
return (
|
||||
<Head>
|
||||
<title>{config.title ?? "Homarr 🦞"}</title>
|
||||
<link rel="shortcut icon" href={config.favicon ?? "/favicon.svg"} />
|
||||
</Head>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
import { Group, Image, Text } from '@mantine/core';
|
||||
import { NextLink } from '@mantine/next';
|
||||
import * as React from 'react';
|
||||
import { useConfig } from '../../tools/state';
|
||||
|
||||
export function Logo({ style }: any) {
|
||||
const { config } = useConfig();
|
||||
|
||||
return (
|
||||
<Group spacing="xs">
|
||||
<Image
|
||||
width={50}
|
||||
src="/imgs/logo.png"
|
||||
src={config.logo ?? "/imgs/logo.png"}
|
||||
style={{
|
||||
position: 'relative',
|
||||
}}
|
||||
@@ -25,7 +28,8 @@ export function Logo({ style }: any) {
|
||||
variant="gradient"
|
||||
gradient={{ from: 'red', to: 'orange', deg: 145 }}
|
||||
>
|
||||
Homarr
|
||||
{/* Added the .replace to remove emojis because they get screwed up by the gradient */}
|
||||
{config.title.replace(/([\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g, '') ?? "Homarr"}
|
||||
</Text>
|
||||
</NextLink>
|
||||
</Group>
|
||||
|
||||
@@ -10,6 +10,9 @@ export function getConfig(name: string) {
|
||||
configName: name,
|
||||
config: {
|
||||
name: name.toString(),
|
||||
title: 'Homarr 🦞',
|
||||
logo: '/imgs/logo.png',
|
||||
favicon: '/favicon.svg',
|
||||
services: [],
|
||||
settings: {
|
||||
searchUrl: 'https://www.google.com/search?q=',
|
||||
|
||||
@@ -15,14 +15,17 @@ type configContextType = {
|
||||
const configContext = createContext<configContextType>({
|
||||
config: {
|
||||
name: 'default',
|
||||
title: 'Homarr 🦞',
|
||||
logo: '/imgs/logo.png',
|
||||
favicon: '/favicon.svg',
|
||||
services: [],
|
||||
settings: {
|
||||
searchUrl: 'https://google.com/search?q=',
|
||||
},
|
||||
modules: {},
|
||||
},
|
||||
setConfig: () => {},
|
||||
loadConfig: async (name: string) => {},
|
||||
setConfig: () => { },
|
||||
loadConfig: async (name: string) => { },
|
||||
getConfigs: async () => [],
|
||||
});
|
||||
|
||||
@@ -41,6 +44,9 @@ type Props = {
|
||||
export function ConfigProvider({ children }: Props) {
|
||||
const [config, setConfigInternal] = useState<Config>({
|
||||
name: 'default',
|
||||
title: 'Homarr 🦞',
|
||||
logo: '/imgs/logo.png',
|
||||
favicon: '/favicon.svg',
|
||||
services: [],
|
||||
settings: {
|
||||
searchUrl: 'https://www.google.com/search?q=',
|
||||
|
||||
@@ -6,6 +6,9 @@ export interface Settings {
|
||||
|
||||
export interface Config {
|
||||
name: string;
|
||||
title: string;
|
||||
logo: string;
|
||||
favicon: string;
|
||||
services: serviceItem[];
|
||||
settings: Settings;
|
||||
modules: {
|
||||
|
||||
Reference in New Issue
Block a user