diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx deleted file mode 100644 index 5b3ccbd4b..000000000 --- a/src/components/layout/Layout.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { AppShell, createStyles } from '@mantine/core'; - -import { useConfigContext } from '../../config/provider'; -import { Background } from './Background'; -import { Head } from './Meta/Head'; -import { Header } from './header/Header'; - -const useStyles = createStyles(() => ({})); - -export default function Layout({ children }: any) { - const { cx } = useStyles(); - const { config } = useConfigContext(); - - return ( - } - styles={{ - main: { - minHeight: 'calc(100vh - var(--mantine-header-height))', - }, - }} - className="dashboard-app-shell" - > - - - {children} - - - ); -} diff --git a/src/components/layout/Templates/BoardLayout.tsx b/src/components/layout/Templates/BoardLayout.tsx new file mode 100644 index 000000000..27ed51013 --- /dev/null +++ b/src/components/layout/Templates/BoardLayout.tsx @@ -0,0 +1,196 @@ +import { Button, Text, Title, Tooltip, clsx } from '@mantine/core'; +import { useHotkeys, useWindowEvent } from '@mantine/hooks'; +import { openContextModal } from '@mantine/modals'; +import { hideNotification, showNotification } from '@mantine/notifications'; +import { + IconApps, + IconBrandDocker, + IconEditCircle, + IconEditCircleOff, + IconSettings, +} from '@tabler/icons-react'; +import Consola from 'consola'; +import { useSession } from 'next-auth/react'; +import { Trans, useTranslation } from 'next-i18next'; +import Link from 'next/link'; +import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore'; +import { useNamedWrapperColumnCount } from '~/components/Dashboard/Wrappers/gridstack/store'; +import { useConfigContext } from '~/config/provider'; +import { env } from '~/env'; +import { api } from '~/utils/api'; + +import { Background } from '../Background'; +import { HeaderActionButton } from '../Header/ActionButton'; +import { MainLayout } from './MainLayout'; + +type BoardLayoutProps = { + children: React.ReactNode; +}; + +export const BoardLayout = ({ children }: BoardLayoutProps) => { + const { config } = useConfigContext(); + + return ( + }> + + {children} + + + ); +}; + +export const HeaderActions = () => { + const { data: sessionData } = useSession(); + + if (!sessionData?.user?.isAdmin) return null; + + return ( + <> + {env.NEXT_PUBLIC_DOCKER_ENABLED && } + + + + ); +}; + +const DockerButton = () => { + const { t } = useTranslation('modules/docker'); + + return ( + + + + + + ); +}; + +const CustomizeBoardButton = () => { + const { name } = useConfigContext(); + + return ( + + + + + + ); +}; + +const beforeUnloadEventText = 'Exit the edit mode to save your changes'; +const editModeNotificationId = 'toggle-edit-mode'; + +const ToggleEditModeButton = () => { + const { enabled, toggleEditMode } = useEditModeStore(); + const { config, name: configName } = useConfigContext(); + const { mutateAsync: saveConfig } = api.config.save.useMutation(); + const namedWrapperColumnCount = useNamedWrapperColumnCount(); + const { t } = useTranslation(['layout/header/actions/toggle-edit-mode', 'common']); + const translatedSize = + namedWrapperColumnCount !== null + ? t(`common:breakPoints.${namedWrapperColumnCount}`) + : t('common:loading'); + + useHotkeys([['mod+E', toggleEditMode]]); + + useWindowEvent('beforeunload', (event: BeforeUnloadEvent) => { + if (enabled) { + // eslint-disable-next-line no-param-reassign + event.returnValue = beforeUnloadEventText; + return beforeUnloadEventText; + } + + return undefined; + }); + + const save = async () => { + toggleEditMode(); + if (!config || !configName) return; + await saveConfig({ name: configName, config }); + Consola.log('Saved config to server', configName); + hideNotification(editModeNotificationId); + }; + + const enableEditMode = () => { + toggleEditMode(); + showNotification({ + styles: (theme) => ({ + root: { + backgroundColor: theme.colors.orange[7], + borderColor: theme.colors.orange[7], + + '&::before': { backgroundColor: theme.white }, + }, + title: { color: theme.white }, + description: { color: theme.white }, + closeButton: { + color: theme.white, + '&:hover': { backgroundColor: theme.colors.orange[7] }, + }, + }), + radius: 'md', + id: 'toggle-edit-mode', + autoClose: 10000, + title: ( + + <Trans + i18nKey="layout/header/actions/toggle-edit-mode:popover.title" + values={{ size: translatedSize }} + components={{ + 1: ( + <Text + component="a" + style={{ color: 'inherit', textDecoration: 'underline' }} + href="https://homarr.dev/docs/customizations/layout" + target="_blank" + /> + ), + }} + /> + + ), + message: , + }); + }; + + if (enabled) { + return ( + + + + + + + + + ); + } + return ( + + + + + + ); +}; + +const AddElementButton = () => { + const { t } = useTranslation('layout/element-selector/selector'); + + return ( + + + openContextModal({ + modal: 'selectElement', + title: t('modal.title'), + size: 'xl', + innerProps: {}, + }) + } + > + + + + ); +}; diff --git a/src/components/layout/main.tsx b/src/components/layout/Templates/MainLayout.tsx similarity index 58% rename from src/components/layout/main.tsx rename to src/components/layout/Templates/MainLayout.tsx index fae324091..dd1e393f5 100644 --- a/src/components/layout/main.tsx +++ b/src/components/layout/Templates/MainLayout.tsx @@ -1,9 +1,7 @@ -import { AppShell, clsx, useMantineTheme } from '@mantine/core'; -import { useConfigContext } from '~/config/provider'; +import { AppShell, useMantineTheme } from '@mantine/core'; -import { Background } from './Background'; -import { Head } from './Meta/Head'; -import { MainHeader } from './new-header/Header'; +import { MainHeader } from '../Header/Header'; +import { Head } from '../Meta/Head'; type MainLayoutProps = { headerActions?: React.ReactNode; @@ -11,7 +9,6 @@ type MainLayoutProps = { }; export const MainLayout = ({ headerActions, children }: MainLayoutProps) => { - const { config } = useConfigContext(); const theme = useMantineTheme(); return ( @@ -25,9 +22,7 @@ export const MainLayout = ({ headerActions, children }: MainLayoutProps) => { className="dashboard-app-shell" > - {children} - ); }; diff --git a/src/components/layout/admin/main-admin.layout.tsx b/src/components/layout/Templates/ManageLayout.tsx similarity index 86% rename from src/components/layout/admin/main-admin.layout.tsx rename to src/components/layout/Templates/ManageLayout.tsx index 8423e6d7c..ff32aba6d 100644 --- a/src/components/layout/admin/main-admin.layout.tsx +++ b/src/components/layout/Templates/ManageLayout.tsx @@ -1,61 +1,45 @@ import { AppShell, - Avatar, - Box, Burger, Drawer, Flex, Footer, Group, - Header, - Menu, NavLink, Navbar, Paper, Text, - TextInput, ThemeIcon, - UnstyledButton, useMantineTheme, } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { - IconAlertTriangle, IconBook2, IconBrandDiscord, IconBrandGithub, - IconDashboard, IconGitFork, IconHome, IconLayoutDashboard, - IconLogout, IconMailForward, IconQuestionMark, IconSettings2, - IconSun, IconUser, - IconUserSearch, IconUsers, } from '@tabler/icons-react'; -import { signOut } from 'next-auth/react'; -import { useTranslation } from 'next-i18next'; -import Head from 'next/head'; import Image from 'next/image'; import Link from 'next/link'; import { ReactNode } from 'react'; import { useScreenLargerThan } from '~/hooks/useScreenLargerThan'; import { usePackageAttributesStore } from '~/tools/client/zustands/usePackageAttributesStore'; -import { Logo } from '../Logo'; +import { MainHeader } from '../Header/Header'; import { CommonHeader } from '../common-header'; -import { MainHeader } from '../new-header/Header'; -interface MainLayoutProps { +interface ManageLayoutProps { children: ReactNode; } -export const MainLayout = ({ children }: MainLayoutProps) => { - const { t } = useTranslation(); +export const ManageLayout = ({ children }: ManageLayoutProps) => { const { attributes } = usePackageAttributesStore(); const theme = useMantineTheme(); @@ -153,7 +137,9 @@ export const MainLayout = ({ children }: MainLayoutProps) => { ); - const burgerMenu = screenLargerThanMd ? undefined : ; + const burgerMenu = screenLargerThanMd ? undefined : ( + + ); return ( <> @@ -171,13 +157,7 @@ export const MainLayout = ({ children }: MainLayoutProps) => { } - header={ - - } + header={} footer={