@luxfi/core 5.2.8 → 5.2.9
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/commerce/ui/conf.ts +13 -13
- package/commerce/ui/context.tsx +126 -126
- package/commerce/ui/store.ts +304 -304
- package/components/access-code-input.tsx +71 -71
- package/components/auth/auth-listener.tsx +29 -29
- package/components/auth/auth-token/clear-auth-token.tsx +12 -12
- package/components/auth/auth-token/set-auth-token.tsx +16 -16
- package/components/auth/common-auth-domains.ts +16 -16
- package/components/auth/login-panel.tsx +107 -107
- package/components/back-button.tsx +42 -42
- package/components/chat-widget.tsx +85 -85
- package/components/commerce/add-widget.tsx +20 -20
- package/components/commerce/bag-button.tsx +98 -98
- package/components/commerce/buy-button.tsx +34 -34
- package/components/commerce/checkout-button.tsx +129 -129
- package/components/commerce/checkout-panel/dt-bag-carousel.tsx +36 -36
- package/components/commerce/checkout-panel/dt-checkout-panel.tsx +84 -84
- package/components/commerce/checkout-panel/index.tsx +129 -129
- package/components/commerce/checkout-panel/links-row.tsx +21 -21
- package/components/commerce/checkout-panel/mb-checkout-panel.tsx +54 -54
- package/components/commerce/checkout-panel/steps-indicator.tsx +39 -39
- package/components/commerce/checkout-panel/thank-you.tsx +18 -18
- package/components/commerce/checkout-widget/const.ts +13 -13
- package/components/commerce/checkout-widget/index.tsx +192 -192
- package/components/commerce/checkout-widget/obs-string-set.ts +48 -48
- package/components/commerce/checkout-widget/use-anim-clx-set.ts +58 -58
- package/components/commerce/desktop-bag-popup.tsx +78 -78
- package/components/commerce/desktop-nav-menu.tsx +131 -130
- package/components/commerce/drawer/index.tsx +99 -99
- package/components/commerce/drawer/micro.tsx +144 -144
- package/components/commerce/drawer/shell.tsx +85 -85
- package/components/commerce/mobile-bag-drawer.tsx +51 -51
- package/components/commerce/mobile-login-button.tsx +101 -101
- package/components/commerce/mobile-menu-toggle-button.tsx +35 -35
- package/components/commerce/mobile-nav-menu-ai.tsx +48 -42
- package/components/commerce/mobile-nav-menu-item.tsx +49 -49
- package/components/commerce/mobile-nav-menu.tsx +102 -68
- package/components/contact-dialog/contact-form.tsx +113 -113
- package/components/contact-dialog/disclaimer.tsx +13 -13
- package/components/contact-dialog/index.tsx +64 -64
- package/components/copyright.tsx +21 -21
- package/components/drawer-margin.tsx +25 -25
- package/components/footer.tsx +77 -77
- package/components/header/desktop.tsx +50 -49
- package/components/header/index.tsx +52 -52
- package/components/header/mobile.tsx +163 -163
- package/components/header/theme-toggle.tsx +26 -26
- package/components/icons/24k-gold-card.tsx +43 -0
- package/components/icons/ai-chat.tsx +29 -0
- package/components/icons/anodized-titanium.tsx +45 -0
- package/components/icons/avatar.tsx +11 -11
- package/components/icons/bag-icon.tsx +10 -10
- package/components/icons/blog.tsx +20 -0
- package/components/icons/bridge.tsx +68 -0
- package/components/icons/changelog.tsx +21 -0
- package/components/icons/chrome.tsx +45 -0
- package/components/icons/coins.tsx +20 -0
- package/components/icons/compare-cards.tsx +21 -0
- package/components/icons/credit.tsx +20 -0
- package/components/icons/customer-support.tsx +21 -0
- package/components/icons/customers.tsx +33 -0
- package/components/icons/developer-docs.tsx +20 -0
- package/components/icons/exchange.tsx +21 -0
- package/components/icons/explorer.tsx +22 -0
- package/components/icons/faqs.tsx +21 -0
- package/components/icons/github.tsx +14 -14
- package/components/icons/guides.tsx +21 -0
- package/components/icons/gun-metal.tsx +44 -0
- package/components/icons/index.tsx +43 -43
- package/components/icons/integrations.tsx +25 -0
- package/components/icons/irradescent.tsx +41 -0
- package/components/icons/launch-subnet.tsx +21 -0
- package/components/icons/left-arrow.tsx +11 -11
- package/components/icons/lux-finance.tsx +23 -0
- package/components/icons/lux-logo.tsx +10 -10
- package/components/icons/lux-pass.tsx +25 -0
- package/components/icons/lux-quests.tsx +21 -0
- package/components/icons/market.tsx +24 -0
- package/components/icons/mirrored-titanium.tsx +46 -0
- package/components/icons/more-benefits.tsx +21 -0
- package/components/icons/open-source.tsx +26 -0
- package/components/icons/right-arrow.tsx +10 -10
- package/components/icons/safe.tsx +37 -0
- package/components/icons/search.tsx +12 -12
- package/components/icons/secure-delivery.tsx +13 -13
- package/components/icons/shop.tsx +20 -0
- package/components/icons/social-icon.tsx +35 -35
- package/components/icons/social-svg.css +3 -3
- package/components/icons/sterling-silver-card.tsx +44 -0
- package/components/icons/templates.tsx +21 -0
- package/components/icons/validators.tsx +41 -0
- package/components/icons/view-all-card.tsx +20 -0
- package/components/icons/wallet.tsx +20 -0
- package/components/icons/warpcast.tsx +58 -58
- package/components/icons/youtube-logo.tsx +59 -59
- package/components/index.ts +27 -27
- package/components/logo.tsx +89 -89
- package/components/main.tsx +27 -27
- package/components/mini-chart/index.tsx +7 -7
- package/components/mini-chart/mini-chart-props.ts +43 -43
- package/components/mini-chart/mini-chart.tsx +85 -85
- package/components/mini-chart/wrapper.tsx +23 -23
- package/components/not-found/index.tsx +28 -28
- package/components/not-found/not-found-content.mdx +5 -5
- package/components/scripts.tsx +24 -24
- package/components/tooltip.tsx +31 -31
- package/environment.d.ts +5 -5
- package/next/analytics/fpixel.ts +15 -15
- package/next/analytics/google-analytics.ts +13 -13
- package/next/analytics/index.ts +3 -3
- package/next/analytics/pixel-analytics.tsx +54 -54
- package/next/font/get-app-router-font-classes.ts +12 -12
- package/next/font/load-and-return-lux-next-fonts-on-import.ts +68 -68
- package/next/font/next-font-desc.ts +27 -27
- package/next/font/pages-router-font-vars.tsx +18 -18
- package/next/head-metadata/from-next/metadata-types.ts +158 -158
- package/next/head-metadata/from-next/opengraph-types.ts +267 -267
- package/next/head-metadata/from-next/twitter-types.ts +92 -92
- package/next/head-metadata/index.tsx +208 -208
- package/next/middleware/determine-device-mw.ts +16 -16
- package/package.json +79 -79
- package/root-layout/WHY_THIS_IS_SEPARATE.txt +1 -1
- package/root-layout/index.tsx +112 -112
- package/server-actions/firebase-app.ts +14 -14
- package/server-actions/index.ts +5 -5
- package/server-actions/store-contact.ts +51 -51
- package/site-def/footer/community.tsx +67 -67
- package/site-def/footer/company.ts +37 -37
- package/site-def/footer/ecosystem.ts +37 -37
- package/site-def/footer/index.tsx +26 -26
- package/site-def/footer/legal.ts +28 -28
- package/site-def/footer/network.ts +45 -45
- package/site-def/footer/svg/warpcast-logo.svg +11 -11
- package/site-def/index.ts +2 -2
- package/site-def/main-nav.tsx +392 -338
- package/style/cart-animation.css +29 -29
- package/style/checkout-animation.css +23 -23
- package/style/drawer-handle-overrides.css +160 -160
- package/style/lux-colors.css +85 -85
- package/style/lux-global.css +30 -30
- package/tailwind/fontFamily.tailwind.lux.ts +18 -18
- package/tailwind/index.ts +2 -2
- package/tailwind/lux-tw-fonts.ts +39 -39
- package/tailwind/tailwind.config.lux-preset.ts +10 -10
- package/tsconfig.json +15 -15
- package/types/chatbot-config.ts +6 -6
- package/types/chatbot-suggested-question.ts +7 -7
- package/types/contact-info.ts +10 -10
- package/types/index.ts +4 -4
- package/types/site-def.ts +43 -43
|
@@ -1,49 +1,50 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '@hanzo/ui/util'
|
|
4
|
+
import { AuthWidget } from '@hanzo/auth/components'
|
|
5
|
+
|
|
6
|
+
import { Logo } from '..'
|
|
7
|
+
|
|
8
|
+
import DesktopBagPopup from '../commerce/desktop-bag-popup'
|
|
9
|
+
import BagButton from '../commerce/bag-button'
|
|
10
|
+
import DesktopNav from '../commerce/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
|
+
}> = ({
|
|
20
|
+
currentAs,
|
|
21
|
+
links,
|
|
22
|
+
className = ''
|
|
23
|
+
}) => {
|
|
24
|
+
|
|
25
|
+
// TODO move 13px into a size class and configure twMerge to recognize say, 'text-size-nav'
|
|
26
|
+
// (vs be beat out by 'text-color-nav')
|
|
27
|
+
return (
|
|
28
|
+
<header className={cn('bg-background fixed z-header top-0 left-0 right-0', className)} >
|
|
29
|
+
{/* md or larger */}
|
|
30
|
+
<div className={
|
|
31
|
+
'flex flex-row h-[80px] items-center justify-between ' +
|
|
32
|
+
'px-[8px] w-full mx-auto max-w-screen'
|
|
33
|
+
}>
|
|
34
|
+
<Logo size='md' href='/' outerClx='hidden lg:flex' key='two' variant='text-only' />
|
|
35
|
+
<Logo size='sm' href='/' outerClx='hidden md:flex lg:hidden' key='one' variant='text-only' />
|
|
36
|
+
{/* md or larger */}
|
|
37
|
+
<div className='flex w-full gap-4 items-center justify-between lg:ml-22'>
|
|
38
|
+
<DesktopNav links={links} />
|
|
39
|
+
<div className='flex items-center'>
|
|
40
|
+
<DesktopBagPopup popupClx='w-[340px]' trigger={<BagButton className='text-primary -mr-[3px] lg:min-w-0' />} />
|
|
41
|
+
<AuthWidget />
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</header>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default DesktopHeader
|
|
50
|
+
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
|
|
4
|
-
import type { SiteDef } from '../../site-def'
|
|
5
|
-
|
|
6
|
-
import DesktopHeader from './desktop'
|
|
7
|
-
import MobileHeader from './mobile'
|
|
8
|
-
import { cn } from '@hanzo/ui/util'
|
|
9
|
-
import { ChatWidget } from '../../components'
|
|
10
|
-
|
|
11
|
-
const Header: React.FC<{
|
|
12
|
-
siteDef: SiteDef
|
|
13
|
-
className?: string
|
|
14
|
-
}> = ({
|
|
15
|
-
siteDef,
|
|
16
|
-
className = ''
|
|
17
|
-
}) => {
|
|
18
|
-
|
|
19
|
-
// TODO
|
|
20
|
-
const [open, setOpen] = React.useState<boolean>(false);
|
|
21
|
-
|
|
22
|
-
const { nav: { common, featured }, currentAs } = siteDef
|
|
23
|
-
const links = (featured) ? [...common, ...featured] : common
|
|
24
|
-
const isDesktopView = (): boolean => {
|
|
25
|
-
if (typeof window === 'undefined') return false
|
|
26
|
-
return window.innerWidth > 768
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return (<>
|
|
30
|
-
<DesktopHeader
|
|
31
|
-
className={cn(className, 'hidden md:flex')}
|
|
32
|
-
links={links}
|
|
33
|
-
currentAs={currentAs}
|
|
34
|
-
/>
|
|
35
|
-
<MobileHeader
|
|
36
|
-
className={cn(className, 'md:hidden')}
|
|
37
|
-
links={links}
|
|
38
|
-
currentAs={currentAs}
|
|
39
|
-
setChatbotOpen={setOpen}
|
|
40
|
-
/>
|
|
41
|
-
{isDesktopView() && (
|
|
42
|
-
<ChatWidget
|
|
43
|
-
title='LUX'
|
|
44
|
-
subtitle='AI'
|
|
45
|
-
chatbotUrl='https://lux.chat/iframe'
|
|
46
|
-
suggestedQuestions={siteDef.chatbot?.suggestedQuestions ?? []}
|
|
47
|
-
/>
|
|
48
|
-
)}
|
|
49
|
-
</>)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export default Header
|
|
1
|
+
'use client'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import type { SiteDef } from '../../site-def'
|
|
5
|
+
|
|
6
|
+
import DesktopHeader from './desktop'
|
|
7
|
+
import MobileHeader from './mobile'
|
|
8
|
+
import { cn } from '@hanzo/ui/util'
|
|
9
|
+
import { ChatWidget } from '../../components'
|
|
10
|
+
|
|
11
|
+
const Header: React.FC<{
|
|
12
|
+
siteDef: SiteDef
|
|
13
|
+
className?: string
|
|
14
|
+
}> = ({
|
|
15
|
+
siteDef,
|
|
16
|
+
className = ''
|
|
17
|
+
}) => {
|
|
18
|
+
|
|
19
|
+
// TODO
|
|
20
|
+
const [open, setOpen] = React.useState<boolean>(false);
|
|
21
|
+
|
|
22
|
+
const { nav: { common, featured }, currentAs } = siteDef
|
|
23
|
+
const links = (featured) ? [...common, ...featured] : common
|
|
24
|
+
const isDesktopView = (): boolean => {
|
|
25
|
+
if (typeof window === 'undefined') return false
|
|
26
|
+
return window.innerWidth > 768
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (<>
|
|
30
|
+
<DesktopHeader
|
|
31
|
+
className={cn(className, 'hidden md:flex')}
|
|
32
|
+
links={links}
|
|
33
|
+
currentAs={currentAs}
|
|
34
|
+
/>
|
|
35
|
+
<MobileHeader
|
|
36
|
+
className={cn(className, 'md:hidden')}
|
|
37
|
+
links={links}
|
|
38
|
+
currentAs={currentAs}
|
|
39
|
+
setChatbotOpen={setOpen}
|
|
40
|
+
/>
|
|
41
|
+
{isDesktopView() && (
|
|
42
|
+
<ChatWidget
|
|
43
|
+
title='LUX'
|
|
44
|
+
subtitle='AI'
|
|
45
|
+
chatbotUrl='https://lux.chat/iframe'
|
|
46
|
+
suggestedQuestions={siteDef.chatbot?.suggestedQuestions ?? []}
|
|
47
|
+
/>
|
|
48
|
+
)}
|
|
49
|
+
</>)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default Header
|
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
import React, { useState, useEffect } from 'react'
|
|
3
|
-
import { useRouter } from 'next/navigation'
|
|
4
|
-
|
|
5
|
-
import type { LinkDef } from '@hanzo/ui/types'
|
|
6
|
-
import { cn } from '@hanzo/ui/util'
|
|
7
|
-
|
|
8
|
-
import { CartPanel, useCommerce } from '@hanzo/commerce'
|
|
9
|
-
import { AuthWidget, LoginPanel } from '@hanzo/auth/components'
|
|
10
|
-
import sendGAEvent from '../../next/analytics/google-analytics'
|
|
11
|
-
import * as Icons from '../icons'
|
|
12
|
-
|
|
13
|
-
import { Logo } from '..'
|
|
14
|
-
|
|
15
|
-
import MenuToggleButton from '../commerce/mobile-menu-toggle-button'
|
|
16
|
-
import BagButton from '../commerce/bag-button'
|
|
17
|
-
import MobileBagDrawer from '../commerce/mobile-bag-drawer'
|
|
18
|
-
import NavMenu from '../commerce/mobile-nav-menu'
|
|
19
|
-
|
|
20
|
-
const bagClx = 'mt-4 mb-8 border-none py-0 px-4 w-full ' +
|
|
21
|
-
'sm:min-w-[350px] sm:max-w-[500px] sm:mx-auto min-h-[60vh] max-h-[70vh] ' +
|
|
22
|
-
'sm:animate-in sm:zoom-in-90 '
|
|
23
|
-
|
|
24
|
-
const MobileHeader: React.FC<{
|
|
25
|
-
currentAs: string | undefined
|
|
26
|
-
links: LinkDef[]
|
|
27
|
-
className?: string,
|
|
28
|
-
setChatbotOpen: (open: boolean) => void,
|
|
29
|
-
}> = ({
|
|
30
|
-
currentAs,
|
|
31
|
-
links,
|
|
32
|
-
className = '',
|
|
33
|
-
setChatbotOpen,
|
|
34
|
-
}) => {
|
|
35
|
-
const cmmc = useCommerce()
|
|
36
|
-
const [menuState, setMenuState] = useState<'closed' | 'nav' | 'login' | 'bag'>('closed')
|
|
37
|
-
const [bagDrawerOpen, setBagDrawerOpen] = useState<boolean>(false)
|
|
38
|
-
const router = useRouter()
|
|
39
|
-
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
if (menuState === 'bag' || bagDrawerOpen) {
|
|
42
|
-
sendGAEvent('view_cart', {
|
|
43
|
-
items: cmmc.cartItems.map((item) => ({
|
|
44
|
-
item_id: item.sku,
|
|
45
|
-
item_name: item.title,
|
|
46
|
-
item_category: item.familyId,
|
|
47
|
-
price: item.price,
|
|
48
|
-
quantity: item.quantity
|
|
49
|
-
})),
|
|
50
|
-
value: cmmc.cartTotal,
|
|
51
|
-
currency: 'USD',
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
}, [menuState, bagDrawerOpen])
|
|
55
|
-
|
|
56
|
-
const menuOpen = () => (menuState !== 'closed')
|
|
57
|
-
|
|
58
|
-
const onLoginChanged = (token: string) => {
|
|
59
|
-
// by def, menu was in state 'login'
|
|
60
|
-
if (!!token) { setMenuState('nav') }
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const setMenuOpen = (open: boolean) => {
|
|
64
|
-
if (!open) {
|
|
65
|
-
setMenuState('closed')
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
setMenuState('nav')
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const handleCheckout = () => {
|
|
73
|
-
setMenuState('closed')
|
|
74
|
-
setBagDrawerOpen(false)
|
|
75
|
-
router.push('/checkout')
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const openBag = () => {
|
|
79
|
-
if (menuOpen()) {
|
|
80
|
-
setMenuState('bag')
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
setBagDrawerOpen(true)
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
// header element MUST be fixed, and NOT sticky. Or else drawer breaks on mobile browsers
|
|
87
|
-
return (<>
|
|
88
|
-
<header className={cn(
|
|
89
|
-
`bg-background fixed z-header top-0 left-0 w-full ${menuOpen() ? 'hidden' : 'block'}`,
|
|
90
|
-
className
|
|
91
|
-
)}>
|
|
92
|
-
{/* smaller than md: mobile style drawer menu; h-11 is 44px, the standard mobile header height */}
|
|
93
|
-
<div className='w-full h-11 flex flex-row justify-between items-center font-bold pl-6 pr-4'>
|
|
94
|
-
<Logo href='/' size='sm' outerClx={'top-[3px] h-full'} variant='text-only' />
|
|
95
|
-
{/* Not that key to the cross-fade effect
|
|
96
|
-
is that this is **on top of** the logo. */}
|
|
97
|
-
{menuOpen() && (
|
|
98
|
-
<div className={'absolute left-0 top-0 bottom-0 right-0 pl-8 ' +
|
|
99
|
-
'flex flex-row ' +
|
|
100
|
-
'bg-background animate-mobile-menu-open'
|
|
101
|
-
}>
|
|
102
|
-
<Icons.Avatar className='self-center ' />
|
|
103
|
-
</div>
|
|
104
|
-
)}
|
|
105
|
-
<div className='flex gap-0 flex-row'>
|
|
106
|
-
<BagButton className='text-primary -mr-[3px]' onClick={openBag} />
|
|
107
|
-
<MenuToggleButton className='text-foreground' open={menuOpen()} setOpen={setMenuOpen} />
|
|
108
|
-
</div>
|
|
109
|
-
|
|
110
|
-
</div>
|
|
111
|
-
</header>
|
|
112
|
-
<MobileBagDrawer
|
|
113
|
-
className=''
|
|
114
|
-
open={bagDrawerOpen}
|
|
115
|
-
setOpen={setBagDrawerOpen}
|
|
116
|
-
handleCheckout={handleCheckout}
|
|
117
|
-
/>
|
|
118
|
-
{menuOpen() && (
|
|
119
|
-
<div className={
|
|
120
|
-
'fixed top-0 left-0 w-full h-full ' +
|
|
121
|
-
// z must below header itself
|
|
122
|
-
'flex flex-column bg-background z-below-header animate-mobile-menu-open'
|
|
123
|
-
}>
|
|
124
|
-
{menuState === 'login' ? (
|
|
125
|
-
<LoginPanel noHeading onLoginChanged={onLoginChanged} className='sm:animate-in sm:zoom-in-90' />
|
|
126
|
-
) : (
|
|
127
|
-
menuState === 'bag' ? (
|
|
128
|
-
|
|
129
|
-
<CartPanel
|
|
130
|
-
handleCheckout={() => { router.push('/checkout') }}
|
|
131
|
-
className={bagClx}
|
|
132
|
-
listClx='rounded-sm'
|
|
133
|
-
scrollAfter={6}
|
|
134
|
-
scrollHeightClx='h-[80vh]'
|
|
135
|
-
itemClx='mt-2'
|
|
136
|
-
totalClx='sticky px-1 pr-2 border rounded-sm -bottom-[1px] bg-level-1'
|
|
137
|
-
buttonClx='max-w-[220px] flex-none'
|
|
138
|
-
>
|
|
139
|
-
<div className='flex flex-row items-center flex-none justify-center '>
|
|
140
|
-
<Icons.bag className='mr-2 relative w-4 h-5 fill-foreground ' />
|
|
141
|
-
<p className='font-heading text-foreground text-default'>Your Bag</p>
|
|
142
|
-
</div>
|
|
143
|
-
<div className='h-[1px] w-pr-80 bg-muted-3 mx-auto mt-1.5 flex-none' />
|
|
144
|
-
</CartPanel>
|
|
145
|
-
|
|
146
|
-
) : ( /* menuState === 'nav' */
|
|
147
|
-
<NavMenu
|
|
148
|
-
currentAs={currentAs}
|
|
149
|
-
links={links}
|
|
150
|
-
className='sm:animate-in sm:zoom-in-90 w-full'
|
|
151
|
-
commonItemClx='px-0 text-xl h-16 justify-start '
|
|
152
|
-
setMenuState={setMenuState}
|
|
153
|
-
setChatbotOpen={setChatbotOpen}
|
|
154
|
-
setMenuOpen={setMenuOpen}
|
|
155
|
-
/>
|
|
156
|
-
)
|
|
157
|
-
)}
|
|
158
|
-
</div>
|
|
159
|
-
) /* menuOpen */}
|
|
160
|
-
</>)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export default MobileHeader
|
|
1
|
+
'use client'
|
|
2
|
+
import React, { useState, useEffect } from 'react'
|
|
3
|
+
import { useRouter } from 'next/navigation'
|
|
4
|
+
|
|
5
|
+
import type { LinkDef } from '@hanzo/ui/types'
|
|
6
|
+
import { cn } from '@hanzo/ui/util'
|
|
7
|
+
|
|
8
|
+
import { CartPanel, useCommerce } from '@hanzo/commerce'
|
|
9
|
+
import { AuthWidget, LoginPanel } from '@hanzo/auth/components'
|
|
10
|
+
import sendGAEvent from '../../next/analytics/google-analytics'
|
|
11
|
+
import * as Icons from '../icons'
|
|
12
|
+
|
|
13
|
+
import { Logo } from '..'
|
|
14
|
+
|
|
15
|
+
import MenuToggleButton from '../commerce/mobile-menu-toggle-button'
|
|
16
|
+
import BagButton from '../commerce/bag-button'
|
|
17
|
+
import MobileBagDrawer from '../commerce/mobile-bag-drawer'
|
|
18
|
+
import NavMenu from '../commerce/mobile-nav-menu'
|
|
19
|
+
|
|
20
|
+
const bagClx = 'mt-4 mb-8 border-none py-0 px-4 w-full ' +
|
|
21
|
+
'sm:min-w-[350px] sm:max-w-[500px] sm:mx-auto min-h-[60vh] max-h-[70vh] ' +
|
|
22
|
+
'sm:animate-in sm:zoom-in-90 '
|
|
23
|
+
|
|
24
|
+
const MobileHeader: React.FC<{
|
|
25
|
+
currentAs: string | undefined
|
|
26
|
+
links: LinkDef[]
|
|
27
|
+
className?: string,
|
|
28
|
+
setChatbotOpen: (open: boolean) => void,
|
|
29
|
+
}> = ({
|
|
30
|
+
currentAs,
|
|
31
|
+
links,
|
|
32
|
+
className = '',
|
|
33
|
+
setChatbotOpen,
|
|
34
|
+
}) => {
|
|
35
|
+
const cmmc = useCommerce()
|
|
36
|
+
const [menuState, setMenuState] = useState<'closed' | 'nav' | 'login' | 'bag'>('closed')
|
|
37
|
+
const [bagDrawerOpen, setBagDrawerOpen] = useState<boolean>(false)
|
|
38
|
+
const router = useRouter()
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (menuState === 'bag' || bagDrawerOpen) {
|
|
42
|
+
sendGAEvent('view_cart', {
|
|
43
|
+
items: cmmc.cartItems.map((item) => ({
|
|
44
|
+
item_id: item.sku,
|
|
45
|
+
item_name: item.title,
|
|
46
|
+
item_category: item.familyId,
|
|
47
|
+
price: item.price,
|
|
48
|
+
quantity: item.quantity
|
|
49
|
+
})),
|
|
50
|
+
value: cmmc.cartTotal,
|
|
51
|
+
currency: 'USD',
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
}, [menuState, bagDrawerOpen])
|
|
55
|
+
|
|
56
|
+
const menuOpen = () => (menuState !== 'closed')
|
|
57
|
+
|
|
58
|
+
const onLoginChanged = (token: string) => {
|
|
59
|
+
// by def, menu was in state 'login'
|
|
60
|
+
if (!!token) { setMenuState('nav') }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const setMenuOpen = (open: boolean) => {
|
|
64
|
+
if (!open) {
|
|
65
|
+
setMenuState('closed')
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
setMenuState('nav')
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const handleCheckout = () => {
|
|
73
|
+
setMenuState('closed')
|
|
74
|
+
setBagDrawerOpen(false)
|
|
75
|
+
router.push('/checkout')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const openBag = () => {
|
|
79
|
+
if (menuOpen()) {
|
|
80
|
+
setMenuState('bag')
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
setBagDrawerOpen(true)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// header element MUST be fixed, and NOT sticky. Or else drawer breaks on mobile browsers
|
|
87
|
+
return (<>
|
|
88
|
+
<header className={cn(
|
|
89
|
+
`bg-background fixed z-header top-0 left-0 w-full ${menuOpen() ? 'hidden' : 'block'}`,
|
|
90
|
+
className
|
|
91
|
+
)}>
|
|
92
|
+
{/* smaller than md: mobile style drawer menu; h-11 is 44px, the standard mobile header height */}
|
|
93
|
+
<div className='w-full h-11 flex flex-row justify-between items-center font-bold pl-6 pr-4'>
|
|
94
|
+
<Logo href='/' size='sm' outerClx={'top-[3px] h-full'} variant='text-only' />
|
|
95
|
+
{/* Not that key to the cross-fade effect
|
|
96
|
+
is that this is **on top of** the logo. */}
|
|
97
|
+
{menuOpen() && (
|
|
98
|
+
<div className={'absolute left-0 top-0 bottom-0 right-0 pl-8 ' +
|
|
99
|
+
'flex flex-row ' +
|
|
100
|
+
'bg-background animate-mobile-menu-open'
|
|
101
|
+
}>
|
|
102
|
+
<Icons.Avatar className='self-center ' />
|
|
103
|
+
</div>
|
|
104
|
+
)}
|
|
105
|
+
<div className='flex gap-0 flex-row'>
|
|
106
|
+
<BagButton className='text-primary -mr-[3px]' onClick={openBag} />
|
|
107
|
+
<MenuToggleButton className='text-foreground' open={menuOpen()} setOpen={setMenuOpen} />
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
</div>
|
|
111
|
+
</header>
|
|
112
|
+
<MobileBagDrawer
|
|
113
|
+
className=''
|
|
114
|
+
open={bagDrawerOpen}
|
|
115
|
+
setOpen={setBagDrawerOpen}
|
|
116
|
+
handleCheckout={handleCheckout}
|
|
117
|
+
/>
|
|
118
|
+
{menuOpen() && (
|
|
119
|
+
<div className={
|
|
120
|
+
'fixed top-0 left-0 w-full h-full ' +
|
|
121
|
+
// z must below header itself
|
|
122
|
+
'flex flex-column bg-background z-below-header animate-mobile-menu-open'
|
|
123
|
+
}>
|
|
124
|
+
{menuState === 'login' ? (
|
|
125
|
+
<LoginPanel noHeading onLoginChanged={onLoginChanged} className='sm:animate-in sm:zoom-in-90' />
|
|
126
|
+
) : (
|
|
127
|
+
menuState === 'bag' ? (
|
|
128
|
+
|
|
129
|
+
<CartPanel
|
|
130
|
+
handleCheckout={() => { router.push('/checkout') }}
|
|
131
|
+
className={bagClx}
|
|
132
|
+
listClx='rounded-sm'
|
|
133
|
+
scrollAfter={6}
|
|
134
|
+
scrollHeightClx='h-[80vh]'
|
|
135
|
+
itemClx='mt-2'
|
|
136
|
+
totalClx='sticky px-1 pr-2 border rounded-sm -bottom-[1px] bg-level-1'
|
|
137
|
+
buttonClx='max-w-[220px] flex-none'
|
|
138
|
+
>
|
|
139
|
+
<div className='flex flex-row items-center flex-none justify-center '>
|
|
140
|
+
<Icons.bag className='mr-2 relative w-4 h-5 fill-foreground ' />
|
|
141
|
+
<p className='font-heading text-foreground text-default'>Your Bag</p>
|
|
142
|
+
</div>
|
|
143
|
+
<div className='h-[1px] w-pr-80 bg-muted-3 mx-auto mt-1.5 flex-none' />
|
|
144
|
+
</CartPanel>
|
|
145
|
+
|
|
146
|
+
) : ( /* menuState === 'nav' */
|
|
147
|
+
<NavMenu
|
|
148
|
+
currentAs={currentAs}
|
|
149
|
+
links={links}
|
|
150
|
+
className='sm:animate-in sm:zoom-in-90 w-full'
|
|
151
|
+
commonItemClx='px-0 text-xl h-16 justify-start '
|
|
152
|
+
setMenuState={setMenuState}
|
|
153
|
+
setChatbotOpen={setChatbotOpen}
|
|
154
|
+
setMenuOpen={setMenuOpen}
|
|
155
|
+
/>
|
|
156
|
+
)
|
|
157
|
+
)}
|
|
158
|
+
</div>
|
|
159
|
+
) /* menuOpen */}
|
|
160
|
+
</>)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export default MobileHeader
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import React from 'react'
|
|
4
|
-
import { Moon, Sun } from 'lucide-react'
|
|
5
|
-
import { useTheme } from 'next-themes'
|
|
6
|
-
|
|
7
|
-
import { Button } from '@hanzo/ui/primitives'
|
|
8
|
-
|
|
9
|
-
const ThemeToggle: React.FC = () => {
|
|
10
|
-
|
|
11
|
-
const { setTheme, theme } = useTheme()
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<Button
|
|
15
|
-
variant='ghost'
|
|
16
|
-
size='icon'
|
|
17
|
-
onClick={() => {setTheme(theme === 'light' ? 'dark' : 'light')}}
|
|
18
|
-
>
|
|
19
|
-
<Sun className='h-[1.5rem] w-[1.3rem] dark:hidden' />
|
|
20
|
-
<Moon className='hidden h-5 w-5 dark:block' />
|
|
21
|
-
<span className='sr-only'>Toggle theme</span>
|
|
22
|
-
</Button>
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default ThemeToggle
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { Moon, Sun } from 'lucide-react'
|
|
5
|
+
import { useTheme } from 'next-themes'
|
|
6
|
+
|
|
7
|
+
import { Button } from '@hanzo/ui/primitives'
|
|
8
|
+
|
|
9
|
+
const ThemeToggle: React.FC = () => {
|
|
10
|
+
|
|
11
|
+
const { setTheme, theme } = useTheme()
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Button
|
|
15
|
+
variant='ghost'
|
|
16
|
+
size='icon'
|
|
17
|
+
onClick={() => {setTheme(theme === 'light' ? 'dark' : 'light')}}
|
|
18
|
+
>
|
|
19
|
+
<Sun className='h-[1.5rem] w-[1.3rem] dark:hidden' />
|
|
20
|
+
<Moon className='hidden h-5 w-5 dark:block' />
|
|
21
|
+
<span className='sr-only'>Toggle theme</span>
|
|
22
|
+
</Button>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default ThemeToggle
|