@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.
- package/commerce/ui/context.tsx +13 -16
- package/components/access-code-input.tsx +3 -4
- package/components/analytics.tsx +8 -17
- package/components/auth/callback.tsx +40 -0
- package/components/auth/login-panel.tsx +22 -50
- package/components/auth/login.tsx +47 -0
- package/components/auth/provider.tsx +34 -0
- package/components/auth/resume.ts +16 -0
- package/components/auth/widget.tsx +80 -0
- package/components/back-button.tsx +4 -7
- package/components/chat-widget.tsx +9 -11
- package/components/commerce/bag-button.tsx +8 -7
- package/components/commerce/buy-button.tsx +2 -3
- package/components/commerce/checkout-button.tsx +12 -10
- package/components/commerce/checkout-panel/cart-accordian.tsx +3 -4
- package/components/commerce/checkout-panel/desktop-cp.tsx +7 -8
- package/components/commerce/checkout-panel/index.tsx +1 -1
- package/components/commerce/checkout-panel/mobile-cp.tsx +5 -5
- package/components/commerce/checkout-panel/policy-links.tsx +7 -12
- package/components/commerce/checkout-panel/steps-indicator.tsx +1 -1
- package/components/commerce/desktop-bag-popup.tsx +1 -1
- package/components/commerce/drawer/micro.tsx +30 -30
- package/components/commerce/drawer/shell.tsx +3 -5
- package/components/contact-dialog/contact-form.tsx +6 -13
- package/components/contact-dialog/index.tsx +2 -2
- package/components/copyright.tsx +3 -2
- package/components/drawer-margin.tsx +2 -2
- package/components/footer.tsx +7 -8
- package/components/header/desktop-nav-menu.tsx +6 -6
- package/components/header/desktop.tsx +9 -9
- package/components/header/index.tsx +2 -2
- package/components/header/mobile-bag-drawer.tsx +1 -1
- package/components/header/mobile-menu-toggle-button.tsx +5 -6
- package/components/header/mobile-nav-menu-ai.tsx +14 -13
- package/components/header/mobile-nav-menu-item.tsx +12 -11
- package/components/header/mobile-nav-menu.tsx +19 -18
- package/components/header/mobile.tsx +10 -11
- package/components/icons/index.ts +0 -1
- package/components/icons/social-icon.tsx +1 -1
- package/components/index.ts +2 -2
- package/components/logo.tsx +40 -67
- package/components/main.tsx +3 -4
- package/components/mini-chart/mini-chart.tsx +2 -1
- package/components/security/index.tsx +55 -0
- package/next/font/font-desc.ts +18 -0
- package/next/font/fonts.ts +40 -0
- package/next/font/get-app-router-font-classes.ts +14 -12
- package/next/font/load-and-return-lux-next-fonts-on-import.ts +16 -24
- package/next/font/local/Zen-Variable.woff2 +0 -0
- package/next/font/next-font-desc.ts +18 -17
- package/next/head-metadata/index.tsx +7 -6
- package/next/head-metadata/next-metadata.ts +49 -0
- package/next/middleware/determine-device-mw.ts +0 -13
- package/package.json +15 -15
- package/root-layout/index.tsx +42 -29
- package/style/fonts/Zen-Variable.woff2 +0 -0
- package/style/lux-colors.css +0 -1
- package/style/lux-fonts.css +5 -11
- package/style/lux-global-non-next.css +9 -9
- package/style/lux-global.css +99 -15
- package/tsconfig.json +8 -0
- package/types/site-def.ts +7 -0
- package/components/auth/auth-listener.tsx +0 -33
- package/components/auth/auth-token/clear-auth-token.tsx +0 -12
- package/components/auth/auth-token/set-auth-token.tsx +0 -16
- package/components/auth/common-auth-domains.ts +0 -17
- package/components/auth/mobile-login-button.tsx +0 -112
- package/components/auth/signup-panel.tsx +0 -113
- package/components/icons/lux-logo.tsx +0 -10
- package/next/font/local/Druk-Wide-Bold.ttf +0 -0
- package/next/font/local/Druk-Wide-Medium.ttf +0 -0
- package/next/head-metadata/from-next/metadata-types.ts +0 -158
- package/next/head-metadata/from-next/opengraph-types.ts +0 -267
- package/next/head-metadata/from-next/twitter-types.ts +0 -92
- package/style/fonts/Druk-Wide-Bold.ttf +0 -0
- package/style/fonts/Druk-Wide-Medium.ttf +0 -0
- package/tailwind/fontFamily.tailwind.lux.ts +0 -18
- package/tailwind/index.ts +0 -2
- package/tailwind/lux-tw-fonts.ts +0 -40
- package/tailwind/tailwind.config.lux-preset.ts +0 -10
|
@@ -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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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 {
|
|
4
|
+
import type { FontDesc } from './font-desc'
|
|
5
5
|
import type NextFontDesc from './next-font-desc'
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import fonts from './fonts'
|
|
8
8
|
|
|
9
9
|
/*
|
|
10
|
-
Creating NextFontDesc's and
|
|
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
|
|
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-
|
|
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
|
-
|
|
34
|
+
name: 'sans'
|
|
45
35
|
},
|
|
46
36
|
{
|
|
47
37
|
font: inter,
|
|
48
|
-
|
|
38
|
+
name: 'nav'
|
|
49
39
|
},
|
|
50
40
|
{
|
|
51
|
-
|
|
52
|
-
|
|
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
|
|
57
|
-
if (!
|
|
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
|
-
...
|
|
54
|
+
...font,
|
|
63
55
|
nextFont: el.font,
|
|
64
56
|
})
|
|
65
57
|
}
|
|
Binary file
|
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type localFont from 'next/font/local'
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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.
|
|
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/
|
|
47
|
-
"@hanzo/commerce": "7.
|
|
48
|
-
"@hanzo/ui": "
|
|
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.
|
|
55
|
+
"next": "16.3.3",
|
|
54
56
|
"next-themes": "^0.4.0",
|
|
55
|
-
"react": "19.2.
|
|
56
|
-
"react-dom": "19.2.
|
|
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
|
-
"
|
|
74
|
-
"typescript": "5.7.3"
|
|
74
|
+
"typescript": "7.0.2"
|
|
75
75
|
},
|
|
76
76
|
"scripts": {
|
|
77
77
|
"lat": "npm show @luxfi/ui version",
|
package/root-layout/index.tsx
CHANGED
|
@@ -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 {
|
|
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 {
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
<
|
|
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
|
-
|
|
102
|
-
</AuthServiceProvider>
|
|
114
|
+
</Auth>
|
|
103
115
|
<Toaster position='top-center' duration={3000}/>
|
|
116
|
+
</Hanzo>
|
|
104
117
|
</body>
|
|
105
118
|
</html>
|
|
106
119
|
)
|
|
Binary file
|
package/style/lux-colors.css
CHANGED
package/style/lux-fonts.css
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
|
|
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: "
|
|
6
|
-
src: url("/fonts/
|
|
7
|
-
font-weight:
|
|
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
|
-
|
|
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 -
|