Skip to content
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
5 changes: 5 additions & 0 deletions .changeset/brown-monkeys-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphcommerce/next-ui': patch
---

Support beforeHeader in LayoutDefault without breaking the CartFab and CompareFab.
5 changes: 5 additions & 0 deletions .changeset/kind-drinks-relax.md
Original file line number Diff line number Diff line change
@@ -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.
49 changes: 44 additions & 5 deletions examples/magento-graphcms/components/Layout/LayoutNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@ 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'
import { Logo } from './Logo'
import { StickyBox } from '@graphcommerce/framer-utils'
import { productListRenderer } from '../ProductListItems/productListRenderer'

export type LayoutNavigationProps = LayoutQuery &
Expand Down Expand Up @@ -106,7 +108,45 @@ export function LayoutNavigation(props: LayoutNavigationProps) {

<LayoutDefault
{...uiProps}
noSticky={router.asPath.split('?')[0] === '/'}
sx={(theme) => ({
[theme.breakpoints.up('md')]: {
'& .sticky': {
bgcolor: 'background.default',
boxShadow: 1,
},
},
})}
// stickyHeader={router.asPath.split('?')[0] !== '/'}
stickyAfterHeader
// stickyBeforeHeader
beforeHeader={
<Container
sx={{
py: { xs: 0, md: 1 },
position: 'relative',
boxShadow: 1,
textAlign: { xs: 'center', md: 'left' },
}}
>
You are looking at the{' '}
<Link color='inherit' underline='always' href='https://graphcommerce.org'>
GraphCommerce
</Link>{' '}
demo
</Container>
}
afterHeader={
<Container
sx={{
py: { xs: 0, md: 1 },
position: 'relative',
boxShadow: 1,
textAlign: { xs: 'center', md: 'left' },
}}
>
This is a demo store, no actual products are being shipped.
</Container>
}
header={
<>
<Logo />
Expand Down Expand Up @@ -151,17 +191,16 @@ export function LayoutNavigation(props: LayoutNavigationProps) {
</Fab>
<WishlistFab icon={<IconSvg src={iconHeart} size='large' />} />
<CustomerFab guestHref='/account/signin' authHref='/account' />
{/* The placeholder exists because the CartFab is sticky but we want to reserve the space for the <CartFab /> */}
{cartEnabled && <PlaceholderFab />}
<PlaceholderFab />
</DesktopNavActions>

<MobileTopRight>
<SearchFab size='responsiveMedium' />
</MobileTopRight>
</>
}
footer={<Footer footer={footer} />}
cartFab={<CartFab />}
footer={<Footer footer={footer} />}
menuFab={<NavigationFab onClick={() => selection.set([])} />}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 && (
<CategoryBreadcrumbs
category={category}
sx={(theme) => ({
height: 0,
// height: 0,
[theme.breakpoints.down('md')]: {
'& .MuiBreadcrumbs-ol': { justifyContent: 'center' },
},
Expand All @@ -71,14 +72,14 @@ export const ProductListLayoutDefault = memoDeep(function ProductListLayoutDefau
<CategoryDescription
textAlignMd='center'
textAlignSm='center'
sx={(theme) => ({ px: theme.page.horizontal })}
// sx={(theme) => ({ px: theme.page.horizontal })}
category={category}
productListRenderer={productListRenderer}
/>
<CategoryChildren
sx={(theme) => ({
justifyContent: 'center',
'& .CategoryChildren-scroller': { px: theme.page.horizontal },
// '& .CategoryChildren-scroller': { px: theme.page.horizontal },
})}
params={params}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export const ProductListLayoutSidebar = memoDeep(function ProductListLayoutSideb
display: 'grid',
gridAutoFlow: 'row',
rowGap: theme.spacings.xs,
pt: theme.spacings.md,
})}
>
{category ? (
Expand Down Expand Up @@ -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,
})}
>
<ProductFiltersProClearAll sx={{ alignSelf: 'center' }} />
Expand Down
4 changes: 2 additions & 2 deletions examples/magento-graphcms/components/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ export function LayoutNavigation(props: LayoutNavigationProps) {

<LayoutDefault
{...uiProps}
noSticky={router.asPath.split('?')[0] === '/'}
header={
<>
<Logo />
Expand Down
35 changes: 35 additions & 0 deletions packages/framer-utils/components/StickyBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Box, useForkRef } from '@mui/material'
import type { BoxProps } from '@mui/material/Box'
import clsx from 'clsx'
import { px } from 'framer-motion'
import React, { useRef } from 'react'
import type { StickyStackConfig } from '../hooks/useStickyTop'
import { useStickyTop } from '../hooks/useStickyTop'
import { numberToPx } from '../utils/numberToPx'

export const StickyBox = React.forwardRef<
HTMLDivElement,
BoxProps & {
stickyConfig: Omit<StickyStackConfig<HTMLDivElement>, 'ref'>
}
>((props, forwardedRef) => {
const { sx, children, className, stickyConfig, ...rest } = props
const ref = useRef<HTMLDivElement>(null)
const forkedRef = useForkRef(forwardedRef, ref)
const top = useStickyTop({ ref, ...stickyConfig })

return (
<Box
ref={forkedRef}
style={{ '--top': px.transform(top) }}
sx={[
{ '&.sticky': { position: 'sticky', top: 'var(--top, 0px)' } },
...(Array.isArray(sx) ? sx : [sx]),
]}
className={clsx(className, stickyConfig.sticky && 'sticky')}
{...rest}
>
{children}
</Box>
)
})
37 changes: 37 additions & 0 deletions packages/framer-utils/hooks/useMakeFullscreen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { px } from 'framer-motion'
import { numberToPx } from '../utils/numberToPx'
import type { UseMotionRectOptions } from './useMotionRect'
import { useMotionRect } from './useMotionRect'
import { useMotionValueValue } from './useMotionValueValue'

type UseMakeFullScreenReturn = {
marginTop: string
marginBottom: string
marginLeft: string
marginRight: string
margin: `${string} ${string} ${string} ${string}`
}

/** Calculate negative margin values to make an element fullscreen. */
export function useMakeFullscreen<E extends HTMLElement>(
ref: React.RefObject<E>,
options?: UseMotionRectOptions,
): UseMakeFullScreenReturn {
const rect = useMotionRect(ref, options)

return useMotionValueValue(rect, (r) => {
const { top, left, marginBottom, marginRight } = r
const mt = numberToPx(top * -1)
const mb = numberToPx(marginBottom * -1)
const ml = numberToPx(left * -1)
const mr = numberToPx(marginRight * -1)

return {
marginTop: mt,
marginBottom: mb,
marginLeft: ml,
marginRight: mr,
margin: `${mt} ${mr} ${mb} ${ml}`,
}
})
}
73 changes: 73 additions & 0 deletions packages/framer-utils/hooks/useMotionRect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { useMotionValue } from 'framer-motion'
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'

const emptyRect = {
top: 0,
bottom: 0,
left: 0,
right: 0,
height: 0,
width: 0,
marginTop: 0,
marginLeft: 0,
marginRight: 0,
marginBottom: 0,
}

export type Rect = typeof emptyRect

export type UseMotionRectOptions = {
pause?: boolean
windowResize?: boolean
resizeObserver?: boolean
}

export function useMotionRect<E extends HTMLElement>(
ref: React.RefObject<E>,
options?: UseMotionRectOptions,
) {
const { pause = false, windowResize = true, resizeObserver = false } = options ?? {}

const motionRect = useMotionValue<Rect>(emptyRect)

useIsomorphicLayoutEffect(() => {
if (!ref?.current || pause) return () => {}

const onResize = () => {
if (ref.current) {
const { bottom, right, top, left, height, width } = ref.current.getBoundingClientRect()
const { clientHeight, clientWidth } = document.documentElement
motionRect.set({
top,
bottom,
left,
right,
height,
width,
marginRight: clientWidth - right,
marginBottom: clientHeight - bottom,
marginTop: top,
marginLeft: left,
})
}
}
onResize()

let ro: ResizeObserver | undefined
if (resizeObserver) {
ro = new ResizeObserver(onResize)
ro.observe(ref.current)
}

if (windowResize) {
window.addEventListener('resize', onResize)
}

return () => {
ro?.disconnect()
window.removeEventListener('resize', onResize)
}
}, [motionRect, pause, ref, windowResize, resizeObserver])

return motionRect
}
Loading
Loading