From 39588cb3b3b8f054fd4fdbe312bb4992dbf9cb11 Mon Sep 17 00:00:00 2001 From: Paul Hachmang Date: Mon, 9 Dec 2024 11:28:23 +0100 Subject: [PATCH 1/5] Solve issue if LayoutDefault-children wouldn't fill the page, the content would be aligned to the footer. Presence of beforeheader would trigger this. Support beforeHeader in LayoutDefault without breaking the CartFab and CompareFab. --- .changeset/brown-monkeys-lie.md | 5 ++ .changeset/kind-drinks-relax.md | 5 ++ .../components/LayoutDefault.tsx | 71 ++++++++++++------- 3 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 .changeset/brown-monkeys-lie.md create mode 100644 .changeset/kind-drinks-relax.md diff --git a/.changeset/brown-monkeys-lie.md b/.changeset/brown-monkeys-lie.md new file mode 100644 index 00000000000..7955ef500e8 --- /dev/null +++ b/.changeset/brown-monkeys-lie.md @@ -0,0 +1,5 @@ +--- +'@graphcommerce/next-ui': patch +--- + +Support beforeHeader in LayoutDefault without breaking the CartFab and CompareFab. diff --git a/.changeset/kind-drinks-relax.md b/.changeset/kind-drinks-relax.md new file mode 100644 index 00000000000..346c268209a --- /dev/null +++ b/.changeset/kind-drinks-relax.md @@ -0,0 +1,5 @@ +--- +'@graphcommerce/next-ui': patch +--- + +Solve issue if LayoutDefault-children wouldn't fill the page, the content would be aligned to the footer. Presence of beforeheader would trigger this. diff --git a/packages/next-ui/LayoutDefault/components/LayoutDefault.tsx b/packages/next-ui/LayoutDefault/components/LayoutDefault.tsx index 23f18b4cb32..50ef3e00fc1 100644 --- a/packages/next-ui/LayoutDefault/components/LayoutDefault.tsx +++ b/packages/next-ui/LayoutDefault/components/LayoutDefault.tsx @@ -24,7 +24,7 @@ export type LayoutDefaultProps = { type OwnerState = { noSticky?: boolean } -const parts = ['root', 'fabs', 'header', 'children', 'footer'] as const +const parts = ['root', 'fabs', 'beforeHeader', 'header', 'children', 'footer'] as const const { withState } = extendableComponent( 'LayoutDefault', parts, @@ -62,8 +62,13 @@ export function LayoutDefault(props: LayoutDefaultProps) { minHeight: '-webkit-fill-available', }, display: 'grid', - gridTemplateRows: { xs: 'auto 1fr auto', md: 'auto auto 1fr auto' }, - gridTemplateColumns: '100%', + gridTemplate: ` + "beforeHeader" auto + "header" auto + "fabs" auto + "children" 1fr + "footer" auto / 100% + `, background: theme.palette.background.default, }), ...(Array.isArray(sx) ? sx : [sx]), @@ -71,13 +76,18 @@ export function LayoutDefault(props: LayoutDefaultProps) { > - {beforeHeader} + {beforeHeader ? ( + + {beforeHeader} + + ) : null} ({ + gridArea: 'header', zIndex: theme.zIndex.appBar - 1, display: 'flex', alignItems: 'center', @@ -109,27 +119,32 @@ export function LayoutDefault(props: LayoutDefaultProps) { sizing='shell' maxWidth={false} className={classes.fabs} - sx={(theme) => ({ - display: 'flex', - justifyContent: 'space-between', - width: '100%', - height: 0, - zIndex: 'speedDial', - [theme.breakpoints.up('sm')]: { - position: 'sticky', - marginTop: `calc(${theme.appShell.headerHeightMd} * -1 - calc(${fabIconSize} / 2))`, - top: `calc(${theme.appShell.headerHeightMd} / 2 - (${fabIconSize} / 2))`, - }, - [theme.breakpoints.down('md')]: { - position: 'fixed', - top: 'unset', - bottom: `calc(20px + ${fabIconSize})`, - padding: '0 20px', - '@media (max-height: 530px) and (orientation: portrait)': { - display: 'none', + sx={(theme) => { + const negativeHeaderHeightMd = `(${theme.appShell.headerHeightMd} * -1)` + const topMd = `(${theme.appShell.headerHeightMd} - ${fabIconSize}) / 2` + + return { + gridArea: 'fabs', + display: 'flex', + justifyContent: 'space-between', + width: '100%', + height: 0, + zIndex: 'speedDial', + [theme.breakpoints.up('md')]: { + position: 'sticky', + marginTop: `calc(${negativeHeaderHeightMd} + ${topMd})`, + top: `calc(${topMd})`, }, - }, - })} + [theme.breakpoints.down('md')]: { + position: 'fixed', + bottom: `calc(20px + ${fabIconSize})`, + padding: '0 20px', + '@media (max-height: 530px) and (orientation: portrait)': { + display: 'none', + }, + }, + } + }} > {menuFab} {cartFab && ( @@ -151,11 +166,13 @@ export function LayoutDefault(props: LayoutDefaultProps) { ) : (
)} -
+
{children} -
-
{footer}
+
+ + {footer} + ) From 888cadb394891e9e5f61b7c1a71056a8a2f81216 Mon Sep 17 00:00:00 2001 From: Paul Hachmang Date: Mon, 9 Dec 2024 14:40:40 +0100 Subject: [PATCH 2/5] Revert theme colors back to original style --- examples/magento-graphcms/components/theme.ts | 4 ++-- packages/next-ui/Theme/createTheme.ts | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/magento-graphcms/components/theme.ts b/examples/magento-graphcms/components/theme.ts index 39c3402bc61..8ec9c555832 100644 --- a/examples/magento-graphcms/components/theme.ts +++ b/examples/magento-graphcms/components/theme.ts @@ -20,9 +20,9 @@ import { Components, PaletteOptions } from '@mui/material/styles' const lightPalette: PaletteOptions = { mode: 'light', primary: { - main: '#000000', + main: '#47C489', contrastText: '#ffffff', - dark: '#000000', + dark: '#47C489', }, secondary: { main: '#006bff', diff --git a/packages/next-ui/Theme/createTheme.ts b/packages/next-ui/Theme/createTheme.ts index 76769fce4b0..d4f29657185 100644 --- a/packages/next-ui/Theme/createTheme.ts +++ b/packages/next-ui/Theme/createTheme.ts @@ -28,7 +28,15 @@ declare module '@mui/material/styles/createTheme' { headerHeightMd: string appBarHeightMd: string appBarInnerHeightMd: string + /** + * Sizing of the shell of the application. Provide a breakpoint to use the breakpoint value or + * false to disable the breakpoint. + */ containerSizingShell: false | Breakpoint | undefined + /** + * Sizing of the content of the application. Provide a breakpoint to use the breakpoint value + * or false to disable the breakpoint. + */ containerSizingContent: false | Breakpoint | undefined } From 387d94bca2736895a8fe184ad187f21d7d9677c7 Mon Sep 17 00:00:00 2001 From: Paul Hachmang Date: Mon, 9 Dec 2024 14:50:21 +0100 Subject: [PATCH 3/5] Working on sticky header --- .../components/Layout/LayoutNavigation.tsx | 37 +++++++- .../ProductListLayoutDefault.tsx | 9 +- .../ProductListLayoutSidebar.tsx | 3 +- .../components/LayoutDefault.tsx | 91 ++++++++++++++----- 4 files changed, 112 insertions(+), 28 deletions(-) diff --git a/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx b/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx index 4b967b6fb1c..df4b52542e6 100644 --- a/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx +++ b/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx @@ -21,11 +21,12 @@ import { NavigationOverlay, useNavigationSelection, useMemoDeep, + Container, MobileTopRight, } from '@graphcommerce/next-ui' import { i18n } from '@lingui/core' import { Trans } from '@lingui/react' -import { Divider, Fab } from '@mui/material' +import { Divider, Fab, Link } from '@mui/material' import { useRouter } from 'next/router' import { Footer } from './Footer' import { LayoutQuery } from './Layout.gql' @@ -106,7 +107,39 @@ export function LayoutNavigation(props: LayoutNavigationProps) { ({ + [theme.breakpoints.up('md')]: { + '& .LayoutDefault-header.stickyHeader': { + bgcolor: 'background.default', + boxShadow: 1, + + // bgcolor: 'hsl(0deg 0% 100% / 0.95)', + // '&::before': { + // height: '200%', + // content: '""', + // display: 'block', + // position: 'absolute', + // inset: 0, + // WebkitBackdropFilter: 'blur(16px)', + // backdropFilter: 'blur(16px)', + // background: 'linear-gradient(to bottom, hsl(0deg 0% 95%), transparent 50%)', + // pointerEvents: 'none', + // WebkitMaskImage: 'linear-gradient(to bottom, black 0% 50%, transparent 50% 100%)', + // maskImage: 'linear-gradient(to bottom, black 0% 50%, transparent 50% 100%)', + // }, + }, + }, + })} + beforeHeader={ + + You are looking at the{' '} + + GraphCommerce + {' '} + demo environment + + } header={ <> diff --git a/examples/magento-graphcms/components/ProductListLayout/ProductListLayoutDefault.tsx b/examples/magento-graphcms/components/ProductListLayout/ProductListLayoutDefault.tsx index 47c8e8cc2f5..3eb344d1868 100644 --- a/examples/magento-graphcms/components/ProductListLayout/ProductListLayoutDefault.tsx +++ b/examples/magento-graphcms/components/ProductListLayout/ProductListLayoutDefault.tsx @@ -46,16 +46,17 @@ export const ProductListLayoutDefault = memoDeep(function ProductListLayoutDefau sx={(theme) => ({ display: 'grid', rowGap: theme.spacings.sm, + pt: theme.spacings.sm, mb: theme.spacings.sm, gridAutoFlow: 'row', - justifyItems: { xs: 'left', md: 'center' }, + justifyItems: { xs: 'center', md: 'center' }, })} > {import.meta.graphCommerce.breadcrumbs && category && ( ({ - height: 0, + // height: 0, [theme.breakpoints.down('md')]: { '& .MuiBreadcrumbs-ol': { justifyContent: 'center' }, }, @@ -71,14 +72,14 @@ export const ProductListLayoutDefault = memoDeep(function ProductListLayoutDefau ({ px: theme.page.horizontal })} + // sx={(theme) => ({ px: theme.page.horizontal })} category={category} productListRenderer={productListRenderer} /> ({ justifyContent: 'center', - '& .CategoryChildren-scroller': { px: theme.page.horizontal }, + // '& .CategoryChildren-scroller': { px: theme.page.horizontal }, })} params={params} > diff --git a/examples/magento-graphcms/components/ProductListLayout/ProductListLayoutSidebar.tsx b/examples/magento-graphcms/components/ProductListLayout/ProductListLayoutSidebar.tsx index d77744e019f..c0f4fc3d8f0 100644 --- a/examples/magento-graphcms/components/ProductListLayout/ProductListLayoutSidebar.tsx +++ b/examples/magento-graphcms/components/ProductListLayout/ProductListLayoutSidebar.tsx @@ -90,6 +90,7 @@ export const ProductListLayoutSidebar = memoDeep(function ProductListLayoutSideb display: 'grid', gridAutoFlow: 'row', rowGap: theme.spacings.xs, + pt: theme.spacings.md, })} > {category ? ( @@ -177,7 +178,7 @@ export const ProductListLayoutSidebar = memoDeep(function ProductListLayoutSideb display='block' sx={(theme) => ({ gridArea: 'sidebar', - mt: import.meta.graphCommerce.breadcrumbs === true ? 0 : theme.spacings.lg, + mt: import.meta.graphCommerce.breadcrumbs === true ? 0 : theme.spacings.xl, })} > diff --git a/packages/next-ui/LayoutDefault/components/LayoutDefault.tsx b/packages/next-ui/LayoutDefault/components/LayoutDefault.tsx index 50ef3e00fc1..995ee33c8c3 100644 --- a/packages/next-ui/LayoutDefault/components/LayoutDefault.tsx +++ b/packages/next-ui/LayoutDefault/components/LayoutDefault.tsx @@ -17,14 +17,23 @@ export type LayoutDefaultProps = { menuFab?: React.ReactNode cartFab?: React.ReactNode children?: React.ReactNode - noSticky?: boolean sx?: SxProps } & OwnerState type OwnerState = { - noSticky?: boolean + stickyHeader?: boolean } -const parts = ['root', 'fabs', 'beforeHeader', 'header', 'children', 'footer'] as const + +const parts = [ + 'root', + 'fabs', + 'beforeHeader', + 'header', + 'children', + 'footer', + 'cartFab', + 'menuFab', +] as const const { withState } = extendableComponent( 'LayoutDefault', parts, @@ -38,7 +47,7 @@ export function LayoutDefault(props: LayoutDefaultProps) { footer, menuFab, cartFab, - noSticky, + stickyHeader = false, className, sx = [], } = props @@ -49,7 +58,7 @@ export function LayoutDefault(props: LayoutDefaultProps) { ([y, offset]: number[]) => y + offset, ) - const classes = withState({ noSticky }) + const classes = withState({ stickyHeader }) const fabIconSize = useFabSize('responsive') return ( @@ -70,6 +79,17 @@ export function LayoutDefault(props: LayoutDefaultProps) { "footer" auto / 100% `, background: theme.palette.background.default, + + // '&.stickyHeader .LayoutHeaderContent-content': { + // [theme.breakpoints.up('md')]: { + // pt: theme.spacings.sm, + // }, + // }, + // '&.stickyHeader .CompareFab-root': { + // [theme.breakpoints.up('md')]: { + // mt: theme.spacings.sm, + // }, + // }, }), ...(Array.isArray(sx) ? sx : [sx]), ]} @@ -93,9 +113,10 @@ export function LayoutDefault(props: LayoutDefaultProps) { alignItems: 'center', justifyContent: 'center', height: theme.appShell.headerHeightSm, - pointerEvents: 'none', + pointerEvents: 'none' as const, '& > *': { - pointerEvents: 'all', + pointerEvents: 'all' as const, + zIndex: theme.zIndex.appBar, }, [theme.breakpoints.up('md')]: { height: theme.appShell.headerHeightMd, @@ -104,8 +125,8 @@ export function LayoutDefault(props: LayoutDefaultProps) { justifyContent: 'left', width: '100%', }, - '&.sticky': { - [theme.breakpoints.down('md')]: { + '&.stickyHeader': { + [theme.breakpoints.up('md')]: { position: 'sticky', top: 0, }, @@ -129,7 +150,7 @@ export function LayoutDefault(props: LayoutDefaultProps) { justifyContent: 'space-between', width: '100%', height: 0, - zIndex: 'speedDial', + zIndex: theme.zIndex.appBar, [theme.breakpoints.up('md')]: { position: 'sticky', marginTop: `calc(${negativeHeaderHeightMd} + ${topMd})`, @@ -146,18 +167,36 @@ export function LayoutDefault(props: LayoutDefaultProps) { } }} > - {menuFab} + *': { display: { md: 'none' } } }} + > + {menuFab} + {cartFab && ( ({ - display: 'flex', - flexDirection: 'row-reverse', - gap: theme.spacings.sm, - [theme.breakpoints.up('md')]: { - flexDirection: 'column', - alignItems: 'flex-end', - }, - })} + className={classes.cartFab} + sx={(theme) => { + const topMd = `(${theme.appShell.headerHeightMd} - ${fabIconSize}) / 2` + return { + display: 'flex', + flexDirection: 'row-reverse', + + [theme.breakpoints.down('md')]: { + columnGap: theme.spacings.sm, + }, + + [theme.breakpoints.up('md')]: { + rowGap: `calc(${topMd})`, + '&.stickyHeader': { + rowGap: `calc(${topMd} + ${theme.spacings.sm})`, + }, + + flexDirection: 'column', + alignItems: 'flex-end', + }, + } + }} > {cartFab} @@ -166,7 +205,17 @@ export function LayoutDefault(props: LayoutDefaultProps) { ) : (
)} - + ({ + gridArea: 'children', + '&.stickyHeader': { + [theme.breakpoints.up('md')]: { + pt: theme.spacings.sm, + }, + }, + })} + className={classes.children} + >
{children} From d2517413a9df7ad79fb9f4fd0666e0c6f1cbe92a Mon Sep 17 00:00:00 2001 From: Paul Hachmang Date: Mon, 9 Dec 2024 14:58:54 +0100 Subject: [PATCH 4/5] Clear background blur stuff --- .../components/Layout/LayoutNavigation.tsx | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx b/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx index df4b52542e6..d0b86697a8f 100644 --- a/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx +++ b/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx @@ -113,21 +113,6 @@ export function LayoutNavigation(props: LayoutNavigationProps) { '& .LayoutDefault-header.stickyHeader': { bgcolor: 'background.default', boxShadow: 1, - - // bgcolor: 'hsl(0deg 0% 100% / 0.95)', - // '&::before': { - // height: '200%', - // content: '""', - // display: 'block', - // position: 'absolute', - // inset: 0, - // WebkitBackdropFilter: 'blur(16px)', - // backdropFilter: 'blur(16px)', - // background: 'linear-gradient(to bottom, hsl(0deg 0% 95%), transparent 50%)', - // pointerEvents: 'none', - // WebkitMaskImage: 'linear-gradient(to bottom, black 0% 50%, transparent 50% 100%)', - // maskImage: 'linear-gradient(to bottom, black 0% 50%, transparent 50% 100%)', - // }, }, }, })} From 9e4ac01b4f0f5e9d71255aad6c2a4289ff2e6342 Mon Sep 17 00:00:00 2001 From: Paul Hachmang Date: Wed, 11 Dec 2024 12:51:13 +0100 Subject: [PATCH 5/5] Further work on sticky header functionality --- .../components/Layout/LayoutNavigation.tsx | 35 ++- .../components/Layout/LayoutNavigation.tsx | 1 - .../framer-utils/components/StickyBox.tsx | 35 +++ .../framer-utils/hooks/useMakeFullscreen.ts | 37 +++ packages/framer-utils/hooks/useMotionRect.ts | 73 ++++++ packages/framer-utils/hooks/useStickyTop.ts | 103 +++++++++ packages/framer-utils/index.ts | 6 +- packages/framer-utils/package.json | 2 + packages/framer-utils/utils/numberToPx.ts | 3 + .../CategoryChildren/CategoryChildren.tsx | 3 +- .../plugins/AddCompareFabNextToCart.tsx | 2 +- .../next-ui/FramerScroller/SidebarGallery.tsx | 21 +- .../components/LayoutDefault.tsx | 218 +++++++++--------- 13 files changed, 417 insertions(+), 122 deletions(-) create mode 100644 packages/framer-utils/components/StickyBox.tsx create mode 100644 packages/framer-utils/hooks/useMakeFullscreen.ts create mode 100644 packages/framer-utils/hooks/useMotionRect.ts create mode 100644 packages/framer-utils/hooks/useStickyTop.ts create mode 100644 packages/framer-utils/utils/numberToPx.ts diff --git a/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx b/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx index d0b86697a8f..73b523e41d4 100644 --- a/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx +++ b/examples/magento-graphcms/components/Layout/LayoutNavigation.tsx @@ -31,6 +31,7 @@ import { useRouter } from 'next/router' import { Footer } from './Footer' import { LayoutQuery } from './Layout.gql' import { Logo } from './Logo' +import { StickyBox } from '@graphcommerce/framer-utils' import { productListRenderer } from '../ProductListItems/productListRenderer' export type LayoutNavigationProps = LayoutQuery & @@ -107,22 +108,43 @@ export function LayoutNavigation(props: LayoutNavigationProps) { ({ [theme.breakpoints.up('md')]: { - '& .LayoutDefault-header.stickyHeader': { + '& .sticky': { bgcolor: 'background.default', boxShadow: 1, }, }, })} + // stickyHeader={router.asPath.split('?')[0] !== '/'} + stickyAfterHeader + // stickyBeforeHeader beforeHeader={ - + You are looking at the{' '} GraphCommerce {' '} - demo environment + demo + + } + afterHeader={ + + This is a demo store, no actual products are being shipped. } header={ @@ -169,8 +191,7 @@ export function LayoutNavigation(props: LayoutNavigationProps) { } /> - {/* The placeholder exists because the CartFab is sticky but we want to reserve the space for the */} - {cartEnabled && } + @@ -178,8 +199,8 @@ export function LayoutNavigation(props: LayoutNavigationProps) { } - footer={