From 61c55acd50b454e543029d95fdbed594c6de2a0b Mon Sep 17 00:00:00 2001 From: Bjorn L Date: Wed, 18 May 2022 16:55:48 +0200 Subject: [PATCH 1/6] =?UTF-8?q?=F0=9F=93=9D=20Adds=20Request=20Icons=20sec?= =?UTF-8?q?tion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index f92a99571..10e33c9c0 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ - [๐Ÿ“Š Modules](#-modules) - [๐Ÿ” Search Bar](#-search-bar) - [๐Ÿ’– Contributing](#-contributing) + - [๐Ÿ Request Icons](#-request-icons) @@ -187,5 +188,11 @@ The Search Bar will open any Search Query after the Query URL you've specified i **Please read our [Contribution Guidelines](/CONTRIBUTING.md)** All contributions are highly appreciated. + +**[โคด๏ธ Back to Top](#-table-of-contents)** + +## ๐Ÿ Request Icons + +The icons used in Homarr are automatically requested from the [dashboard-icons](https://github.com/walkxhub/dashboard-icons) repo. You can make a icon request by creating an [issue](https://github.com/walkxhub/dashboard-icons/issues/new/choose). **[โคด๏ธ Back to Top](#-table-of-contents)** From 7e5602c88155321c80b1708d078286dcb78e00a0 Mon Sep 17 00:00:00 2001 From: ajnart Date: Wed, 18 May 2022 22:07:28 +0200 Subject: [PATCH 2/6] :rotating_light: Update eslint config Co-authored-by: Bjorn L. --- .eslintrc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.js b/.eslintrc.js index b682aa9dc..abde8f7cb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,6 +20,7 @@ module.exports = { }, rules: { 'react/react-in-jsx-scope': 'off', + 'react/no-children-prop': 'off', "unused-imports/no-unused-imports": "warn", "@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/no-unused-imports": "off", From 879581224a00d0070ef9068fbebeccfa242cf879 Mon Sep 17 00:00:00 2001 From: ajnart Date: Wed, 18 May 2022 22:08:09 +0200 Subject: [PATCH 3/6] :fire: Remove update indicator from settings Co-authored-by: Bjorn L. --- src/components/Settings/SettingsMenu.tsx | 40 +++--------------------- 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/src/components/Settings/SettingsMenu.tsx b/src/components/Settings/SettingsMenu.tsx index cbd30c987..ed7c425c6 100644 --- a/src/components/Settings/SettingsMenu.tsx +++ b/src/components/Settings/SettingsMenu.tsx @@ -2,19 +2,15 @@ import { ActionIcon, Group, Modal, - Switch, Title, Text, Tooltip, SegmentedControl, - Indicator, - Alert, TextInput, } from '@mantine/core'; import { useColorScheme } from '@mantine/hooks'; -import { useEffect, useState } from 'react'; -import { AlertCircle, Settings as SettingsIcon } from 'tabler-icons-react'; -import { CURRENT_VERSION, REPO_URL } from '../../../data/constants'; +import { useState } from 'react'; +import { Settings as SettingsIcon } from 'tabler-icons-react'; import { useConfig } from '../../tools/state'; import { ColorSchemeSwitch } from '../ColorSchemeToggle/ColorSchemeSwitch'; import ConfigChanger from '../Config/ConfigChanger'; @@ -40,14 +36,6 @@ function SettingsMenu(props: any) { return ( - } - title="Update available" - radius="lg" - hidden={current === latest} - > - Version {latest} is available. Current: {current} - Search engine { - // Fetch Data here when component first mounted - fetch(`https://api.github.com/repos/${REPO_URL}/releases/latest`).then((res) => { - res.json().then((data) => { - setLatestVersion(data.tag_name); - if (data.tag_name !== CURRENT_VERSION) { - setUpdate(true); - } - }); - }); - }, []); return ( <> setOpened(false)} > - + setOpened(true)} > - - - + From 0400188ea7ccedc056e77f187a67a7fc5b5cf4af Mon Sep 17 00:00:00 2001 From: ajnart Date: Wed, 18 May 2022 22:09:13 +0200 Subject: [PATCH 4/6] :truck: Move the update indicator to the Footer Co-authored-by: Bjorn L. --- src/components/layout/Footer.tsx | 104 +++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 27 deletions(-) diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index e93a4ff7f..b944eb5f5 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { createStyles, Anchor, @@ -6,9 +6,11 @@ import { Group, ActionIcon, Footer as FooterComponent, + Alert, + useMantineTheme, } from '@mantine/core'; -import { BrandGithub } from 'tabler-icons-react'; -import { CURRENT_VERSION } from '../../../data/constants'; +import { AlertCircle, BrandGithub } from 'tabler-icons-react'; +import { CURRENT_VERSION, REPO_URL } from '../../../data/constants'; const useStyles = createStyles((theme) => ({ footer: { @@ -41,6 +43,8 @@ interface FooterCenteredProps { } export function Footer({ links }: FooterCenteredProps) { + const [update, setUpdate] = useState(false); + const theme = useMantineTheme(); const { classes } = useStyles(); const items = links.map((link) => ( @@ -55,42 +59,88 @@ export function Footer({ links }: FooterCenteredProps) { )); + const [latestVersion, setLatestVersion] = useState(CURRENT_VERSION); + const [isOpen, setOpen] = useState(true); + useEffect(() => { + // Fetch Data here when component first mounted + fetch(`https://api.github.com/repos/${REPO_URL}/releases/latest`).then((res) => { + res.json().then((data) => { + setLatestVersion(data.tag_name); + if (data.tag_name !== CURRENT_VERSION) { + setUpdate(true); + } + }); + }); + }, []); + return ( - - - component="a" href="https://github.com/ajnart/homarr" size="lg"> - - + + + setOpen(false)} + icon={} + title={`Updated version: ${latestVersion} is available. Current version: ${CURRENT_VERSION}`} + withCloseButton + radius="lg" + hidden={CURRENT_VERSION === latestVersion || !isOpen} + variant="outline" + styles={{ + root: { + backgroundColor: + theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[1], + }, + + closeButton: { + marginLeft: '5px', + }, + }} + children={undefined} + /> + + + + component="a" href="https://github.com/ajnart/homarr" size="lg"> + + + + {CURRENT_VERSION} + + - {CURRENT_VERSION} + Made with โค๏ธ by @ + + ajnart + - - Made with โค๏ธ by @ - - ajnart - - ); From b0be26300e89cf8b328f6a79ee805f512de06288 Mon Sep 17 00:00:00 2001 From: ajnart Date: Wed, 18 May 2022 22:10:31 +0200 Subject: [PATCH 5/6] :lipstick: Update AppShell menu and item styling Co-authored-by: Bjorn L. --- src/components/AppShelf/AppShelf.tsx | 4 ++-- src/components/AppShelf/AppShelfMenu.tsx | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/AppShelf/AppShelf.tsx b/src/components/AppShelf/AppShelf.tsx index 761320294..41ac8baf5 100644 --- a/src/components/AppShelf/AppShelf.tsx +++ b/src/components/AppShelf/AppShelf.tsx @@ -52,8 +52,8 @@ export function AppShelfItem(props: any) { setOpened(false)} title="Modify a service" @@ -28,7 +29,16 @@ export default function AppShelfMenu(props: any) { message="Save service" /> - + Settings Date: Wed, 18 May 2022 22:11:37 +0200 Subject: [PATCH 6/6] :sparkles: Add a proceudally generated options manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows for options in settings generated based on their name in module config. Very important change ๐Ÿง™โ€ --- src/components/modules/date/DateModule.tsx | 31 ++++++---- src/components/modules/moduleWrapper.tsx | 67 +++++++++++++++++++++- src/components/modules/modules.tsx | 11 +++- 3 files changed, 94 insertions(+), 15 deletions(-) diff --git a/src/components/modules/date/DateModule.tsx b/src/components/modules/date/DateModule.tsx index ba653f862..7b31f859e 100644 --- a/src/components/modules/date/DateModule.tsx +++ b/src/components/modules/date/DateModule.tsx @@ -2,6 +2,7 @@ import { Group, Text, Title } from '@mantine/core'; import dayjs from 'dayjs'; import { useEffect, useState } from 'react'; import { Clock } from 'tabler-icons-react'; +import { useConfig } from '../../../tools/state'; import { IModule } from '../modules'; export const DateModule: IModule = { @@ -9,33 +10,39 @@ export const DateModule: IModule = { description: 'Show the current time and date in a card', icon: Clock, component: DateComponent, + options: { + full: { + name: 'Display full time (24-hour)', + value: true, + }, + }, }; export default function DateComponent(props: any) { const [date, setDate] = useState(new Date()); + const { config } = useConfig(); const hours = date.getHours(); const minutes = date.getMinutes(); - + const fullSetting = config.settings[`${DateModule.title}.full`]; // Change date on minute change // Note: Using 10 000ms instead of 1000ms to chill a little :) useEffect(() => { setInterval(() => { setDate(new Date()); - }, 10000); + }, 1000 * 60); }, []); + const timeString = `${hours < 10 ? `0${hours}` : hours}:${ + minutes < 10 ? `0${minutes}` : minutes + }`; + const halfTimeString = `${hours < 10 ? `${hours % 12}` : hours % 12}:${ + minutes < 10 ? `0${minutes}` : minutes + } ${hours < 12 ? 'AM' : 'PM'}`; + const finalTimeString = fullSetting ? timeString : halfTimeString; return ( - - {hours < 10 ? `0${hours}` : hours}:{minutes < 10 ? `0${minutes}` : minutes} - - - { - // Use dayjs to format the date - // https://day.js.org/en/getting-started/installation/ - dayjs(date).format('dddd, MMMM D') - } - + {finalTimeString} + {dayjs(date).format('dddd, MMMM D')} ); } diff --git a/src/components/modules/moduleWrapper.tsx b/src/components/modules/moduleWrapper.tsx index 55b421a5e..d081f013d 100644 --- a/src/components/modules/moduleWrapper.tsx +++ b/src/components/modules/moduleWrapper.tsx @@ -1,19 +1,82 @@ -import { Card, useMantineTheme } from '@mantine/core'; +import { Card, Menu, Switch, useMantineTheme } from '@mantine/core'; import { useConfig } from '../../tools/state'; import { IModule } from './modules'; export default function ModuleWrapper(props: any) { const { module }: { module: IModule } = props; - const { config } = useConfig(); + const { config, setConfig } = useConfig(); const enabledModules = config.settings.enabledModules ?? []; // Remove 'Module' from enabled modules titles const isShown = enabledModules.includes(module.title); const theme = useMantineTheme(); + const items: JSX.Element[] = []; + if (module.options) { + const keys = Object.keys(module.options); + const values = Object.values(module.options); + // Get the value and the name of the option + const types = values.map((v) => typeof v.value); + // Loop over all the types with a for each loop + types.forEach((type, index) => { + const optionName = `${module.title}.${keys[index]}`; + // TODO: Add support for other types + if (type === 'boolean') { + items.push( + { + setConfig({ + ...config, + settings: { + ...config.settings, + enabledModules: [...config.settings.enabledModules], + [optionName]: e.currentTarget.checked, + }, + }); + }} + label={values[index].name} + /> + ); + } + }); + } + // Sussy baka if (!isShown) { return null; } return ( ); diff --git a/src/components/modules/modules.tsx b/src/components/modules/modules.tsx index 60ce7d55d..c3c3ef1dd 100644 --- a/src/components/modules/modules.tsx +++ b/src/components/modules/modules.tsx @@ -7,5 +7,14 @@ export interface IModule { description: string; icon: React.ReactNode; component: React.ComponentType; - props?: any; + options?: Option; +} + +interface Option { + [x: string]: OptionValues; +} + +interface OptionValues { + name: string; + value: boolean; }