@luxfi/core 5.1.6 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- package/commerce/ui/conf.ts +1 -1
- package/components/commerce/drawer/index.tsx +1 -3
- package/components/commerce/drawer/micro.tsx +29 -21
- package/components/commerce/drawer/shell.tsx +17 -13
- package/package.json +1 -1
- package/root-layout/index.tsx +1 -7
- package/types/index.ts +0 -1
- package/types/site-def.ts +1 -1
- package/commerce/data/AUTO-GEN-bullion-by-family.json +0 -34
- package/commerce/data/EDIT-ME-bullion-market-prices.ts +0 -12
- package/commerce/data/assign-prices.ts +0 -50
- package/commerce/data/assign-videos-by-family-group.ts +0 -14
- package/commerce/data/bullion-price-1oz.ts +0 -5
- package/commerce/data/index.ts +0 -18
- package/conf/index.ts +0 -52
- package/conf/lux-commerce-options.ts +0 -6
- package/types/commerce-config.ts +0 -10
package/commerce/ui/conf.ts
CHANGED
@@ -30,9 +30,7 @@ const CommerceUIComponent: React.FC = observer(() => {
|
|
30
30
|
// see handleCloseGesture()
|
31
31
|
const setOpen = (b: boolean): void => {
|
32
32
|
if (!b) {
|
33
|
-
console.log("ON CLOSE")
|
34
33
|
if (!drawer.closedByUser) {
|
35
|
-
console.log("syncing closed state to UI gesture")
|
36
34
|
drawer.setClosedByUser(true)
|
37
35
|
}
|
38
36
|
}
|
@@ -107,7 +105,7 @@ const CommerceUIComponent: React.FC = observer(() => {
|
|
107
105
|
<Micro
|
108
106
|
handleCheckout={handleCheckout}
|
109
107
|
handleItemClicked={handleItemClicked}
|
110
|
-
clx='w-full sm:w-[460px] sm:mx-auto md:w-[550px]'
|
108
|
+
clx='w-full px-2 sm:w-[460px] sm:mx-auto md:w-[550px]'
|
111
109
|
/>
|
112
110
|
)}
|
113
111
|
</CommerceDrawer>
|
@@ -12,17 +12,9 @@ import { useCommerceDrawer, useRecentActivity } from '../../../commerce/ui/conte
|
|
12
12
|
|
13
13
|
const CN = {
|
14
14
|
// h: mind padding!
|
15
|
-
mobile: { w: 36, h:
|
16
|
-
sm: { w: 60, h:
|
17
|
-
desktop: { w: 60, h:
|
18
|
-
}
|
19
|
-
|
20
|
-
const renderTitle = (item: LineItem): React.ReactNode => {
|
21
|
-
const toks = item.title.split(', ')
|
22
|
-
if (toks.length === 2) {
|
23
|
-
return <><p>{toks[0]},</p><p className=''>{toks[1]}</p></>
|
24
|
-
}
|
25
|
-
return <p>{item.title}</p>
|
15
|
+
mobile: { w: 36, h: 32 },
|
16
|
+
sm: { w: 60, h: 34 },
|
17
|
+
desktop: { w: 60, h: 32 },
|
26
18
|
}
|
27
19
|
|
28
20
|
const Info: React.FC<{
|
@@ -62,6 +54,7 @@ const Info: React.FC<{
|
|
62
54
|
</>)
|
63
55
|
}
|
64
56
|
|
57
|
+
const PROMPT_COMMON_CLX = 'block absolute top-0 left-0 bg-transparent duration-400 transition-opacity'
|
65
58
|
|
66
59
|
const Micro: React.FC<{
|
67
60
|
clx?: string
|
@@ -75,32 +68,45 @@ const Micro: React.FC<{
|
|
75
68
|
|
76
69
|
const drawer = useCommerceDrawer()
|
77
70
|
const recent = useRecentActivity()
|
71
|
+
const mobile = drawer.isMobile
|
78
72
|
|
79
73
|
return (
|
80
74
|
<div className={cn(
|
81
|
-
'
|
82
|
-
(drawer.showAdded ? '
|
75
|
+
(drawer.showAdded ? 'grid grid-cols-2' : 'flex justify-center items-center '),
|
76
|
+
(drawer.showAdded ? ((drawer.isMobile) ? '-mt-3' : '-mt-3') : ''),
|
83
77
|
'gap-2 md:gap-3 relative',
|
84
78
|
clx
|
85
79
|
)}>
|
86
80
|
{drawer.showAdded && (
|
87
|
-
<div className='
|
88
|
-
<p className='text-muted text-xxs md:text-xs leading-none pl-1'
|
81
|
+
<div className={'flex flex-col items-stretch ' + (drawer.isMobile ? 'justify-start' : 'group')}>
|
82
|
+
<p className={'relative text-muted text-xxs md:text-xs leading-none pl-1 self-start ' + (drawer.isMobile ? 'top-[3px]' : 'top-[1px]')}>
|
83
|
+
<span className='invisible'>scrictly for layout</span>
|
84
|
+
{drawer.isMobile ? (
|
85
|
+
<span className={PROMPT_COMMON_CLX}>tap for options:</span>
|
86
|
+
) : (<>
|
87
|
+
<span className={PROMPT_COMMON_CLX + ' group-hover:opacity-0'}>recent item:</span>
|
88
|
+
<span className={PROMPT_COMMON_CLX + ' opacity-0 group-hover:opacity-100'}>view options:</span>
|
89
|
+
</>)}
|
90
|
+
</p>
|
89
91
|
<Button
|
90
92
|
variant='ghost'
|
91
|
-
rounded='
|
93
|
+
rounded={drawer.isMobile ? 'md' : 'lg'}
|
94
|
+
size={drawer.isMobile ? 'default' : 'lg'}
|
92
95
|
onClick={handleItemClicked}
|
93
96
|
className={cn(
|
97
|
+
'box-content',
|
94
98
|
'flex flex-row justify-between items-center gap-1',
|
95
99
|
'-ml-1.5',
|
96
100
|
'overflow-hidden ',
|
97
|
-
'px-1
|
101
|
+
'px-1 md:px-2 py-[2px]',
|
102
|
+
'border border-transparent group-hover:border-muted-3',
|
103
|
+
'group-hover:!bg-transparent '
|
98
104
|
)}
|
99
105
|
>
|
100
106
|
{recent.item?.img && (<>
|
101
107
|
<Image def={recent.item.img} constrainTo={CN.mobile} preload className='sm:hidden grow-0 shrink-0'/>
|
102
|
-
<Image def={recent.item.img} constrainTo={CN.sm} preload className='hidden sm:
|
103
|
-
<Image def={recent.item.img} constrainTo={CN.desktop} preload className='hidden md:
|
108
|
+
<Image def={recent.item.img} constrainTo={CN.sm} preload className='hidden sm:block md:hidden grow-0 shrink-0'/>
|
109
|
+
<Image def={recent.item.img} constrainTo={CN.desktop} preload className='hidden md:block grow-0 shrink-0'/>
|
104
110
|
</>)}
|
105
111
|
{recent.item && (
|
106
112
|
<div className='grow w-full'>
|
@@ -112,9 +118,11 @@ const Micro: React.FC<{
|
|
112
118
|
)}
|
113
119
|
{drawer.showCheckout && (
|
114
120
|
<div className={cn(
|
115
|
-
'flex flex-col
|
116
|
-
(drawer.showAdded ? 'items-stretch' : 'items-center
|
121
|
+
'flex flex-col w-full',
|
122
|
+
(drawer.showAdded ? 'items-stretch' : 'items-center' ),
|
123
|
+
(drawer.isMobile ? 'justify-start' : 'justify-center')
|
117
124
|
)}>
|
125
|
+
{drawer.showAdded && <p className='invisible text-muted text-xxs md:text-xs leading-none pl-1 self-start'>for layout</p>}
|
118
126
|
<CheckoutButton
|
119
127
|
handleCheckout={handleCheckout}
|
120
128
|
variant='primary'
|
@@ -1,10 +1,7 @@
|
|
1
1
|
'use client'
|
2
2
|
import React, {type PropsWithChildren } from 'react'
|
3
3
|
|
4
|
-
import { X as LucideX} from 'lucide-react'
|
5
|
-
|
6
4
|
import {
|
7
|
-
Button,
|
8
5
|
Drawer,
|
9
6
|
DrawerContent,
|
10
7
|
DrawerHandle,
|
@@ -48,29 +45,36 @@ const CommerceDrawer: React.FC<PropsWithChildren &
|
|
48
45
|
fastDragSkipsToEnd={false}
|
49
46
|
dragHandleOnly={true}
|
50
47
|
handleHandleClicked={handleHandleClicked}
|
48
|
+
extendHandleDragRegion={false}
|
51
49
|
// debugOutput
|
52
50
|
{...rest}
|
53
51
|
>
|
54
52
|
<DrawerContent
|
55
53
|
defaultHandle={false}
|
56
54
|
className={cn(
|
57
|
-
|
58
|
-
(micro ? (mobile ? 'mt-4 pt-1.5' : 'mt-5 pt-4') : 'mt-5 pt-5'),
|
59
|
-
'
|
55
|
+
'border-0',
|
56
|
+
//(micro ? (mobile ? 'mt-4 pt-1.5' : 'mt-5 pt-4') : 'mt-5 pt-5'),
|
57
|
+
mobile ? 'pt-5' : 'pt-6',
|
58
|
+
'w-full h-full',
|
60
59
|
)}
|
61
60
|
// https://github.com/radix-ui/primitives/discussions/935
|
62
61
|
onOpenAutoFocus={(e) => {e.preventDefault()}}
|
63
62
|
>
|
64
63
|
<DrawerHandle
|
65
64
|
className={cn(
|
66
|
-
'absolute left-0 right-0 mx-auto z-10',
|
67
|
-
'
|
68
|
-
|
69
|
-
|
70
|
-
'[&>[vaul-handle-hitarea]]:hidden',
|
71
|
-
//(!micro ? 'bg-level-3 hover:bg-level-2 ' : 'bg-level-1 hover:bg-level-2 ')
|
65
|
+
'absolute top-0 left-0 right-0 mx-auto z-10',
|
66
|
+
'flex justify-center items-start',
|
67
|
+
'border-t rounded-t-lg border-muted-2',
|
68
|
+
mobile ? 'h-5 touch-pan-y' : 'h-6',
|
72
69
|
)}
|
73
|
-
|
70
|
+
>
|
71
|
+
<div className={cn(
|
72
|
+
// pseudo-handle
|
73
|
+
'rounded-[3px] bg-level-3',
|
74
|
+
mobile ? 'w-[155px] mt-[5px] h-1.5' : 'w-[180px] mt-[3px] h-2.5 hover:bg-level-4',
|
75
|
+
!mobile ? 'cursor-grab active:cursor-grabbing' : '',
|
76
|
+
)} />
|
77
|
+
</DrawerHandle>
|
74
78
|
{children}
|
75
79
|
</DrawerContent>
|
76
80
|
</Drawer>
|
package/package.json
CHANGED
package/root-layout/index.tsx
CHANGED
@@ -15,7 +15,6 @@ import { AuthListener, ChatWidget, Header, Scripts } from '../components'
|
|
15
15
|
|
16
16
|
import CommerceDrawer from '../components/commerce/drawer'
|
17
17
|
|
18
|
-
import { selectionUISpecifiers } from '../conf'
|
19
18
|
import type SiteDef from '../types/site-def'
|
20
19
|
|
21
20
|
import '../style/lux-global.css'
|
@@ -90,12 +89,7 @@ async function RootLayout({
|
|
90
89
|
<Scripts/>
|
91
90
|
<AuthServiceProvider user={currentUser} conf={{} as AuthServiceConf}>
|
92
91
|
{siteDef?.commerce ? (
|
93
|
-
<CommerceProvider
|
94
|
-
rootNode={siteDef.commerce!.rootNode}
|
95
|
-
families={siteDef.commerce!.families}
|
96
|
-
options={siteDef.commerce!.options}
|
97
|
-
uiSpecs={selectionUISpecifiers}
|
98
|
-
>
|
92
|
+
<CommerceProvider config={siteDef.commerce!} >
|
99
93
|
<CommerceUIProvider >
|
100
94
|
<Guts />
|
101
95
|
<CommerceDrawer />
|
package/types/index.ts
CHANGED
@@ -2,4 +2,3 @@ export type { ContactInfo, ContactInfoFields } from './contact-info'
|
|
2
2
|
export type { default as SiteDef } from './site-def'
|
3
3
|
export type { default as ChatbotSuggestedQuestion } from './chatbot-suggested-question'
|
4
4
|
export type { default as ChatbotConfig } from './chatbot-config'
|
5
|
-
export type { default as CommerceConfig } from './commerce-config'
|
package/types/site-def.ts
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
import React from 'react'
|
2
2
|
|
3
3
|
import type { LinkDef } from '@hanzo/ui/types'
|
4
|
+
import type { CommerceConfig } from '@hanzo/commerce/types'
|
4
5
|
|
5
|
-
import type CommerceConfig from './commerce-config'
|
6
6
|
import type ChatbotConfig from './chatbot-config'
|
7
7
|
|
8
8
|
interface SiteDef {
|
@@ -1,34 +0,0 @@
|
|
1
|
-
[
|
2
|
-
{
|
3
|
-
"id": "LXM-AG-B",
|
4
|
-
"title": "Minted Bar",
|
5
|
-
"parentTitle": "Lux Silver",
|
6
|
-
"desc": "Get unprecedented access to silver with 1:1 asset-backed Lux Silver NFTs, sovereign ownership of physical silver without management fees, and mine-direct discount pricing.",
|
7
|
-
"img": {
|
8
|
-
"src": "/assets/commerce/silver/product/silver-bar-pt-800x800.png",
|
9
|
-
"dim": {
|
10
|
-
"w": 800,
|
11
|
-
"h": 800
|
12
|
-
}
|
13
|
-
},
|
14
|
-
"products": [
|
15
|
-
{
|
16
|
-
"id": "fce17569-a86c-4f69-bc61-ab435ed0c46f",
|
17
|
-
"sku": "LXM-AG-B-1_OZ",
|
18
|
-
"fullTitle": "Lux Silver, 1oz Minted Bar",
|
19
|
-
"optionLabel": "1oz",
|
20
|
-
"familyTitle": "Minted Bar",
|
21
|
-
"familyId": "LXM-AG-B",
|
22
|
-
"desc": "Get unprecedented access to silver with 1:1 asset-backed Lux Silver NFTs, sovereign ownership of physical silver without management fees, and mine-direct discount pricing.",
|
23
|
-
"price": 0,
|
24
|
-
"img": {
|
25
|
-
"src": "/assets/commerce/silver/product/silver-bar-pt-800x800.png",
|
26
|
-
"dim": {
|
27
|
-
"w": 800,
|
28
|
-
"h": 800
|
29
|
-
}
|
30
|
-
}
|
31
|
-
}
|
32
|
-
]
|
33
|
-
}
|
34
|
-
]
|
@@ -1,50 +0,0 @@
|
|
1
|
-
import type { Family } from '@hanzo/commerce/types'
|
2
|
-
|
3
|
-
import prices from './EDIT-ME-bullion-market-prices'
|
4
|
-
|
5
|
-
const sep = {
|
6
|
-
tok: '-',
|
7
|
-
subTok: '_',
|
8
|
-
decimal: '.'
|
9
|
-
}
|
10
|
-
|
11
|
-
const GRAMS_PER_OZ = 28.3495
|
12
|
-
|
13
|
-
const tree: any = {}
|
14
|
-
for (let key in prices) {
|
15
|
-
const values = prices[key as keyof typeof prices]
|
16
|
-
tree[key] = {
|
17
|
-
oz: values.market1oz * (1 - values.discount),
|
18
|
-
g: values.market1oz * (1 - values.discount) / GRAMS_PER_OZ
|
19
|
-
}
|
20
|
-
}
|
21
|
-
|
22
|
-
// LXB-AU-B-1_OZ, LXB-AU-B-2.5_g
|
23
|
-
const priceFromSKU = (
|
24
|
-
sku: string
|
25
|
-
) => {
|
26
|
-
const tokens = sku.split(sep.tok)
|
27
|
-
const type_ = tokens[1].toLowerCase()
|
28
|
-
|
29
|
-
const quanAndUnit = tokens[tokens.length - 1]
|
30
|
-
const quanAndUnitToks = quanAndUnit.split(sep.subTok)
|
31
|
-
let quantity = quanAndUnitToks[0].includes(sep.decimal) ? parseFloat(quanAndUnitToks[0].split(sep.decimal).join('.')) : parseInt(quanAndUnitToks[0])
|
32
|
-
let unit = quanAndUnitToks[1].toLowerCase()
|
33
|
-
if (unit === 'kg') {
|
34
|
-
quantity *= 1000
|
35
|
-
unit = 'g'
|
36
|
-
}
|
37
|
-
else if (unit === 'lb') {
|
38
|
-
quantity *= 16
|
39
|
-
unit = 'oz'
|
40
|
-
}
|
41
|
-
|
42
|
-
return tree[type_][unit] * quantity
|
43
|
-
}
|
44
|
-
|
45
|
-
export default (c: Family): Family => {
|
46
|
-
for (let prod of c.products) {
|
47
|
-
prod.price = priceFromSKU(prod.sku)
|
48
|
-
}
|
49
|
-
return c
|
50
|
-
}
|
@@ -1,14 +0,0 @@
|
|
1
|
-
import type { VideoDef } from '@hanzo/ui/types'
|
2
|
-
import type { Family } from '@hanzo/commerce/types'
|
3
|
-
|
4
|
-
export default (fam: Family, map: Map<string, VideoDef>): Family => {
|
5
|
-
if (fam.parentTitle) {
|
6
|
-
for (let prod of fam.products) {
|
7
|
-
const video = map.get(fam.parentTitle)
|
8
|
-
if (video) {
|
9
|
-
prod.video = video
|
10
|
-
}
|
11
|
-
}
|
12
|
-
}
|
13
|
-
return fam
|
14
|
-
}
|
package/commerce/data/index.ts
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
import type { VideoDef } from '@hanzo/ui/types'
|
2
|
-
|
3
|
-
import bullionByFamily from './AUTO-GEN-bullion-by-family.json'
|
4
|
-
|
5
|
-
import assignPrices from './assign-prices'
|
6
|
-
import assignVideosByFamilyGroup from './assign-videos-by-family-group'
|
7
|
-
|
8
|
-
export const getBullionFamilies = (videoMap: Map<string, VideoDef>) => (
|
9
|
-
bullionByFamily.map(
|
10
|
-
(fam) => (assignPrices(fam))).map(
|
11
|
-
(fam) => (assignVideosByFamilyGroup(fam, videoMap)
|
12
|
-
)
|
13
|
-
)
|
14
|
-
)
|
15
|
-
|
16
|
-
export { default as serviceOptions } from '../../conf/lux-commerce-options'
|
17
|
-
export { default as bullionPrice1oz } from './bullion-price-1oz'
|
18
|
-
|
package/conf/index.ts
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
import type { SelectionUISpecifier } from '@hanzo/commerce/types'
|
2
|
-
|
3
|
-
export { default as commerceServiceOptions } from './lux-commerce-options'
|
4
|
-
|
5
|
-
export const selectionUISpecifiers = {
|
6
|
-
|
7
|
-
'LXM-CN': {
|
8
|
-
singleFamily: {
|
9
|
-
type: 'carousel',
|
10
|
-
options: {
|
11
|
-
familyTitle: 'long',
|
12
|
-
showByline: false,
|
13
|
-
showPrice: true,
|
14
|
-
}
|
15
|
-
}
|
16
|
-
},
|
17
|
-
'LXM-FC': {
|
18
|
-
singleFamily: {
|
19
|
-
type: 'carousel',
|
20
|
-
options: {
|
21
|
-
//showQuantity: true
|
22
|
-
}
|
23
|
-
}
|
24
|
-
},
|
25
|
-
'LXM-CR': {
|
26
|
-
multiFamily: {
|
27
|
-
type: 'all-variants-carousel',
|
28
|
-
selectorOptions: {
|
29
|
-
showParentTitle: false,
|
30
|
-
showItemSwatches: true
|
31
|
-
},
|
32
|
-
itemOptions: {
|
33
|
-
familyTitle: 'long',
|
34
|
-
showFamilyByline: true,
|
35
|
-
showPrice: false,
|
36
|
-
}
|
37
|
-
}
|
38
|
-
},
|
39
|
-
'LXM-AG': {
|
40
|
-
multiFamily: {
|
41
|
-
type: 'all-variants-carousel',
|
42
|
-
selectorOptions: {
|
43
|
-
showParentTitle: true,
|
44
|
-
showItemSwatches: false
|
45
|
-
},
|
46
|
-
itemOptions: {
|
47
|
-
familyTitle: 'long',
|
48
|
-
}
|
49
|
-
}
|
50
|
-
},
|
51
|
-
|
52
|
-
} satisfies Record<string, SelectionUISpecifier>
|
package/types/commerce-config.ts
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
import type { ServiceOptions } from '@hanzo/commerce'
|
2
|
-
import type { CategoryNode, Family } from '@hanzo/commerce/types'
|
3
|
-
|
4
|
-
interface CommerceConfig {
|
5
|
-
families: Family[]
|
6
|
-
rootNode: CategoryNode
|
7
|
-
options?: ServiceOptions
|
8
|
-
}
|
9
|
-
|
10
|
-
export { type CommerceConfig as default }
|