Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: menu for hidden nav items #77

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
"storage": "Storage",
"about": "About",
"shiftSchedule": "Shift Schedule",
"desktopNavMenu": "{open, select, true {Open} other {Close}} navigation menu",
"matrix": "Go to matrix",
"changeLocale": "Change language",
"toggleTheme": "Toggle theme",
"light": "Light",
Expand Down
2 changes: 2 additions & 0 deletions messages/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
"storage": "Lager",
"about": "Om oss",
"shiftSchedule": "Vaktliste",
"desktopNavMenu": "{open, select, true {Åpne} other {Lukk}} navigasjonsmeny",
"matrix": "Dra til matrix",
"changeLocale": "Bytt språk",
"toggleTheme": "Bytt tema",
"light": "Lys",
Expand Down
2 changes: 1 addition & 1 deletion src/components/composites/ResponsiveDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ interface ResponsiveDialogProps extends BaseProps {
asChild?: true;
}

const desktop = '(min-width: 768px)';
const desktop = '(min-width: 48rem)';

/**
* This uses a drawer on mobile and a dialog on desktop so it is usually the preffered way to use dialogs in the app for a repsonsive experience.
Expand Down
9 changes: 7 additions & 2 deletions src/components/layout/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ function Footer() {
<div className='grid grid-cols-1 xs:grid-cols-2 gap-x-4 gap-y-12 sm:grid-cols-3 lg:grid-cols-4'>
<div>
<div className='flex'>
<LogoLink className='justify-start' />
<LogoLink
className='justify-start'
t={{
hackerspaceHome: t('hackerspaceHome'),
}}
/>
</div>
<p className='ml-2 leading-tight'>
<strong>{t('openingHours')}:</strong>
Expand Down Expand Up @@ -114,7 +119,7 @@ function Footer() {
<div>
<h4>{t('links')}</h4>
<Nav
className='mt-2 ml-2 space-y-1.5'
className='mt-2 ml-2 flex flex-col items-start gap-1.5'
t={{
news: t('news'),
events: t('events'),
Expand Down
37 changes: 29 additions & 8 deletions src/components/layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { LogoLink } from '@/components/layout/LogoLink';
import { DarkModeMenu } from '@/components/layout/header/DarkModeMenu';
import { DesktopNavMenu } from '@/components/layout/header/DesktopNavMenu';
import { LocaleMenu } from '@/components/layout/header/LocaleMenu';
import { MobileSheet } from '@/components/layout/header/MobileSheet';
import { Nav } from '@/components/layout/header/Nav';
import { ProfileMenu } from '@/components/layout/header/ProfileMenu';
import { useTranslations } from 'next-intl';
import { MatrixButton } from './header/MatrixButton';

function Header() {
const t = useTranslations('layout');

return (
<header className='~px-4/24 sticky top-0 z-20 mx-auto flex min-h-14 w-full max-w-screen-2xl items-center justify-between border-border/40 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60'>
<div className='flex gap-2'>
Expand All @@ -18,21 +21,39 @@ function Header() {
news: t('news'),
events: t('events'),
about: t('about'),
storage: t('storage'),
shiftSchedule: t('shiftSchedule'),
hackerspaceHome: t('hackerspaceHome'),
close: useTranslations('ui')('close'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unrelated to this issue but the 'ui' namespaces is available in all client components so when we use from it we dont have to pass it as a prop we can use useTranslations('ui') within the client component

}}
/>
<LogoLink />
</div>
<div className='flex gap-10'>
<Nav
className='hidden items-center gap-6 text-sm md:flex'
<LogoLink
t={{
news: t('news'),
events: t('events'),
about: t('about'),
hackerspaceHome: t('hackerspaceHome'),
}}
/>
</div>
<div className='flex gap-10'>
<div className='hidden items-center gap-6 md:flex'>
<Nav
className='flex items-center gap-6 text-sm'
t={{
news: t('news'),
events: t('events'),
about: t('about'),
}}
/>
<DesktopNavMenu
t={{
open: t('desktopNavMenu', { open: true }),
close: t('desktopNavMenu', { open: false }),
storage: t('storage'),
shiftSchedule: t('shiftSchedule'),
}}
/>
</div>
<div className='flex'>
<MatrixButton />
<LocaleMenu
t={{
changeLocale: t('changeLocale'),
Expand Down
16 changes: 8 additions & 8 deletions src/components/layout/LogoLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@ import { Logo } from '@/components/assets/Logo';
import { Button } from '@/components/ui/Button';
import { Link } from '@/lib/locale/navigation';
import { cx } from '@/lib/utils';
import { useTranslations } from 'next-intl';

function LogoLink({
className,
onClick,
}: {
type LogoLinkProps = {
className?: string;
onClick?: () => void;
}) {
const t = useTranslations('layout');
t: {
hackerspaceHome: string;
};
};

function LogoLink({ className, onClick, t }: LogoLinkProps) {
return (
<Button
className={cx('flex items-center space-x-2', className)}
asChild
variant='none'
size='none'
>
<Link href='/' aria-label={t('hackerspaceHome')} onClick={onClick}>
<Link href='/' aria-label={t.hackerspaceHome} onClick={onClick}>
<Logo className='size-6 md:size-8 lg:size-10' />
<span className='font-bold font-montserrat text-md md:text-lg lg:text-2xl'>
HACKERSPACE
Expand Down
19 changes: 14 additions & 5 deletions src/components/layout/header/DarkModeMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
} from '@/components/ui/DropdownMenu';
import { MoonIcon, SunIcon } from 'lucide-react';
import { useTheme } from 'next-themes';
import * as React from 'react';

type DarkModeMenuProps = {
t: {
Expand All @@ -26,10 +25,20 @@ function DarkModeMenu({ t }: DarkModeMenuProps) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant='ghost' size='icon'>
<SunIcon className='dark:-rotate-90 h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:scale-0' />
<MoonIcon className='absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100' />
<span className='sr-only'>{t.toggleTheme}</span>
<Button
variant='ghost'
size='icon'
title={t.toggleTheme}
aria-label={t.toggleTheme}
>
<SunIcon
className='dark:-rotate-90 h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:scale-0'
aria-hidden='true'
/>
<MoonIcon
className='absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100'
aria-hidden='true'
/>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className='min-w-[6rem]' align='end'>
Expand Down
58 changes: 58 additions & 0 deletions src/components/layout/header/DesktopNavMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use client';

import { SecondaryNav } from '@/components/layout/header/SecondaryNav';
import { Button } from '@/components/ui/Button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
} from '@/components/ui/DropdownMenu';
import { useMediaQuery } from '@/lib/hooks/useMediaQuery';
import { EllipsisIcon } from 'lucide-react';
import { useEffect, useState } from 'react';

type DesktopNavMenuProps = {
className?: string;
t: {
open: string;
close: string;
storage: string;
shiftSchedule: string;
};
};

function DesktopNavMenu({ t }: DesktopNavMenuProps) {
const [open, setOpen] = useState(false);
const visible = useMediaQuery('(min-width: 48rem)');

useEffect(() => {
if (!visible) {
setOpen(false);
}
}, [visible]);

return (
<DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger asChild>
<Button
className='h-fit'
variant='nav'
size='none'
aria-label={open ? t.close : t.open}
>
<EllipsisIcon aria-hidden='true' />
</Button>
</DropdownMenuTrigger>
<SecondaryNav
asDropDown
onClick={() => setOpen(false)}
t={{
storage: t.storage,
shiftSchedule: t.shiftSchedule,
}}
/>
</DropdownMenu>
);
}

export { DesktopNavMenu };
11 changes: 7 additions & 4 deletions src/components/layout/header/LocaleMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { localeIcons, routing } from '@/lib/locale';
import { usePathname, useRouter } from '@/lib/locale/navigation';
import { Globe2Icon } from 'lucide-react';
import { useParams } from 'next/navigation';
import * as React from 'react';

function LocaleMenu({ t }: { t: { changeLocale: string } }) {
const router = useRouter();
Expand All @@ -20,9 +19,13 @@ function LocaleMenu({ t }: { t: { changeLocale: string } }) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant='ghost' size='icon'>
<Globe2Icon className='h-[1.2rem] w-[1.2rem]' />
<span className='sr-only'>{t.changeLocale}</span>
<Button
variant='ghost'
size='icon'
title={t.changeLocale}
aria-label={t.changeLocale}
>
<Globe2Icon className='h-[1.2rem] w-[1.2rem]' aria-hidden='true' />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className='min-w-[6rem]' align='end'>
Expand Down
21 changes: 21 additions & 0 deletions src/components/layout/header/MatrixButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Button } from '@/components/ui/Button';
import { MessageSquareMoreIcon } from 'lucide-react';
import { useTranslations } from 'next-intl';
import Link from 'next/link';

function MatrixButton() {
const t = useTranslations('layout');

return (
<Button variant='ghost' size='icon' asChild>
<Link href='/' title={t('matrix')} aria-label={t('matrix')}>
<MessageSquareMoreIcon
className='h-[1.2rem] w-[1.2rem]'
aria-hidden='true'
/>
</Link>
</Button>
);
}

export { MatrixButton };
43 changes: 37 additions & 6 deletions src/components/layout/header/MobileSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@

import { LogoLink } from '@/components/layout/LogoLink';
import { Nav } from '@/components/layout/header/Nav';
import { SecondaryNav } from '@/components/layout/header/SecondaryNav';
import { Button } from '@/components/ui/Button';
import { Separator } from '@/components/ui/Separator';
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@/components/ui/Sheet';
import { useMediaQuery } from '@/lib/hooks/useMediaQuery';
import { MenuIcon } from 'lucide-react';
import * as React from 'react';
import { useEffect, useState } from 'react';

type MobileSheetProps = {
className?: string;
Expand All @@ -20,39 +23,67 @@ type MobileSheetProps = {
news: string;
events: string;
about: string;
storage: string;
shiftSchedule: string;
hackerspaceHome: string;
close: string;
};
};

function MobileSheet({ className, t }: MobileSheetProps) {
const [open, setOpen] = React.useState(false);
const [open, setOpen] = useState(false);
const visible = useMediaQuery('(max-width: 48rem)');

useEffect(() => {
if (!visible) {
setOpen(false);
}
}, [visible]);

return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<Button
className={className}
variant='ghost'
size='icon'
title={t.navigationMenu}
aria-label={t.navigationMenu}
>
<MenuIcon className='h-5 w-5' />
<MenuIcon className='h-5 w-5' aria-hidden='true' />
</Button>
</SheetTrigger>
<SheetContent side='left' close={t.close}>
<SheetContent className='w-72' side='left' close={t.close}>
<SheetHeader>
<SheetTitle className='flex'>
<LogoLink onClick={() => setOpen(false)} />
<LogoLink
onClick={() => setOpen(false)}
t={{
hackerspaceHome: t.hackerspaceHome,
}}
/>
</SheetTitle>
</SheetHeader>
<Nav
className='flex flex-col space-y-3 pt-6'
className='flex flex-col items-start space-y-3 py-6'
onClick={() => setOpen(false)}
t={{
news: t.news,
events: t.events,
about: t.about,
}}
/>
<Separator />
<div className='mt-6 ml-2 flex flex-row gap-2'>
<Separator orientation='vertical' className='h-auto' />
<SecondaryNav
onClick={() => setOpen(false)}
t={{
storage: t.storage,
shiftSchedule: t.shiftSchedule,
}}
/>
</div>
</SheetContent>
</Sheet>
);
Expand Down
Loading