Skip to content

Commit

Permalink
feat: add drawer to show hearder items on small screens
Browse files Browse the repository at this point in the history
  • Loading branch information
beeman committed Jan 13, 2024
1 parent 8ba66a3 commit e2cac97
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 18 deletions.
4 changes: 4 additions & 0 deletions apps/web/src/app/app-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import { IconSettings, IconUser, IconUserCog } from '@tabler/icons-react'
import { ReactNode } from 'react'
import { AccountChecker } from './features/account/account-ui'
import { ClusterChecker, ClusterUiSelect } from './features/cluster/cluster-ui'
import { useDisclosure } from '@mantine/hooks'

export function AppLayout({ children }: { children: ReactNode }) {
const [opened, { toggle }] = useDisclosure(false)
return (
<UiLayout
header={
<UiHeader
opened={opened}
toggle={toggle}
links={[
{ label: 'Dashboard', link: '/dashboard' },
{ label: 'Account', link: '/account' },
Expand Down
43 changes: 34 additions & 9 deletions packages/core/src/lib/ui-header/ui-header.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Anchor, Burger, Group } from '@mantine/core'
import { Anchor, Burger, Drawer, DrawerProps, Group, ScrollArea, Stack } from '@mantine/core'
import { ReactNode } from 'react'
import cx from 'clsx'
import { useDisclosure } from '@mantine/hooks'
import { Link, useLocation } from 'react-router-dom'
import { UiLogo, UiLogoType } from '../ui-logo'

import classes from './ui-header.module.css'

export interface UiHeaderProps {
base?: string
drawerProps?: DrawerProps
logo?: ReactNode
logoSmall?: ReactNode
links?: UiHeaderLink[]
Expand All @@ -20,39 +22,62 @@ export interface UiHeaderLink {
label: string
}

export function UiHeader({ base, links = [], logo, logoSmall, opened, profile, toggle }: UiHeaderProps) {
export function UiHeader(props: UiHeaderProps) {
const { pathname } = useLocation()
const items = links.map((link) => (
const [drawerOpened, { toggle: drawerToggle }] = useDisclosure(false)
const burger = props.toggle ? <Burger opened={props.opened} onClick={props.toggle} size="sm" hiddenFrom="md" /> : null
const opened = props.opened ?? drawerOpened
const toggle = props.toggle ?? drawerToggle
const close = () => {
if (opened && props.toggle) props.toggle()
}

const items = props.links?.map((link) => (
<Anchor
component={Link}
key={link.label}
to={link.link}
className={cx(classes.link, { [classes.linkActive]: pathname.startsWith(link.link) })}
onClick={close}
>
{link.label}
</Anchor>
))

const burger = toggle ? <Burger opened={opened} onClick={toggle} size="sm" hiddenFrom="md" /> : null

return (
<header className={classes.header}>
<div className={classes.inner}>
<Group>
<Group>
{burger}
<Anchor component={Link} to={base ?? '/'} display="flex">
<Group hiddenFrom="md">{logoSmall ?? <UiLogo height={28} />}</Group>
<Group visibleFrom="md">{logo ?? <UiLogoType height={28} />}</Group>
<Anchor component={Link} to={props.base ?? '/'} display="flex">
<Group hiddenFrom="md">{props.logoSmall ?? <UiLogo height={28} />}</Group>
<Group visibleFrom="md">{props.logo ?? <UiLogoType height={28} />}</Group>
</Anchor>
</Group>
<Group gap={5} className={classes.links} visibleFrom="md">
{items}
</Group>
</Group>

<Group>{profile}</Group>
{props.profile ? <Group>{props.profile}</Group> : null}
</div>
<Drawer
opened={opened}
onClose={toggle}
title={
<Group>
<Anchor component={Link} to={props.base ?? '/'} display="flex" onClick={close}>
{props.logo ?? <UiLogoType height={28} />}
</Anchor>
</Group>
}
hiddenFrom="md"
scrollAreaComponent={ScrollArea}
{...props.drawerProps}
>
<Stack gap="sm">{items}</Stack>
</Drawer>
</header>
)
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Anchor, Burger, Group } from '@mantine/core'
import { Anchor, Burger, Drawer, DrawerProps, Group, ScrollArea, Stack } from '@mantine/core'
import { ReactNode } from 'react'
import cx from 'clsx'
import { useDisclosure } from '@mantine/hooks'
import { Link, useLocation } from 'react-router-dom'
import { <%= prefix.className %>Logo, <%= prefix.className %>LogoType } from '../<%= prefix.fileName %>-logo'

import classes from './<%= prefix.fileName %>-header.module.css'

export interface <%= prefix.className %>HeaderProps {
base?: string
drawerProps?: DrawerProps
logo?: ReactNode
logoSmall?: ReactNode
links?: <%= prefix.className %>HeaderLink[]
Expand All @@ -20,39 +22,62 @@ export interface <%= prefix.className %>HeaderLink {
label: string
}

export function <%= prefix.className %>Header({ base, links = [], logo, logoSmall, opened, profile, toggle }: <%= prefix.className %>HeaderProps) {
export function <%= prefix.className %>Header(props: <%= prefix.className %>HeaderProps) {
const { pathname } = useLocation()
const items = links.map((link) => (
const [drawerOpened, { toggle: drawerToggle }] = useDisclosure(false)
const burger = props.toggle ? <Burger opened={props.opened} onClick={props.toggle} size="sm" hiddenFrom="md" /> : null
const opened = props.opened ?? drawerOpened
const toggle = props.toggle ?? drawerToggle
const close = () => {
if (opened && props.toggle) props.toggle()
}

const items = props.links?.map((link) => (
<Anchor
component={Link}
key={link.label}
to={link.link}
className={cx(classes.link, { [classes.linkActive]: pathname.startsWith(link.link) })}
onClick={close}
>
{link.label}
</Anchor>
))

const burger = toggle ? <Burger opened={opened} onClick={toggle} size="sm" hiddenFrom="md" /> : null

return (
<header className={classes.header}>
<div className={classes.inner}>
<Group>
<Group>
{burger}
<Anchor component={Link} to={base ?? '/'} display="flex">
<Group hiddenFrom="md">{logoSmall ?? <<%= prefix.className %>Logo height={28} />}</Group>
<Group visibleFrom="md">{logo ?? <<%= prefix.className %>LogoType height={28} />}</Group>
<Anchor component={Link} to={props.base ?? '/'} display="flex">
<Group hiddenFrom="md">{props.logoSmall ?? <<%= prefix.className %>Logo height={28} />}</Group>
<Group visibleFrom="md">{props.logo ?? <<%= prefix.className %>LogoType height={28} />}</Group>
</Anchor>
</Group>
<Group gap={5} className={classes.links} visibleFrom="md">
{items}
</Group>
</Group>

<Group>{profile}</Group>
{props.profile ? <Group>{props.profile}</Group> : null}
</div>
<Drawer
opened={opened}
onClose={toggle}
title={
<Group>
<Anchor component={Link} to={props.base ?? '/'} display="flex" onClick={close}>
{props.logo ?? <<%= prefix.className %>LogoType height={28} />}
</Anchor>
</Group>
}
hiddenFrom="md"
scrollAreaComponent={ScrollArea}
{...props.drawerProps}
>
<Stack gap="sm">{items}</Stack>
</Drawer>
</header>
)
}

0 comments on commit e2cac97

Please sign in to comment.