@graphcommerce/next-ui 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +3 -0
- package/AnimatedRow/index.tsx +20 -0
- package/ApolloError/ApolloErrorAlert.tsx +59 -0
- package/ApolloError/ApolloErrorFullPage.tsx +25 -0
- package/AppShell/AppShellHeader/appShellHeaderContext.tsx +11 -0
- package/AppShell/AppShellHeader/index.tsx +433 -0
- package/AppShell/AppShellHeader/useAppShellHeaderContext.tsx +6 -0
- package/AppShell/AppShellProvider/index.tsx +18 -0
- package/AppShell/AppShellSticky/index.tsx +66 -0
- package/AppShell/AppShellTitle/index.tsx +45 -0
- package/AppShell/DesktopNavActions.tsx +28 -0
- package/AppShell/DesktopNavBar.tsx +110 -0
- package/AppShell/FixedFab.tsx +41 -0
- package/AppShell/ForwardButton.tsx +53 -0
- package/AppShell/FullPageShellBase.tsx +59 -0
- package/AppShell/Menu.tsx +7 -0
- package/AppShell/MenuFab.tsx +132 -0
- package/AppShell/MenuFabSecondaryItem.tsx +32 -0
- package/AppShell/MinimalPageShellBase.tsx +22 -0
- package/AppShell/PageShellHeader/index.tsx +14 -0
- package/AppShell/SheetShellBase/index.tsx +107 -0
- package/AppShell/SheetShellBase/useSheetStyles.ts +11 -0
- package/AppShell/SheetShellDragIndicator/index.tsx +48 -0
- package/AppShell/SheetShellHeader/index.tsx +28 -0
- package/AppShell/ShellBase.tsx +45 -0
- package/AppShell/useFabAnimation.tsx +19 -0
- package/AppShell/useFixedFabAnimation.tsx +18 -0
- package/AspectRatioContainer/index.tsx +27 -0
- package/Blog/BlogAuthor/index.tsx +60 -0
- package/Blog/BlogContent/index.tsx +24 -0
- package/Blog/BlogHeader/index.tsx +64 -0
- package/Blog/BlogList/index.tsx +27 -0
- package/Blog/BlogListItem/index.tsx +83 -0
- package/Blog/BlogTags/index.tsx +34 -0
- package/Blog/BlogTitle/index.tsx +29 -0
- package/Button/index.tsx +164 -0
- package/ButtonLink/index.tsx +45 -0
- package/CHANGELOG.md +1095 -0
- package/ChipMenu/index.tsx +130 -0
- package/ContainerWithHeader/index.tsx +49 -0
- package/Debug/DebugSpacer.tsx +51 -0
- package/FlagAvatar/index.tsx +28 -0
- package/Form/FormActions.tsx +15 -0
- package/Form/FormDivider.tsx +14 -0
- package/Form/FormHeader.tsx +27 -0
- package/Form/FormRow.tsx +14 -0
- package/Form/InputCheckmark.tsx +19 -0
- package/Form/index.tsx +62 -0
- package/FramerNextPagesSlider/Slide.tsx +71 -0
- package/FramerNextPagesSlider/Slider.tsx +39 -0
- package/FramerNextPagesSlider/index.ts +1 -0
- package/FramerNextPagesSlider/types.ts +3 -0
- package/FramerScroller/components/SidebarGallery.tsx +246 -0
- package/FramerScroller/components/SidebarSlider.tsx +103 -0
- package/FullPageMessage/index.tsx +68 -0
- package/Highlight/index.tsx +14 -0
- package/IconHeader/index.tsx +109 -0
- package/JsonLd/index.tsx +18 -0
- package/Page/App.tsx +15 -0
- package/Page/Document.tsx +23 -0
- package/Page/framerFeatures.ts +4 -0
- package/Page/types.ts +19 -0
- package/PageLoadIndicator/index.tsx +46 -0
- package/PageMeta/index.tsx +40 -0
- package/Pagination/index.tsx +123 -0
- package/RenderType/index.tsx +40 -0
- package/Row/ButtonLinkList/index.tsx +53 -0
- package/Row/ColumnOne/index.tsx +11 -0
- package/Row/ColumnOneBoxed/index.tsx +27 -0
- package/Row/ColumnOneCentered/index.tsx +22 -0
- package/Row/ColumnThree/index.tsx +66 -0
- package/Row/ColumnTwo/index.tsx +44 -0
- package/Row/ColumnTwoSpread/index.tsx +41 -0
- package/Row/ColumnTwoWithTop/index.tsx +53 -0
- package/Row/ContentLinks/index.tsx +48 -0
- package/Row/HeroBanner/index.tsx +102 -0
- package/Row/IconBlocks/IconBlock/index.tsx +56 -0
- package/Row/IconBlocks/index.tsx +57 -0
- package/Row/ParagraphWithSidebarSlide/index.tsx +114 -0
- package/Row/Quote/index.tsx +13 -0
- package/Row/RowImageText/index.tsx +67 -0
- package/Row/RowImageTextBoxed/index.tsx +75 -0
- package/Row/SpecialBanner/index.tsx +107 -0
- package/Row/index.tsx +13 -0
- package/SectionContainer/index.tsx +39 -0
- package/SectionHeader/index.tsx +69 -0
- package/Separator/index.tsx +33 -0
- package/Snackbar/ErrorSnackbar.tsx +9 -0
- package/Snackbar/MessageSnackbar.tsx +5 -0
- package/Snackbar/MessageSnackbarImpl.tsx +202 -0
- package/StarRatingField/index.tsx +58 -0
- package/Stepper/Stepper.tsx +45 -0
- package/StyledBadge/index.tsx +21 -0
- package/Styles/index.tsx +3 -0
- package/Styles/responsiveVal.tsx +20 -0
- package/SvgImage/SvgImageSimple.tsx +66 -0
- package/SvgImage/index.tsx +76 -0
- package/TextInputNumber/index.tsx +169 -0
- package/Theme/types.ts +63 -0
- package/TimeAgo/index.tsx +29 -0
- package/Title/index.tsx +71 -0
- package/ToggleButton/index.tsx +100 -0
- package/ToggleButtonGroup/index.tsx +112 -0
- package/UspList/UspListItem.tsx +46 -0
- package/UspList/index.tsx +32 -0
- package/icons/icon_addresses.svg +17 -0
- package/icons/icon_arrow_back.svg +1 -0
- package/icons/icon_arrow_forward.svg +1 -0
- package/icons/icon_box.svg +6 -0
- package/icons/icon_chat.svg +1 -0
- package/icons/icon_checkmark.svg +1 -0
- package/icons/icon_checkmark_green.svg +1 -0
- package/icons/icon_chevron_back.svg +8 -0
- package/icons/icon_chevron_down.svg +8 -0
- package/icons/icon_chevron_left.svg +8 -0
- package/icons/icon_chevron_right.svg +8 -0
- package/icons/icon_chevron_up.svg +8 -0
- package/icons/icon_close.svg +6 -0
- package/icons/icon_close_circle.svg +1 -0
- package/icons/icon_collapse_vertical.svg +11 -0
- package/icons/icon_customer_service.svg +6 -0
- package/icons/icon_email.svg +1 -0
- package/icons/icon_email_outline.svg +6 -0
- package/icons/icon_expand_vertical.svg +11 -0
- package/icons/icon_heart.svg +15 -0
- package/icons/icon_home.svg +6 -0
- package/icons/icon_id.svg +6 -0
- package/icons/icon_invoice_red.svg +7 -0
- package/icons/icon_location_red.svg +7 -0
- package/icons/icon_lock.svg +6 -0
- package/icons/icon_menu.svg +1 -0
- package/icons/icon_min.svg +1 -0
- package/icons/icon_newspaper.svg +6 -0
- package/icons/icon_party.svg +7 -0
- package/icons/icon_person.svg +6 -0
- package/icons/icon_person_alt.svg +6 -0
- package/icons/icon_person_alt_big.svg +15 -0
- package/icons/icon_phone.svg +1 -0
- package/icons/icon_plus.svg +1 -0
- package/icons/icon_sad_face.svg +11 -0
- package/icons/icon_sad_shoppingbag.svg +16 -0
- package/icons/icon_search.svg +1 -0
- package/icons/icon_shopping_bag.svg +7 -0
- package/icons/icon_shutdown.svg +6 -0
- package/icons/icon_star.svg +6 -0
- package/icons/icon_star_filled_muted.svg +6 -0
- package/icons/icon_star_yellow.svg +6 -0
- package/icons/index.tsx +42 -0
- package/index.ts +163 -0
- package/package.json +61 -0
- package/tsconfig.json +5 -0
- package/types.d.ts +13 -0
- package/useIntersectionObserver/index.tsx +31 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { Fab, makeStyles, Theme, useTheme } from '@material-ui/core'
|
|
2
|
+
import {
|
|
3
|
+
ScrollerButton,
|
|
4
|
+
ScrollerDots,
|
|
5
|
+
ScrollerProvider,
|
|
6
|
+
Scroller,
|
|
7
|
+
MotionImageAspectProps,
|
|
8
|
+
CenterSlide,
|
|
9
|
+
MotionImageAspect,
|
|
10
|
+
} from '@graphcommerce/framer-scroller'
|
|
11
|
+
import { clientSize, useMotionValueValue } from '@graphcommerce/framer-utils'
|
|
12
|
+
import clsx from 'clsx'
|
|
13
|
+
import { m } from 'framer-motion'
|
|
14
|
+
import React, { useState } from 'react'
|
|
15
|
+
import { UseStyles } from '../../Styles'
|
|
16
|
+
import responsiveVal from '../../Styles/responsiveVal'
|
|
17
|
+
import SvgImage from '../../SvgImage'
|
|
18
|
+
import SvgImageSimple from '../../SvgImage/SvgImageSimple'
|
|
19
|
+
import {
|
|
20
|
+
iconChevronLeft,
|
|
21
|
+
iconChevronRight,
|
|
22
|
+
iconCollapseVertical,
|
|
23
|
+
iconExpandVertical,
|
|
24
|
+
} from '../../icons'
|
|
25
|
+
|
|
26
|
+
type StyleProps = {
|
|
27
|
+
aspectRatio: [number, number]
|
|
28
|
+
clientHeight: number
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const useStyles = makeStyles(
|
|
32
|
+
(theme: Theme) => ({
|
|
33
|
+
root: {
|
|
34
|
+
display: 'grid',
|
|
35
|
+
[theme.breakpoints.up('md')]: {
|
|
36
|
+
gridTemplateColumns: '1fr auto',
|
|
37
|
+
},
|
|
38
|
+
background: theme.palette.background.highlight,
|
|
39
|
+
paddingRight: `calc((100% - ${theme.breakpoints.values.lg}px) / 2)`,
|
|
40
|
+
marginBottom: theme.spacings.lg,
|
|
41
|
+
},
|
|
42
|
+
rootZoomed: {
|
|
43
|
+
position: 'relative',
|
|
44
|
+
zIndex: theme.zIndex.modal,
|
|
45
|
+
marginTop: 0,
|
|
46
|
+
[theme.breakpoints.up('md')]: {
|
|
47
|
+
marginTop: `calc(${theme.page.headerInnerHeight.md} * -1 - ${theme.spacings.sm} * 2)`,
|
|
48
|
+
},
|
|
49
|
+
paddingRight: 0,
|
|
50
|
+
},
|
|
51
|
+
scrollerContainer: ({ aspectRatio: [width, height] }: StyleProps) => {
|
|
52
|
+
const headerHeight = `${theme.page.headerInnerHeight.sm} - ${theme.spacings.sm} * 2`
|
|
53
|
+
const galleryMargin = theme.spacings.lg
|
|
54
|
+
const extraSpacing = theme.spacings.md
|
|
55
|
+
|
|
56
|
+
const maxHeight = `calc(100vh - ${headerHeight} - ${galleryMargin} - ${extraSpacing})`
|
|
57
|
+
const ratio = `calc(${height} / ${width} * 100%)`
|
|
58
|
+
return {
|
|
59
|
+
height: 0, // https://stackoverflow.com/questions/44770074/css-grid-row-height-safari-bug
|
|
60
|
+
position: 'relative',
|
|
61
|
+
minHeight: '100%',
|
|
62
|
+
paddingTop: `min(${ratio}, ${maxHeight})`,
|
|
63
|
+
borderRadius: 2,
|
|
64
|
+
[theme.breakpoints.down('sm')]: {
|
|
65
|
+
width: '100vw',
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
scrollerContainerZoomed: ({ clientHeight }: StyleProps) => ({
|
|
70
|
+
paddingTop: clientHeight,
|
|
71
|
+
}),
|
|
72
|
+
scroller: {
|
|
73
|
+
position: 'absolute',
|
|
74
|
+
top: 0,
|
|
75
|
+
width: '100%',
|
|
76
|
+
height: '100%',
|
|
77
|
+
display: `grid`,
|
|
78
|
+
gridAutoFlow: `column`,
|
|
79
|
+
gridTemplateColumns: `repeat(100, 100%)`,
|
|
80
|
+
gridTemplateRows: `100%`,
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
sidebarWrapper: {
|
|
84
|
+
boxSizing: 'content-box',
|
|
85
|
+
display: 'grid',
|
|
86
|
+
justifyItems: 'start',
|
|
87
|
+
alignContent: 'center',
|
|
88
|
+
position: 'relative',
|
|
89
|
+
[theme.breakpoints.up('md')]: {
|
|
90
|
+
width: `calc(${responsiveVal(300, 500, theme.breakpoints.values.lg)} + ${
|
|
91
|
+
theme.page.horizontal
|
|
92
|
+
} * 2)`,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
sidebarWrapperZoomed: {
|
|
96
|
+
[theme.breakpoints.up('md')]: {
|
|
97
|
+
marginLeft: `calc((${responsiveVal(300, 500, theme.breakpoints.values.lg)} + ${
|
|
98
|
+
theme.page.horizontal
|
|
99
|
+
} * 2) * -1)`,
|
|
100
|
+
left: `calc(${responsiveVal(300, 500, theme.breakpoints.values.lg)} + ${
|
|
101
|
+
theme.page.horizontal
|
|
102
|
+
} * 2)`,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
sidebar: {
|
|
106
|
+
boxSizing: 'border-box',
|
|
107
|
+
width: '100%',
|
|
108
|
+
padding: `${theme.spacings.md} ${theme.page.horizontal}`,
|
|
109
|
+
[theme.breakpoints.up('md')]: {
|
|
110
|
+
paddingLeft: theme.spacings.lg,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
bottomCenter: {
|
|
114
|
+
display: 'grid',
|
|
115
|
+
gridAutoFlow: 'column',
|
|
116
|
+
gap: theme.spacings.xxs,
|
|
117
|
+
position: 'absolute',
|
|
118
|
+
bottom: theme.spacings.xxs,
|
|
119
|
+
justifyContent: 'center',
|
|
120
|
+
width: '100%',
|
|
121
|
+
pointerEvents: 'none',
|
|
122
|
+
'& > *': {
|
|
123
|
+
pointerEvents: 'all',
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
sliderButtons: {
|
|
127
|
+
[theme.breakpoints.down('sm')]: {
|
|
128
|
+
display: 'none',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
toggleIcon: {
|
|
132
|
+
boxShadow: theme.shadows[2],
|
|
133
|
+
},
|
|
134
|
+
topRight: {
|
|
135
|
+
display: 'grid',
|
|
136
|
+
gridAutoFlow: 'column',
|
|
137
|
+
top: theme.spacings.sm,
|
|
138
|
+
gap: theme.spacings.xxs,
|
|
139
|
+
position: 'absolute',
|
|
140
|
+
right: theme.spacings.sm,
|
|
141
|
+
},
|
|
142
|
+
centerLeft: {
|
|
143
|
+
display: 'grid',
|
|
144
|
+
gridAutoFlow: 'row',
|
|
145
|
+
gap: theme.spacings.xxs,
|
|
146
|
+
position: 'absolute',
|
|
147
|
+
left: theme.spacings.sm,
|
|
148
|
+
top: `calc(50% - 28px)`,
|
|
149
|
+
},
|
|
150
|
+
centerRight: {
|
|
151
|
+
display: 'grid',
|
|
152
|
+
gap: theme.spacings.xxs,
|
|
153
|
+
position: 'absolute',
|
|
154
|
+
right: theme.spacings.sm,
|
|
155
|
+
top: `calc(50% - 28px)`,
|
|
156
|
+
},
|
|
157
|
+
}),
|
|
158
|
+
{ name: 'SidebarGallery' },
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
export type SidebarGalleryProps = {
|
|
162
|
+
sidebar: React.ReactNode
|
|
163
|
+
images: MotionImageAspectProps[]
|
|
164
|
+
aspectRatio?: [number, number]
|
|
165
|
+
} & UseStyles<typeof useStyles>
|
|
166
|
+
|
|
167
|
+
export default function SidebarGallery(props: SidebarGalleryProps) {
|
|
168
|
+
const { sidebar, images, aspectRatio = [1, 1] } = props
|
|
169
|
+
const [zoomed, setZoomed] = useState(false)
|
|
170
|
+
|
|
171
|
+
const clientHeight = useMotionValueValue(clientSize.y, (y) => y)
|
|
172
|
+
const classes = useStyles({ clientHeight, aspectRatio })
|
|
173
|
+
|
|
174
|
+
const toggle = () => {
|
|
175
|
+
setZoomed(!zoomed)
|
|
176
|
+
if (!zoomed) {
|
|
177
|
+
document.body.style.overflow = 'hidden'
|
|
178
|
+
window.scrollTo({ top: 0, behavior: 'smooth' })
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const clsxZoom = (key: string) => clsx(classes?.[key], zoomed && classes?.[`${key}Zoomed`])
|
|
183
|
+
|
|
184
|
+
const theme = useTheme()
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<ScrollerProvider scrollSnapAlign='center'>
|
|
188
|
+
<m.div layout className={clsxZoom('root')}>
|
|
189
|
+
<m.div
|
|
190
|
+
layout
|
|
191
|
+
className={clsxZoom('scrollerContainer')}
|
|
192
|
+
onLayoutAnimationComplete={() => {
|
|
193
|
+
if (!zoomed) document.body.style.overflow = ''
|
|
194
|
+
}}
|
|
195
|
+
>
|
|
196
|
+
<Scroller className={clsxZoom('scroller')} hideScrollbar>
|
|
197
|
+
{images.map((image, idx) => (
|
|
198
|
+
<CenterSlide key={typeof image.src === 'string' ? image.src : idx}>
|
|
199
|
+
<MotionImageAspect
|
|
200
|
+
layout
|
|
201
|
+
src={image.src}
|
|
202
|
+
width={image.width}
|
|
203
|
+
height={image.height}
|
|
204
|
+
loading={idx === 0 ? 'eager' : 'lazy'}
|
|
205
|
+
sizes={{
|
|
206
|
+
0: '100vw',
|
|
207
|
+
[theme.breakpoints.values.md]: zoomed ? '100vw' : '60vw',
|
|
208
|
+
}}
|
|
209
|
+
dontReportWronglySizedImages
|
|
210
|
+
/>
|
|
211
|
+
</CenterSlide>
|
|
212
|
+
))}
|
|
213
|
+
</Scroller>
|
|
214
|
+
<m.div layout className={classes.topRight}>
|
|
215
|
+
<Fab color='inherit' size='small' className={classes.toggleIcon} onClick={toggle}>
|
|
216
|
+
{!zoomed ? (
|
|
217
|
+
<SvgImage src={iconExpandVertical} alt='Zoom in' loading='eager' />
|
|
218
|
+
) : (
|
|
219
|
+
<SvgImage src={iconCollapseVertical} alt='Zoom out' loading='eager' />
|
|
220
|
+
)}
|
|
221
|
+
</Fab>
|
|
222
|
+
</m.div>
|
|
223
|
+
<div className={classes.centerLeft}>
|
|
224
|
+
<ScrollerButton layout direction='left' size='small' className={classes.sliderButtons}>
|
|
225
|
+
<SvgImageSimple src={iconChevronLeft} />
|
|
226
|
+
</ScrollerButton>
|
|
227
|
+
</div>
|
|
228
|
+
<div className={classes.centerRight}>
|
|
229
|
+
<ScrollerButton layout direction='right' size='small' className={classes.sliderButtons}>
|
|
230
|
+
<SvgImageSimple src={iconChevronRight} />
|
|
231
|
+
</ScrollerButton>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<div className={classes.bottomCenter}>
|
|
235
|
+
<ScrollerDots layout />
|
|
236
|
+
</div>
|
|
237
|
+
</m.div>
|
|
238
|
+
<div className={clsxZoom('sidebarWrapper')}>
|
|
239
|
+
<m.div layout className={clsxZoom('sidebar')}>
|
|
240
|
+
{sidebar}
|
|
241
|
+
</m.div>
|
|
242
|
+
</div>
|
|
243
|
+
</m.div>
|
|
244
|
+
</ScrollerProvider>
|
|
245
|
+
)
|
|
246
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { relative } from 'path/posix'
|
|
2
|
+
import { Theme } from '@material-ui/core'
|
|
3
|
+
import { makeStyles } from '@material-ui/styles'
|
|
4
|
+
import {
|
|
5
|
+
Scroller,
|
|
6
|
+
ScrollerButton,
|
|
7
|
+
ScrollerPageCounter,
|
|
8
|
+
ScrollerProvider,
|
|
9
|
+
} from '@graphcommerce/framer-scroller'
|
|
10
|
+
import React, { ReactNode } from 'react'
|
|
11
|
+
import { SvgImageSimple, iconChevronLeft, iconChevronRight } from '../..'
|
|
12
|
+
import { UseStyles } from '../../Styles'
|
|
13
|
+
import responsiveVal from '../../Styles/responsiveVal'
|
|
14
|
+
|
|
15
|
+
const useStyles = makeStyles(
|
|
16
|
+
(theme: Theme) => ({
|
|
17
|
+
root: {
|
|
18
|
+
display: 'grid',
|
|
19
|
+
gridTemplateColumns: 'minmax(150px, 25%) 1fr',
|
|
20
|
+
maxWidth: '100%',
|
|
21
|
+
marginBottom: `${theme.spacings.xl}`,
|
|
22
|
+
},
|
|
23
|
+
sidebar: {
|
|
24
|
+
display: 'grid',
|
|
25
|
+
alignContent: 'space-between',
|
|
26
|
+
padding: `0 ${theme.spacings.lg} 0 ${theme.page.horizontal}`,
|
|
27
|
+
},
|
|
28
|
+
scrollerContainer: {
|
|
29
|
+
position: 'relative',
|
|
30
|
+
minWidth: 1,
|
|
31
|
+
},
|
|
32
|
+
scroller: {
|
|
33
|
+
width: '100%',
|
|
34
|
+
display: 'grid',
|
|
35
|
+
gridAutoFlow: 'column',
|
|
36
|
+
gridColumnGap: theme.spacings.md,
|
|
37
|
+
gridRowGap: theme.spacings.lg,
|
|
38
|
+
alignContent: 'space-around',
|
|
39
|
+
paddingRight: theme.page.horizontal,
|
|
40
|
+
|
|
41
|
+
'& > *': {
|
|
42
|
+
minWidth: responsiveVal(200, 400),
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
sliderButtons: {
|
|
46
|
+
[theme.breakpoints.down('sm')]: {
|
|
47
|
+
display: 'none',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
centerLeft: {
|
|
51
|
+
display: 'grid',
|
|
52
|
+
gridAutoFlow: 'row',
|
|
53
|
+
gap: theme.spacings.xxs,
|
|
54
|
+
position: 'absolute',
|
|
55
|
+
left: theme.spacings.sm,
|
|
56
|
+
top: `calc(50% - 28px)`,
|
|
57
|
+
},
|
|
58
|
+
centerRight: {
|
|
59
|
+
display: 'grid',
|
|
60
|
+
gap: theme.spacings.xxs,
|
|
61
|
+
position: 'absolute',
|
|
62
|
+
right: theme.spacings.sm,
|
|
63
|
+
top: `calc(50% - 28px)`,
|
|
64
|
+
},
|
|
65
|
+
}),
|
|
66
|
+
{ name: 'SidebarSlider' },
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
export type SidebarSliderProps = { children: ReactNode; sidebar: ReactNode } & UseStyles<
|
|
70
|
+
typeof useStyles
|
|
71
|
+
>
|
|
72
|
+
|
|
73
|
+
export default function SidebarSlider(props: SidebarSliderProps) {
|
|
74
|
+
const { children, sidebar } = props
|
|
75
|
+
const classes = useStyles(props)
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<ScrollerProvider scrollSnapAlign='start'>
|
|
79
|
+
<div className={classes.root}>
|
|
80
|
+
<div className={classes.sidebar}>
|
|
81
|
+
<div>{sidebar}</div>
|
|
82
|
+
<ScrollerPageCounter />
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<div className={classes.scrollerContainer}>
|
|
86
|
+
<Scroller className={classes.scroller} hideScrollbar>
|
|
87
|
+
{children}
|
|
88
|
+
</Scroller>
|
|
89
|
+
<div className={classes.centerLeft}>
|
|
90
|
+
<ScrollerButton layout direction='left' className={classes.sliderButtons}>
|
|
91
|
+
<SvgImageSimple src={iconChevronLeft} />
|
|
92
|
+
</ScrollerButton>
|
|
93
|
+
</div>
|
|
94
|
+
<div className={classes.centerRight}>
|
|
95
|
+
<ScrollerButton layout direction='right' className={classes.sliderButtons}>
|
|
96
|
+
<SvgImageSimple src={iconChevronRight} />
|
|
97
|
+
</ScrollerButton>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</ScrollerProvider>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Container, Theme, Typography } from '@material-ui/core'
|
|
2
|
+
import { makeStyles } from '@material-ui/styles'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import PageMeta from '../PageMeta'
|
|
5
|
+
import responsiveVal from '../Styles/responsiveVal'
|
|
6
|
+
|
|
7
|
+
const useStyles = makeStyles(
|
|
8
|
+
(theme: Theme) => ({
|
|
9
|
+
root: {
|
|
10
|
+
marginTop: responsiveVal(50, 250),
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
},
|
|
13
|
+
subject: {
|
|
14
|
+
textAlign: 'center',
|
|
15
|
+
margin: `${theme.spacings.sm} 0`,
|
|
16
|
+
},
|
|
17
|
+
description: {
|
|
18
|
+
marginTop: 8,
|
|
19
|
+
},
|
|
20
|
+
innerContainer: {
|
|
21
|
+
display: 'grid',
|
|
22
|
+
alignItems: 'center',
|
|
23
|
+
justifyItems: 'center',
|
|
24
|
+
},
|
|
25
|
+
button: {
|
|
26
|
+
marginTop: 6,
|
|
27
|
+
},
|
|
28
|
+
}),
|
|
29
|
+
{
|
|
30
|
+
name: 'FullPageMessage',
|
|
31
|
+
},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
export type FullPageMessageProps = {
|
|
35
|
+
icon: React.ReactNode
|
|
36
|
+
title: React.ReactNode
|
|
37
|
+
description?: React.ReactNode
|
|
38
|
+
button?: React.ReactNode
|
|
39
|
+
altButton?: React.ReactNode
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default function FullPageMessage(props: FullPageMessageProps) {
|
|
43
|
+
const { icon, title, description, button, altButton } = props
|
|
44
|
+
const classes = useStyles()
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className={classes.root}>
|
|
48
|
+
<Container maxWidth='md' className={classes.innerContainer}>
|
|
49
|
+
<PageMeta title='Account' metaDescription='Account Dashboard' metaRobots={['noindex']} />
|
|
50
|
+
{icon}
|
|
51
|
+
|
|
52
|
+
<div className={classes.subject}>
|
|
53
|
+
<Typography component='h2' variant='h4'>
|
|
54
|
+
{title}
|
|
55
|
+
</Typography>
|
|
56
|
+
{description && (
|
|
57
|
+
<Typography component='p' variant='body1' className={classes.description}>
|
|
58
|
+
{description}
|
|
59
|
+
</Typography>
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div>{button}</div>
|
|
64
|
+
<div className={classes.button}>{altButton}</div>
|
|
65
|
+
</Container>
|
|
66
|
+
</div>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export default function Highlight(props: { text: string; highlight: string }) {
|
|
2
|
+
const { text, highlight } = props
|
|
3
|
+
const start = text.toLocaleLowerCase().indexOf(highlight.toLocaleLowerCase())
|
|
4
|
+
|
|
5
|
+
if (start < 0) return <>{text}</>
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
{text.slice(0, start)}
|
|
10
|
+
<strong>{text.slice(start, highlight.length + start)}</strong>
|
|
11
|
+
{text.slice(start + highlight.length)}
|
|
12
|
+
</>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { makeStyles, Theme, Typography } from '@material-ui/core'
|
|
2
|
+
import clsx from 'clsx'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import responsiveVal from '../Styles/responsiveVal'
|
|
5
|
+
import SvgImage, { SvgImageProps } from '../SvgImage'
|
|
6
|
+
|
|
7
|
+
// TODO: remove all occurrences. deprecated component
|
|
8
|
+
|
|
9
|
+
const useStyles = makeStyles(
|
|
10
|
+
(theme: Theme) => ({
|
|
11
|
+
container: {
|
|
12
|
+
textAlign: 'center',
|
|
13
|
+
fontSize: responsiveVal(16, 24),
|
|
14
|
+
},
|
|
15
|
+
innerContainer: {
|
|
16
|
+
display: 'flex',
|
|
17
|
+
alignItems: 'center',
|
|
18
|
+
justifyContent: 'center',
|
|
19
|
+
gap: 4,
|
|
20
|
+
},
|
|
21
|
+
breakColumnsDesktop: {
|
|
22
|
+
[theme.breakpoints.up('md')]: {
|
|
23
|
+
display: 'unset',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
margin: {
|
|
27
|
+
marginTop: theme.spacings.sm,
|
|
28
|
+
marginBottom: theme.spacings.sm,
|
|
29
|
+
},
|
|
30
|
+
ellipsis: {
|
|
31
|
+
whiteSpace: 'nowrap',
|
|
32
|
+
overflow: 'hidden',
|
|
33
|
+
textOverflow: 'ellipsis',
|
|
34
|
+
},
|
|
35
|
+
mediumFontWeight: {
|
|
36
|
+
fontWeight: 700,
|
|
37
|
+
},
|
|
38
|
+
}),
|
|
39
|
+
{ name: 'IconHeader' },
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
export type IconHeaderSize = 'small' | 'medium' | 'large'
|
|
43
|
+
|
|
44
|
+
type IconHeaderProps = {
|
|
45
|
+
title: string
|
|
46
|
+
size?: IconHeaderSize
|
|
47
|
+
iconSize?: number
|
|
48
|
+
iconSizeMobile?: number
|
|
49
|
+
noMargin?: boolean
|
|
50
|
+
stayInline?: boolean
|
|
51
|
+
ellipsis?: boolean
|
|
52
|
+
} & Pick<SvgImageProps, 'src' | 'alt'>
|
|
53
|
+
|
|
54
|
+
type IconHeaderHeadings = 'h2' | 'h4' | 'h5'
|
|
55
|
+
|
|
56
|
+
export default function IconHeader(props: IconHeaderProps) {
|
|
57
|
+
const {
|
|
58
|
+
title,
|
|
59
|
+
size = 'large',
|
|
60
|
+
stayInline = false,
|
|
61
|
+
noMargin = false,
|
|
62
|
+
ellipsis = false,
|
|
63
|
+
iconSize,
|
|
64
|
+
iconSizeMobile,
|
|
65
|
+
...svgImageProps
|
|
66
|
+
} = props
|
|
67
|
+
const classes = useStyles()
|
|
68
|
+
|
|
69
|
+
const variants: Record<IconHeaderSize, IconHeaderHeadings> = {
|
|
70
|
+
small: 'h5',
|
|
71
|
+
medium: 'h4',
|
|
72
|
+
large: 'h2',
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const iconSizes = {
|
|
76
|
+
small: 32,
|
|
77
|
+
medium: 48,
|
|
78
|
+
large: 64,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const iconMobileSizes = {
|
|
82
|
+
small: 24,
|
|
83
|
+
medium: 32,
|
|
84
|
+
large: 40,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<div className={clsx(classes.container, !noMargin && classes.margin)}>
|
|
89
|
+
<div className={clsx(classes.innerContainer, !stayInline && classes.breakColumnsDesktop)}>
|
|
90
|
+
<SvgImage
|
|
91
|
+
{...svgImageProps}
|
|
92
|
+
size={iconSize ?? iconSizes[size]}
|
|
93
|
+
mobileSize={iconSizeMobile ?? iconMobileSizes[size]}
|
|
94
|
+
loading='eager'
|
|
95
|
+
/>
|
|
96
|
+
<Typography
|
|
97
|
+
variant={variants[size]}
|
|
98
|
+
component='h2'
|
|
99
|
+
className={clsx(
|
|
100
|
+
ellipsis && classes.ellipsis,
|
|
101
|
+
size === 'medium' && classes.mediumFontWeight,
|
|
102
|
+
)}
|
|
103
|
+
>
|
|
104
|
+
{title}
|
|
105
|
+
</Typography>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
)
|
|
109
|
+
}
|
package/JsonLd/index.tsx
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Head from 'next/head'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { jsonLdScriptProps } from 'react-schemaorg'
|
|
4
|
+
import { Thing, WithContext } from 'schema-dts'
|
|
5
|
+
|
|
6
|
+
export type JsonLdProps<T extends Thing> = {
|
|
7
|
+
item: WithContext<T>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function JsonLd<T extends Thing>(props: JsonLdProps<T>) {
|
|
11
|
+
const { item } = props
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Head>
|
|
15
|
+
<script key='jsonld' {...jsonLdScriptProps<T>(item)} />
|
|
16
|
+
</Head>
|
|
17
|
+
)
|
|
18
|
+
}
|
package/Page/App.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FramerNextPages } from '@graphcommerce/framer-next-pages'
|
|
2
|
+
import { LazyMotion } from 'framer-motion'
|
|
3
|
+
import { AppPropsType } from 'next/dist/shared/lib/utils'
|
|
4
|
+
import React, { useEffect } from 'react'
|
|
5
|
+
import { AppProps } from './types'
|
|
6
|
+
|
|
7
|
+
export default function App(props: AppProps & AppPropsType) {
|
|
8
|
+
useEffect(() => document.getElementById('jss-server-side')?.remove())
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<LazyMotion features={async () => (await import('./framerFeatures')).default} strict>
|
|
12
|
+
<FramerNextPages {...props} />
|
|
13
|
+
</LazyMotion>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ServerStyleSheets } from '@material-ui/core/styles'
|
|
2
|
+
import NextDocument, { DocumentContext } from 'next/document'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
export default class Document extends NextDocument {
|
|
6
|
+
static getInitialProps = async (ctx: DocumentContext) => {
|
|
7
|
+
const sheets = new ServerStyleSheets()
|
|
8
|
+
const originalRenderPage = ctx.renderPage
|
|
9
|
+
|
|
10
|
+
ctx.renderPage = () =>
|
|
11
|
+
originalRenderPage({
|
|
12
|
+
enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const initialProps = await NextDocument.getInitialProps(ctx)
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
...initialProps,
|
|
19
|
+
// Styles fragment is rendered after the app and page rendering finish.
|
|
20
|
+
styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()],
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
package/Page/types.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ParsedUrlQuery } from 'querystring'
|
|
2
|
+
import { NormalizedCacheObject } from '@apollo/client'
|
|
3
|
+
import { GetStaticProps as GetStaticPropsNext } from 'next'
|
|
4
|
+
import { AppProps as NextAppProps } from 'next/app'
|
|
5
|
+
|
|
6
|
+
type AnyObj = Record<string, unknown>
|
|
7
|
+
|
|
8
|
+
type ApolloStateProps = { apolloState: NormalizedCacheObject }
|
|
9
|
+
|
|
10
|
+
export type GetStaticProps<
|
|
11
|
+
PL extends AnyObj,
|
|
12
|
+
P extends AnyObj = AnyObj,
|
|
13
|
+
Q extends ParsedUrlQuery = ParsedUrlQuery
|
|
14
|
+
> = GetStaticPropsNext<P & Omit<PL, 'children'> & ApolloStateProps, Q>
|
|
15
|
+
|
|
16
|
+
/** Used by _app */
|
|
17
|
+
export type AppProps = Omit<NextAppProps, 'pageProps'> & {
|
|
18
|
+
pageProps: ApolloStateProps
|
|
19
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { LinearProgress, makeStyles, Fade } from '@material-ui/core'
|
|
2
|
+
import zIndex from '@material-ui/core/styles/zIndex'
|
|
3
|
+
import { useRouter } from 'next/router'
|
|
4
|
+
import React, { useEffect, useState } from 'react'
|
|
5
|
+
|
|
6
|
+
const useStyles = makeStyles(
|
|
7
|
+
{
|
|
8
|
+
progress: {
|
|
9
|
+
position: 'fixed',
|
|
10
|
+
width: '100%',
|
|
11
|
+
top: 0,
|
|
12
|
+
height: 3,
|
|
13
|
+
marginBottom: -3,
|
|
14
|
+
zIndex: zIndex.tooltip,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
{ name: 'PageLoadIndicator' },
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
function PageLoadIndicator() {
|
|
21
|
+
const router = useRouter()
|
|
22
|
+
const classes = useStyles()
|
|
23
|
+
const [loading, setLoading] = useState<boolean>(false)
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const show = () => setLoading(true)
|
|
27
|
+
const hide = () => setLoading(false)
|
|
28
|
+
router.events.on('routeChangeStart', show)
|
|
29
|
+
router.events.on('routeChangeComplete', hide)
|
|
30
|
+
router.events.on('routeChangeError', hide)
|
|
31
|
+
|
|
32
|
+
return () => {
|
|
33
|
+
router.events.off('routeChangeStart', show)
|
|
34
|
+
router.events.off('routeChangeComplete', hide)
|
|
35
|
+
router.events.off('routeChangeError', hide)
|
|
36
|
+
}
|
|
37
|
+
}, [router.events])
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Fade in={loading}>
|
|
41
|
+
<LinearProgress className={classes.progress} />
|
|
42
|
+
</Fade>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default PageLoadIndicator
|