@luxfi/core 4.3.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. package/components/access-code-input.tsx +71 -0
  2. package/components/auth/login-panel.tsx +80 -0
  3. package/components/chat-widget.tsx +77 -0
  4. package/components/commerce/bag-button.tsx +67 -0
  5. package/components/commerce/checkout-panel/close-button.tsx +23 -0
  6. package/components/commerce/checkout-panel/dt-bag-carousel.tsx +36 -0
  7. package/components/commerce/checkout-panel/dt-checkout-panel.tsx +68 -0
  8. package/components/commerce/checkout-panel/index.tsx +124 -0
  9. package/components/commerce/checkout-panel/links-row.tsx +21 -0
  10. package/components/commerce/checkout-panel/mb-checkout-panel.tsx +51 -0
  11. package/components/commerce/checkout-panel/steps-indicator.tsx +39 -0
  12. package/components/commerce/checkout-panel/thank-you.tsx +18 -0
  13. package/components/commerce/desktop-bag-popup.tsx +78 -0
  14. package/components/commerce/mobile-bag-drawer.tsx +51 -0
  15. package/components/commerce/mobile-menu-toggle-button.tsx +35 -0
  16. package/components/commerce/mobile-nav-menu.tsx +64 -0
  17. package/components/contact-dialog/contact-form.tsx +112 -0
  18. package/components/contact-dialog/disclaimer.tsx +13 -0
  19. package/components/contact-dialog/index.tsx +64 -0
  20. package/components/copyright.tsx +21 -0
  21. package/components/footer.tsx +78 -0
  22. package/components/header/desktop.tsx +54 -0
  23. package/components/header/index.tsx +26 -0
  24. package/components/header/mobile.tsx +161 -0
  25. package/components/header/theme-toggle.tsx +26 -0
  26. package/components/icons/bag-icon.tsx +10 -0
  27. package/components/icons/github.tsx +14 -0
  28. package/components/icons/index.tsx +35 -0
  29. package/components/icons/lux-logo.tsx +10 -0
  30. package/components/icons/secure-delivery.tsx +13 -0
  31. package/components/icons/social-icon.tsx +35 -0
  32. package/components/icons/social-svg.css +3 -0
  33. package/components/icons/youtube-logo.tsx +59 -0
  34. package/components/index.ts +26 -0
  35. package/components/logo.tsx +81 -0
  36. package/components/mini-chart/index.tsx +8 -0
  37. package/components/mini-chart/mini-chart-props.ts +44 -0
  38. package/components/mini-chart/mini-chart.tsx +85 -0
  39. package/components/mini-chart/wrapper.tsx +23 -0
  40. package/components/not-found/index.tsx +27 -0
  41. package/components/not-found/not-found-content.mdx +5 -0
  42. package/components/root-layout.tsx +71 -0
  43. package/components/scripts.tsx +23 -0
  44. package/conf/index.ts +50 -0
  45. package/environment.d.ts +6 -0
  46. package/next/analytics/fpixel.ts +16 -0
  47. package/next/analytics/google-analytics.ts +14 -0
  48. package/next/analytics/index.ts +3 -0
  49. package/next/analytics/pixel-analytics.tsx +55 -0
  50. package/next/determine-device-mw.ts +16 -0
  51. package/next/font/get-app-router-font-classes.ts +12 -0
  52. package/next/font/load-and-return-lux-next-fonts-on-import.ts +67 -0
  53. package/next/font/local/Druk-Wide-Bold.ttf +0 -0
  54. package/next/font/local/Druk-Wide-Medium.ttf +0 -0
  55. package/next/font/next-font-desc.ts +28 -0
  56. package/next/font/pages-router-font-vars.tsx +18 -0
  57. package/next/head-metadata/from-next/metadata-types.ts +158 -0
  58. package/next/head-metadata/from-next/opengraph-types.ts +267 -0
  59. package/next/head-metadata/from-next/twitter-types.ts +92 -0
  60. package/next/head-metadata/index.tsx +208 -0
  61. package/next/index.ts +1 -0
  62. package/package.json +72 -0
  63. package/server-actions/firebase-app.ts +14 -0
  64. package/server-actions/index.ts +5 -0
  65. package/server-actions/store-contact.ts +51 -0
  66. package/site-def/footer/community.tsx +67 -0
  67. package/site-def/footer/company.ts +37 -0
  68. package/site-def/footer/ecosystem.ts +37 -0
  69. package/site-def/footer/index.tsx +26 -0
  70. package/site-def/footer/legal.ts +28 -0
  71. package/site-def/footer/network.ts +45 -0
  72. package/site-def/footer/svg/warpcast-logo.svg +12 -0
  73. package/site-def/index.ts +3 -0
  74. package/site-def/main-nav.ts +35 -0
  75. package/site-def/site-def.ts +37 -0
  76. package/style/lux-colors.css +85 -0
  77. package/style/lux-global.css +19 -0
  78. package/tailwind/fontFamily.tailwind.lux.ts +18 -0
  79. package/tailwind/index.ts +2 -0
  80. package/tailwind/lux-tw-fonts.ts +40 -0
  81. package/tailwind/tailwind.config.lux-preset.ts +10 -0
  82. package/tsconfig.json +10 -0
  83. package/types/contact-info.ts +11 -0
  84. package/types/index.ts +1 -0
@@ -0,0 +1,78 @@
1
+ 'use client'
2
+ import React, { useState, useEffect } from 'react'
3
+ import { useRouter } from 'next/navigation'
4
+
5
+ import { X } from 'lucide-react'
6
+
7
+ import {
8
+ Popover,
9
+ PopoverContent,
10
+ PopoverTrigger,
11
+ PopoverClose,
12
+ } from "@hanzo/ui/primitives"
13
+
14
+ import { cn } from '@hanzo/ui/util'
15
+ import { CartPanel, useCommerce } from '@hanzo/commerce'
16
+
17
+ import * as Icons from '../icons'
18
+ import sendGAEvent from '../../next/analytics/google-analytics'
19
+
20
+ const DesktopBagPopup: React.FC<{
21
+ triggerClx?: string
22
+ popupClx?: string
23
+ trigger: React.ReactNode
24
+ }> = ({
25
+ triggerClx='',
26
+ popupClx='',
27
+ trigger
28
+ }) => {
29
+ const cmmc = useCommerce()
30
+
31
+ const [bagOpen, setBagOpen] = useState<boolean>(false)
32
+ const router = useRouter()
33
+
34
+ useEffect(() => {
35
+ if (bagOpen) {
36
+ sendGAEvent('view_cart', {
37
+ items: cmmc.cartItems.map((item) => ({
38
+ item_id: item.sku,
39
+ item_name: item.title,
40
+ item_category: item.familyId,
41
+ price: item.price,
42
+ quantity: item.quantity
43
+ })),
44
+ value: cmmc.cartTotal,
45
+ currency: 'USD',
46
+ })
47
+ }
48
+ }, [bagOpen])
49
+
50
+ return (
51
+ <Popover open={bagOpen} onOpenChange={setBagOpen}>
52
+ <PopoverTrigger className={triggerClx}>
53
+ {trigger}
54
+ </PopoverTrigger>
55
+ <PopoverContent sideOffset={28} className={cn('relative flex flex-col p-0 px-4 pb-4 pt-2', popupClx)}>
56
+ <PopoverClose className='absolute z-above-content right-2 top-2 self-end hover:bg-level-3 text-muted hover:text-accent p-1 rounded-full'><X className='w-5 h-5'/></PopoverClose>
57
+ <CartPanel
58
+ handleCheckout={() => {router.push('/checkout')}}
59
+ className='mt-4 mb-4 border-none py-0 px-4'
60
+ listClx='rounded-sm'
61
+ scrollAfter={5}
62
+ scrollHeightClx='h-[70vh]'
63
+ itemClx='mt-3'
64
+ totalClx='sticky px-1 pr-2 -bottom-[1px] bg-level-1'
65
+ buttonClx='max-w-[220px] flex-none'
66
+ >
67
+ <div className='flex flex-row items-center flex-none justify-center '>
68
+ <Icons.bag className='mr-2 relative w-6 h-7 fill-foreground ' />
69
+ <p className='font-heading text-foreground text-default'>Your Bag</p>
70
+ </div>
71
+ <div className='h-[1px] w-pr-80 bg-muted-3 mx-auto mt-1.5 flex-none'/>
72
+ </CartPanel>
73
+ </PopoverContent>
74
+ </Popover>
75
+ )
76
+ }
77
+
78
+ export default DesktopBagPopup
@@ -0,0 +1,51 @@
1
+ 'use client'
2
+ import React from 'react'
3
+
4
+ import { Drawer, DrawerContent} from '@hanzo/ui/primitives'
5
+ import { cn } from '@hanzo/ui/util'
6
+ import { CartPanel } from '@hanzo/commerce'
7
+
8
+ import BagButton from './bag-button'
9
+
10
+ const MobileBagDrawer: React.FC<{
11
+ open: boolean,
12
+ setOpen: (b: boolean) => void
13
+ handleCheckout: () => void
14
+ className?: string
15
+ }> = ({
16
+ open,
17
+ setOpen,
18
+ handleCheckout,
19
+ className='',
20
+ }) => {
21
+
22
+ return (
23
+ <Drawer open={open} onOpenChange={setOpen}>
24
+ <DrawerContent className={cn('rounded-t-xl mt-6 pb-12 h-auto', className)} >
25
+ <CartPanel
26
+ handleCheckout={handleCheckout}
27
+ className='mt-4 mb-4 border-none py-0 px-4 w-full '
28
+ listClx='rounded-sm'
29
+ scrollAfter={5}
30
+ itemClx='mt-2'
31
+ totalClx='sticky px-1 pr-2 border rounded-sm -bottom-[1px] bg-background'
32
+ buttonClx='max-w-[220px] flex-none'
33
+ >
34
+ <div className='flex flex-row items-center flex-none justify-center '>
35
+ <BagButton
36
+ noHoverEffects
37
+ showIfEmpty
38
+ className=
39
+ 'mr-2 relative w-6 h-7'
40
+ iconClx='fill-foreground '
41
+ />
42
+ <p className='font-heading text-foreground text-default'>Your Bag</p>
43
+ </div>
44
+ <div className='h-[1px] w-pr-80 bg-muted-3 mx-auto mt-1.5 flex-none'/>
45
+ </CartPanel>
46
+ </DrawerContent>
47
+ </Drawer>
48
+ )
49
+ }
50
+
51
+ export default MobileBagDrawer
@@ -0,0 +1,35 @@
1
+ 'use client'
2
+ import React, { useState } from 'react'
3
+
4
+ import { Plus } from 'lucide-react'
5
+
6
+ import { Button } from '@hanzo/ui/primitives'
7
+ import { cn } from '@hanzo/ui/util'
8
+
9
+ const MobileMenuToggleButton: React.FC<{
10
+ open: boolean
11
+ setOpen: (b: boolean) => void
12
+ className?: string
13
+ }> = ({
14
+ open,
15
+ setOpen,
16
+ className=''
17
+ }) => {
18
+
19
+ return (
20
+ <Button
21
+ variant='ghost'
22
+ size='default'
23
+ rounded='full'
24
+ onClick={() => {setOpen(!open)}}
25
+ className={cn('p-0 aspect-square hover:bg-background sm:hover:bg-level-1 active:scale-75', className)}
26
+ >
27
+ <Plus width={28} height={28} className={
28
+ 'block h-full will-change-transform transition-transform transition-scale transition-duration-[1500] ' +
29
+ (open ? 'rotate-[135deg] scale-110' : 'rotate-none')
30
+ } />
31
+ </Button>
32
+ )
33
+ }
34
+
35
+ export default MobileMenuToggleButton
@@ -0,0 +1,64 @@
1
+ 'use client'
2
+ import React from 'react'
3
+
4
+ import type { LinkDef } from '@hanzo/ui/types'
5
+ import { LinkElement } from '@hanzo/ui/primitives'
6
+ import { cn } from '@hanzo/ui/util'
7
+
8
+ const MobileNav: React.FC<{
9
+ currentAs: string | undefined
10
+ links: LinkDef[]
11
+ className?: string
12
+ commonItemClx?: string | ((def: LinkDef) => string),
13
+ /**
14
+ * This is called *in addition* to the link's actual navigation
15
+ * action. eg, I link is clicked, and the modal menu is closes
16
+ */
17
+ onAction?: () => void
18
+ }> = ({
19
+ currentAs,
20
+ links,
21
+ onAction,
22
+ className='',
23
+ commonItemClx,
24
+ }) => (
25
+
26
+ links.length > 0 ? (
27
+
28
+ <nav className={className} >
29
+ {links.map((el, index) => {
30
+ const variant = el.variant ?? 'link'
31
+ let internalClx = ''
32
+ // note that linkFG (or any other variant of 'link')
33
+ // will not get assigned these classes,
34
+ // and will remain styles is 'foreground' (hence the name)
35
+ if (variant === 'link') {
36
+ internalClx+= ' text-muted hover:text-foreground active:text-accent rounded-none'
37
+ if (currentAs && currentAs === el.href) {
38
+ internalClx += ' text-accent '
39
+ }
40
+ }
41
+ else {
42
+ internalClx+= ' min-w-0'
43
+ }
44
+ if (currentAs && currentAs === el.href) {
45
+ internalClx += ' pointer-events-none'
46
+ }
47
+ const itemClx = (commonItemClx) ? (typeof commonItemClx === 'string' ? commonItemClx : commonItemClx(el)) : ''
48
+
49
+ return (
50
+ <LinkElement
51
+ def={el}
52
+ key={`common-${index}`}
53
+ size='lg'
54
+ className={cn(internalClx, itemClx)}
55
+ onClick={onAction}
56
+ />
57
+ )
58
+ })}
59
+ </nav>
60
+ )
61
+ : null
62
+ )
63
+
64
+ export default MobileNav
@@ -0,0 +1,112 @@
1
+ 'use client'
2
+
3
+ import React, { useTransition } from 'react'
4
+
5
+ import { zodResolver } from '@hookform/resolvers/zod'
6
+ import { useForm, type SubmitHandler, type ControllerRenderProps } from 'react-hook-form'
7
+ import * as z from 'zod'
8
+ // @ts-ignore
9
+ import validator from 'validator'
10
+
11
+ import { Loader2 } from 'lucide-react'
12
+
13
+ import {
14
+ Button,
15
+ Input,
16
+ Form,
17
+ FormControl,
18
+ FormField,
19
+ FormItem,
20
+ FormMessage,
21
+ } from '@hanzo/ui/primitives'
22
+
23
+ import type { SubmitServerAction } from '@hanzo/ui/types'
24
+ import type { ContactInfo } from '../../types'
25
+
26
+ const ValidationSchema = z.object({
27
+ email: z
28
+ .string()
29
+ .min(1, { message: "Email must be provided." })
30
+ .email("Invalid email."),
31
+ phone: z
32
+ .string()
33
+ .min(1, { message: "Telephone must be provided." })
34
+ .refine(validator.isMobilePhone, { message: "Invalid format." })
35
+ })
36
+
37
+ const ContactForm: React.FC<{
38
+ onSubmit: SubmitServerAction
39
+ enclosure: any
40
+ }> = ({
41
+ onSubmit,
42
+ enclosure
43
+ }) => {
44
+
45
+ const form = useForm<ContactInfo>({
46
+ // @ts-ignore (pnpm linking / tsc bug )
47
+ resolver: zodResolver(ValidationSchema),
48
+ defaultValues: {
49
+ email: '',
50
+ phone: '',
51
+ },
52
+ })
53
+
54
+ const [isPending, startTransition] = useTransition()
55
+
56
+ const onFormSubmit: SubmitHandler<ContactInfo> = (data) => {
57
+ // https://github.com/orgs/react-hook-form/discussions/10757#discussioncomment-6672403
58
+ // @ts-ignore
59
+ startTransition(async () => {
60
+ await onSubmit(data, enclosure)
61
+ })
62
+ }
63
+
64
+ const MyFormItem: React.FC<{
65
+ field: ControllerRenderProps<ContactInfo, 'email'> | ControllerRenderProps<ContactInfo, 'phone'>
66
+ placeholder: string
67
+ }> = ({
68
+ field,
69
+ placeholder
70
+ }) => (
71
+ <FormItem className="space-y-0" >
72
+ <FormControl>
73
+ <Input placeholder={placeholder} {...field} className="mt-0 text-foreground"/>
74
+ </FormControl>
75
+ <div className="flex flex-row justify-start items-stretch gap-2">
76
+ <FormMessage />
77
+ </div>
78
+ </FormItem>
79
+ )
80
+
81
+ return (
82
+ <Form {...form}>
83
+ <form onSubmit={form.handleSubmit(onFormSubmit)} className="w-3/4">
84
+ <div className='flex flex-col justify-start items-stretch mt-4'>
85
+ <FormField
86
+ control={form.control}
87
+ name='email'
88
+ // @ts-ignore
89
+ render={({ field }) => ( <MyFormItem field={field} placeholder='email'/> )}
90
+ />
91
+ <FormField
92
+ control={form.control}
93
+ name='phone'
94
+ // @ts-ignore
95
+ render={({ field }) => ( <MyFormItem field={field} placeholder='phone'/> )}
96
+ />
97
+ <Button disabled={isPending} type='submit' className='bg-primary text-primary-fg hover:bg-primary-hover'>
98
+ {isPending ? (<>
99
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
100
+ Please wait
101
+ </>
102
+ ) : (
103
+ <>Submit</>
104
+ )}
105
+ </Button>
106
+ </div>
107
+ </form>
108
+ </Form>
109
+ )
110
+ }
111
+
112
+ export default ContactForm
@@ -0,0 +1,13 @@
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
+
@@ -0,0 +1,64 @@
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
@@ -0,0 +1,21 @@
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}`}&nbsp;<br className='sm:hidden'/>Lux Partners Ltd.&nbsp;<br className='md:hidden'/>&nbsp;All rights reserved.
17
+ </div>
18
+ )
19
+ }
20
+
21
+ export default Copyright
@@ -0,0 +1,78 @@
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 max-w-screen-2xl ' +
33
+ 'md:flex md:flex-row md:justify-between '
34
+ }>
35
+ <div className='hidden lg:flex flex-col' key={0}>
36
+ <Logo size='md' layout='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 text-foreground tracking-normal'
55
+ :
56
+ 'text-[15px]/[1.1] font-normal tracking-[0.2px] text-muted-1'
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
@@ -0,0 +1,54 @@
1
+ import React from 'react'
2
+
3
+ import { NavItems } from '@hanzo/ui/primitives'
4
+ import { cn } from '@hanzo/ui/util'
5
+ import { AuthWidget } from '@hanzo/auth/components'
6
+
7
+ import { Logo } from '..'
8
+
9
+ import DesktopBagPopup from '../commerce/desktop-bag-popup'
10
+ import BagButton from '../commerce/bag-button'
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 sticky z-header top-0 ', className)} >
29
+ {/* md or larger */}
30
+ <div className={
31
+ 'flex flex-row h-[80px] items-center justify-between ' +
32
+ 'px-[32px] w-full 2xl:mx-auto max-w-screen-2xl'
33
+ }>
34
+ <Logo size='md' href='/' className='hidden lg:flex' key='two' layout='text-only'/>
35
+ <Logo size='sm' href='/' className='hidden md:flex lg:hidden' key='one' layout='text-only'/>
36
+ {/* md or larger */}
37
+ <div className='flex gap-4 items-center'>
38
+ <NavItems
39
+ currentAs={currentAs}
40
+ items={links}
41
+ className='flex md:gap-4 lg:justify-between lg:gap-7'
42
+ itemClx='font-nav h-8'
43
+ key='three'
44
+ />
45
+ <DesktopBagPopup popupClx='w-[340px]' trigger={<BagButton className='text-primary -mr-[3px] lg:min-w-0' />} />
46
+ <AuthWidget/>
47
+ </div>
48
+ </div>
49
+ </header>
50
+ )
51
+ }
52
+
53
+ export default DesktopHeader
54
+
@@ -0,0 +1,26 @@
1
+ import React from 'react'
2
+
3
+ import type { SiteDef } from '../../site-def'
4
+
5
+ import DesktopHeader from './desktop'
6
+ import MobileHeader from './mobile'
7
+ import { cn } from '@hanzo/ui/util'
8
+
9
+ const Header: React.FC<{
10
+ siteDef: SiteDef
11
+ className?: string
12
+ }> = ({
13
+ siteDef,
14
+ className = ''
15
+ }) => {
16
+
17
+ const { nav: { common, featured }, currentAs } = siteDef
18
+ const links = (featured) ? [...common, ...featured] : common
19
+
20
+ return (<>
21
+ <DesktopHeader className={cn(className, 'hidden md:flex')} links={links} currentAs={currentAs} />
22
+ <MobileHeader className={cn(className, 'md:hidden')} links={links} currentAs={currentAs} />
23
+ </>)
24
+ }
25
+
26
+ export default Header