Skip to content

Commit

Permalink
refactor: breadcrumb comply with submenu nav
Browse files Browse the repository at this point in the history
  • Loading branch information
onursagir committed May 9, 2024
1 parent 76667e6 commit f1a2cde
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 111 deletions.
5 changes: 5 additions & 0 deletions .changeset/tasty-timers-travel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'web': minor
---

Refactored breadcrumb component to comply with new navigation structure
3 changes: 3 additions & 0 deletions apps/web/src/app/(common-page)/agenda/[event]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { OpenInMapDropdown } from './open-in-map-dropdown';
import { Metadata } from 'next';
import { truncateStringAtWord } from '@/common/truncate-string-at-word';
import slugify from '@sindresorhus/slugify';
import { EnhanceMenuBreadcrumbs } from '@/app/menu-breadcrumbs';

interface Props {
params: { event: string };
Expand All @@ -35,6 +36,8 @@ export default async function EventPage({ params }: Props) {

return (
<>
<EnhanceMenuBreadcrumbs append={title} />

<div className="relative -mt-14 h-[300px] w-full overflow-hidden object-fill">
{cover && (
<Image
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { resolveCmsImage } from '@/common/resolve-cms-image';
import { truncateStringAtWord } from '@/common/truncate-string-at-word';
import { Breadcrumbs } from '@/components/breadcrumbs';
import { Button } from '@/components/button';
import { Container } from '@/components/container';
import { RemoteMdx } from '@/components/remote-mdx';
Expand All @@ -12,7 +11,8 @@ import { Metadata } from 'next';
import Image from 'next/image';
import Link from 'next/link';
import { notFound } from 'next/navigation';
import { ShareBar } from '../../../../components/share-bar';
import { EnhanceMenuBreadcrumbs } from '@/app/menu-breadcrumbs';
import { ShareBar } from '@/components/share-bar';

interface Props {
params: {
Expand All @@ -30,60 +30,50 @@ export default async function BlogArticlePage(props: Props) {
if (!blogArticle.title || !blogArticle.content) return notFound();

return (
<>
<Container component="main" className="pb-8">
<EnhanceMenuBreadcrumbs append={blogArticle.title} />
<header>
<nav>
<Breadcrumbs>
<Link href="/">Home</Link>
<Link href="/blog">Blog</Link>
<span>{blogArticle.title}</span>
</Breadcrumbs>
</nav>
</header>
<Container component="main" className="pb-8 pt-14">
<header>
<Button component={Link} variant="text" startIcon={<IconArrowLeft />} href="/blog">
Overzicht
</Button>
<Typography variant="h1" className="mb-12 mt-4 ">
{blogArticle.title}
</Typography>
{blogArticle.publishedAt && (
<span className="text-grey-light">
Publicatiedatum{' '}
{new Date(blogArticle.publishedAt).toLocaleDateString('nl-NL', {
month: 'long',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
})}
</span>
<Button component={Link} variant="text" startIcon={<IconArrowLeft />} href="/blog">
Overzicht
</Button>
<Typography variant="h1" className="mb-12 mt-4 ">
{blogArticle.title}
</Typography>
{blogArticle.publishedAt && (
<span className="text-grey-light">
Publicatiedatum{' '}
{new Date(blogArticle.publishedAt).toLocaleDateString('nl-NL', {
month: 'long',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
})}
</span>
)}
<figure className="relative mb-12 mt-3 aspect-[308/140] overflow-hidden rounded-lg">
{blogArticle.cover.ext && blogArticle.cover.hash && (
<Image
fill
className="object-cover"
src={resolveCmsImage({
ext: blogArticle.cover.ext,
hash: blogArticle.cover.hash,
width: 1235,
}).toString()}
alt={blogArticle.cover.alt || blogArticle?.title}
/>
)}
<figure className="relative mb-12 mt-3 aspect-[308/140] overflow-hidden rounded-lg">
{blogArticle.cover.ext && blogArticle.cover.hash && (
<Image
fill
className="object-cover"
src={resolveCmsImage({
ext: blogArticle.cover.ext,
hash: blogArticle.cover.hash,
width: 1235,
}).toString()}
alt={blogArticle.cover.alt || blogArticle?.title}
/>
)}
</figure>
</header>
<article>
<RemoteMdx content={blogArticle?.content || ''} />
</article>
<div className="mt-6 border-b border-t border-grey-light py-6">Categorie: {blogArticle?.category}</div>
</figure>
</header>
<article>
<RemoteMdx content={blogArticle?.content || ''} />
</article>
<div className="mt-6 border-b border-t border-grey-light py-6">Categorie: {blogArticle?.category}</div>

<p className="mb-2 mt-12 text-xl">Deel deze pagina</p>
<ShareBar title={blogArticle.title} />
</Container>
</>
<p className="mb-2 mt-12 text-xl">Deel deze pagina</p>
<ShareBar title={blogArticle.title} />
</Container>
);
}

Expand Down
27 changes: 0 additions & 27 deletions apps/web/src/app/(common-page)/breadcrumbs.tsx

This file was deleted.

15 changes: 0 additions & 15 deletions apps/web/src/app/(common-page)/layout.tsx

This file was deleted.

2 changes: 2 additions & 0 deletions apps/web/src/app/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Logo from './logo.png';
import { MenuContext } from './menu-context';
import { MenuDesktop } from './menu-desktop';
import { MenuMobile, MenuToggle } from './menu-mobile';
import { MenuBreadcrumbs } from './menu-breadcrumbs';

export interface Page {
id: number;
Expand All @@ -28,6 +29,7 @@ export const Header: React.FC = async () => {
</MenuContext>
</Container>
<MenuDesktop navbar={navbar} />
<MenuBreadcrumbs navbar={navbar} />
</header>
);
};
9 changes: 6 additions & 3 deletions apps/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import localFont from 'next/font/local';
import { Footer } from './footer';
import './globals.css';
import { Header } from './header';
import { MenuBreadcrumbsProvider } from './menu-breadcrumbs';

const RoSansWeb = localFont({
src: [
Expand All @@ -22,9 +23,11 @@ export default async function RootLayout({ children }: { children: React.ReactNo
return (
<html lang="nl">
<body className={`${RoSansWeb.className} flex min-h-screen min-w-full flex-col`}>
<Header />
{children}
<Footer />
<MenuBreadcrumbsProvider>
<Header />
<main className="pb-8 pt-14">{children}</main>
<Footer />
</MenuBreadcrumbsProvider>
</body>
</html>
);
Expand Down
117 changes: 117 additions & 0 deletions apps/web/src/app/menu-breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
'use client';

import { Container } from '@/components/container';
import { getNavbarNodeByUrl } from '@/services/cms/get-navbar-node-by-url';
import { NavbarNode } from '@/services/cms/get-navbar-tree';
import { IconChevronRight } from '@tabler/icons-react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import React, {
Dispatch,
Fragment,
PropsWithChildren,
SetStateAction,
createContext,
useContext,
useEffect,
useState,
} from 'react';

interface CrumbProps {
name: string;
href?: string;
}

const Crumb: React.FC<CrumbProps> = ({ name, href }) => {
if (name === 'root') return <Link href="/">Home</Link>;

if (!href) return <span>{name}</span>;

return <Link href={href.startsWith('/') ? href : '/' + href}>{name}</Link>;
};

interface MenuBreadcrumbsProps {
navbar: NavbarNode;
}

export const MenuBreadcrumbs: React.FC<MenuBreadcrumbsProps> = ({ navbar }) => {
const { additionalCrumbs } = useMenuBreadcrumbs();
const pathName = usePathname();

const pathSegments = pathName.split('/');

const targetNode = pathSegments[1] || '/';

const node = getNavbarNodeByUrl(navbar, targetNode);

if (!node) return null;

const nodes = [node];
let current = node;

while (current.parent) {
current = current.parent;
nodes.push(current);
}

return (
<div className="bg-primary-lighter">
<Container component="nav" className="flex h-14 items-center gap-x-4 text-base font-bold text-primary-dark">
{nodes.toReversed().map((node, i) => {
return (
<Fragment key={node.id}>
{i > 0 && <IconChevronRight size={24} />}
<Crumb name={node.name} href={node.url} />
</Fragment>
);
})}
{additionalCrumbs.map((name, i) => {
return (
<Fragment key={name}>
<IconChevronRight size={24} />
<Crumb name={name} />
</Fragment>
);
})}
</Container>
</div>
);
};

interface Value {
additionalCrumbs: string[];
setAdditionalCrumbs: Dispatch<SetStateAction<string[]>>;
}

const context = createContext<Value>({} as Value);

interface MenuBreadcrumbsProvider extends PropsWithChildren {}

export const MenuBreadcrumbsProvider: React.FC<MenuBreadcrumbsProvider> = ({ children }) => {
const [additionalCrumbs, setAdditionalCrumbs] = useState<string[]>([]);

console.log({ additionalCrumbs });

return <context.Provider value={{ additionalCrumbs, setAdditionalCrumbs }}>{children}</context.Provider>;
};

const useMenuBreadcrumbs = () => useContext(context);

interface EnhanceMenuBreadcrumbsProps {
append: string;
}

export const EnhanceMenuBreadcrumbs: React.FC<EnhanceMenuBreadcrumbsProps> = ({ append }) => {
const { setAdditionalCrumbs } = useMenuBreadcrumbs();

useEffect(() => {
setAdditionalCrumbs([append]);

return () => {
console.log('cleanup');
setAdditionalCrumbs([]);
};
}, [append, setAdditionalCrumbs]);

return null;
};
13 changes: 0 additions & 13 deletions apps/web/src/components/breadcrumbs.tsx

This file was deleted.

0 comments on commit f1a2cde

Please sign in to comment.