@luxfi/core 4.3.11
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/components/access-code-input.tsx +71 -0
- package/components/auth/login-panel.tsx +80 -0
- package/components/chat-widget.tsx +77 -0
- package/components/commerce/bag-button.tsx +67 -0
- package/components/commerce/checkout-panel/close-button.tsx +23 -0
- package/components/commerce/checkout-panel/dt-bag-carousel.tsx +36 -0
- package/components/commerce/checkout-panel/dt-checkout-panel.tsx +68 -0
- package/components/commerce/checkout-panel/index.tsx +124 -0
- package/components/commerce/checkout-panel/links-row.tsx +21 -0
- package/components/commerce/checkout-panel/mb-checkout-panel.tsx +51 -0
- package/components/commerce/checkout-panel/steps-indicator.tsx +39 -0
- package/components/commerce/checkout-panel/thank-you.tsx +18 -0
- package/components/commerce/desktop-bag-popup.tsx +78 -0
- package/components/commerce/mobile-bag-drawer.tsx +51 -0
- package/components/commerce/mobile-menu-toggle-button.tsx +35 -0
- package/components/commerce/mobile-nav-menu.tsx +64 -0
- package/components/contact-dialog/contact-form.tsx +112 -0
- package/components/contact-dialog/disclaimer.tsx +13 -0
- package/components/contact-dialog/index.tsx +64 -0
- package/components/copyright.tsx +21 -0
- package/components/footer.tsx +78 -0
- package/components/header/desktop.tsx +54 -0
- package/components/header/index.tsx +26 -0
- package/components/header/mobile.tsx +161 -0
- package/components/header/theme-toggle.tsx +26 -0
- package/components/icons/bag-icon.tsx +10 -0
- package/components/icons/github.tsx +14 -0
- package/components/icons/index.tsx +35 -0
- package/components/icons/lux-logo.tsx +10 -0
- package/components/icons/secure-delivery.tsx +13 -0
- package/components/icons/social-icon.tsx +35 -0
- package/components/icons/social-svg.css +3 -0
- package/components/icons/youtube-logo.tsx +59 -0
- package/components/index.ts +26 -0
- package/components/logo.tsx +81 -0
- package/components/mini-chart/index.tsx +8 -0
- package/components/mini-chart/mini-chart-props.ts +44 -0
- package/components/mini-chart/mini-chart.tsx +85 -0
- package/components/mini-chart/wrapper.tsx +23 -0
- package/components/not-found/index.tsx +27 -0
- package/components/not-found/not-found-content.mdx +5 -0
- package/components/root-layout.tsx +71 -0
- package/components/scripts.tsx +23 -0
- package/conf/index.ts +50 -0
- package/environment.d.ts +6 -0
- package/next/analytics/fpixel.ts +16 -0
- package/next/analytics/google-analytics.ts +14 -0
- package/next/analytics/index.ts +3 -0
- package/next/analytics/pixel-analytics.tsx +55 -0
- package/next/determine-device-mw.ts +16 -0
- package/next/font/get-app-router-font-classes.ts +12 -0
- package/next/font/load-and-return-lux-next-fonts-on-import.ts +67 -0
- package/next/font/local/Druk-Wide-Bold.ttf +0 -0
- package/next/font/local/Druk-Wide-Medium.ttf +0 -0
- package/next/font/next-font-desc.ts +28 -0
- package/next/font/pages-router-font-vars.tsx +18 -0
- package/next/head-metadata/from-next/metadata-types.ts +158 -0
- package/next/head-metadata/from-next/opengraph-types.ts +267 -0
- package/next/head-metadata/from-next/twitter-types.ts +92 -0
- package/next/head-metadata/index.tsx +208 -0
- package/next/index.ts +1 -0
- package/package.json +72 -0
- package/server-actions/firebase-app.ts +14 -0
- package/server-actions/index.ts +5 -0
- package/server-actions/store-contact.ts +51 -0
- package/site-def/footer/community.tsx +67 -0
- package/site-def/footer/company.ts +37 -0
- package/site-def/footer/ecosystem.ts +37 -0
- package/site-def/footer/index.tsx +26 -0
- package/site-def/footer/legal.ts +28 -0
- package/site-def/footer/network.ts +45 -0
- package/site-def/footer/svg/warpcast-logo.svg +12 -0
- package/site-def/index.ts +3 -0
- package/site-def/main-nav.ts +35 -0
- package/site-def/site-def.ts +37 -0
- package/style/lux-colors.css +85 -0
- package/style/lux-global.css +19 -0
- package/tailwind/fontFamily.tailwind.lux.ts +18 -0
- package/tailwind/index.ts +2 -0
- package/tailwind/lux-tw-fonts.ts +40 -0
- package/tailwind/tailwind.config.lux-preset.ts +10 -0
- package/tsconfig.json +10 -0
- package/types/contact-info.ts +11 -0
- package/types/index.ts +1 -0
@@ -0,0 +1,267 @@
|
|
1
|
+
import type { AbsoluteTemplateString, TemplateString } from './metadata-types'
|
2
|
+
|
3
|
+
export type OpenGraphType =
|
4
|
+
| 'article'
|
5
|
+
| 'book'
|
6
|
+
| 'music.song'
|
7
|
+
| 'music.album'
|
8
|
+
| 'music.playlist'
|
9
|
+
| 'music.radio_station'
|
10
|
+
| 'profile'
|
11
|
+
| 'website'
|
12
|
+
| 'video.tv_show'
|
13
|
+
| 'video.other'
|
14
|
+
| 'video.movie'
|
15
|
+
| 'video.episode'
|
16
|
+
|
17
|
+
export type OpenGraph =
|
18
|
+
| OpenGraphWebsite
|
19
|
+
| OpenGraphArticle
|
20
|
+
| OpenGraphBook
|
21
|
+
| OpenGraphProfile
|
22
|
+
| OpenGraphMusicSong
|
23
|
+
| OpenGraphMusicAlbum
|
24
|
+
| OpenGraphMusicPlaylist
|
25
|
+
| OpenGraphRadioStation
|
26
|
+
| OpenGraphVideoMovie
|
27
|
+
| OpenGraphVideoEpisode
|
28
|
+
| OpenGraphVideoTVShow
|
29
|
+
| OpenGraphVideoOther
|
30
|
+
| OpenGraphMetadata
|
31
|
+
|
32
|
+
// update this type to reflect actual locales
|
33
|
+
type Locale = string
|
34
|
+
|
35
|
+
type OpenGraphMetadata = {
|
36
|
+
determiner?: 'a' | 'an' | 'the' | 'auto' | ''
|
37
|
+
title?: string | TemplateString
|
38
|
+
description?: string
|
39
|
+
emails?: string | Array<string>
|
40
|
+
phoneNumbers?: string | Array<string>
|
41
|
+
faxNumbers?: string | Array<string>
|
42
|
+
siteName?: string
|
43
|
+
locale?: Locale
|
44
|
+
alternateLocale?: Locale | Array<Locale>
|
45
|
+
images?: OGImage | Array<OGImage>
|
46
|
+
audio?: OGAudio | Array<OGAudio>
|
47
|
+
videos?: OGVideo | Array<OGVideo>
|
48
|
+
url?: string | URL
|
49
|
+
countryName?: string
|
50
|
+
ttl?: number
|
51
|
+
}
|
52
|
+
export type OpenGraphWebsite = OpenGraphMetadata & {
|
53
|
+
type: 'website'
|
54
|
+
}
|
55
|
+
type OpenGraphArticle = OpenGraphMetadata & {
|
56
|
+
type: 'article'
|
57
|
+
publishedTime?: string // datetime
|
58
|
+
modifiedTime?: string // datetime
|
59
|
+
expirationTime?: string // datetime
|
60
|
+
authors?: null | string | URL | Array<string | URL>
|
61
|
+
section?: null | string
|
62
|
+
tags?: null | string | Array<string>
|
63
|
+
}
|
64
|
+
type OpenGraphBook = OpenGraphMetadata & {
|
65
|
+
type: 'book'
|
66
|
+
isbn?: null | string
|
67
|
+
releaseDate?: null | string // datetime
|
68
|
+
authors?: null | string | URL | Array<string | URL>
|
69
|
+
tags?: null | string | Array<string>
|
70
|
+
}
|
71
|
+
type OpenGraphProfile = OpenGraphMetadata & {
|
72
|
+
type: 'profile'
|
73
|
+
firstName?: null | string
|
74
|
+
lastName?: null | string
|
75
|
+
username?: null | string
|
76
|
+
gender?: null | string
|
77
|
+
}
|
78
|
+
type OpenGraphMusicSong = OpenGraphMetadata & {
|
79
|
+
type: 'music.song'
|
80
|
+
duration?: null | number
|
81
|
+
albums?: null | string | URL | OGAlbum | Array<string | URL | OGAlbum>
|
82
|
+
musicians?: null | string | URL | Array<string | URL>
|
83
|
+
}
|
84
|
+
type OpenGraphMusicAlbum = OpenGraphMetadata & {
|
85
|
+
type: 'music.album'
|
86
|
+
songs?: null | string | URL | OGSong | Array<string | URL | OGSong>
|
87
|
+
musicians?: null | string | URL | Array<string | URL>
|
88
|
+
releaseDate?: null | string // datetime
|
89
|
+
}
|
90
|
+
type OpenGraphMusicPlaylist = OpenGraphMetadata & {
|
91
|
+
type: 'music.playlist'
|
92
|
+
songs?: null | string | URL | OGSong | Array<string | URL | OGSong>
|
93
|
+
creators?: null | string | URL | Array<string | URL>
|
94
|
+
}
|
95
|
+
type OpenGraphRadioStation = OpenGraphMetadata & {
|
96
|
+
type: 'music.radio_station'
|
97
|
+
creators?: null | string | URL | Array<string | URL>
|
98
|
+
}
|
99
|
+
type OpenGraphVideoMovie = OpenGraphMetadata & {
|
100
|
+
type: 'video.movie'
|
101
|
+
actors?: null | string | URL | OGActor | Array<string | URL | OGActor>
|
102
|
+
directors?: null | string | URL | Array<string | URL>
|
103
|
+
writers?: null | string | URL | Array<string | URL>
|
104
|
+
duration?: null | number
|
105
|
+
releaseDate?: null | string // datetime
|
106
|
+
tags?: null | string | Array<string>
|
107
|
+
}
|
108
|
+
type OpenGraphVideoEpisode = OpenGraphMetadata & {
|
109
|
+
type: 'video.episode'
|
110
|
+
actors?: null | string | URL | OGActor | Array<string | URL | OGActor>
|
111
|
+
directors?: null | string | URL | Array<string | URL>
|
112
|
+
writers?: null | string | URL | Array<string | URL>
|
113
|
+
duration?: null | number
|
114
|
+
releaseDate?: null | string // datetime
|
115
|
+
tags?: null | string | Array<string>
|
116
|
+
series?: null | string | URL
|
117
|
+
}
|
118
|
+
type OpenGraphVideoTVShow = OpenGraphMetadata & {
|
119
|
+
type: 'video.tv_show'
|
120
|
+
}
|
121
|
+
type OpenGraphVideoOther = OpenGraphMetadata & {
|
122
|
+
type: 'video.other'
|
123
|
+
}
|
124
|
+
|
125
|
+
export type OGImage = string | OGImageDescriptor | URL
|
126
|
+
type OGImageDescriptor = {
|
127
|
+
url: string | URL
|
128
|
+
secureUrl?: string | URL
|
129
|
+
alt?: string
|
130
|
+
type?: string
|
131
|
+
width?: string | number
|
132
|
+
height?: string | number
|
133
|
+
}
|
134
|
+
type OGAudio = string | OGAudioDescriptor | URL
|
135
|
+
type OGAudioDescriptor = {
|
136
|
+
url: string | URL
|
137
|
+
secureUrl?: string | URL
|
138
|
+
type?: string
|
139
|
+
}
|
140
|
+
type OGVideo = string | OGVideoDescriptor | URL
|
141
|
+
type OGVideoDescriptor = {
|
142
|
+
url: string | URL
|
143
|
+
secureUrl?: string | URL
|
144
|
+
type?: string
|
145
|
+
width?: string | number
|
146
|
+
height?: string | number
|
147
|
+
}
|
148
|
+
|
149
|
+
export type ResolvedOpenGraph =
|
150
|
+
| ResolvedOpenGraphWebsite
|
151
|
+
| ResolvedOpenGraphArticle
|
152
|
+
| ResolvedOpenGraphBook
|
153
|
+
| ResolvedOpenGraphProfile
|
154
|
+
| ResolvedOpenGraphMusicSong
|
155
|
+
| ResolvedOpenGraphMusicAlbum
|
156
|
+
| ResolvedOpenGraphMusicPlaylist
|
157
|
+
| ResolvedOpenGraphRadioStation
|
158
|
+
| ResolvedOpenGraphVideoMovie
|
159
|
+
| ResolvedOpenGraphVideoEpisode
|
160
|
+
| ResolvedOpenGraphVideoTVShow
|
161
|
+
| ResolvedOpenGraphVideoOther
|
162
|
+
| ResolvedOpenGraphMetadata
|
163
|
+
|
164
|
+
type ResolvedOpenGraphMetadata = {
|
165
|
+
determiner?: 'a' | 'an' | 'the' | 'auto' | ''
|
166
|
+
title: AbsoluteTemplateString
|
167
|
+
description?: string
|
168
|
+
emails?: Array<string>
|
169
|
+
phoneNumbers?: Array<string>
|
170
|
+
faxNumbers?: Array<string>
|
171
|
+
siteName?: string
|
172
|
+
locale?: Locale
|
173
|
+
alternateLocale?: Array<Locale>
|
174
|
+
images?: Array<OGImage>
|
175
|
+
audio?: Array<OGAudio>
|
176
|
+
videos?: Array<OGVideo>
|
177
|
+
url: null | URL | string
|
178
|
+
countryName?: string
|
179
|
+
ttl?: number
|
180
|
+
}
|
181
|
+
type ResolvedOpenGraphWebsite = ResolvedOpenGraphMetadata & {
|
182
|
+
type: 'website'
|
183
|
+
}
|
184
|
+
type ResolvedOpenGraphArticle = ResolvedOpenGraphMetadata & {
|
185
|
+
type: 'article'
|
186
|
+
publishedTime?: string // datetime
|
187
|
+
modifiedTime?: string // datetime
|
188
|
+
expirationTime?: string // datetime
|
189
|
+
authors?: Array<string>
|
190
|
+
section?: string
|
191
|
+
tags?: Array<string>
|
192
|
+
}
|
193
|
+
type ResolvedOpenGraphBook = ResolvedOpenGraphMetadata & {
|
194
|
+
type: 'book'
|
195
|
+
isbn?: string
|
196
|
+
releaseDate?: string // datetime
|
197
|
+
authors?: Array<string>
|
198
|
+
tags?: Array<string>
|
199
|
+
}
|
200
|
+
type ResolvedOpenGraphProfile = ResolvedOpenGraphMetadata & {
|
201
|
+
type: 'profile'
|
202
|
+
firstName?: string
|
203
|
+
lastName?: string
|
204
|
+
username?: string
|
205
|
+
gender?: string
|
206
|
+
}
|
207
|
+
type ResolvedOpenGraphMusicSong = ResolvedOpenGraphMetadata & {
|
208
|
+
type: 'music.song'
|
209
|
+
duration?: number
|
210
|
+
albums?: Array<OGAlbum>
|
211
|
+
musicians?: Array<string | URL>
|
212
|
+
}
|
213
|
+
type ResolvedOpenGraphMusicAlbum = ResolvedOpenGraphMetadata & {
|
214
|
+
type: 'music.album'
|
215
|
+
songs?: Array<string | URL | OGSong>
|
216
|
+
musicians?: Array<string | URL>
|
217
|
+
releaseDate?: string // datetime
|
218
|
+
}
|
219
|
+
type ResolvedOpenGraphMusicPlaylist = ResolvedOpenGraphMetadata & {
|
220
|
+
type: 'music.playlist'
|
221
|
+
songs?: Array<string | URL | OGSong>
|
222
|
+
creators?: Array<string | URL>
|
223
|
+
}
|
224
|
+
type ResolvedOpenGraphRadioStation = ResolvedOpenGraphMetadata & {
|
225
|
+
type: 'music.radio_station'
|
226
|
+
creators?: Array<string | URL>
|
227
|
+
}
|
228
|
+
type ResolvedOpenGraphVideoMovie = ResolvedOpenGraphMetadata & {
|
229
|
+
type: 'video.movie'
|
230
|
+
actors?: Array<string | URL | OGActor>
|
231
|
+
directors?: Array<string | URL>
|
232
|
+
writers?: Array<string | URL>
|
233
|
+
duration?: number
|
234
|
+
releaseDate?: string // datetime
|
235
|
+
tags?: Array<string>
|
236
|
+
}
|
237
|
+
type ResolvedOpenGraphVideoEpisode = ResolvedOpenGraphMetadata & {
|
238
|
+
type: 'video.episode'
|
239
|
+
actors?: Array<string | URL | OGActor>
|
240
|
+
directors?: Array<string | URL>
|
241
|
+
writers?: Array<string | URL>
|
242
|
+
duration?: number
|
243
|
+
releaseDate?: string // datetime
|
244
|
+
tags?: Array<string>
|
245
|
+
series?: string | URL
|
246
|
+
}
|
247
|
+
type ResolvedOpenGraphVideoTVShow = ResolvedOpenGraphMetadata & {
|
248
|
+
type: 'video.tv_show'
|
249
|
+
}
|
250
|
+
type ResolvedOpenGraphVideoOther = ResolvedOpenGraphMetadata & {
|
251
|
+
type: 'video.other'
|
252
|
+
}
|
253
|
+
|
254
|
+
type OGSong = {
|
255
|
+
url: string | URL
|
256
|
+
disc?: number
|
257
|
+
track?: number
|
258
|
+
}
|
259
|
+
type OGAlbum = {
|
260
|
+
url: string | URL
|
261
|
+
disc?: number
|
262
|
+
track?: number
|
263
|
+
}
|
264
|
+
type OGActor = {
|
265
|
+
url: string | URL
|
266
|
+
role?: string
|
267
|
+
}
|
@@ -0,0 +1,92 @@
|
|
1
|
+
// Reference: https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/markup
|
2
|
+
|
3
|
+
import type { AbsoluteTemplateString, TemplateString } from './metadata-types'
|
4
|
+
|
5
|
+
export type Twitter =
|
6
|
+
| TwitterSummary
|
7
|
+
| TwitterSummaryLargeImage
|
8
|
+
| TwitterPlayer
|
9
|
+
| TwitterApp
|
10
|
+
| TwitterMetadata
|
11
|
+
|
12
|
+
type TwitterMetadata = {
|
13
|
+
// defaults to card="summary"
|
14
|
+
site?: string // username for account associated to the site itself
|
15
|
+
siteId?: string // id for account associated to the site itself
|
16
|
+
creator?: string // username for the account associated to the creator of the content on the site
|
17
|
+
creatorId?: string // id for the account associated to the creator of the content on the site
|
18
|
+
description?: string
|
19
|
+
title?: string | TemplateString
|
20
|
+
images?: TwitterImage | Array<TwitterImage>
|
21
|
+
}
|
22
|
+
type TwitterSummary = TwitterMetadata & {
|
23
|
+
card: 'summary'
|
24
|
+
}
|
25
|
+
type TwitterSummaryLargeImage = TwitterMetadata & {
|
26
|
+
card: 'summary_large_image'
|
27
|
+
}
|
28
|
+
type TwitterPlayer = TwitterMetadata & {
|
29
|
+
card: 'player'
|
30
|
+
players: TwitterPlayerDescriptor | Array<TwitterPlayerDescriptor>
|
31
|
+
}
|
32
|
+
type TwitterApp = TwitterMetadata & {
|
33
|
+
card: 'app'
|
34
|
+
app: TwitterAppDescriptor
|
35
|
+
}
|
36
|
+
export type TwitterAppDescriptor = {
|
37
|
+
id: {
|
38
|
+
iphone?: string | number
|
39
|
+
ipad?: string | number
|
40
|
+
googleplay?: string
|
41
|
+
}
|
42
|
+
url?: {
|
43
|
+
iphone?: string | URL
|
44
|
+
ipad?: string | URL
|
45
|
+
googleplay?: string | URL
|
46
|
+
}
|
47
|
+
name?: string
|
48
|
+
}
|
49
|
+
|
50
|
+
export type TwitterImage = string | TwitterImageDescriptor | URL
|
51
|
+
type TwitterImageDescriptor = {
|
52
|
+
url: string | URL
|
53
|
+
alt?: string
|
54
|
+
secureUrl?: string | URL
|
55
|
+
type?: string
|
56
|
+
width?: string | number
|
57
|
+
height?: string | number
|
58
|
+
}
|
59
|
+
type TwitterPlayerDescriptor = {
|
60
|
+
playerUrl: string | URL
|
61
|
+
streamUrl: string | URL
|
62
|
+
width: number
|
63
|
+
height: number
|
64
|
+
}
|
65
|
+
|
66
|
+
type ResolvedTwitterImage = {
|
67
|
+
url: string | URL
|
68
|
+
alt?: string
|
69
|
+
secureUrl?: string | URL
|
70
|
+
type?: string
|
71
|
+
width?: string | number
|
72
|
+
height?: string | number
|
73
|
+
}
|
74
|
+
type ResolvedTwitterSummary = {
|
75
|
+
site: string | null
|
76
|
+
siteId: string | null
|
77
|
+
creator: string | null
|
78
|
+
creatorId: string | null
|
79
|
+
description: string | null
|
80
|
+
title: AbsoluteTemplateString
|
81
|
+
images?: Array<ResolvedTwitterImage>
|
82
|
+
}
|
83
|
+
type ResolvedTwitterPlayer = ResolvedTwitterSummary & {
|
84
|
+
players: Array<TwitterPlayerDescriptor>
|
85
|
+
}
|
86
|
+
type ResolvedTwitterApp = ResolvedTwitterSummary & { app: TwitterAppDescriptor }
|
87
|
+
|
88
|
+
export type ResolvedTwitterMetadata =
|
89
|
+
| ({ card: 'summary' } & ResolvedTwitterSummary)
|
90
|
+
| ({ card: 'summary_large_image' } & ResolvedTwitterSummary)
|
91
|
+
| ({ card: 'player' } & ResolvedTwitterPlayer)
|
92
|
+
| ({ card: 'app' } & ResolvedTwitterApp)
|
@@ -0,0 +1,208 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
|
3
|
+
import type { Metadata } from 'next'
|
4
|
+
import Head from "next/head"
|
5
|
+
|
6
|
+
import type {
|
7
|
+
IconDescriptor,
|
8
|
+
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'
|
15
|
+
|
16
|
+
/*
|
17
|
+
NOTE: This is ONLY for sites that use the pages router in next.
|
18
|
+
The app router does this automatically
|
19
|
+
*/
|
20
|
+
|
21
|
+
const getURLasString = (url: string | URL) => {
|
22
|
+
return (
|
23
|
+
(typeof url === 'string') ? (url as string) : (url.href)
|
24
|
+
)
|
25
|
+
}
|
26
|
+
|
27
|
+
// https://stackoverflow.com/questions/68746228/next-head-wont-render-meta-tags-inside-of-fragment
|
28
|
+
const Icons: React.FC<{icons: IconDescriptor[]}> = ({
|
29
|
+
icons
|
30
|
+
}) => {
|
31
|
+
return <Head>
|
32
|
+
{icons.map(({url, ...rest}: IconDescriptor, index) => (
|
33
|
+
<link {...rest} href={getURLasString(url)} key={`icons-${index}`}/>
|
34
|
+
))}
|
35
|
+
</Head>
|
36
|
+
}
|
37
|
+
|
38
|
+
export const getTitleFromTemplateString = (title: string | TemplateString | null | undefined): string | null => {
|
39
|
+
|
40
|
+
if (!title) {
|
41
|
+
return null
|
42
|
+
}
|
43
|
+
if (typeof title === 'object') {
|
44
|
+
if ('default' in title) {
|
45
|
+
return title.default
|
46
|
+
}
|
47
|
+
else if ('absolute' in title) {
|
48
|
+
return title.absolute
|
49
|
+
}
|
50
|
+
}
|
51
|
+
return title as string
|
52
|
+
}
|
53
|
+
|
54
|
+
const Authors: React.FC<{
|
55
|
+
authors: null | undefined | Author | Array<Author>
|
56
|
+
}> = ({
|
57
|
+
authors
|
58
|
+
}) => {
|
59
|
+
|
60
|
+
const Author: React.FC<{author: Author}> = ({author}) => (<>
|
61
|
+
{author.name && <meta name="author" content={author.name} />}
|
62
|
+
{author.url && <link rel="author" href={getURLasString(author.url)}/>}
|
63
|
+
</>)
|
64
|
+
|
65
|
+
if (!authors) {
|
66
|
+
return null
|
67
|
+
}
|
68
|
+
|
69
|
+
if (Array.isArray(authors)) {
|
70
|
+
return (<>
|
71
|
+
{authors.map((el: Author, index) => (
|
72
|
+
<Author author={el} key={`authors-${index}`} />
|
73
|
+
))}
|
74
|
+
</>)
|
75
|
+
}
|
76
|
+
return (<Author author={authors as Author} />)
|
77
|
+
}
|
78
|
+
|
79
|
+
const Keywords: React.FC<{keywords: undefined | null | string | Array<string>}> = ({
|
80
|
+
keywords
|
81
|
+
}) => {
|
82
|
+
if (!keywords) return null
|
83
|
+
const content = (Array.isArray(keywords) ? keywords.join(', ') : keywords as string)
|
84
|
+
return (<meta name="keywords" content={content} />)
|
85
|
+
}
|
86
|
+
|
87
|
+
const ThemeColor: React.FC<{
|
88
|
+
thColors: null | undefined | string | ThemeColorDescriptor | ThemeColorDescriptor[]
|
89
|
+
}> = ({
|
90
|
+
thColors
|
91
|
+
}) => {
|
92
|
+
|
93
|
+
const ThColor: React.FC<{thColor: ThemeColorDescriptor}> = ({thColor}) => {
|
94
|
+
const toSpread: any = {
|
95
|
+
content: thColor.color
|
96
|
+
}
|
97
|
+
|
98
|
+
if ('media' in thColor) {
|
99
|
+
toSpread.media = thColor.media
|
100
|
+
}
|
101
|
+
|
102
|
+
return <meta name="theme-color" {...toSpread}/>
|
103
|
+
}
|
104
|
+
|
105
|
+
if (!thColors) {
|
106
|
+
return null
|
107
|
+
}
|
108
|
+
|
109
|
+
if (Array.isArray(thColors)) {
|
110
|
+
return (<>
|
111
|
+
{thColors.map((el: ThemeColorDescriptor, index) => (
|
112
|
+
<ThColor thColor={el} key={`theme-colors-${index}`} />
|
113
|
+
))}
|
114
|
+
</>)
|
115
|
+
}
|
116
|
+
else if (typeof thColors === 'string') {
|
117
|
+
<meta name="theme-color" content={thColors as string}/>
|
118
|
+
}
|
119
|
+
return (<ThColor thColor={thColors as ThemeColorDescriptor} />)
|
120
|
+
}
|
121
|
+
|
122
|
+
const Manifest: React.FC<{
|
123
|
+
manifest: undefined | null | string | URL
|
124
|
+
}> = ({
|
125
|
+
manifest
|
126
|
+
}) => (
|
127
|
+
manifest && (<link rel="manifest" href={getURLasString(manifest)}/>)
|
128
|
+
)
|
129
|
+
|
130
|
+
const getOGImageURL = (img: OGImage | undefined): string | null => {
|
131
|
+
|
132
|
+
if (!img) {
|
133
|
+
return null
|
134
|
+
}
|
135
|
+
if (typeof img === 'object' && 'url' in img) { // this is a OGImageDescriptor
|
136
|
+
return getURLasString(img.url)
|
137
|
+
}
|
138
|
+
return getURLasString(img) // this is a URL or string
|
139
|
+
}
|
140
|
+
|
141
|
+
const getTwitterImageURL = (img: TwitterImage | undefined): string | null => {
|
142
|
+
|
143
|
+
if (!img) {
|
144
|
+
return null
|
145
|
+
}
|
146
|
+
if (typeof img === 'object' && 'url' in img) { // this is a TwitterImageDescriptor
|
147
|
+
return getURLasString(img.url)
|
148
|
+
}
|
149
|
+
return getURLasString(img) // this is a URL or string
|
150
|
+
}
|
151
|
+
|
152
|
+
// https://stackoverflow.com/questions/68746228/next-head-wont-render-meta-tags-inside-of-fragment
|
153
|
+
const OpenGraphComponent: React.FC<{
|
154
|
+
og: OpenGraph | undefined | null
|
155
|
+
}> = ({
|
156
|
+
og
|
157
|
+
}) => (og && (<Head>
|
158
|
+
{og.url && (<meta property="og:url" content={(typeof og.url === 'string') ? (og.url as string) : (og.url.href)} />)}
|
159
|
+
{(og as any).type && (<meta property="og:type" content={(og as any).type} />)}
|
160
|
+
{og.title && (<meta property="og:title" content={getTitleFromTemplateString(og.title)!} />)}
|
161
|
+
{og.description && (<meta property="og:description" content={og.description} />)}
|
162
|
+
{og.images && (<meta property="og:image" content={getOGImageURL(Array.isArray(og.images) ? og.images[0] : og.images)!} />)}
|
163
|
+
</Head>))
|
164
|
+
|
165
|
+
// https://stackoverflow.com/questions/68746228/next-head-wont-render-meta-tags-inside-of-fragment
|
166
|
+
export const TwitterComponent: React.FC<{
|
167
|
+
tw: Twitter | undefined | null
|
168
|
+
}> = ({
|
169
|
+
tw
|
170
|
+
}) => (tw && (<Head>
|
171
|
+
{(tw as any).card && (<meta name="twitter:card" content={(tw as any).card} />)}
|
172
|
+
{tw.title && (<meta name="twitter:title" content={getTitleFromTemplateString(tw.title)!} />)}
|
173
|
+
{tw.description && (<meta name="twitter:description" content={tw.description} />)}
|
174
|
+
{tw.images && (<meta name="twitter:image" content={getTwitterImageURL(Array.isArray(tw.images) ? tw.images[0] : tw.images)!} />)}
|
175
|
+
{tw.site && (<meta name="twitter:site" content={tw.site} />)}
|
176
|
+
</Head>))
|
177
|
+
|
178
|
+
/* See NOTE at top of file! */
|
179
|
+
// https://stackoverflow.com/questions/68746228/next-head-wont-render-meta-tags-inside-of-fragment
|
180
|
+
const HeadMetadataComponent: React.FC<{
|
181
|
+
metadata: Metadata
|
182
|
+
}> = ({
|
183
|
+
metadata
|
184
|
+
}) => {
|
185
|
+
const mainTitle = getTitleFromTemplateString(metadata.title)
|
186
|
+
|
187
|
+
return (<>
|
188
|
+
<Head>
|
189
|
+
{mainTitle && (<title>{mainTitle}</title>) /* must be here, directly under Head component */}
|
190
|
+
{metadata.description && (
|
191
|
+
<meta name="description" content={metadata.description} />
|
192
|
+
)}
|
193
|
+
{metadata.applicationName && (
|
194
|
+
<meta name="application-name" content={metadata.applicationName} />
|
195
|
+
)}
|
196
|
+
<Authors authors={metadata.authors} />
|
197
|
+
<Keywords keywords={metadata.keywords} />
|
198
|
+
<ThemeColor thColors={metadata.themeColor} />
|
199
|
+
<Manifest manifest={metadata.manifest} />
|
200
|
+
</Head>
|
201
|
+
{/* Icons: We only support this format for now */}
|
202
|
+
<Icons icons={metadata.icons as IconDescriptor[]} />
|
203
|
+
<OpenGraphComponent og={metadata.openGraph} />
|
204
|
+
<TwitterComponent tw={metadata.twitter} />
|
205
|
+
</>)
|
206
|
+
}
|
207
|
+
|
208
|
+
export default HeadMetadataComponent
|
package/next/index.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export { default as determineDeviceMW } from './determine-device-mw'
|
package/package.json
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
{
|
2
|
+
"name": "@luxfi/core",
|
3
|
+
"version": "4.3.11",
|
4
|
+
"description": "Library that contains shared UI primitives, support for a common design system, and other boilerplate support.",
|
5
|
+
"publishConfig": {
|
6
|
+
"registry": "https://registry.npmjs.org/",
|
7
|
+
"access": "public",
|
8
|
+
"scope": "@luxfi"
|
9
|
+
},
|
10
|
+
"repository": {
|
11
|
+
"type": "git",
|
12
|
+
"url": "git+https://github.com/luxfi/web.git",
|
13
|
+
"directory": "packages/common"
|
14
|
+
},
|
15
|
+
"keywords": [
|
16
|
+
"components",
|
17
|
+
"radix-ui",
|
18
|
+
"hanzo",
|
19
|
+
"luxdefi"
|
20
|
+
],
|
21
|
+
"scripts": {
|
22
|
+
"lat": "npm show @luxfi/common version",
|
23
|
+
"pub": "npm publish",
|
24
|
+
"build": "tsc",
|
25
|
+
"tc": "tsc",
|
26
|
+
"ln:ui": "pnpm link -g @hanzo/ui",
|
27
|
+
"ln:auth": "pnpm link -g @hanzo/auth",
|
28
|
+
"ln:cmmc": "pnpm link -g @hanzo/commerce",
|
29
|
+
"ul:all": "rm node_modules/@hanzo/*",
|
30
|
+
"clean": "rm -rf node_modules"
|
31
|
+
},
|
32
|
+
"exports": {
|
33
|
+
".": "./components/index.ts",
|
34
|
+
"./server-actions": "./server-actions/index.ts",
|
35
|
+
"./next": "./next/index.ts",
|
36
|
+
"./style/": "./style/",
|
37
|
+
"./site-def": "./site-def/index.ts",
|
38
|
+
"./tailwind": "./tailwind/index.ts",
|
39
|
+
"./conf": "./conf/index.ts"
|
40
|
+
},
|
41
|
+
"dependencies": {
|
42
|
+
"@hanzo/auth": "2.3.5",
|
43
|
+
"@hanzo/commerce": "6.3.2",
|
44
|
+
"@hanzo/ui": "3.6.3",
|
45
|
+
"@next/third-parties": "^14.1.0",
|
46
|
+
"embla-carousel-autoplay": "^8.0.1",
|
47
|
+
"react-device-detect": "^2.2.3",
|
48
|
+
"react-social-icons": "^6.4.0"
|
49
|
+
},
|
50
|
+
"peerDependencies": {
|
51
|
+
"@hookform/resolvers": "^3.3.2",
|
52
|
+
"lucide-react": "^0.344.0",
|
53
|
+
"next": "14.1.3",
|
54
|
+
"next-themes": "^0.2.1",
|
55
|
+
"react": "^18.2.0",
|
56
|
+
"react-dom": "^18.2.0",
|
57
|
+
"react-hook-form": "^7.47.0",
|
58
|
+
"validator": "^13.11.0",
|
59
|
+
"zod": "3.21.4"
|
60
|
+
},
|
61
|
+
"devDependencies": {
|
62
|
+
"@mdx-js/loader": "^3.0.0",
|
63
|
+
"@mdx-js/react": "^3.0.0",
|
64
|
+
"@types/facebook-pixel": "^0.0.30",
|
65
|
+
"@types/gtag.js": "^0.0.19",
|
66
|
+
"@types/mdx": "^2.0.9",
|
67
|
+
"@types/react": "^18.2.64",
|
68
|
+
"@types/react-dom": "^18.2.18",
|
69
|
+
"tailwindcss": "^3.4.2",
|
70
|
+
"typescript": "5.3.3"
|
71
|
+
}
|
72
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { initializeApp, getApps } from 'firebase/app'
|
2
|
+
|
3
|
+
const firebaseConfig = {
|
4
|
+
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
|
5
|
+
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
|
6
|
+
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
|
7
|
+
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
|
8
|
+
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
|
9
|
+
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
|
10
|
+
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
|
11
|
+
}
|
12
|
+
|
13
|
+
// Initialize Firebase instance if there isn't one already
|
14
|
+
export default getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0]
|