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: (
+
+
+ ),
+ }}
+ />
+
+ ),
+ 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={