diff --git a/packages/ui/src/components/Molecules/Breadcrumbs.stories.tsx b/packages/ui/src/components/Molecules/Breadcrumbs.stories.tsx new file mode 100644 index 000000000..9a7c6d0e5 --- /dev/null +++ b/packages/ui/src/components/Molecules/Breadcrumbs.stories.tsx @@ -0,0 +1,24 @@ +import { FrameQuery, OperationExecutor } from '@custom/schema'; +import { Meta } from '@storybook/react'; +import React from 'react'; + +import { Default as FrameStory } from '../Routes/Frame.stories'; +import { BreadCrumbs } from './Breadcrumbs'; + +export default { + component: BreadCrumbs, + parameters: { + layout: 'fullscreen', + location: new URL('local:/gatsby-turbo'), + }, +} satisfies Meta; + +export const Default = { + render: () => { + return ( + + + + ); + }, +}; diff --git a/packages/ui/src/components/Molecules/Breadcrumbs.tsx b/packages/ui/src/components/Molecules/Breadcrumbs.tsx new file mode 100644 index 000000000..cdbaa5f57 --- /dev/null +++ b/packages/ui/src/components/Molecules/Breadcrumbs.tsx @@ -0,0 +1,56 @@ +import { Link } from '@custom/schema'; +import { ChevronRightIcon } from '@heroicons/react/24/outline'; +import clsx from 'clsx'; +import React from 'react'; + +import { isTruthy } from '../../utils/isTruthy'; +import { useBreadcrumbs } from '../Routes/Menu'; + +export function BreadCrumbs({ className }: { className?: string }) { + const breadcrumbs = useBreadcrumbs(); + + console.log('breadcrumbs:', breadcrumbs); + + if (!breadcrumbs.length) { + return null; + } + + return ( + + ); +} diff --git a/packages/ui/src/components/Organisms/PageDisplay.tsx b/packages/ui/src/components/Organisms/PageDisplay.tsx index 86813de03..008a582c9 100644 --- a/packages/ui/src/components/Organisms/PageDisplay.tsx +++ b/packages/ui/src/components/Organisms/PageDisplay.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { isTruthy } from '../../utils/isTruthy'; import { UnreachableCaseError } from '../../utils/unreachable-case-error'; +import { BreadCrumbs } from '../Molecules/Breadcrumbs'; import { PageTransition } from '../Molecules/PageTransition'; import { BlockCta } from './PageContent/BlockCta'; import { BlockForm } from './PageContent/BlockForm'; @@ -15,8 +16,9 @@ export function PageDisplay(page: PageFragment) { return (
- {page.hero ? : null} + {page.hero && }
+
{page?.content?.filter(isTruthy).map((block, index) => { switch (block.__typename) { diff --git a/packages/ui/src/components/Routes/Menu.tsx b/packages/ui/src/components/Routes/Menu.tsx new file mode 100644 index 000000000..ea867bbd8 --- /dev/null +++ b/packages/ui/src/components/Routes/Menu.tsx @@ -0,0 +1,95 @@ +import { FrameQuery, NavigationItem, Url, useLocation } from '@custom/schema'; +import { useIntl } from 'react-intl'; + +import { useOperation } from '../../utils/operation'; + +export type MenuNameType = 'main' | 'footer'; + +export function useMenus() { + const intl = useIntl(); + const locale = intl.locale; + const settings = useOperation(FrameQuery).data; + + console.log('settings:', settings); + return { + main: settings?.mainNavigation + ?.filter((nav) => nav?.locale === locale) + .pop(), + footer: settings?.footerNavigation + ?.filter((nav) => nav?.locale === locale) + .pop(), + }; +} + +export function useCurrentPath() { + const [loc] = useLocation(); + return loc.pathname; +} + +export function useMenuItem(path: string, menuName: MenuNameType) { + const menus = useMenus(); + + return ( + menus && + menus[menuName]?.items.find((menuItem) => menuItem?.target === path) + ); +} + +export function useMenuChildren(path: string, menuName: MenuNameType) { + const menus = useMenus(); + const menuItemFromPath = useMenuItem(path, menuName); + return ( + menus && + menus[menuName]?.items.filter( + (menuItem) => menuItem?.parent === menuItemFromPath?.id, + ) + ); +} + +export function useCurrentMenuItem(menuName: MenuNameType) { + const currentPath = useCurrentPath(); + return useMenuItem(currentPath || '', menuName); +} + +export function useCurrentMenuChildren(menuName: MenuNameType) { + const currentPath = useCurrentPath(); + return useMenuChildren(currentPath || '', menuName); +} + +export function useMenuAncestors(path: string, menuName: MenuNameType) { + const menus = useMenus(); + const menuItemFromPath = useMenuItem(path, menuName); + let processingMenuItem = menuItemFromPath; + const ancestors: Array = []; + + // Set current page breadcrumb + if (typeof processingMenuItem !== 'undefined') { + // If not home path then only push into breadcrumbs array + processingMenuItem.target !== '/' && ancestors.push(processingMenuItem); + } + + while ( + typeof processingMenuItem !== 'undefined' && + processingMenuItem?.parent + ) { + processingMenuItem = + menus && + menus[menuName]?.items.find( + (menuItem) => menuItem?.id === processingMenuItem?.parent, + ); + if (typeof processingMenuItem !== 'undefined') { + ancestors.push(processingMenuItem); + } + } + if (ancestors.length > 0) { + ancestors.push({ id: '_', target: '/' as Url, title: 'Home' }); + } + + return ancestors.reverse(); +} + +export const useBreadcrumbs = (menuName?: MenuNameType, path?: string) => { + const currentPath = useCurrentPath(); + console.log('currentPath', currentPath); + return useMenuAncestors(path || currentPath || '', menuName || 'main'); +}; diff --git a/packages/ui/src/components/Routes/Page.stories.tsx b/packages/ui/src/components/Routes/Page.stories.tsx index f3d048c25..27ead643b 100644 --- a/packages/ui/src/components/Routes/Page.stories.tsx +++ b/packages/ui/src/components/Routes/Page.stories.tsx @@ -40,12 +40,6 @@ export const Default = { }, ], path: '/test' as Url, - hero: { - headline: 'Page Hero Headline', - lead: 'A longer lead text that even might break into multiple lines.', - ctaUrl: '/test' as Url, - ctaText: 'Call to action', - }, content: [ { __typename: 'BlockMarkup', @@ -62,6 +56,25 @@ export const Default = { ] as Exclude['content'], }, }, + parameters: { + location: new URL('local:/gatsby-turbo'), + }, +} satisfies StoryObj; + +export const Hero = { + ...Default, + args: { + ...Default.args, + page: { + ...Default.args.page, + hero: { + headline: 'Page Hero Headline', + lead: 'A longer lead text that even might break into multiple lines.', + ctaUrl: '/test' as Url, + ctaText: 'Call to action', + }, + }, + }, } satisfies StoryObj; export const FullHero = {