@luxfi/ui 5.5.3 → 6.0.0
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/README.md +109 -0
- package/package.json +81 -73
- package/commerce/ui/conf.ts +0 -13
- package/commerce/ui/context.tsx +0 -123
- package/commerce/ui/store.ts +0 -295
- package/components/access-code-input.tsx +0 -71
- package/components/analytics.tsx +0 -23
- package/components/auth/auth-listener.tsx +0 -29
- package/components/auth/auth-token/clear-auth-token.tsx +0 -12
- package/components/auth/auth-token/set-auth-token.tsx +0 -16
- package/components/auth/common-auth-domains.ts +0 -17
- package/components/auth/login-panel.tsx +0 -111
- package/components/auth/mobile-login-button.tsx +0 -107
- package/components/auth/signup-panel.tsx +0 -113
- package/components/back-button.tsx +0 -49
- package/components/chat-widget.tsx +0 -85
- package/components/commerce/bag-button.tsx +0 -98
- package/components/commerce/buy-button.tsx +0 -34
- package/components/commerce/checkout-button.tsx +0 -129
- package/components/commerce/checkout-panel/cart-accordian.tsx +0 -66
- package/components/commerce/checkout-panel/checkout-panel-props.ts +0 -10
- package/components/commerce/checkout-panel/desktop-bag-carousel.tsx +0 -36
- package/components/commerce/checkout-panel/desktop-cp.tsx +0 -83
- package/components/commerce/checkout-panel/index.tsx +0 -126
- package/components/commerce/checkout-panel/mobile-cp.tsx +0 -67
- package/components/commerce/checkout-panel/policy-links.tsx +0 -29
- package/components/commerce/checkout-panel/steps-indicator.tsx +0 -39
- package/components/commerce/checkout-panel/thank-you.tsx +0 -18
- package/components/commerce/desktop-bag-popup.tsx +0 -78
- package/components/commerce/drawer/index.tsx +0 -88
- package/components/commerce/drawer/micro.tsx +0 -145
- package/components/commerce/drawer/shell.tsx +0 -85
- package/components/contact-dialog/contact-form.tsx +0 -116
- package/components/contact-dialog/disclaimer.tsx +0 -13
- package/components/contact-dialog/index.tsx +0 -64
- package/components/copyright.tsx +0 -21
- package/components/drawer-margin.tsx +0 -28
- package/components/footer.tsx +0 -78
- package/components/header/desktop-nav-menu.tsx +0 -204
- package/components/header/desktop.tsx +0 -65
- package/components/header/index.tsx +0 -50
- package/components/header/mobile-bag-drawer.tsx +0 -51
- package/components/header/mobile-menu-toggle-button.tsx +0 -35
- package/components/header/mobile-nav-menu-ai.tsx +0 -51
- package/components/header/mobile-nav-menu-item.tsx +0 -47
- package/components/header/mobile-nav-menu.tsx +0 -102
- package/components/header/mobile.tsx +0 -170
- package/components/header/theme-toggle.tsx +0 -26
- package/components/icons/avatar.tsx +0 -11
- package/components/icons/bag-icon.tsx +0 -10
- package/components/icons/index.ts +0 -6
- package/components/icons/left-arrow.tsx +0 -11
- package/components/icons/lux-logo.tsx +0 -10
- package/components/icons/right-arrow.tsx +0 -10
- package/components/icons/social-icon.tsx +0 -35
- package/components/icons/social-svg.css +0 -3
- package/components/index.ts +0 -26
- package/components/logo.tsx +0 -92
- package/components/main.tsx +0 -27
- package/components/mini-chart/index.tsx +0 -8
- package/components/mini-chart/mini-chart-props.ts +0 -44
- package/components/mini-chart/mini-chart.tsx +0 -85
- package/components/mini-chart/wrapper.tsx +0 -23
- package/components/not-found/index.tsx +0 -28
- package/components/not-found/not-found-content.mdx +0 -5
- package/components/tooltip.tsx +0 -31
- package/environment.d.ts +0 -6
- package/next/analytics/fpixel.ts +0 -16
- package/next/analytics/google-analytics.ts +0 -14
- package/next/analytics/index.ts +0 -3
- package/next/analytics/pixel-analytics.tsx +0 -55
- package/next/font/get-app-router-font-classes.ts +0 -17
- package/next/font/load-and-return-lux-next-fonts-on-import.ts +0 -68
- package/next/font/local/Druk-Wide-Bold.ttf +0 -0
- package/next/font/local/Druk-Wide-Medium.ttf +0 -0
- package/next/font/local/InterVariable-Italic.ttf +0 -0
- package/next/font/local/InterVariable-Italic.woff2 +0 -0
- package/next/font/local/InterVariable.ttf +0 -0
- package/next/font/local/InterVariable.woff2 +0 -0
- package/next/font/next-font-desc.ts +0 -28
- package/next/font/pages-router-font-vars.tsx +0 -18
- package/next/head-metadata/from-next/metadata-types.ts +0 -158
- package/next/head-metadata/from-next/opengraph-types.ts +0 -267
- package/next/head-metadata/from-next/twitter-types.ts +0 -92
- package/next/head-metadata/index.tsx +0 -208
- package/next/index.ts +0 -2
- package/next/middleware/determine-device-mw.ts +0 -29
- package/root-layout/WHY_THIS_IS_SEPARATE.txt +0 -2
- package/root-layout/index.tsx +0 -112
- package/site-def/footer/community.tsx +0 -61
- package/site-def/footer/company.ts +0 -37
- package/site-def/footer/ecosystem.ts +0 -37
- package/site-def/footer/index.tsx +0 -26
- package/site-def/footer/legal.ts +0 -28
- package/site-def/footer/network.ts +0 -45
- package/site-def/footer/svg/warpcast-logo.svg +0 -12
- package/site-def/index.ts +0 -4
- package/site-def/main-nav.tsx +0 -460
- package/style/cart-animation.css +0 -29
- package/style/checkout-animation.css +0 -23
- package/style/drawer-handle-overrides.css +0 -160
- package/style/fonts/COPY_TO_PUBLIC_FOR_NON_NEXT.txt +0 -0
- package/style/fonts/Druk-Wide-Bold.ttf +0 -0
- package/style/fonts/Druk-Wide-Medium.ttf +0 -0
- package/style/fonts/InterVariable-Italic.ttf +0 -0
- package/style/fonts/InterVariable-Italic.woff2 +0 -0
- package/style/fonts/InterVariable.ttf +0 -0
- package/style/fonts/InterVariable.woff2 +0 -0
- package/style/lux-colors.css +0 -85
- package/style/lux-fonts.css +0 -30
- package/style/lux-global-non-next.css +0 -52
- package/style/lux-global.css +0 -51
- package/tailwind/fontFamily.tailwind.lux.ts +0 -18
- package/tailwind/index.ts +0 -2
- package/tailwind/lux-tw-fonts.ts +0 -40
- package/tailwind/tailwind.config.lux-preset.ts +0 -10
- package/tsconfig.json +0 -15
- package/types/chatbot-config.ts +0 -7
- package/types/chatbot-suggested-question.ts +0 -7
- package/types/contact-info.ts +0 -11
- package/types/index.ts +0 -4
- package/types/site-def.ts +0 -46
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
import React, {type PropsWithChildren } from 'react'
|
|
3
|
-
import { observer } from 'mobx-react-lite'
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
Drawer,
|
|
7
|
-
DrawerContent,
|
|
8
|
-
DrawerHandle,
|
|
9
|
-
type DrawerProps,
|
|
10
|
-
} from '@hanzo/ui/primitives'
|
|
11
|
-
import { cn } from '@hanzo/ui/util'
|
|
12
|
-
|
|
13
|
-
import '../../../style/drawer-handle-overrides.css'
|
|
14
|
-
import { useCommerceDrawer } from '../../../commerce/ui/context'
|
|
15
|
-
|
|
16
|
-
const CommerceDrawer: React.FC<PropsWithChildren &
|
|
17
|
-
Omit<DrawerProps,
|
|
18
|
-
'onOpenChange' |
|
|
19
|
-
'open' |
|
|
20
|
-
'snapPoints' |
|
|
21
|
-
'modal' |
|
|
22
|
-
'setActiveSnapPoint' |
|
|
23
|
-
'activeSnapPoint'
|
|
24
|
-
> &
|
|
25
|
-
{
|
|
26
|
-
handleHandleClicked: () => void
|
|
27
|
-
drawerClx?: string
|
|
28
|
-
}
|
|
29
|
-
> = observer(({
|
|
30
|
-
children,
|
|
31
|
-
handleHandleClicked,
|
|
32
|
-
drawerClx='',
|
|
33
|
-
...rest
|
|
34
|
-
}) => {
|
|
35
|
-
|
|
36
|
-
const drawer = useCommerceDrawer()
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<Drawer
|
|
40
|
-
open={drawer.open}
|
|
41
|
-
onOpenChange={() => {}}
|
|
42
|
-
modal={drawer.modal}
|
|
43
|
-
snapPoints={drawer.points}
|
|
44
|
-
activeSnapPoint={drawer.activePoint}
|
|
45
|
-
setActiveSnapPoint={drawer.onActivePointChanged.bind(drawer)}
|
|
46
|
-
fastDragSkipsToEnd={false}
|
|
47
|
-
dragHandleOnly={true}
|
|
48
|
-
handleHandleClicked={handleHandleClicked}
|
|
49
|
-
extendHandleDragRegion={false}
|
|
50
|
-
// debugOutput
|
|
51
|
-
{...rest}
|
|
52
|
-
>
|
|
53
|
-
<DrawerContent
|
|
54
|
-
defaultHandle={false}
|
|
55
|
-
className={cn(
|
|
56
|
-
'border-0',
|
|
57
|
-
drawer.isMobile ? 'pt-5' : 'pt-6',
|
|
58
|
-
'w-full h-full',
|
|
59
|
-
)}
|
|
60
|
-
// https://github.com/radix-ui/primitives/discussions/935
|
|
61
|
-
onOpenAutoFocus={(e) => {e.preventDefault()}}
|
|
62
|
-
>
|
|
63
|
-
<DrawerHandle
|
|
64
|
-
className={cn(
|
|
65
|
-
'absolute top-0 left-0 right-0 mx-auto z-10',
|
|
66
|
-
'flex justify-center items-start',
|
|
67
|
-
'border-t rounded-t-lg border-muted-3',
|
|
68
|
-
drawer.isMobile ? 'h-5 touch-pan-y' : 'h-6',
|
|
69
|
-
)}
|
|
70
|
-
>
|
|
71
|
-
<div className={cn(
|
|
72
|
-
// pseudo-handle
|
|
73
|
-
'rounded-[3px] bg-level-3',
|
|
74
|
-
drawer.isMobile ? 'w-[155px] mt-[5px] h-1.5' : 'w-[180px] mt-[3px] h-2.5 hover:bg-level-4',
|
|
75
|
-
!drawer.isMobile ? 'cursor-grab active:cursor-grabbing' : '',
|
|
76
|
-
)} />
|
|
77
|
-
</DrawerHandle>
|
|
78
|
-
{children}
|
|
79
|
-
</DrawerContent>
|
|
80
|
-
</Drawer>
|
|
81
|
-
)
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
export default CommerceDrawer
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import React, { useTransition } from 'react'
|
|
4
|
-
|
|
5
|
-
import { useForm, type SubmitHandler, type ControllerRenderProps } from 'react-hook-form'
|
|
6
|
-
import { z } from 'zod'
|
|
7
|
-
import { zodResolver } from '@hookform/resolvers/zod'
|
|
8
|
-
|
|
9
|
-
// @ts-ignore
|
|
10
|
-
import validator from 'validator'
|
|
11
|
-
|
|
12
|
-
import { Loader2 } from 'lucide-react'
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
Button,
|
|
16
|
-
Input,
|
|
17
|
-
} from '@hanzo/ui/primitives'
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
Form,
|
|
21
|
-
FormControl,
|
|
22
|
-
FormField,
|
|
23
|
-
FormItem,
|
|
24
|
-
FormMessage,
|
|
25
|
-
} from '@hanzo/ui/form'
|
|
26
|
-
|
|
27
|
-
import type { SubmitServerAction } from '@hanzo/ui/types'
|
|
28
|
-
import type { ContactInfo } from '../../types'
|
|
29
|
-
|
|
30
|
-
const ContactFormSchema = z.object({
|
|
31
|
-
email: z
|
|
32
|
-
.string()
|
|
33
|
-
.min(1, { message: "Email must be provided." })
|
|
34
|
-
.email("Invalid email."),
|
|
35
|
-
phone: z
|
|
36
|
-
.string()
|
|
37
|
-
.min(1, { message: "Telephone must be provided." })
|
|
38
|
-
.refine(validator.isMobilePhone, { message: "Invalid format." })
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
type ContactFormSchemaType = z.infer<typeof ContactFormSchema>
|
|
42
|
-
|
|
43
|
-
const ContactForm: React.FC<{
|
|
44
|
-
onSubmit: (data: ContactFormSchemaType, enc: any) => void
|
|
45
|
-
enclosure: any
|
|
46
|
-
}> = ({
|
|
47
|
-
onSubmit: _onSubmit,
|
|
48
|
-
enclosure
|
|
49
|
-
}) => {
|
|
50
|
-
|
|
51
|
-
const form = useForm<ContactFormSchemaType>({
|
|
52
|
-
resolver: zodResolver(ContactFormSchema),
|
|
53
|
-
defaultValues: {
|
|
54
|
-
email: '',
|
|
55
|
-
phone: '',
|
|
56
|
-
},
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
const [isPending, startTransition] = useTransition()
|
|
60
|
-
|
|
61
|
-
const onSubmit: SubmitHandler<ContactFormSchemaType> = (data) => {
|
|
62
|
-
// https://github.com/orgs/react-hook-form/discussions/10757#discussioncomment-6672403
|
|
63
|
-
// @ts-ignore
|
|
64
|
-
startTransition(async () => {
|
|
65
|
-
await _onSubmit(data, enclosure)
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const MyFormItem: React.FC<{
|
|
70
|
-
field: ControllerRenderProps<ContactFormSchemaType, 'email'> | ControllerRenderProps<ContactFormSchemaType, 'phone'>
|
|
71
|
-
placeholder: string
|
|
72
|
-
}> = ({
|
|
73
|
-
field,
|
|
74
|
-
placeholder
|
|
75
|
-
}) => (
|
|
76
|
-
<FormItem className="space-y-0" >
|
|
77
|
-
<FormControl>
|
|
78
|
-
<Input placeholder={placeholder} {...field} className="mt-0 text-foreground"/>
|
|
79
|
-
</FormControl>
|
|
80
|
-
<div className="flex flex-row justify-start items-stretch gap-2">
|
|
81
|
-
<FormMessage />
|
|
82
|
-
</div>
|
|
83
|
-
</FormItem>
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<Form {...form}>
|
|
88
|
-
<form onSubmit={form.handleSubmit(onSubmit)} className="w-3/4">
|
|
89
|
-
<div className='flex flex-col justify-start items-stretch mt-4'>
|
|
90
|
-
<FormField
|
|
91
|
-
control={form.control}
|
|
92
|
-
name='email'
|
|
93
|
-
render={({ field }) => ( <MyFormItem field={field} placeholder='email'/> )}
|
|
94
|
-
/>
|
|
95
|
-
<FormField
|
|
96
|
-
control={form.control}
|
|
97
|
-
name='phone'
|
|
98
|
-
// @ts-ignore
|
|
99
|
-
render={({ field }) => ( <MyFormItem field={field} placeholder='phone'/> )}
|
|
100
|
-
/>
|
|
101
|
-
<Button disabled={isPending} type='submit' className='bg-primary text-primary-fg hover:bg-primary-hover'>
|
|
102
|
-
{isPending ? (<>
|
|
103
|
-
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
104
|
-
Please wait
|
|
105
|
-
</>
|
|
106
|
-
) : (
|
|
107
|
-
<>Submit</>
|
|
108
|
-
)}
|
|
109
|
-
</Button>
|
|
110
|
-
</div>
|
|
111
|
-
</form>
|
|
112
|
-
</Form>
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export default ContactForm
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
const Disclaimer: React.FC = () => (
|
|
4
|
-
<div>
|
|
5
|
-
By entering your mobile number and submitting, you consent to receive text messages from Lux at the number provided.
|
|
6
|
-
Message and data rates may apply. Message frequency varies.
|
|
7
|
-
You can unsubscribe at any time by replying STOP.
|
|
8
|
-
View our <a href='/privacy'>Privacy Policy</a> and <a href='/terms'>Terms & conditions</a>.
|
|
9
|
-
</div>
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
export default Disclaimer
|
|
13
|
-
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import React, { useState } from 'react'
|
|
4
|
-
|
|
5
|
-
import type { ButtonModalProps} from '@hanzo/ui/types'
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
Button,
|
|
9
|
-
Dialog,
|
|
10
|
-
DialogContent,
|
|
11
|
-
DialogDescription,
|
|
12
|
-
DialogHeader,
|
|
13
|
-
DialogTitle,
|
|
14
|
-
DialogTrigger,
|
|
15
|
-
} from '@hanzo/ui/primitives'
|
|
16
|
-
|
|
17
|
-
import ContactForm from './contact-form'
|
|
18
|
-
import Disclaimer from './disclaimer'
|
|
19
|
-
|
|
20
|
-
const ContactDialog: React.FC<ButtonModalProps> = ({
|
|
21
|
-
open,
|
|
22
|
-
onOpenChange,
|
|
23
|
-
buttonText,
|
|
24
|
-
buttonProps,
|
|
25
|
-
title,
|
|
26
|
-
byline,
|
|
27
|
-
action,
|
|
28
|
-
actionEnclosure
|
|
29
|
-
}) => {
|
|
30
|
-
const [success, setSuccess] = useState(false)
|
|
31
|
-
|
|
32
|
-
const onSubmit = async (formData: any, enclosure: any) => {
|
|
33
|
-
const result = await action(formData, enclosure)
|
|
34
|
-
if (result.success) {
|
|
35
|
-
setSuccess(true)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<Dialog open={open} onOpenChange={onOpenChange} >
|
|
41
|
-
<DialogTrigger asChild>
|
|
42
|
-
<Button {...buttonProps} >{buttonText}</Button>
|
|
43
|
-
</DialogTrigger>
|
|
44
|
-
<DialogContent className="sm:max-w-[500px] p-0 gap-0 bg-background border">
|
|
45
|
-
<DialogHeader className='py-6 text-foreground'>
|
|
46
|
-
<DialogTitle className='text-4xl text-center text-inherit'>{title}</DialogTitle>
|
|
47
|
-
{byline && (<DialogDescription className='text-inherit text-lg text-center'>{byline} </DialogDescription>)}
|
|
48
|
-
</DialogHeader>
|
|
49
|
-
<div className='px-8 pb-8 rounded-e-lg flex flex-col justify-start items-center'>
|
|
50
|
-
{success ? (
|
|
51
|
-
<p>{actionEnclosure?.reply}</p>
|
|
52
|
-
) : (
|
|
53
|
-
<ContactForm onSubmit={onSubmit} enclosure={actionEnclosure}/>
|
|
54
|
-
)}
|
|
55
|
-
<div className='text-muted-1 text-xs mt-4' >
|
|
56
|
-
<Disclaimer />
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
</DialogContent>
|
|
60
|
-
</Dialog>
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export default ContactDialog
|
package/components/copyright.tsx
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
const FIRST = 2020
|
|
4
|
-
|
|
5
|
-
const Copyright: React.FC<{
|
|
6
|
-
className?: string
|
|
7
|
-
}> = ({
|
|
8
|
-
className=''
|
|
9
|
-
}) => {
|
|
10
|
-
|
|
11
|
-
const year = new Date().getFullYear()
|
|
12
|
-
const yearString = (year > FIRST) ? `${FIRST} - ${year}` : FIRST.toString()
|
|
13
|
-
|
|
14
|
-
return (
|
|
15
|
-
<div className={className}>
|
|
16
|
-
{`Copyright © ${yearString}`} <br className='sm:hidden'/>Lux Partners Limited. <br className='md:hidden'/> All rights reserved.
|
|
17
|
-
</div>
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export default Copyright
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
|
|
4
|
-
import { cn } from '@hanzo/ui/util'
|
|
5
|
-
import { useCommerceDrawer } from '@luxfi/ui/commerce'
|
|
6
|
-
import { observer } from 'mobx-react-lite'
|
|
7
|
-
|
|
8
|
-
const DrawerMargin: React.FC<{
|
|
9
|
-
clx?: string
|
|
10
|
-
}> = observer(({
|
|
11
|
-
clx=''
|
|
12
|
-
}) => {
|
|
13
|
-
|
|
14
|
-
const drawer = useCommerceDrawer()
|
|
15
|
-
if (!drawer) {
|
|
16
|
-
throw new Error("DrawerMargin must be used with a CommerceUIContext!")
|
|
17
|
-
}
|
|
18
|
-
return (
|
|
19
|
-
<div
|
|
20
|
-
className={cn('transition-height', clx)}
|
|
21
|
-
style={{
|
|
22
|
-
height: drawer.state === 'micro' ? drawer.microHeight : 0
|
|
23
|
-
}}
|
|
24
|
-
/>
|
|
25
|
-
)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
export default DrawerMargin
|
package/components/footer.tsx
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
import type { LinkDef } from '@hanzo/ui/types'
|
|
4
|
-
import { NavItems } from '@hanzo/ui/primitives'
|
|
5
|
-
import { cn } from '@hanzo/ui/util'
|
|
6
|
-
|
|
7
|
-
import Copyright from './copyright'
|
|
8
|
-
import type { SiteDef } from '../site-def'
|
|
9
|
-
import { legal } from '../site-def/footer/legal'
|
|
10
|
-
import Logo from './logo'
|
|
11
|
-
|
|
12
|
-
const Footer: React.FC<{
|
|
13
|
-
siteDef: SiteDef,
|
|
14
|
-
className?: string,
|
|
15
|
-
noHorizPadding?: boolean
|
|
16
|
-
}> = ({
|
|
17
|
-
siteDef,
|
|
18
|
-
className='',
|
|
19
|
-
noHorizPadding=false
|
|
20
|
-
}) => {
|
|
21
|
-
|
|
22
|
-
const { footer, aboveCopyright } = siteDef
|
|
23
|
-
const smGridCols = Math.floor(footer.length/2)
|
|
24
|
-
const smGridColsClx = `sm:grid-cols-${smGridCols} `
|
|
25
|
-
const _aboveCopyright = (typeof aboveCopyright === 'undefined') ? legal : aboveCopyright
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<footer className={cn('grow flex flex-col justify-between gap-6 pb-[2vh]', className)}>
|
|
29
|
-
<div className={
|
|
30
|
-
(noHorizPadding ? '' : 'px-5 md:px-8 ') +
|
|
31
|
-
'grid grid-cols-2 gap-4 gap-y-6 md:gap-x-6 lg:gap-8 ' + smGridColsClx +
|
|
32
|
-
'md:w-full sm:justify-items-center md:mx-0 lg:w-full ' +
|
|
33
|
-
'md:flex md:flex-row md:justify-between px-[24px]'
|
|
34
|
-
}>
|
|
35
|
-
<div className='hidden lg:flex flex-col' key={0}>
|
|
36
|
-
<Logo size='md' variant='text-only' />
|
|
37
|
-
</div>
|
|
38
|
-
{footer.map((defs: LinkDef[], index: number) => {
|
|
39
|
-
|
|
40
|
-
const xsColSpanClx = ((index === footer.length - 1) && (footer.length % 2 === 1)) ?
|
|
41
|
-
'xs:col-span-2 xs:mx-auto md:col-span-1 md:mx-0 ' : ''
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<NavItems
|
|
45
|
-
items={defs}
|
|
46
|
-
currentAs={siteDef.currentAs}
|
|
47
|
-
as='nav'
|
|
48
|
-
className={cn('sm:min-w-[150px] md:min-w-0 flex flex-col justify-start items-start ' +
|
|
49
|
-
'gap-[11px] sm:gap-[12px] md:gap-[15px] ',
|
|
50
|
-
xsColSpanClx
|
|
51
|
-
)}
|
|
52
|
-
key={index + 1}
|
|
53
|
-
itemClx={(def: LinkDef) => ((def.variant === 'linkFG') ?
|
|
54
|
-
'font-nav text-[15px]/[1.3] font-medium tracking-normal text-muted-1 sm:hover:text-foreground transition-color duration-500'
|
|
55
|
-
:
|
|
56
|
-
'text-[15px]/[1.1] font-normal tracking-[0.2px] text-muted-1 sm:hover:text-foreground transition-color duration-500'
|
|
57
|
-
)}
|
|
58
|
-
/>
|
|
59
|
-
)
|
|
60
|
-
})}
|
|
61
|
-
</div>
|
|
62
|
-
<div className='md:mt-[2vh]'>
|
|
63
|
-
{_aboveCopyright.length > 0 && (
|
|
64
|
-
<NavItems
|
|
65
|
-
items={_aboveCopyright}
|
|
66
|
-
as='div'
|
|
67
|
-
className={'flex flex-row justify-center gap-4 mb-2'}
|
|
68
|
-
itemClx={'text-sm text-center text-muted-2 underline hover:text-foreground'}
|
|
69
|
-
/>
|
|
70
|
-
)}
|
|
71
|
-
<Copyright className='text-sm text-center text-muted-3'/>
|
|
72
|
-
</div>
|
|
73
|
-
</footer>
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export default Footer
|
|
78
|
-
// flex flex-col justify-between gap-6
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as React from 'react'
|
|
4
|
-
import Link from 'next/link'
|
|
5
|
-
import { cn } from '@hanzo/ui/util'
|
|
6
|
-
import type { ChildMenu, LinkDefExtended } from '../../site-def/main-nav'
|
|
7
|
-
import {
|
|
8
|
-
NavigationMenu,
|
|
9
|
-
NavigationMenuContent,
|
|
10
|
-
NavigationMenuItem,
|
|
11
|
-
NavigationMenuLink,
|
|
12
|
-
NavigationMenuList,
|
|
13
|
-
NavigationMenuTrigger,
|
|
14
|
-
navigationMenuTriggerStyle
|
|
15
|
-
} from '@hanzo/ui/primitives'
|
|
16
|
-
|
|
17
|
-
const DesktopNav: React.FC<{
|
|
18
|
-
links: LinkDefExtended[],
|
|
19
|
-
isMenuOpened: boolean,
|
|
20
|
-
setIsMenuOpen: React.Dispatch<React.SetStateAction<boolean>>
|
|
21
|
-
}> = ({ links, isMenuOpened, setIsMenuOpen }) => {
|
|
22
|
-
|
|
23
|
-
React.useEffect(() => {
|
|
24
|
-
const preventScroll = (e: WheelEvent | TouchEvent) => {
|
|
25
|
-
e.preventDefault()
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (isMenuOpened) {
|
|
29
|
-
window.addEventListener('wheel', preventScroll, { passive: false })
|
|
30
|
-
window.addEventListener('touchmove', preventScroll, { passive: false })
|
|
31
|
-
window.addEventListener('keydown', preventScrollKeys, { passive: false })
|
|
32
|
-
} else {
|
|
33
|
-
window.removeEventListener('wheel', preventScroll)
|
|
34
|
-
window.removeEventListener('touchmove', preventScroll)
|
|
35
|
-
window.removeEventListener('keydown', preventScrollKeys)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return () => {
|
|
39
|
-
window.removeEventListener('wheel', preventScroll)
|
|
40
|
-
window.removeEventListener('touchmove', preventScroll)
|
|
41
|
-
window.removeEventListener('keydown', preventScrollKeys)
|
|
42
|
-
}
|
|
43
|
-
}, [isMenuOpened])
|
|
44
|
-
|
|
45
|
-
const preventScrollKeys = (e: KeyboardEvent) => {
|
|
46
|
-
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', ' '].includes(e.key)) {
|
|
47
|
-
e.preventDefault()
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const handleMouseEnter = React.useCallback(() => {
|
|
52
|
-
setIsMenuOpen(true)
|
|
53
|
-
}, [setIsMenuOpen])
|
|
54
|
-
|
|
55
|
-
const handleMouseLeave = React.useCallback(() => {
|
|
56
|
-
setIsMenuOpen(false)
|
|
57
|
-
}, [setIsMenuOpen])
|
|
58
|
-
|
|
59
|
-
const handleContentMouseMove = () => {
|
|
60
|
-
setIsMenuOpen(false)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const menuHiddenClass = !isMenuOpened ? 'invisible' : ''
|
|
64
|
-
|
|
65
|
-
return links.length > 0 ? (
|
|
66
|
-
<NavigationMenu>
|
|
67
|
-
<NavigationMenuList>
|
|
68
|
-
{links.map((el, index) => (
|
|
69
|
-
<NavigationMenuItem key={index} className='!m-0'>
|
|
70
|
-
{el.isAIMenu ? (
|
|
71
|
-
<Link href={el.href} legacyBehavior passHref>
|
|
72
|
-
<NavigationMenuLink className={cn(navigationMenuTriggerStyle(), ' text-muted-1 bg-transparent')}>
|
|
73
|
-
{el.title}
|
|
74
|
-
</NavigationMenuLink>
|
|
75
|
-
</Link>
|
|
76
|
-
) : el.title === 'Cards' ? (
|
|
77
|
-
<>
|
|
78
|
-
<NavigationMenuTrigger
|
|
79
|
-
className='text-muted-1 bg-transparent'
|
|
80
|
-
onMouseEnter={handleMouseEnter}
|
|
81
|
-
onFocus={handleMouseEnter}
|
|
82
|
-
onMouseLeave={handleMouseLeave}
|
|
83
|
-
onBlur={handleMouseLeave}
|
|
84
|
-
>
|
|
85
|
-
<Link href={el.href} legacyBehavior passHref>
|
|
86
|
-
{el.title}
|
|
87
|
-
</Link>
|
|
88
|
-
</NavigationMenuTrigger>
|
|
89
|
-
<NavigationMenuContent
|
|
90
|
-
className={cn('fixed left-0 top-14 pt-6 w-screen h-full border-0 !backdrop-blur-3xl bg-transparent mt-0', menuHiddenClass)}
|
|
91
|
-
onMouseEnter={handleMouseEnter}
|
|
92
|
-
onMouseLeave={handleMouseLeave}
|
|
93
|
-
>
|
|
94
|
-
<div className='flex justify-center items-start'>
|
|
95
|
-
<div
|
|
96
|
-
className='grid xl:grid-cols-3 w-full justify-center max-w-[750px]'
|
|
97
|
-
onMouseLeave={handleContentMouseMove}
|
|
98
|
-
>
|
|
99
|
-
{GroupChildMenu({ childs: el.childMenu, isCards: true })}
|
|
100
|
-
</div>
|
|
101
|
-
</div>
|
|
102
|
-
</NavigationMenuContent>
|
|
103
|
-
</>
|
|
104
|
-
) : (
|
|
105
|
-
<>
|
|
106
|
-
<NavigationMenuTrigger
|
|
107
|
-
className='text-muted-1 bg-transparent'
|
|
108
|
-
onMouseEnter={handleMouseEnter}
|
|
109
|
-
onFocus={handleMouseEnter}
|
|
110
|
-
onMouseLeave={handleMouseLeave}
|
|
111
|
-
onBlur={handleMouseLeave}
|
|
112
|
-
>
|
|
113
|
-
{
|
|
114
|
-
el.href && el.href !== '' ?
|
|
115
|
-
<Link href={el.href} legacyBehavior passHref>
|
|
116
|
-
{el.title}
|
|
117
|
-
</Link> : <>{el.title}</>
|
|
118
|
-
}
|
|
119
|
-
</NavigationMenuTrigger>
|
|
120
|
-
<NavigationMenuContent
|
|
121
|
-
className={cn('fixed left-0 top-14 pt-6 w-screen h-full border-0 !backdrop-blur-3xl bg-transparent mt-0', menuHiddenClass)}
|
|
122
|
-
onMouseEnter={handleMouseEnter}
|
|
123
|
-
onMouseLeave={handleMouseLeave}
|
|
124
|
-
>
|
|
125
|
-
<div
|
|
126
|
-
className='flex flex-row w-full justify-center'
|
|
127
|
-
onMouseLeave={handleContentMouseMove}
|
|
128
|
-
>
|
|
129
|
-
{GroupChildMenu({ childs: el.childMenu })}
|
|
130
|
-
</div>
|
|
131
|
-
</NavigationMenuContent>
|
|
132
|
-
</>
|
|
133
|
-
)}
|
|
134
|
-
</NavigationMenuItem>
|
|
135
|
-
))}
|
|
136
|
-
</NavigationMenuList>
|
|
137
|
-
</NavigationMenu>
|
|
138
|
-
) : null
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export default DesktopNav
|
|
142
|
-
|
|
143
|
-
const ListItem = React.forwardRef<
|
|
144
|
-
React.ElementRef<'a'>,
|
|
145
|
-
React.ComponentPropsWithoutRef<'a'>
|
|
146
|
-
>(({ className, title, children, ...props }, ref) => (
|
|
147
|
-
<li key={title}>
|
|
148
|
-
<NavigationMenuLink asChild>
|
|
149
|
-
<a
|
|
150
|
-
ref={ref}
|
|
151
|
-
className={cn(
|
|
152
|
-
'block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:text-accent-foreground focus:bg-level-1 focus:text-accent-foreground text-muted-1 hover:text-primary hover:bg-transparent duration-1000 ease-in-out',
|
|
153
|
-
className
|
|
154
|
-
)}
|
|
155
|
-
{...props}
|
|
156
|
-
>
|
|
157
|
-
<div className='text-sm font-medium leading-none'>{title}</div>
|
|
158
|
-
<p className='line-clamp-3 text-sm leading-snug text-muted-1'>
|
|
159
|
-
{children}
|
|
160
|
-
</p>
|
|
161
|
-
</a>
|
|
162
|
-
</NavigationMenuLink>
|
|
163
|
-
</li>
|
|
164
|
-
))
|
|
165
|
-
ListItem.displayName = 'ListItem'
|
|
166
|
-
|
|
167
|
-
const GroupChildMenu = (params: { childs: ChildMenu[] | undefined, isCards?: boolean }) => {
|
|
168
|
-
const { childs, isCards = false } = params
|
|
169
|
-
|
|
170
|
-
if (!childs) {
|
|
171
|
-
return null
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const groupedChildMenus = childs.reduce((grouped: Record<string, ChildMenu[]>, childLink) => {
|
|
175
|
-
if (childLink.groupName) {
|
|
176
|
-
grouped[childLink.groupName] = grouped[childLink.groupName] || []
|
|
177
|
-
grouped[childLink.groupName].push(childLink)
|
|
178
|
-
}
|
|
179
|
-
return grouped
|
|
180
|
-
}, {})
|
|
181
|
-
|
|
182
|
-
const getChildExtraClass = (index: number) => {
|
|
183
|
-
if (isCards && (index === 3 || index === 4)) {
|
|
184
|
-
return 'xl:-mt-32'
|
|
185
|
-
}
|
|
186
|
-
return ''
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return Object.entries(groupedChildMenus).map(([groupName, childLinks], index) => (
|
|
190
|
-
<div key={groupName} className={cn('py-4 px-4 ', getChildExtraClass(index))}>
|
|
191
|
-
<h2 className='text-muted-1'>{groupName}</h2>
|
|
192
|
-
<ul className='w-[200px] gap-3 md:w-[250px] lg:w-[250px]'>
|
|
193
|
-
{childLinks.map((link) => (
|
|
194
|
-
<div className='flex justify-start items-center' key={link.title}>
|
|
195
|
-
{link.icon}
|
|
196
|
-
<ListItem key={link.title} title={link.title} href={link.href} className='ml-[14px]'>
|
|
197
|
-
{link.contents}
|
|
198
|
-
</ListItem>
|
|
199
|
-
</div>
|
|
200
|
-
))}
|
|
201
|
-
</ul>
|
|
202
|
-
</div>
|
|
203
|
-
))
|
|
204
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import React, { type PropsWithChildren } from 'react'
|
|
2
|
-
|
|
3
|
-
import { cn } from '@hanzo/ui/util'
|
|
4
|
-
import { AuthWidget } from '@hanzo/auth/components'
|
|
5
|
-
|
|
6
|
-
import Logo, { type LogoVariant } from '../logo'
|
|
7
|
-
|
|
8
|
-
import DesktopBagPopup from '../commerce/desktop-bag-popup'
|
|
9
|
-
import BagButton from '../commerce/bag-button'
|
|
10
|
-
import DesktopNav from './desktop-nav-menu'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import type { LinkDef } from '@hanzo/ui/types'
|
|
14
|
-
|
|
15
|
-
const DesktopHeader: React.FC<{
|
|
16
|
-
currentAs: string | undefined
|
|
17
|
-
links: LinkDef[]
|
|
18
|
-
className?: string
|
|
19
|
-
noAuth?: boolean
|
|
20
|
-
noCommerce?: boolean
|
|
21
|
-
logoVariant?: LogoVariant
|
|
22
|
-
} & PropsWithChildren> = ({
|
|
23
|
-
links,
|
|
24
|
-
className = '',
|
|
25
|
-
noAuth=false,
|
|
26
|
-
noCommerce=false,
|
|
27
|
-
children,
|
|
28
|
-
logoVariant='text-only'
|
|
29
|
-
}) => {
|
|
30
|
-
const [isMenuOpened, setIsMenuOpen] = React.useState(false);
|
|
31
|
-
|
|
32
|
-
// TODO move 13px into a size class and configure twMerge to recognize say, 'text-size-nav'
|
|
33
|
-
// (vs be beat out by 'text-color-nav')
|
|
34
|
-
return (
|
|
35
|
-
<header id='DESKTOP_HEADER' className={cn(
|
|
36
|
-
'bg-[rgba(0, 0, 0, 0.5)] !backdrop-blur-3xl fixed z-header top-0 left-0 right-0',
|
|
37
|
-
className,
|
|
38
|
-
isMenuOpened ? ' h-full' : ''
|
|
39
|
-
)} >
|
|
40
|
-
{/* md or larger */}
|
|
41
|
-
<div className={
|
|
42
|
-
'flex flex-row h-[80px] items-center justify-between ' +
|
|
43
|
-
'mx-[24px] w-full max-w-screen'
|
|
44
|
-
}>
|
|
45
|
-
<Logo size={logoVariant === 'logo-only' ? 'lg' : 'md'} href='/' outerClx='hidden lg:flex' key='two' variant={logoVariant} />
|
|
46
|
-
<Logo size='sm' href='/' outerClx='hidden md:flex lg:hidden' key='one' variant={logoVariant} />
|
|
47
|
-
{/* md or larger */}
|
|
48
|
-
<div className='flex w-full gap-4 items-center justify-center'>
|
|
49
|
-
<DesktopNav links={links} isMenuOpened={isMenuOpened} setIsMenuOpen={setIsMenuOpen} />
|
|
50
|
-
</div>
|
|
51
|
-
<div className='flex items-center'>
|
|
52
|
-
{!noCommerce && (
|
|
53
|
-
<DesktopBagPopup popupClx='w-[340px]' trigger={<BagButton className='text-primary -mr-[3px] lg:min-w-0' />} />
|
|
54
|
-
)}
|
|
55
|
-
<AuthWidget noLogin={noAuth}/>
|
|
56
|
-
{children}
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
</header>
|
|
60
|
-
)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export default DesktopHeader
|
|
64
|
-
|
|
65
|
-
|