@luxfi/ui 5.5.3 → 5.5.5

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.
Files changed (39) hide show
  1. package/LICENSE +29 -0
  2. package/components/auth/callback.tsx +40 -0
  3. package/components/auth/login-panel.tsx +15 -44
  4. package/components/auth/login.tsx +47 -0
  5. package/components/auth/provider.tsx +34 -0
  6. package/components/auth/resume.ts +16 -0
  7. package/components/auth/widget.tsx +80 -0
  8. package/components/chat-widget.tsx +6 -7
  9. package/components/commerce/checkout-panel/desktop-cp.tsx +2 -2
  10. package/components/commerce/checkout-panel/mobile-cp.tsx +2 -2
  11. package/components/footer-nav.tsx +31 -0
  12. package/components/footer.tsx +7 -12
  13. package/components/header/desktop-nav-menu.tsx +4 -6
  14. package/components/header/desktop.tsx +4 -4
  15. package/components/header/index.tsx +1 -1
  16. package/components/header/mobile-nav-menu-ai.tsx +1 -1
  17. package/components/header/mobile-nav-menu.tsx +2 -2
  18. package/components/header/mobile.tsx +3 -3
  19. package/components/icons/index.ts +0 -1
  20. package/components/index.ts +2 -2
  21. package/components/logo.tsx +39 -67
  22. package/components/security/index.tsx +55 -0
  23. package/next/analytics/fpixel.ts +1 -1
  24. package/next/middleware/determine-device-mw.ts +0 -13
  25. package/package.json +31 -28
  26. package/root-layout/index.tsx +3 -10
  27. package/site-def/footer/community.tsx +1 -4
  28. package/site-def/footer/network.ts +2 -2
  29. package/site-def/main-nav.tsx +19 -19
  30. package/style/lux-global.css +49 -0
  31. package/types/site-def.ts +7 -0
  32. package/util/index.ts +11 -0
  33. package/components/auth/auth-listener.tsx +0 -29
  34. package/components/auth/auth-token/clear-auth-token.tsx +0 -12
  35. package/components/auth/auth-token/set-auth-token.tsx +0 -16
  36. package/components/auth/common-auth-domains.ts +0 -17
  37. package/components/auth/mobile-login-button.tsx +0 -107
  38. package/components/auth/signup-panel.tsx +0 -113
  39. package/components/icons/lux-logo.tsx +0 -10
package/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2024, Lux Partners Limited
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,40 @@
1
+ 'use client'
2
+
3
+ import React, { useEffect, useState } from 'react'
4
+
5
+ import { useIam } from '@hanzo/iam/react'
6
+
7
+ import { resume } from './resume'
8
+
9
+ /**
10
+ * The site's OAuth redirect target. IAM sends the authorization code here and
11
+ * this redeems it for tokens with the PKCE verifier the browser kept, then
12
+ * returns the visitor to the page they left.
13
+ */
14
+ const Callback = () => {
15
+
16
+ const { handleCallback } = useIam()
17
+ const [error, setError] = useState<string | null>(null)
18
+
19
+ useEffect(() => {
20
+ handleCallback()
21
+ .then(() => { window.location.replace(resume()) })
22
+ .catch((e: Error) => { setError(e.message) })
23
+ /* Runs once: the authorization code is single-use. */
24
+ }, [])
25
+
26
+ return (
27
+ <main className='flex min-h-screen items-center justify-center p-8 text-center'>
28
+ {error ? (
29
+ <div className='flex flex-col gap-4'>
30
+ <p role='alert'>{error}</p>
31
+ <a href='/' className='underline'>Back to the site</a>
32
+ </div>
33
+ ) : (
34
+ <p>Signing you in…</p>
35
+ )}
36
+ </main>
37
+ )
38
+ }
39
+
40
+ export default Callback
@@ -1,55 +1,26 @@
1
1
  'use client'
2
2
 
3
+ import React from 'react'
3
4
  import Link from 'next/link'
4
- import { useRouter } from 'next/navigation'
5
- import { setCookie } from 'cookies-next'
6
5
 
7
6
  import { cn } from '@hanzo/ui/util'
8
7
  import { Button, Carousel, CarouselContent, CarouselItem } from '@hanzo/ui/primitives'
9
- import { LoginPanel as Login } from '@hanzo/auth/components'
10
8
 
11
- import { LuxLogo } from '../icons'
9
+ import Login from './login'
10
+ import { LuxLogo } from '@luxfi/logo'
12
11
  import Logo from '../logo'
13
12
  import { EmblaAutoplay } from '..'
14
13
  import { legal } from '../../site-def/footer'
15
14
 
16
15
  const LoginPanel: React.FC<{
17
16
  close: () => void
18
- getStartedUrl?: string
19
- redirectUrl?: string
20
17
  className?: string
21
18
  reviews: { text: string, author: string, href: string }[]
22
- setIsLogin?: React.Dispatch<React.SetStateAction<boolean>>
23
19
  }> = ({
24
20
  close,
25
- getStartedUrl = '/',
26
- redirectUrl,
27
21
  className = '',
28
- reviews,
29
- setIsLogin
22
+ reviews
30
23
  }) => {
31
- const router = useRouter()
32
-
33
- const termsOfServiceUrl = legal.find(({ title }) => title === 'Terms and Conditions')?.href || ''
34
- const privacyPolicyUrl = legal.find(({ title }) => title === 'Privacy Policy')?.href || ''
35
- const domains = ['lux.id', 'lux.credit', 'lux.market', 'lux.network', 'lux.shop', 'wallet.lux.network', 'safe.lux.network', 'lux.finance', 'lux.exchange', 'lux.quest']
36
- // TODO :aa shouldn't this happen in @hanzo/auth: components/LoginPanel ??
37
- // Otherwise, the functionality is split across modules! (and client/fw!)
38
- // (This was never my intent w the onLoginChanged callback.)
39
- const onLogin = (token: string) => {
40
- for (let i = 0; i < domains.length; i ++) {
41
- setCookie('auth-token', token, {
42
- domain: domains[i],
43
- path: '/',
44
- sameSite: 'none',
45
- secure: true,
46
- httpOnly: false,
47
- expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30), // 30 days
48
- })
49
- }
50
-
51
- redirectUrl && router.push(redirectUrl)
52
- }
53
24
 
54
25
  return (
55
26
  <div className={cn('grid grid-cols-1 md:grid-cols-2', className)}>
@@ -61,7 +32,7 @@ const LoginPanel: React.FC<{
61
32
  onClick={close}
62
33
  className='w-fit !min-w-0 p-2'
63
34
  >
64
- <Logo size='md' textClx='!cursor-pointer' variant='text-only' />
35
+ <Logo size='md' variant='wordmark' />
65
36
  </Button>
66
37
  <Carousel
67
38
  options={{ align: 'center', loop: true }}
@@ -90,17 +61,17 @@ const LoginPanel: React.FC<{
90
61
  onClick={close}
91
62
  className='block md:hidden absolute rounded-full p-2 left-0 h-auto hover:bg-background'
92
63
  >
93
- <LuxLogo className='w-5 h-5' />
64
+ <LuxLogo variant='white' size={20} />
94
65
  </Button>
95
- <Login
96
- getStartedUrl={getStartedUrl}
97
- redirectUrl={redirectUrl}
98
- className='w-full max-w-sm'
99
- termsOfServiceUrl={termsOfServiceUrl}
100
- privacyPolicyUrl={privacyPolicyUrl}
101
- onLoginChanged={onLogin}
102
- setIsLogin={setIsLogin}
103
- />
66
+ <Login className='w-full max-w-sm' />
67
+ <p className='text-sm opacity-50'>
68
+ {legal.map(({ title, href }, index) => (
69
+ <React.Fragment key={href}>
70
+ {index > 0 && ' · '}
71
+ <Link href={href} className='underline'>{title}</Link>
72
+ </React.Fragment>
73
+ ))}
74
+ </p>
104
75
  </div>
105
76
  </div>
106
77
  </div>
@@ -0,0 +1,47 @@
1
+ 'use client'
2
+
3
+ import React, { useEffect, useState } from 'react'
4
+
5
+ import { cn } from '@hanzo/ui/util'
6
+ import { Login as IamLogin, useIam } from '@hanzo/iam/react'
7
+
8
+ import { remember } from './resume'
9
+
10
+ /**
11
+ * Sign-in rendered in place, on this site's own domain: IAM mints an
12
+ * authorization code bound to a PKCE challenge and the form navigates to
13
+ * /auth/callback to redeem it. No credential ever reaches this bundle's
14
+ * origin, and there is one sign-in surface rather than one per app.
15
+ */
16
+ const Login: React.FC<{
17
+ className?: string
18
+ onSuccess?: (token: string) => void
19
+ }> = ({
20
+ className,
21
+ onSuccess
22
+ }) => {
23
+
24
+ const { config } = useIam()
25
+ /* OIDC anti-CSRF nonce, one per mounted form. */
26
+ const [state] = useState(() => crypto.randomUUID())
27
+
28
+ /* Sign-in leaves for /auth/callback, so record the page holding this form to
29
+ come back to. */
30
+ useEffect(remember, [])
31
+
32
+ return (
33
+ <IamLogin
34
+ serverUrl={config.serverUrl}
35
+ clientId={config.clientId}
36
+ redirectUri={config.redirectUri}
37
+ organization={config.organization}
38
+ state={state}
39
+ /* Naming a class replaces the view's own, so keep both: the site skins
40
+ .hanzo-iam-* once, in lux-global.css. */
41
+ className={cn('hanzo-iam-card', className)}
42
+ onSuccess={onSuccess}
43
+ />
44
+ )
45
+ }
46
+
47
+ export default Login
@@ -0,0 +1,34 @@
1
+ 'use client'
2
+
3
+ import React, { type PropsWithChildren } from 'react'
4
+
5
+ import { IamProvider } from '@hanzo/iam/react'
6
+ import { BRAND_SERVER_URLS } from '@hanzo/iam/paths'
7
+ import type { IAMConfig } from '@hanzo/iam/browser'
8
+
9
+ /* These are Lux sites, so they sign in at Lux's own issuer. Naming another
10
+ brand's would send a Lux user to a login page that has never heard of the
11
+ redirect_uri they came from. */
12
+ const ORG = 'lux'
13
+
14
+ /* Where the authorization code comes back. Every site mounts <Callback/> here. */
15
+ const CALLBACK = '/auth/callback'
16
+
17
+ /* The OAuth client a site presents itself as: the `<org>-<app>` pair registered
18
+ on lux.id, so lux.shop is `lux-shop`. */
19
+ const configure = (app: string): IAMConfig => ({
20
+ serverUrl: BRAND_SERVER_URLS[ORG],
21
+ organization: ORG,
22
+ clientId: `${ORG}-${app}`,
23
+ /* Read per render rather than at module load: one bundle serves the real
24
+ host and any preview of it, and each must redeem its code back to itself. */
25
+ redirectUri: (typeof window === 'undefined' ? '' : window.location.origin) + CALLBACK,
26
+ })
27
+
28
+ /* Provider is memoized on the config's values, not its identity, so building a
29
+ fresh object here does not rebuild the SDK. */
30
+ const Auth: React.FC<{ app: string } & PropsWithChildren> = ({ app, children }) => (
31
+ <IamProvider config={configure(app)}>{children}</IamProvider>
32
+ )
33
+
34
+ export default Auth
@@ -0,0 +1,16 @@
1
+ /* Where the visitor was when they chose to sign in. The OIDC round-trip lands
2
+ on /auth/callback, so without this every sign-in would end at the home page.
3
+ Session-scoped: it describes one trip through the browser, not a preference. */
4
+ const KEY = 'lux-auth-resume'
5
+
6
+ const remember = () => {
7
+ sessionStorage.setItem(KEY, window.location.pathname + window.location.search)
8
+ }
9
+
10
+ const resume = (): string => {
11
+ const to = sessionStorage.getItem(KEY)
12
+ sessionStorage.removeItem(KEY)
13
+ return to ?? '/'
14
+ }
15
+
16
+ export { remember, resume }
@@ -0,0 +1,80 @@
1
+ 'use client'
2
+
3
+ import React, { useContext } from 'react'
4
+
5
+ import { Button, Popover, PopoverContent, PopoverTrigger, Separator } from '@hanzo/ui/primitives'
6
+ import { cn } from '@hanzo/ui/util'
7
+ import { IamContext, useIam, useIamIdentity } from '@hanzo/iam/react'
8
+
9
+ import { remember } from './resume'
10
+
11
+ interface Props {
12
+ /** Hide the sign-in button, leaving only the profile of an already signed-in
13
+ user. Checkout wants this: it has its own sign-in step. */
14
+ noLogin?: boolean
15
+ className?: string
16
+ /** Sign in in place instead of leaving for lux.id — the mobile drawer opens
17
+ its own panel. */
18
+ handleLogin?: () => void
19
+ }
20
+
21
+ const Widget: React.FC<Props> = ({
22
+ noLogin = false,
23
+ handleLogin,
24
+ className
25
+ }) => {
26
+
27
+ const { isAuthenticated, isLoading, login, logout } = useIam()
28
+ const identity = useIamIdentity()
29
+
30
+ /* Say nothing until the stored token has been read, rather than flashing
31
+ "Login" at someone who is already signed in. */
32
+ if (isLoading) {
33
+ return null
34
+ }
35
+
36
+ if (!isAuthenticated) {
37
+ return noLogin ? null : (
38
+ <Button
39
+ variant='primary'
40
+ className={cn('h-8 w-fit !min-w-0', className)}
41
+ onClick={handleLogin ?? (() => { remember(); void login() })}
42
+ >
43
+ Login
44
+ </Button>
45
+ )
46
+ }
47
+
48
+ return (
49
+ <Popover>
50
+ <PopoverTrigger asChild>
51
+ <Button
52
+ variant='outline'
53
+ size='icon'
54
+ className={cn('rounded-full text-muted border-2 border-muted bg-level-1 hover:bg-level-2 hover:border-foreground hover:text-foreground uppercase w-8 h-8', className)}
55
+ >{identity?.initials}</Button>
56
+ </PopoverTrigger>
57
+ <PopoverContent className='bg-level-0'>
58
+ <div className='grid gap-4'>
59
+ <div className='space-y-2 truncate'>
60
+ <h4 className='font-medium leading-none truncate'>{identity?.name}</h4>
61
+ {identity?.email && identity.email !== identity.name && (
62
+ <p className='text-sm opacity-50 truncate'>{identity.email}</p>
63
+ )}
64
+ </div>
65
+ <Separator />
66
+ <Button variant='outline' onClick={() => { logout() }}>Logout</Button>
67
+ </div>
68
+ </PopoverContent>
69
+ </Popover>
70
+ )
71
+ }
72
+
73
+ /* The widget rides in shared chrome, and not every site mounts <Auth> —
74
+ app/credit carries its own root layout. A site that offers no sign-in shows
75
+ no sign-in, which is why the context is read before any hook that needs it. */
76
+ const AuthWidget: React.FC<Props> = (props) => (
77
+ useContext(IamContext) ? <Widget {...props} /> : null
78
+ )
79
+
80
+ export default AuthWidget
@@ -4,7 +4,7 @@ import React from 'react'
4
4
  import { Button, Card } from '@hanzo/ui/primitives'
5
5
  import { cn } from '@hanzo/ui/util'
6
6
 
7
- import { LuxLogo } from './icons'
7
+ import { LuxLogo } from '@luxfi/logo'
8
8
  import type { ChatbotSuggestedQuestion } from '../types'
9
9
 
10
10
  const ChatWidget: React.FC<{
@@ -58,16 +58,14 @@ const ChatWidget: React.FC<{
58
58
  <div className='flex px-4 py-2 h-12 bg-level-0 items-center justify-between'>
59
59
  <h1 className='font-semibold font-heading'>{title} <span className='opacity-60'>{subtitle}</span></h1>
60
60
  <Button onClick={onClick} variant='link' size='icon' className='w-fit sm:hidden'>
61
- <LuxLogo width={24} height={24}/>
61
+ <LuxLogo variant='white' size={24}/>
62
62
  </Button>
63
63
  </div>
64
64
  <iframe src={iframeSrc} className='h-full' />
65
65
  </Card>
66
66
  </div>
67
67
 
68
- <LuxLogo
69
- width={28}
70
- height={28}
68
+ <span
71
69
  onClick={onClick}
72
70
  className={cn(
73
71
  // z-index should be below anything in commerce-iu (buy drawer and checkout widget)
@@ -77,8 +75,9 @@ const ChatWidget: React.FC<{
77
75
  showChatbot ? 'rotate-180' : '',
78
76
  buttonClx
79
77
  )}
80
- strokeWidth={1}
81
- />
78
+ >
79
+ <LuxLogo variant='white' size={28} />
80
+ </span>
82
81
  </>)
83
82
  }
84
83
 
@@ -3,7 +3,7 @@ import React, { type PropsWithChildren } from 'react'
3
3
  import { observer } from 'mobx-react-lite'
4
4
 
5
5
  import { ScrollArea, StepIndicator } from '@hanzo/ui/primitives'
6
- import { AuthWidget } from '@hanzo/auth/components'
6
+ import AuthWidget from '../../auth/widget'
7
7
  import { CartPanel, useCommerce } from '@hanzo/commerce'
8
8
  import { cn } from '@hanzo/ui/util'
9
9
 
@@ -26,7 +26,7 @@ const DesktopCheckoutPanel: React.FC<PropsWithChildren & CheckoutPanelProps> = o
26
26
  <div key={1} className='w-full h-full bg-background flex flex-row items-start justify-end'>
27
27
  <div className='w-full h-full max-w-[750px] relative flex flex-col items-stretch justify-start px-8 pb-8'>
28
28
  <div key={1} className='h-[80px] grow-0 flex flex-row items-center z-10' >
29
- <Logo size='md' href='/' onClick={onLeave} variant='text-only' outerClx='logo-outer-tooltip-class' />
29
+ <Logo size='md' href='/' onClick={onLeave} variant='wordmark' outerClx='logo-outer-tooltip-class' />
30
30
  <Tooltip select='.logo-outer-tooltip-class' text='home' position='right' offset={6}/>
31
31
  </div>
32
32
  <BackButton
@@ -3,7 +3,7 @@ import React, { type PropsWithChildren } from 'react'
3
3
 
4
4
  import { StepIndicator } from '@hanzo/ui/primitives'
5
5
  import { cn } from '@hanzo/ui/util'
6
- import { AuthWidget } from '@hanzo/auth/components'
6
+ import AuthWidget from '../../auth/widget'
7
7
 
8
8
  import { BackButton, Logo } from '../..'
9
9
  import BagButton from '../bag-button'
@@ -31,7 +31,7 @@ const MobileCheckoutPanel: React.FC<PropsWithChildren & CheckoutPanelProps> = ({
31
31
  }
32
32
  onBack={onLeave}
33
33
  />
34
- <Logo size='xs' variant='text-only' href='/' onClick={onLeave} outerClx='-ml-2'/>
34
+ <Logo size='xs' variant='wordmark' href='/' onClick={onLeave} outerClx='-ml-2'/>
35
35
  </div>
36
36
  <StepIndicator
37
37
  dotSizeRem={1}
@@ -0,0 +1,31 @@
1
+ 'use client'
2
+ import React from 'react'
3
+
4
+ import type { LinkDef } from '@hanzo/ui/types'
5
+ import { NavItems } from '@hanzo/ui/primitives'
6
+
7
+ // NavItems styles each item via a callback, and a callback cannot cross the
8
+ // server/client boundary. Creating it here keeps Footer itself on the server.
9
+ const FooterNav: React.FC<{
10
+ items: LinkDef[]
11
+ currentAs?: string
12
+ className?: string
13
+ }> = ({
14
+ items,
15
+ currentAs,
16
+ className = ''
17
+ }) => (
18
+ <NavItems
19
+ items={items}
20
+ currentAs={currentAs}
21
+ as='nav'
22
+ className={className}
23
+ itemClx={(def: LinkDef) => ((def.variant === 'linkFG') ?
24
+ 'font-nav text-[15px]/[1.3] font-medium tracking-normal text-muted-1 sm:hover:text-foreground transition-color duration-500'
25
+ :
26
+ 'text-[15px]/[1.1] font-normal tracking-[0.2px] text-muted-1 sm:hover:text-foreground transition-color duration-500'
27
+ )}
28
+ />
29
+ )
30
+
31
+ export default FooterNav
@@ -7,6 +7,7 @@ import { cn } from '@hanzo/ui/util'
7
7
  import Copyright from './copyright'
8
8
  import type { SiteDef } from '../site-def'
9
9
  import { legal } from '../site-def/footer/legal'
10
+ import FooterNav from './footer-nav'
10
11
  import Logo from './logo'
11
12
 
12
13
  const Footer: React.FC<{
@@ -33,7 +34,7 @@ const Footer: React.FC<{
33
34
  'md:flex md:flex-row md:justify-between px-[24px]'
34
35
  }>
35
36
  <div className='hidden lg:flex flex-col' key={0}>
36
- <Logo size='md' variant='text-only' />
37
+ <Logo size='md' variant='wordmark' />
37
38
  </div>
38
39
  {footer.map((defs: LinkDef[], index: number) => {
39
40
 
@@ -41,21 +42,15 @@ const Footer: React.FC<{
41
42
  'xs:col-span-2 xs:mx-auto md:col-span-1 md:mx-0 ' : ''
42
43
 
43
44
  return (
44
- <NavItems
45
- items={defs}
45
+ <FooterNav
46
+ items={defs}
46
47
  currentAs={siteDef.currentAs}
47
- as='nav'
48
- className={cn('sm:min-w-[150px] md:min-w-0 flex flex-col justify-start items-start ' +
48
+ className={cn('sm:min-w-[150px] md:min-w-0 flex flex-col justify-start items-start ' +
49
49
  'gap-[11px] sm:gap-[12px] md:gap-[15px] ',
50
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
51
  )}
58
- />
52
+ key={index + 1}
53
+ />
59
54
  )
60
55
  })}
61
56
  </div>
@@ -68,10 +68,8 @@ const DesktopNav: React.FC<{
68
68
  {links.map((el, index) => (
69
69
  <NavigationMenuItem key={index} className='!m-0'>
70
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>
71
+ <Link href={el.href} className={cn(navigationMenuTriggerStyle(), ' text-muted-1 bg-transparent')}>
72
+ {el.title}
75
73
  </Link>
76
74
  ) : el.title === 'Cards' ? (
77
75
  <>
@@ -82,7 +80,7 @@ const DesktopNav: React.FC<{
82
80
  onMouseLeave={handleMouseLeave}
83
81
  onBlur={handleMouseLeave}
84
82
  >
85
- <Link href={el.href} legacyBehavior passHref>
83
+ <Link href={el.href}>
86
84
  {el.title}
87
85
  </Link>
88
86
  </NavigationMenuTrigger>
@@ -112,7 +110,7 @@ const DesktopNav: React.FC<{
112
110
  >
113
111
  {
114
112
  el.href && el.href !== '' ?
115
- <Link href={el.href} legacyBehavior passHref>
113
+ <Link href={el.href}>
116
114
  {el.title}
117
115
  </Link> : <>{el.title}</>
118
116
  }
@@ -1,7 +1,7 @@
1
1
  import React, { type PropsWithChildren } from 'react'
2
2
 
3
3
  import { cn } from '@hanzo/ui/util'
4
- import { AuthWidget } from '@hanzo/auth/components'
4
+ import AuthWidget from '../auth/widget'
5
5
 
6
6
  import Logo, { type LogoVariant } from '../logo'
7
7
 
@@ -25,7 +25,7 @@ const DesktopHeader: React.FC<{
25
25
  noAuth=false,
26
26
  noCommerce=false,
27
27
  children,
28
- logoVariant='text-only'
28
+ logoVariant='full'
29
29
  }) => {
30
30
  const [isMenuOpened, setIsMenuOpen] = React.useState(false);
31
31
 
@@ -42,7 +42,7 @@ const DesktopHeader: React.FC<{
42
42
  'flex flex-row h-[80px] items-center justify-between ' +
43
43
  'mx-[24px] w-full max-w-screen'
44
44
  }>
45
- <Logo size={logoVariant === 'logo-only' ? 'lg' : 'md'} href='/' outerClx='hidden lg:flex' key='two' variant={logoVariant} />
45
+ <Logo size={logoVariant === 'mark' ? 'lg' : 'md'} href='/' outerClx='hidden lg:flex' key='two' variant={logoVariant} />
46
46
  <Logo size='sm' href='/' outerClx='hidden md:flex lg:hidden' key='one' variant={logoVariant} />
47
47
  {/* md or larger */}
48
48
  <div className='flex w-full gap-4 items-center justify-center'>
@@ -52,7 +52,7 @@ const DesktopHeader: React.FC<{
52
52
  {!noCommerce && (
53
53
  <DesktopBagPopup popupClx='w-[340px]' trigger={<BagButton className='text-primary -mr-[3px] lg:min-w-0' />} />
54
54
  )}
55
- <AuthWidget noLogin={noAuth}/>
55
+ {!noAuth && <AuthWidget />}
56
56
  {children}
57
57
  </div>
58
58
  </div>
@@ -18,7 +18,7 @@ const Header: React.FC<{
18
18
  siteDef,
19
19
  className = '',
20
20
  children,
21
- logoVariant='text-only'
21
+ logoVariant='full'
22
22
  }) => {
23
23
 
24
24
  // TODO
@@ -15,7 +15,7 @@ const MobileNavMenuAI: React.FC<MobileNavMenuAIProps> = ({ setMenuOpen }) => {
15
15
  <>
16
16
  <div className="w-full text-2xl cursor-pointer">
17
17
  <div className='flex justify-between'>
18
- <Logo variant='text-only' size='md' outerClx={'p-6 h-full'} />
18
+ <Logo variant='wordmark' size='md' outerClx={'p-6 h-full'} />
19
19
  <Plus width={28} height={28} className={
20
20
  'block h-full aspect-square hover:bg-background sm:hover:bg-level-1 active:scale-75 text-foreground will-change-transform transition-transform transition-scale transition-duration-[1500] mt-6 mr-6 ' +
21
21
  (!open ? 'rotate-none' : 'rotate-[135deg] scale-110')
@@ -5,7 +5,7 @@ import { cn } from '@hanzo/ui/util'
5
5
  import type { LinkDefExtended, ChildMenu } from '../../site-def/main-nav'
6
6
  import MobileNavMenuAI from './mobile-nav-menu-ai'
7
7
  import MobileNavMenuItem from './mobile-nav-menu-item'
8
- import MobileAuthWidget from '../auth/mobile-login-button'
8
+ import AuthWidget from '../auth/widget'
9
9
  import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@hanzo/ui/primitives'
10
10
  import { ChevronDown } from 'lucide-react'
11
11
  import Link from 'next/link'
@@ -94,7 +94,7 @@ const MobileNav: React.FC<{
94
94
  })}
95
95
  </Accordion>
96
96
  </div>
97
- <MobileAuthWidget className='text-2xl z-10' handleLogin={() => { setMenuState('login') }} />
97
+ <AuthWidget className='text-2xl z-10' handleLogin={() => { setMenuState('login') }} />
98
98
  </div>
99
99
  ) : null
100
100
  );
@@ -6,7 +6,7 @@ import type { LinkDef } from '@hanzo/ui/types'
6
6
  import { cn } from '@hanzo/ui/util'
7
7
 
8
8
  import { CartPanel, useCommerce } from '@hanzo/commerce'
9
- import { LoginPanel } from '@hanzo/auth/components'
9
+ import Login from '../auth/login'
10
10
  import sendGAEvent from '../../next/analytics/google-analytics'
11
11
 
12
12
  import { Avatar, Bag } from '../icons'
@@ -95,7 +95,7 @@ const MobileHeader: React.FC<{
95
95
  )}>
96
96
  {/* smaller than md: mobile style drawer menu; h-11 is 44px, the standard mobile header height */}
97
97
  <div className='w-full h-full flex flex-row justify-between items-center font-bold pr-5'>
98
- <Logo href='/' size='md' outerClx={'p-6 h-full'} variant='text-only' />
98
+ <Logo href='/' size='md' outerClx={'p-6 h-full'} variant='wordmark' />
99
99
  {/* Not that key to the cross-fade effect
100
100
  is that this is **on top of** the logo. */}
101
101
  {menuOpen() && (
@@ -129,7 +129,7 @@ const MobileHeader: React.FC<{
129
129
  'flex flex-column bg-background z-below-header animate-mobile-menu-open'
130
130
  }>
131
131
  {(!!!noAuth && menuState === 'login') ? (
132
- <LoginPanel noHeading onLoginChanged={onLoginChanged} className='sm:animate-in sm:zoom-in-90' />
132
+ <Login onSuccess={onLoginChanged} className='sm:animate-in sm:zoom-in-90 m-auto w-full max-w-sm px-8' />
133
133
  ) : (
134
134
  (!!!noCommerce && menuState === 'bag') ? (
135
135
 
@@ -1,6 +1,5 @@
1
1
  export { default as Avatar } from './avatar'
2
2
  export { default as Bag } from './bag-icon'
3
3
  export { default as LeftArrow } from './left-arrow'
4
- export { default as LuxLogo } from './lux-logo'
5
4
  export { default as RightArrow } from './right-arrow'
6
5
  export { default as SocialIcon, type SocialIconProps } from './social-icon'