@luxfi/ui 5.5.4 → 5.5.6

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 (80) hide show
  1. package/commerce/ui/context.tsx +13 -16
  2. package/components/access-code-input.tsx +3 -4
  3. package/components/analytics.tsx +8 -17
  4. package/components/auth/callback.tsx +40 -0
  5. package/components/auth/login-panel.tsx +22 -50
  6. package/components/auth/login.tsx +47 -0
  7. package/components/auth/provider.tsx +34 -0
  8. package/components/auth/resume.ts +16 -0
  9. package/components/auth/widget.tsx +80 -0
  10. package/components/back-button.tsx +4 -7
  11. package/components/chat-widget.tsx +9 -11
  12. package/components/commerce/bag-button.tsx +8 -7
  13. package/components/commerce/buy-button.tsx +2 -3
  14. package/components/commerce/checkout-button.tsx +12 -10
  15. package/components/commerce/checkout-panel/cart-accordian.tsx +3 -4
  16. package/components/commerce/checkout-panel/desktop-cp.tsx +7 -8
  17. package/components/commerce/checkout-panel/index.tsx +1 -1
  18. package/components/commerce/checkout-panel/mobile-cp.tsx +5 -5
  19. package/components/commerce/checkout-panel/policy-links.tsx +7 -12
  20. package/components/commerce/checkout-panel/steps-indicator.tsx +1 -1
  21. package/components/commerce/desktop-bag-popup.tsx +1 -1
  22. package/components/commerce/drawer/micro.tsx +30 -30
  23. package/components/commerce/drawer/shell.tsx +3 -5
  24. package/components/contact-dialog/contact-form.tsx +6 -13
  25. package/components/contact-dialog/index.tsx +2 -2
  26. package/components/copyright.tsx +3 -2
  27. package/components/drawer-margin.tsx +2 -2
  28. package/components/footer.tsx +7 -8
  29. package/components/header/desktop-nav-menu.tsx +6 -6
  30. package/components/header/desktop.tsx +9 -9
  31. package/components/header/index.tsx +2 -2
  32. package/components/header/mobile-bag-drawer.tsx +1 -1
  33. package/components/header/mobile-menu-toggle-button.tsx +5 -6
  34. package/components/header/mobile-nav-menu-ai.tsx +14 -13
  35. package/components/header/mobile-nav-menu-item.tsx +12 -11
  36. package/components/header/mobile-nav-menu.tsx +19 -18
  37. package/components/header/mobile.tsx +10 -11
  38. package/components/icons/index.ts +0 -1
  39. package/components/icons/social-icon.tsx +1 -1
  40. package/components/index.ts +2 -2
  41. package/components/logo.tsx +40 -67
  42. package/components/main.tsx +3 -4
  43. package/components/mini-chart/mini-chart.tsx +2 -1
  44. package/components/security/index.tsx +55 -0
  45. package/next/font/font-desc.ts +18 -0
  46. package/next/font/fonts.ts +40 -0
  47. package/next/font/get-app-router-font-classes.ts +14 -12
  48. package/next/font/load-and-return-lux-next-fonts-on-import.ts +16 -24
  49. package/next/font/local/Zen-Variable.woff2 +0 -0
  50. package/next/font/next-font-desc.ts +18 -17
  51. package/next/head-metadata/index.tsx +7 -6
  52. package/next/head-metadata/next-metadata.ts +49 -0
  53. package/next/middleware/determine-device-mw.ts +0 -13
  54. package/package.json +15 -15
  55. package/root-layout/index.tsx +42 -29
  56. package/style/fonts/Zen-Variable.woff2 +0 -0
  57. package/style/lux-colors.css +0 -1
  58. package/style/lux-fonts.css +5 -11
  59. package/style/lux-global-non-next.css +9 -9
  60. package/style/lux-global.css +99 -15
  61. package/tsconfig.json +8 -0
  62. package/types/site-def.ts +7 -0
  63. package/components/auth/auth-listener.tsx +0 -33
  64. package/components/auth/auth-token/clear-auth-token.tsx +0 -12
  65. package/components/auth/auth-token/set-auth-token.tsx +0 -16
  66. package/components/auth/common-auth-domains.ts +0 -17
  67. package/components/auth/mobile-login-button.tsx +0 -112
  68. package/components/auth/signup-panel.tsx +0 -113
  69. package/components/icons/lux-logo.tsx +0 -10
  70. package/next/font/local/Druk-Wide-Bold.ttf +0 -0
  71. package/next/font/local/Druk-Wide-Medium.ttf +0 -0
  72. package/next/head-metadata/from-next/metadata-types.ts +0 -158
  73. package/next/head-metadata/from-next/opengraph-types.ts +0 -267
  74. package/next/head-metadata/from-next/twitter-types.ts +0 -92
  75. package/style/fonts/Druk-Wide-Bold.ttf +0 -0
  76. package/style/fonts/Druk-Wide-Medium.ttf +0 -0
  77. package/tailwind/fontFamily.tailwind.lux.ts +0 -18
  78. package/tailwind/index.ts +0 -2
  79. package/tailwind/lux-tw-fonts.ts +0 -40
  80. package/tailwind/tailwind.config.lux-preset.ts +0 -10
@@ -0,0 +1,18 @@
1
+ /**
2
+ * A font in this site's vocabulary.
3
+ *
4
+ * `name` is the ROLE the font plays — `sans`, `nav`, `heading`, `serif`, `mono`
5
+ * — not a file and not a family. The stack is what the browser resolves, and
6
+ * `cssVar` is the custom property the next/font loader publishes the loaded
7
+ * face under, so the stack can point at it.
8
+ *
9
+ * It lived in a Tailwind preset and was called `TwFontDesc`, which named the
10
+ * engine that happened to read it rather than what it is. The engine is gone;
11
+ * the fonts are not.
12
+ */
13
+ export type FontDesc = {
14
+ /** The role: `sans`, `nav`, `heading`, `serif`, `mono`. */
15
+ name: string
16
+ fontFamily: string[]
17
+ cssVar?: string
18
+ }
@@ -0,0 +1,40 @@
1
+ import type { FontDesc } from './font-desc'
2
+
3
+
4
+ /* Read by ./load-and-return-lux-next-fonts-on-import.ts */
5
+
6
+ export default [
7
+ {
8
+ fontFamily: ['var(--font-inter)'], // do not provide fall-backs due to next bug
9
+ cssVar: '--font-inter',
10
+ name: 'sans'
11
+ },
12
+ {
13
+ fontFamily: ['var(--font-inter)'], // do not provide fall-backs due to next bug
14
+ cssVar: '--font-inter',
15
+ name: 'nav'
16
+ },
17
+ {
18
+ fontFamily: ['var(--font-zen-sans)'], // do not provide fall-backs due to next bug
19
+ cssVar: '--font-zen-sans',
20
+ name: 'heading'
21
+ },
22
+ {
23
+ name: 'serif',
24
+ fontFamily: ['ui-serif', 'Georgia', 'Cambria', '"Times New Roman"', 'Times']
25
+ },
26
+ {
27
+ name: 'mono',
28
+ fontFamily: [
29
+ 'ui-monospace',
30
+ 'SFMono-Regular',
31
+ 'Menlo',
32
+ 'Monaco',
33
+ 'Consolas',
34
+ '"Liberation Mono"',
35
+ '"Courier New"',
36
+ 'monospace',
37
+ ]
38
+ }
39
+
40
+ ] as FontDesc[]
@@ -1,17 +1,19 @@
1
1
  import nextFonts from './load-and-return-lux-next-fonts-on-import'
2
2
  import type NextFontDesc from './next-font-desc'
3
3
 
4
- // These will be injected for <body> in app router app that uses our RootLayout
5
-
6
- // First is assumed to be mapped to the default font and is injected into <body>
7
- // as a normal tw font family class.
4
+ /**
5
+ * next/font's own generated class names, for <body> in an app-router app using
6
+ * our RootLayout.
7
+ *
8
+ * Each one DEFINES a custom property holding the face it loaded, so they have
9
+ * to land on an element before anything can name `var(--font-inter)`.
10
+ *
11
+ * It used to append `font-<role>` for the default face as well. That was a
12
+ * utility class, and with no engine generating it the body had a name no sheet
13
+ * served — the family is set on `body` in lux-global.css instead, where it can
14
+ * point at the property these classes define.
15
+ */
8
16
  export default () => {
9
- let nf = nextFonts.map((desc: NextFontDesc) => (desc.nextFont!.variable))
10
- // dedupe
11
- nf = nf.filter(
12
- (str, i, arr) => (
13
- arr.indexOf(str) === i
14
- )
15
- )
16
- return nf.join(' ') + ` font-${nextFonts[0].twName}`
17
+ const named = nextFonts.map((desc: NextFontDesc) => desc.nextFont!.variable)
18
+ return [...new Set(named)].join(' ')
17
19
  }
@@ -1,13 +1,13 @@
1
1
  // import { Inter } from 'next/font/google'
2
2
  import localFont from 'next/font/local'
3
3
 
4
- import type { TwFontDesc } from '@hanzo/ui/tailwind' // TODO
4
+ import type { FontDesc } from './font-desc'
5
5
  import type NextFontDesc from './next-font-desc'
6
6
 
7
- import twFonts from '../../tailwind/lux-tw-fonts'
7
+ import fonts from './fonts'
8
8
 
9
9
  /*
10
- Creating NextFontDesc's and TwFontDesc's has to be seperated because they are needed
10
+ Creating NextFontDesc's and FontDesc's has to be seperated because they are needed
11
11
  at different times during the next compile / build. Otherwise a nasty
12
12
  race condition happens!
13
13
 
@@ -15,21 +15,11 @@ import twFonts from '../../tailwind/lux-tw-fonts'
15
15
 
16
16
  */
17
17
 
18
- const drukWide = localFont({
19
- src: [
20
- {
21
- path: './local/Druk-Wide-Bold.ttf',
22
- weight: '700',
23
- style: 'normal'
24
- },
25
- {
26
- path: './local/Druk-Wide-Medium.ttf',
27
- weight: '500',
28
- style: 'normal',
29
- },
30
- ],
18
+ const zen = localFont({
19
+ src: './local/Zen-Variable.woff2',
20
+ weight: '100 900',
31
21
  display: 'swap',
32
- variable: '--font-druk-wide',
22
+ variable: '--font-zen-sans',
33
23
  })
34
24
 
35
25
  const inter = localFont({
@@ -41,25 +31,27 @@ const inter = localFont({
41
31
  export default [
42
32
  {
43
33
  font: inter,
44
- twName: 'sans'
34
+ name: 'sans'
45
35
  },
46
36
  {
47
37
  font: inter,
48
- twName: 'nav'
38
+ name: 'nav'
49
39
  },
50
40
  {
51
- font: drukWide,
52
- twName: 'heading'
41
+ // Zen is one variable face over 100-900, so the display cut is weight and
42
+ // tracking in CSS rather than a second file: '.font-heading' in style/lux-global.css.
43
+ font: zen,
44
+ name: 'heading'
53
45
  }
54
46
  ].map (
55
47
  (el) => {
56
- const twFont: TwFontDesc | undefined = twFonts.find((twf: TwFontDesc) => (el.twName === twf.twName))
57
- if (!twFont) {
48
+ const font: FontDesc | undefined = fonts.find((f: FontDesc) => (el.name === f.name))
49
+ if (!font) {
58
50
  throw new Error('lux-next-fonts: Next font is not paired to a TW font!')
59
51
  }
60
52
 
61
53
  return ({
62
- ...twFont,
54
+ ...font,
63
55
  nextFont: el.font,
64
56
  })
65
57
  }
@@ -1,28 +1,29 @@
1
- import type { TwFontDesc } from '@hanzo/ui/tailwind'
1
+ import type localFont from 'next/font/local'
2
2
 
3
- // from next repo
4
- type NextFont = {
5
- className: string
6
- style: { fontFamily: string; fontWeight?: number; fontStyle?: string }
7
- }
8
-
9
- // from next repo
10
- type NextFontWithVariable = NextFont & {
11
- variable: string
12
- }
3
+ import type { FontDesc } from './font-desc'
13
4
 
5
+ /**
6
+ * What a next/font loader hands back, DERIVED from the loader.
7
+ *
8
+ * These were two hand-copied declarations marked "from next repo" — a copy of a
9
+ * type that keeps moving, which is how the OpenGraph types in ../head-metadata
10
+ * went stale and failed as "two different types with this name exist, but they
11
+ * are unrelated". `ReturnType` names the position and lets Next say what lives
12
+ * there. The loader answers with a union — a font is only given a variable
13
+ * when it was asked for one — so `Extract` picks the half that has it.
14
+ */
15
+ export type NextFontWithVariable = Extract<ReturnType<typeof localFont>, { variable: string }>
14
16
 
15
17
  /*
16
- NextFontDesc and TwFontDesc have to be seperate because they are needed
17
- at different times during the next compile / build. Otherwise a nasty
18
+ NextFontDesc and FontDesc have to be seperate because they are needed
19
+ at different times during the next compile / build. Otherwise a nasty
18
20
  race condition happens! That's why they are in different files.
19
21
  */
20
22
 
21
- interface NextFontDesc extends TwFontDesc {
22
- nextFont: NextFontWithVariable
23
+ interface NextFontDesc extends FontDesc {
24
+ nextFont: NextFontWithVariable
23
25
  }
24
26
 
25
27
  export {
26
28
  type NextFontDesc as default,
27
- type NextFontWithVariable,
28
- }
29
+ }
@@ -4,14 +4,15 @@ import type { Metadata } from 'next'
4
4
  import Head from "next/head"
5
5
 
6
6
  import type {
7
+ Author,
7
8
  IconDescriptor,
9
+ OGImage,
10
+ OpenGraph,
8
11
  TemplateString,
9
- Author,
10
- ThemeColorDescriptor
11
- } from './from-next/metadata-types'
12
-
13
- import type { OpenGraph, OGImage } from './from-next/opengraph-types'
14
- import type { Twitter, TwitterImage } from './from-next/twitter-types'
12
+ ThemeColorDescriptor,
13
+ Twitter,
14
+ TwitterImage,
15
+ } from './next-metadata'
15
16
 
16
17
  /*
17
18
  NOTE: This is ONLY for sites that use the pages router in next.
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Next's metadata vocabulary, DERIVED from Next's own `Metadata` type.
3
+ *
4
+ * These were three files of hand-copied declarations under `from-next/`, which
5
+ * is a copy of a type that keeps moving: Next 16 changed `OpenGraph` and the
6
+ * copy stayed where it was, so passing `metadata.openGraph` into a component
7
+ * typed against the copy failed with
8
+ *
9
+ * Two different types with this name exist, but they are unrelated.
10
+ *
11
+ * — a message that reads like a duplicate package rather than a stale copy.
12
+ *
13
+ * Derivation cannot drift. Nothing here restates a shape; each line names a
14
+ * position inside `Metadata` and lets Next say what lives there.
15
+ */
16
+ import type { Metadata } from 'next'
17
+
18
+ /** The element type of an array, or the type itself when it is not one. */
19
+ type Item<T> = T extends readonly (infer E)[] ? E : T
20
+
21
+ /** Metadata fields are nullable by convention; this is the value half. */
22
+ type Set<T> = Exclude<T, null | undefined>
23
+
24
+ export type OpenGraph = Set<Metadata['openGraph']>
25
+ export type OGImage = Item<Set<OpenGraph['images']>>
26
+
27
+ export type Twitter = Set<Metadata['twitter']>
28
+ export type TwitterImage = Item<Set<Twitter['images']>>
29
+
30
+ export type Author = Item<Set<Metadata['authors']>>
31
+ /**
32
+ * A theme colour with its media query. `Metadata['themeColor']` also admits a
33
+ * bare colour string; this is the form with fields, picked out by the one it
34
+ * always has.
35
+ */
36
+ export type ThemeColorDescriptor = Extract<Item<Set<Metadata['themeColor']>>, { color: unknown }>
37
+
38
+ /**
39
+ * The title's object form. `Metadata['title']` is that OR a plain string, and
40
+ * the string is the case with nothing to read.
41
+ */
42
+ export type TemplateString = Exclude<Set<Metadata['title']>, string>
43
+
44
+ /**
45
+ * One icon, in its descriptor form. `Metadata['icons']` also admits a bare url
46
+ * and a grouping object (`{ icon, shortcut, apple }`); this is the one that
47
+ * describes a single icon, picked out by the field only it has.
48
+ */
49
+ export type IconDescriptor = Extract<Item<Set<Metadata['icons']>>, { url: unknown }>
@@ -1,6 +1,5 @@
1
1
  import { NextRequest, NextResponse, userAgent } from 'next/server'
2
2
  import { getSelectorsByUserAgent } from 'react-device-detect'
3
- import { setCookie } from 'cookies-next'
4
3
 
5
4
  // writed this way so they can be chained :)
6
5
  const determineDeviceMW = async (request: NextRequest) => {
@@ -10,18 +9,6 @@ const determineDeviceMW = async (request: NextRequest) => {
10
9
  const agent = isMobileOnly ? 'phone' : (isTablet ? 'tablet' : (isDesktop ? 'desktop' : 'unknown'))
11
10
  const { nextUrl: url } = request
12
11
  //console.log(`\n=== from ${url.href} on a *${agent && agent.toUpperCase()}* device. ===\n`)
13
- const auth_token = url.searchParams.get('auth-token')
14
- if (auth_token) {
15
- setCookie('auth-token', auth_token, {
16
- domain: url.hostname,
17
- path: '/',
18
- sameSite: 'none',
19
- secure: true,
20
- httpOnly: false,
21
- expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30), // 30 days
22
- })
23
- url.searchParams.delete('auth-token')
24
- }
25
12
  url.searchParams.set('agent', agent)
26
13
  return NextResponse.rewrite(url)
27
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luxfi/ui",
3
- "version": "5.5.4",
3
+ "version": "5.5.6",
4
4
  "description": "Library that contains shared UI primitives, support for a common design system, and other boilerplate support.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
@@ -20,44 +20,45 @@
20
20
  ],
21
21
  "exports": {
22
22
  ".": "./components/index.ts",
23
+ "./auth-callback": "./components/auth/callback.tsx",
24
+ "./security": "./components/security/index.tsx",
23
25
  "./commerce": "./commerce/ui/context.tsx",
24
26
  "./root-layout": "./root-layout/index.tsx",
25
27
  "./next": "./next/index.ts",
26
28
  "./style/": "./style/",
27
29
  "./site-def": "./site-def/index.ts",
28
- "./tailwind": "./tailwind/index.ts",
29
30
  "./util": "./util/index.ts"
30
31
  },
31
32
  "dependencies": {
33
+ "@luxfi/logo": "^1.0.10",
32
34
  "@next/third-parties": "^16.1.0",
33
- "cookies-next": "^4.1.1",
34
35
  "date-fns": "^3.6.0",
35
36
  "embla-carousel-autoplay": "^8.1.6",
36
- "firebase": "10.12.0",
37
37
  "framer-motion": "^11.2.12",
38
38
  "markdown-to-jsx": "^7.4.7",
39
39
  "react-device-detect": "^2.2.3",
40
40
  "react-social-icons": "^6.4.0",
41
41
  "react-tooltip": "^5.26.4",
42
42
  "request": "^2.88.2",
43
- "usehooks-ts": "^3.1.0"
43
+ "usehooks-ts": "^3.1.0",
44
+ "react-native-web": "^0.21.2"
44
45
  },
45
46
  "peerDependencies": {
46
- "@hanzo/auth": "2.5.8",
47
- "@hanzo/commerce": "7.3.10",
48
- "@hanzo/ui": "5.3.34",
47
+ "@hanzo/iam": "0.21.9",
48
+ "@hanzo/commerce": "7.7.0",
49
+ "@hanzo/ui": "8.23.2",
50
+ "@luxfi/menu-icons": "^1.0.2",
49
51
  "@hookform/resolvers": "^3.3.2",
50
52
  "lucide-react": "0.470.0",
51
53
  "mobx": "^6.12.3",
52
54
  "mobx-react-lite": "^4.0.7",
53
- "next": "16.1.0",
55
+ "next": "16.3.3",
54
56
  "next-themes": "^0.4.0",
55
- "react": "19.2.0",
56
- "react-dom": "19.2.0",
57
+ "react": "19.2.8",
58
+ "react-dom": "19.2.8",
57
59
  "react-hook-form": "7.54.2",
58
60
  "validator": "^13.11.0",
59
- "zod": "3.23.8",
60
- "@luxfi/menu-icons": "1.0.2"
61
+ "zod": "3.23.8"
61
62
  },
62
63
  "devDependencies": {
63
64
  "@hookform/resolvers": "^3.3.2",
@@ -70,8 +71,7 @@
70
71
  "@types/react": "19.0.2",
71
72
  "@types/react-dom": "19.0.2",
72
73
  "@types/validator": "^13.12.1",
73
- "tailwindcss": "3.4.17",
74
- "typescript": "5.7.3"
74
+ "typescript": "7.0.2"
75
75
  },
76
76
  "scripts": {
77
77
  "lat": "npm show @luxfi/ui version",
@@ -2,20 +2,26 @@ import React, { type PropsWithChildren } from 'react'
2
2
  import type { Viewport } from 'next'
3
3
 
4
4
  import { Toaster } from '@hanzo/ui/primitives'
5
- import { AuthServiceProvider } from '@hanzo/auth/service'
6
- import type { AuthServiceConf } from '@hanzo/auth/types'
5
+ import { Hanzo } from '@hanzo/ui'
7
6
  import { CommerceProvider } from '@hanzo/commerce'
8
7
 
9
8
  import getAppRouterBodyFontClasses from '../next/font/get-app-router-font-classes'
10
9
  import { FacebookPixelHead } from '../next/analytics/pixel-analytics'
11
10
 
12
11
  import { CommerceUIProvider } from '../commerce/ui/context'
13
- import { AuthListener, ChatWidget, Header, Analytics } from '../components'
12
+ import { Auth, ChatWidget, Header, Analytics } from '../components'
14
13
 
15
14
  import CommerceDrawer from '../components/commerce/drawer'
16
15
 
17
16
  import type SiteDef from '../types/site-def'
18
17
 
18
+ // BY NAME, and before the Lux sheets so those can override. Next does not
19
+ // follow a CSS import out of node_modules on a consumer's behalf, so naming
20
+ // these here is what actually puts the reset and the token scale on the page —
21
+ // a site that omits them renders with browser defaults and no palette.
22
+ import '@hanzo/ui/theme.css'
23
+ import '@hanzo/ui/styles.css'
24
+
19
25
  import '../style/lux-global.css'
20
26
  import '../style/cart-animation.css'
21
27
  import '../style/checkout-animation.css'
@@ -30,21 +36,20 @@ const viewport = {
30
36
  } satisfies Viewport
31
37
 
32
38
  /*
33
- These '.variable' fields are actually autogenerate css classnames that *define* the actual
34
- css variables ('--<ugly-name>') that one asks for in the tailwind classes.
35
- They are what make them available in the global scope. So this MUST
36
- be done like this for the tailwind font classes to work.
37
-
38
- (...not to be confused with the css var itself. This field should be named something else!)
39
+ The only classes left on <body> are next/font's own generated ones. Each
40
+ DEFINES a custom property (`--font-inter`, `--font-zen-sans`) holding the face
41
+ it loaded, and they have to be on an element for the rest of the sheet to
42
+ resolve those names which is why they are classes and not a stylesheet.
43
+
44
+ The ground, the ink and the family that used to sit here as utility classes
45
+ are in lux-global.css, on `body` itself. They were `bg-background
46
+ text-foreground flex flex-col min-h-full`, and with no engine generating them
47
+ they were four names no sheet served.
48
+
49
+ re body: not overflow-hidden and not h-full — scroll-snap does not work on iOS
50
+ with those on the body tag.
39
51
  */
40
-
41
- /*
42
- re body: overflow-y-hidden overflow-x-hidden, h-full
43
- We cannot have these on body tag for scroll-snap to work on iOS!
44
- */
45
- const bodyClasses =
46
- 'bg-background text-foreground flex flex-col min-h-full ' +
47
- getAppRouterBodyFontClasses()
52
+ const bodyClasses = getAppRouterBodyFontClasses()
48
53
 
49
54
  function RootLayout({
50
55
  showHeader = false,
@@ -57,10 +62,6 @@ function RootLayout({
57
62
  chatbot?: boolean
58
63
  } & PropsWithChildren) {
59
64
 
60
- // For static export, we don't have server-side auth
61
- // User auth will be handled client-side via AuthListener
62
- const currentUser = null
63
-
64
65
  const Guts: React.FC = () => (<>
65
66
  {showHeader && <Header siteDef={siteDef}/>}
66
67
  {children}
@@ -81,13 +82,25 @@ function RootLayout({
81
82
  <FacebookPixelHead/>
82
83
  </head>
83
84
 
84
- <body suppressHydrationWarning className={bodyClasses} style={{
85
-
86
- // As noted above: 'overflow: hidden' on the <body> tag breaks scroll snap!
87
- display: 'none', // see analytics.tsx
88
- }}>
85
+ {/* No inline style. The body's layout is stated once, in lux-global.css,
86
+ where it applies whether or not any script runs.
87
+
88
+ It used to render `display: none` here and a mount effect in
89
+ analytics.tsx set it back — hiding the page until React had hydrated.
90
+ That trades a flash for a site that is blank to anything without
91
+ JavaScript, and it silently outranked the sheet: the effect wrote
92
+ `flex`, so the `display: grid` the sheet asks for never once applied
93
+ on any of these sites.
94
+
95
+ Note the other half of that comment, still true: `overflow: hidden` on
96
+ <body> breaks scroll-snap on iOS, so it does not go here either. */}
97
+ <body suppressHydrationWarning className={bodyClasses}>
98
+ {/* The root every @hanzo/ui component reads its config from. Without it
99
+ a prerender throws `Err0` from inside gui — a message that names
100
+ neither the component nor the missing provider. */}
101
+ <Hanzo theme='dark'>
89
102
  <Analytics/>
90
- <AuthServiceProvider user={currentUser} conf={{} as AuthServiceConf}>
103
+ <Auth app={siteDef.app}>
91
104
  {siteDef?.commerce ? (
92
105
  <CommerceProvider config={siteDef.commerce!} >
93
106
  <CommerceUIProvider >
@@ -98,9 +111,9 @@ function RootLayout({
98
111
  ) : (
99
112
  <Guts />
100
113
  )}
101
- <AuthListener/>
102
- </AuthServiceProvider>
114
+ </Auth>
103
115
  <Toaster position='top-center' duration={3000}/>
116
+ </Hanzo>
104
117
  </body>
105
118
  </html>
106
119
  )
Binary file
@@ -1,4 +1,3 @@
1
- @tailwind base;
2
1
  /* see https://stackoverflow.com/questions/69746121/using-nextjs-how-can-you-import-in-css-using-tailwind-css */
3
2
 
4
3
  @layer base {
@@ -1,16 +1,10 @@
1
- @tailwind base;
2
-
1
+ /* Both faces are served from the app's own /fonts. The Next path (../next/font)
2
+ emits the same two through next/font instead. */
3
3
  @layer base {
4
4
  @font-face {
5
- font-family: "DrukWide";
6
- src: url("/fonts/Druk-Wide-Medium.ttf");
7
- font-weight: 500;
8
- font-style: normal;
9
- }
10
- @font-face {
11
- font-family: "DrukWide";
12
- src: url("/fonts/Druk-Wide-Bold.ttf");
13
- font-weight: 700;
5
+ font-family: "Zen";
6
+ src: url("/fonts/Zen-Variable.woff2") format("woff2");
7
+ font-weight: 100 900;
14
8
  font-style: normal;
15
9
  }
16
10
  @font-face {
@@ -1,22 +1,22 @@
1
1
  /* Note, preflight is applied first:
2
2
  https://unpkg.com/tailwindcss@3.3.5/src/css/preflight.css
3
3
  */
4
- @import "tailwindcss/base";
5
-
6
4
  /* see https://stackoverflow.com/questions/69746121/using-nextjs-how-can-you-import-in-css-using-tailwind-css */
7
5
  /* @import "@hanzo/ui/style/hanzo-common"; */
8
- @import "lux-colors";
9
- @import "lux-fonts";
10
-
11
- @import "tailwindcss/components";
12
- @import "tailwindcss/utilities";
13
-
6
+ @import "./lux-colors.css";
7
+ @import "./lux-fonts.css";
14
8
  div.nextjs-toast-errors-parent[data-nextjs-toast="true"] {
15
9
  display: none;
16
10
  }
17
11
 
12
+ /* Headings are Zen cut wide: the '.zen-wide' preset from @hanzo/font, fitted
13
+ against Druk Wide Bold. The preset's scaleX(1.56) is left out on purpose -- a
14
+ transform does not reflow, and these land on block h1-h4 that would overrun
15
+ their container. Use the class itself where a word has room to be monumental. */
18
16
  .font-heading {
19
- @apply uppercase;
17
+ text-transform: uppercase;
18
+ font-variation-settings: 'wght' 845;
19
+ letter-spacing: -0.04em;
20
20
  }
21
21
 
22
22
  /* Specific style fixes for react-square-web-payments-sdk -