🚧 Add board, Improve header
This commit is contained in:
@@ -5,12 +5,16 @@ import { useConfigContext } from '../../config/provider';
|
||||
export function Background() {
|
||||
const { config } = useConfigContext();
|
||||
|
||||
if (!config?.settings.customization.backgroundImageUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Global
|
||||
styles={{
|
||||
body: {
|
||||
minHeight: '100vh',
|
||||
backgroundImage: `url('${config?.settings.customization.backgroundImageUrl}')` || '',
|
||||
backgroundImage: `url('${config?.settings.customization.backgroundImageUrl}')`,
|
||||
backgroundPosition: 'center center',
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
|
||||
@@ -2,8 +2,8 @@ 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';
|
||||
import { Head } from './header/Meta/Head';
|
||||
|
||||
const useStyles = createStyles(() => ({}));
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import NextHead from 'next/head';
|
||||
import React from 'react';
|
||||
|
||||
import { useConfigContext } from '../../../../config/provider';
|
||||
import { useConfigContext } from '../../../config/provider';
|
||||
import { SafariStatusBarStyle } from './SafariStatusBarStyle';
|
||||
|
||||
export function Head() {
|
||||
@@ -1,13 +1,19 @@
|
||||
import { AppShell, useMantineTheme } from '@mantine/core';
|
||||
import { AppShell, clsx, useMantineTheme } from '@mantine/core';
|
||||
import { useConfigContext } from '~/config/provider';
|
||||
|
||||
import { Background } from './Background';
|
||||
import { Head } from './Meta/Head';
|
||||
import { MainHeader } from './new-header/Header';
|
||||
|
||||
type MainLayoutProps = {
|
||||
headerActions?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export const MainLayout = ({ children }: MainLayoutProps) => {
|
||||
export const MainLayout = ({ headerActions, children }: MainLayoutProps) => {
|
||||
const { config } = useConfigContext();
|
||||
const theme = useMantineTheme();
|
||||
|
||||
return (
|
||||
<AppShell
|
||||
styles={{
|
||||
@@ -15,9 +21,13 @@ export const MainLayout = ({ children }: MainLayoutProps) => {
|
||||
background: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[1],
|
||||
},
|
||||
}}
|
||||
header={<MainHeader />}
|
||||
header={<MainHeader headerActions={headerActions} />}
|
||||
className="dashboard-app-shell"
|
||||
>
|
||||
<Head />
|
||||
<Background />
|
||||
{children}
|
||||
<style>{clsx(config?.settings.customization.customCss)}</style>
|
||||
</AppShell>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,25 +9,29 @@ import {
|
||||
IconSun,
|
||||
IconUserCog,
|
||||
} from '@tabler/icons-react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { User } from 'next-auth';
|
||||
import { signOut, useSession } from 'next-auth/react';
|
||||
import Link from 'next/link';
|
||||
import { forwardRef } from 'react';
|
||||
import { AboutModal } from '~/components/Dashboard/Modals/AboutModal/AboutModal';
|
||||
import { useColorScheme } from '~/hooks/use-colorscheme';
|
||||
import { usePackageAttributesStore } from '~/tools/client/zustands/usePackageAttributesStore';
|
||||
|
||||
import { REPO_URL } from '../../../../data/constants';
|
||||
|
||||
export const AvatarMenu = () => {
|
||||
const newVersionAvailable = '0.13.0';
|
||||
const [aboutModalOpened, aboutModal] = useDisclosure(false);
|
||||
const { data: sessionData } = useSession();
|
||||
const { colorScheme, toggleColorScheme } = useColorScheme();
|
||||
const newVersionAvailable = useNewVersionAvailable();
|
||||
|
||||
const Icon = colorScheme === 'dark' ? IconSun : IconMoonStars;
|
||||
|
||||
return (
|
||||
<>
|
||||
<UnstyledButton>
|
||||
<Menu>
|
||||
<Menu width={192}>
|
||||
<Menu.Target>
|
||||
<CurrentUserAvatar user={sessionData?.user ?? null} />
|
||||
</Menu.Target>
|
||||
@@ -88,6 +92,7 @@ export const AvatarMenu = () => {
|
||||
type CurrentUserAvatarProps = {
|
||||
user: User | null;
|
||||
};
|
||||
|
||||
const CurrentUserAvatar = forwardRef<HTMLDivElement, CurrentUserAvatarProps>(
|
||||
({ user, ...others }, ref) => {
|
||||
const { primaryColor } = useMantineTheme();
|
||||
@@ -99,3 +104,15 @@ const CurrentUserAvatar = forwardRef<HTMLDivElement, CurrentUserAvatarProps>(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const useNewVersionAvailable = () => {
|
||||
const { attributes } = usePackageAttributesStore();
|
||||
const { data } = useQuery({
|
||||
queryKey: ['github/latest'],
|
||||
cacheTime: 1000 * 60 * 60 * 24,
|
||||
staleTime: 1000 * 60 * 60 * 5,
|
||||
queryFn: () =>
|
||||
fetch(`https://api.github.com/repos/${REPO_URL}/releases/latest`).then((res) => res.json()),
|
||||
});
|
||||
return data?.tag_name > `v${attributes.packageVersion}` ? data?.tag_name : undefined;
|
||||
};
|
||||
|
||||
@@ -1,24 +1,8 @@
|
||||
import {
|
||||
Anchor,
|
||||
Avatar,
|
||||
Box,
|
||||
Flex,
|
||||
Group,
|
||||
Header,
|
||||
Menu,
|
||||
Text,
|
||||
TextInput,
|
||||
UnstyledButton,
|
||||
} from '@mantine/core';
|
||||
import {
|
||||
IconAlertTriangle,
|
||||
IconDashboard,
|
||||
IconLogout,
|
||||
IconSun,
|
||||
IconUserSearch,
|
||||
} from '@tabler/icons-react';
|
||||
import { signOut } from 'next-auth/react';
|
||||
import { Box, Flex, Group, Header, Text, UnstyledButton, useMantineTheme } from '@mantine/core';
|
||||
import { useMediaQuery } from '@mantine/hooks';
|
||||
import { IconAlertTriangle } from '@tabler/icons-react';
|
||||
import Link from 'next/link';
|
||||
import { useScreenLargerThan } from '~/hooks/useScreenLargerThan';
|
||||
|
||||
import { Logo } from '../Logo';
|
||||
import { AvatarMenu } from './AvatarMenu';
|
||||
@@ -27,21 +11,33 @@ import { Search } from './search';
|
||||
type MainHeaderProps = {
|
||||
logoHref?: string;
|
||||
showExperimental?: boolean;
|
||||
headerActions?: React.ReactNode;
|
||||
};
|
||||
|
||||
export const MainHeader = ({ showExperimental = false, logoHref = '/' }: MainHeaderProps) => {
|
||||
const headerHeight = showExperimental ? 60 + 30 : 60;
|
||||
export const MainHeader = ({
|
||||
showExperimental = false,
|
||||
logoHref = '/',
|
||||
headerActions,
|
||||
}: MainHeaderProps) => {
|
||||
const { breakpoints } = useMantineTheme();
|
||||
const isSmallerThanMd = useMediaQuery(`(max-width: ${breakpoints.sm})`);
|
||||
const experimentalHeaderNoteHeight = isSmallerThanMd ? 50 : 30;
|
||||
const headerHeight = showExperimental ? 60 + experimentalHeaderNoteHeight : 60;
|
||||
|
||||
return (
|
||||
<Header height={headerHeight} pb="sm" pt={0}>
|
||||
<ExperimentalHeaderNote visible={showExperimental} />
|
||||
<ExperimentalHeaderNote visible={showExperimental} height={experimentalHeaderNoteHeight} />
|
||||
<Group spacing="xl" mt="xs" px="md" position="apart" noWrap>
|
||||
<UnstyledButton component={Link} href={logoHref}>
|
||||
<UnstyledButton component={Link} href={logoHref} style={{ flex: 1 }}>
|
||||
<Logo />
|
||||
</UnstyledButton>
|
||||
|
||||
<Search />
|
||||
|
||||
<Group noWrap>
|
||||
<Group noWrap style={{ flex: 1 }} position="right">
|
||||
<Group noWrap spacing={8}>
|
||||
{headerActions}
|
||||
</Group>
|
||||
<AvatarMenu />
|
||||
</Group>
|
||||
</Group>
|
||||
@@ -50,16 +46,17 @@ export const MainHeader = ({ showExperimental = false, logoHref = '/' }: MainHea
|
||||
};
|
||||
|
||||
type ExperimentalHeaderNoteProps = {
|
||||
height?: 30 | 50;
|
||||
visible?: boolean;
|
||||
};
|
||||
const ExperimentalHeaderNote = ({ visible = false }: ExperimentalHeaderNoteProps) => {
|
||||
const ExperimentalHeaderNote = ({ visible = false, height = 30 }: ExperimentalHeaderNoteProps) => {
|
||||
if (!visible) return null;
|
||||
|
||||
return (
|
||||
<Box bg="red" h={30} p={3} px={6}>
|
||||
<Box bg="red" h={height} p={3} px={6}>
|
||||
<Flex h="100%" align="center" columnGap={7}>
|
||||
<IconAlertTriangle color="white" size="1rem" />
|
||||
<Text color="white">
|
||||
<IconAlertTriangle color="white" size="1rem" style={{ minWidth: '1rem' }} />
|
||||
<Text color="white" lineClamp={height === 30 ? 1 : 2}>
|
||||
This is an experimental feature of Homarr. Please report any issues to the official Homarr
|
||||
team.
|
||||
</Text>
|
||||
|
||||
Reference in New Issue
Block a user