mirror of
https://github.com/FoxxMD/multi-scrobbler.git
synced 2026-07-09 17:28:28 +00:00
refactor(ui): Remove non-mobile sidebar and ad header links
Some checks are pending
Publish Docker image to Dockerhub / test (push) Waiting to run
Publish Docker image to Dockerhub / Build OCI Images (push) Blocked by required conditions
Publish Docker image to Dockerhub / Build OCI Images-1 (push) Blocked by required conditions
Publish Docker image to Dockerhub / Merge OCI Images and Push (push) Blocked by required conditions
Some checks are pending
Publish Docker image to Dockerhub / test (push) Waiting to run
Publish Docker image to Dockerhub / Build OCI Images (push) Blocked by required conditions
Publish Docker image to Dockerhub / Build OCI Images-1 (push) Blocked by required conditions
Publish Docker image to Dockerhub / Merge OCI Images and Push (push) Blocked by required conditions
* Remove non-mobile sidebar to free up some more screen real estate * Add quick Links menu to header that hides on mobile breakpoint
This commit is contained in:
parent
be872d5ce1
commit
f431f4d5af
6 changed files with 78 additions and 31 deletions
|
|
@ -13,10 +13,8 @@ import { Provider } from './components/Provider';
|
||||||
import { Container, Box, Center, Splitter, useSplitter } from '@chakra-ui/react';
|
import { Container, Box, Center, Splitter, useSplitter } from '@chakra-ui/react';
|
||||||
import { MsSseEvent } from '../core/Api';
|
import { MsSseEvent } from '../core/Api';
|
||||||
import { SSEProvider } from "@flamefrontend/sse-runtime-react";
|
import { SSEProvider } from "@flamefrontend/sse-runtime-react";
|
||||||
import { AppHeader, RightHeaderFloatingLogs, RightHeaderSwitchLogs } from './components/AppHeader';
|
import { AppHeader } from './components/AppHeader';
|
||||||
import { NAV_LINKS, SideNavItems } from './components/SideNav';
|
import { NAV_LINKS, SideNavItems } from './components/SideNav';
|
||||||
import { LogsFetchable } from './components/LogsNext';
|
|
||||||
import { SplitLayout } from './components/layouts/SplitLayout';
|
|
||||||
import { ComponentDetailedRoutable } from './components/msComponent/MSComponentDetailed';
|
import { ComponentDetailedRoutable } from './components/msComponent/MSComponentDetailed';
|
||||||
import { MSErrorBoundary } from './components/ErrorBoundary';
|
import { MSErrorBoundary } from './components/ErrorBoundary';
|
||||||
|
|
||||||
|
|
@ -60,9 +58,11 @@ const Layout = () => {
|
||||||
//const [logsEnabled, setLogsEnabled] = useState(true);
|
//const [logsEnabled, setLogsEnabled] = useState(true);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
return (<>
|
return (<>
|
||||||
<Box px="4" py="2" mb="4" pb="4" position="sticky" top="0" zIndex="1" bg="bg" borderBottomWidth="1px"><AppHeader fetchable><RightHeaderFloatingLogs streamable/></AppHeader></Box>
|
<Box px="4" py="2" mb="4" pb="4" position="sticky" top="0" zIndex="1" bg="bg" borderBottomWidth="1px">
|
||||||
|
<AppHeader fetchable/>
|
||||||
|
</Box>
|
||||||
<Container display="flex">
|
<Container display="flex">
|
||||||
<Box hideBelow="md" display="flex" flexDir="column" pr="2" gap="6" flexShrink="1"><SideNavItems items={NAV_LINKS} currentUrl={location.pathname}/></Box>
|
<Box hideBelow="md" display="flex" flexDir="column" pr="2" gap="6" flexShrink="1"></Box>
|
||||||
<Outlet/>
|
<Outlet/>
|
||||||
</Container>
|
</Container>
|
||||||
</>);
|
</>);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import { ToggleTip } from "./ToggleTip";
|
||||||
import { ErrorLike } from "../../core/Atomic";
|
import { ErrorLike } from "../../core/Atomic";
|
||||||
import { ErrorAlert } from "./ErrorAlert";
|
import { ErrorAlert } from "./ErrorAlert";
|
||||||
import { MSErrorBoundary } from "./ErrorBoundary";
|
import { MSErrorBoundary } from "./ErrorBoundary";
|
||||||
|
import { ExternaLinksMenu } from "./ExternaLinksMenu";
|
||||||
|
|
||||||
export const AppTitle = (props: { fetchable?: boolean } = {}) => {
|
export const AppTitle = (props: { fetchable?: boolean } = {}) => {
|
||||||
const {
|
const {
|
||||||
|
|
@ -121,8 +122,7 @@ export const SSEStatus = (props: {live?: boolean, status?: ReturnType<typeof use
|
||||||
export const RightHeaderFloatingLogs = (props: {streamable?: boolean}) => {
|
export const RightHeaderFloatingLogs = (props: {streamable?: boolean}) => {
|
||||||
const [width, height] = useWindowSize();
|
const [width, height] = useWindowSize();
|
||||||
|
|
||||||
return <HStack gap="2">
|
return (
|
||||||
<Box marginRight="2"><SSEStatus live={props.streamable}/></Box>
|
|
||||||
<FloatingPanel.Root
|
<FloatingPanel.Root
|
||||||
defaultPosition={{x: width * 0.03, y: height * 0.65}}
|
defaultPosition={{x: width * 0.03, y: height * 0.65}}
|
||||||
defaultSize={{ width: width * 0.95, height: height * 0.3 }}
|
defaultSize={{ width: width * 0.95, height: height * 0.3 }}
|
||||||
|
|
@ -160,14 +160,18 @@ export const RightHeaderFloatingLogs = (props: {streamable?: boolean}) => {
|
||||||
</FloatingPanel.Positioner>
|
</FloatingPanel.Positioner>
|
||||||
</Portal>
|
</Portal>
|
||||||
</FloatingPanel.Root>
|
</FloatingPanel.Root>
|
||||||
</HStack>
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AppHeader = (props: PropsWithChildren<{ fetchable?: boolean }>) => {
|
export const AppHeader = (props: PropsWithChildren<{ fetchable?: boolean }>) => {
|
||||||
return (
|
return (
|
||||||
<Flex justify="space-between">
|
<Flex justify="space-between">
|
||||||
<AppTitle fetchable={props.fetchable} />
|
<AppTitle fetchable={props.fetchable} />
|
||||||
<Flex justify="flex-start" alignItems="flex-end">{props.children}</Flex>
|
<Flex justify="flex-start" gap="1" alignItems="flex-end">
|
||||||
|
<ExternaLinksMenu hideBelow="sm"/>
|
||||||
|
<Box marginRight="2"><SSEStatus live={props.fetchable}/></Box>
|
||||||
|
<RightHeaderFloatingLogs streamable={props.fetchable}/>
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
30
src/client/components/ExternaLinksMenu.tsx
Normal file
30
src/client/components/ExternaLinksMenu.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Button, Menu, Portal, Box, ChakraComponent } from "@chakra-ui/react"
|
||||||
|
import { ExternalLinkIcon } from "./icons/ChakraIcons"
|
||||||
|
import { EXTERNAL_LINKS } from "./SideNav"
|
||||||
|
import { ComponentProps } from "react"
|
||||||
|
|
||||||
|
|
||||||
|
export const ExternaLinksMenu = (props: ComponentProps<typeof Box> = {}) => (
|
||||||
|
<Box {...props}>
|
||||||
|
<Menu.Root>
|
||||||
|
<Menu.Trigger asChild>
|
||||||
|
<Button size="sm" variant="ghost">
|
||||||
|
Links
|
||||||
|
</Button>
|
||||||
|
</Menu.Trigger>
|
||||||
|
<Portal>
|
||||||
|
<Menu.Positioner>
|
||||||
|
<Menu.Content>
|
||||||
|
{EXTERNAL_LINKS.items.map((link) => (
|
||||||
|
<Menu.Item key={link.url} asChild value={link.title} cursor="pointer">
|
||||||
|
<a href={link.url} target="_blank" rel="noreferrer">
|
||||||
|
{link.title} <ExternalLinkIcon />
|
||||||
|
</a>
|
||||||
|
</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu.Content>
|
||||||
|
</Menu.Positioner>
|
||||||
|
</Portal>
|
||||||
|
</Menu.Root>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
|
@ -12,9 +12,6 @@ import { NAV_LINKS, SideNavItems } from "./SideNav";
|
||||||
const MobileMenuButton = MenuButton;
|
const MobileMenuButton = MenuButton;
|
||||||
|
|
||||||
export const MobileSidebarNav = (props: { hideFrom?: BreakpointName | false } = {}) => {
|
export const MobileSidebarNav = (props: { hideFrom?: BreakpointName | false } = {}) => {
|
||||||
const {
|
|
||||||
hideFrom = 'md'
|
|
||||||
} = props;
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
let location = useLocation();
|
let location = useLocation();
|
||||||
|
|
@ -22,11 +19,11 @@ export const MobileSidebarNav = (props: { hideFrom?: BreakpointName | false } =
|
||||||
const closeMenu = () => setIsOpen(false)
|
const closeMenu = () => setIsOpen(false)
|
||||||
|
|
||||||
const menuButtonProps: ComponentProps<typeof MobileMenuButton> = {
|
const menuButtonProps: ComponentProps<typeof MobileMenuButton> = {
|
||||||
variant: 'ghost'
|
variant: 'ghost',
|
||||||
|
iconProps: {
|
||||||
|
size: 'lg'
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if (hideFrom !== false) {
|
|
||||||
menuButtonProps.hideFrom = hideFrom;
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
|
|
|
||||||
|
|
@ -104,18 +104,7 @@ const StatusBadge = (props: BadgeProps) => (
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
export const NAV_LINKS: SideNavProps[] = [
|
export const EXTERNAL_LINKS: SideNavProps = {
|
||||||
{
|
|
||||||
title: 'Main',
|
|
||||||
id: 'Main',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
title: 'Dashboard',
|
|
||||||
url: '/next/'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Links',
|
title: 'Links',
|
||||||
id: 'Links',
|
id: 'Links',
|
||||||
items: [
|
items: [
|
||||||
|
|
@ -135,5 +124,18 @@ export const NAV_LINKS: SideNavProps[] = [
|
||||||
external: true
|
external: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
|
||||||
|
export const NAV_LINKS: SideNavProps[] = [
|
||||||
|
{
|
||||||
|
title: 'Main',
|
||||||
|
id: 'Main',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
title: 'Dashboard',
|
||||||
|
url: '/next/'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
EXTERNAL_LINKS
|
||||||
|
];
|
||||||
|
|
@ -48,6 +48,20 @@ export const makeIconButton = (Icon: IconType) => (props: PropsWithChildren<Comp
|
||||||
</IconButton>
|
</IconButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export const makeChakraIconButton = (IconBase: IconType) => (props: PropsWithChildren<ComponentProps<typeof IconButton>> & { iconProps?: ComponentProps<typeof Icon>, loading?: boolean }) => {
|
||||||
|
const {
|
||||||
|
iconProps = {},
|
||||||
|
children,
|
||||||
|
loading = false,
|
||||||
|
size = 'xs',
|
||||||
|
...rest
|
||||||
|
} = props;
|
||||||
|
return (
|
||||||
|
<IconButton variant="surface" disabled={loading} size={size} {...rest}>
|
||||||
|
{loading ? <Spinner/> : <Icon {...iconProps}><IconBase/></Icon>}{children}
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
|
}
|
||||||
export const makeChakraIcon = (IconComponent: IconType) => (props: ComponentProps<typeof Icon> & { iconProps?: IconBaseProps }) => {
|
export const makeChakraIcon = (IconComponent: IconType) => (props: ComponentProps<typeof Icon> & { iconProps?: IconBaseProps }) => {
|
||||||
const {
|
const {
|
||||||
iconProps,
|
iconProps,
|
||||||
|
|
@ -95,7 +109,7 @@ export const TerminalButton = (props: ComponentProps<typeof IconButton>) => (
|
||||||
);
|
);
|
||||||
|
|
||||||
export const MenuIcon = LuAlignJustify;
|
export const MenuIcon = LuAlignJustify;
|
||||||
export const MenuButton = makeIconButton(MenuIcon);
|
export const MenuButton = makeChakraIconButton(MenuIcon);
|
||||||
|
|
||||||
export const XIcon = LuX;
|
export const XIcon = LuX;
|
||||||
export const XButton = makeIconButton(XIcon);
|
export const XButton = makeIconButton(XIcon);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue