@luxfi/core 5.3.1 → 5.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. package/commerce/ui/conf.ts +13 -13
  2. package/commerce/ui/context.tsx +123 -126
  3. package/commerce/ui/store.ts +289 -304
  4. package/components/access-code-input.tsx +71 -71
  5. package/components/auth/auth-listener.tsx +29 -29
  6. package/components/auth/auth-token/clear-auth-token.tsx +12 -12
  7. package/components/auth/auth-token/set-auth-token.tsx +16 -16
  8. package/components/auth/common-auth-domains.ts +16 -16
  9. package/components/auth/login-panel.tsx +107 -107
  10. package/components/back-button.tsx +49 -42
  11. package/components/chat-widget.tsx +85 -85
  12. package/components/commerce/{checkout-widget → _to_deprecate_checkout-widget}/const.ts +13 -13
  13. package/components/commerce/{checkout-widget/index.tsx → _to_deprecate_checkout-widget/index.tsx_} +188 -192
  14. package/components/commerce/{checkout-widget → _to_deprecate_checkout-widget}/obs-string-set.ts +48 -48
  15. package/components/commerce/{checkout-widget → _to_deprecate_checkout-widget}/use-anim-clx-set.ts +58 -58
  16. package/components/commerce/bag-button.tsx +98 -98
  17. package/components/commerce/buy-button.tsx +34 -34
  18. package/components/commerce/checkout-button.tsx +129 -129
  19. package/components/commerce/checkout-panel/cart-accordian.tsx +66 -0
  20. package/components/commerce/checkout-panel/checkout-panel-props.ts +10 -0
  21. package/components/commerce/checkout-panel/{dt-bag-carousel.tsx → desktop-bag-carousel.tsx} +36 -36
  22. package/components/commerce/checkout-panel/desktop-cp.tsx +83 -0
  23. package/components/commerce/checkout-panel/index.tsx +126 -129
  24. package/components/commerce/checkout-panel/mobile-cp.tsx +67 -0
  25. package/components/commerce/checkout-panel/policy-links.tsx +29 -0
  26. package/components/commerce/checkout-panel/steps-indicator.tsx +39 -39
  27. package/components/commerce/checkout-panel/thank-you.tsx +18 -18
  28. package/components/commerce/desktop-bag-popup.tsx +78 -78
  29. package/components/commerce/desktop-nav-menu.tsx +130 -130
  30. package/components/commerce/drawer/index.tsx +88 -99
  31. package/components/commerce/drawer/micro.tsx +145 -144
  32. package/components/commerce/drawer/shell.tsx +85 -85
  33. package/components/commerce/mobile-bag-drawer.tsx +51 -51
  34. package/components/commerce/mobile-login-button.tsx +107 -107
  35. package/components/commerce/mobile-menu-toggle-button.tsx +35 -35
  36. package/components/commerce/mobile-nav-menu-ai.tsx +50 -51
  37. package/components/commerce/mobile-nav-menu-item.tsx +49 -49
  38. package/components/commerce/mobile-nav-menu.tsx +101 -101
  39. package/components/contact-dialog/contact-form.tsx +113 -113
  40. package/components/contact-dialog/disclaimer.tsx +13 -13
  41. package/components/contact-dialog/index.tsx +64 -64
  42. package/components/copyright.tsx +21 -21
  43. package/components/drawer-margin.tsx +25 -25
  44. package/components/footer.tsx +77 -77
  45. package/components/header/desktop.tsx +51 -51
  46. package/components/header/index.tsx +50 -50
  47. package/components/header/mobile.tsx +163 -163
  48. package/components/header/theme-toggle.tsx +26 -26
  49. package/components/icons/24k-gold-card.tsx +43 -43
  50. package/components/icons/ai-chat-act.tsx +47 -47
  51. package/components/icons/ai-chat.tsx +29 -29
  52. package/components/icons/anodized-titanium.tsx +45 -45
  53. package/components/icons/avatar.tsx +11 -11
  54. package/components/icons/bag-icon.tsx +10 -10
  55. package/components/icons/blog-act.tsx +14 -14
  56. package/components/icons/blog.tsx +20 -20
  57. package/components/icons/bridge-act.tsx +18 -18
  58. package/components/icons/bridge.tsx +68 -68
  59. package/components/icons/changelog-act.tsx +15 -15
  60. package/components/icons/changelog.tsx +21 -21
  61. package/components/icons/chrome.tsx +45 -45
  62. package/components/icons/coins-act.tsx +29 -29
  63. package/components/icons/coins.tsx +20 -20
  64. package/components/icons/compare-cards-act.tsx +30 -30
  65. package/components/icons/compare-cards.tsx +21 -21
  66. package/components/icons/credit-act.tsx +29 -29
  67. package/components/icons/credit.tsx +20 -20
  68. package/components/icons/customer-support-act.tsx +27 -27
  69. package/components/icons/customer-support.tsx +21 -21
  70. package/components/icons/customers-act.tsx +65 -65
  71. package/components/icons/customers.tsx +33 -33
  72. package/components/icons/developer-docs-act.tsx +26 -26
  73. package/components/icons/developer-docs.tsx +20 -20
  74. package/components/icons/exchange-act.tsx +27 -27
  75. package/components/icons/exchange.tsx +21 -21
  76. package/components/icons/explorer-act.tsx +27 -27
  77. package/components/icons/explorer.tsx +22 -22
  78. package/components/icons/faqs-act.tsx +27 -27
  79. package/components/icons/faqs.tsx +21 -21
  80. package/components/icons/github.tsx +14 -14
  81. package/components/icons/guides-act.tsx +26 -26
  82. package/components/icons/guides.tsx +21 -21
  83. package/components/icons/gun-metal.tsx +44 -44
  84. package/components/icons/index.tsx +43 -43
  85. package/components/icons/integrations-act.tsx +41 -41
  86. package/components/icons/integrations.tsx +25 -25
  87. package/components/icons/irradescent.tsx +41 -41
  88. package/components/icons/launch-subnet.tsx +21 -21
  89. package/components/icons/launchsubnet-act.tsx +29 -29
  90. package/components/icons/left-arrow.tsx +11 -11
  91. package/components/icons/lux-finance-act.tsx +34 -34
  92. package/components/icons/lux-finance.tsx +23 -23
  93. package/components/icons/lux-logo.tsx +10 -10
  94. package/components/icons/lux-pass-act.tsx +41 -41
  95. package/components/icons/lux-pass.tsx +25 -25
  96. package/components/icons/lux-quests-act.tsx +15 -15
  97. package/components/icons/lux-quests.tsx +21 -21
  98. package/components/icons/market-act.tsx +39 -39
  99. package/components/icons/market.tsx +24 -24
  100. package/components/icons/mirrored-titanium.tsx +46 -46
  101. package/components/icons/more-benefits-act.tsx +29 -29
  102. package/components/icons/more-benefits.tsx +21 -21
  103. package/components/icons/open-source-act.tsx +41 -41
  104. package/components/icons/open-source.tsx +26 -26
  105. package/components/icons/right-arrow.tsx +10 -10
  106. package/components/icons/safe-act.tsx +77 -77
  107. package/components/icons/safe.tsx +37 -37
  108. package/components/icons/search.tsx +12 -12
  109. package/components/icons/secure-delivery.tsx +13 -13
  110. package/components/icons/shop-act.tsx +29 -29
  111. package/components/icons/shop.tsx +20 -20
  112. package/components/icons/social-icon.tsx +35 -35
  113. package/components/icons/social-svg.css +3 -3
  114. package/components/icons/sterling-silver-card.tsx +44 -44
  115. package/components/icons/templates-act.tsx +29 -29
  116. package/components/icons/templates.tsx +21 -21
  117. package/components/icons/validators-act.tsx +42 -42
  118. package/components/icons/validators.tsx +41 -41
  119. package/components/icons/view-all-card-act.tsx +28 -28
  120. package/components/icons/view-all-card.tsx +20 -20
  121. package/components/icons/wallet-act.tsx +29 -29
  122. package/components/icons/wallet.tsx +20 -20
  123. package/components/icons/warpcast.tsx +58 -58
  124. package/components/icons/youtube-logo.tsx +59 -59
  125. package/components/index.ts +25 -27
  126. package/components/logo.tsx +89 -89
  127. package/components/main.tsx +27 -27
  128. package/components/mini-chart/index.tsx +7 -7
  129. package/components/mini-chart/mini-chart-props.ts +43 -43
  130. package/components/mini-chart/mini-chart.tsx +85 -85
  131. package/components/mini-chart/wrapper.tsx +23 -23
  132. package/components/not-found/index.tsx +28 -28
  133. package/components/not-found/not-found-content.mdx +5 -5
  134. package/components/scripts.tsx +24 -24
  135. package/components/tooltip.tsx +31 -31
  136. package/environment.d.ts +5 -5
  137. package/next/analytics/fpixel.ts +15 -15
  138. package/next/analytics/google-analytics.ts +13 -13
  139. package/next/analytics/index.ts +3 -3
  140. package/next/analytics/pixel-analytics.tsx +54 -54
  141. package/next/font/get-app-router-font-classes.ts +12 -12
  142. package/next/font/load-and-return-lux-next-fonts-on-import.ts +68 -68
  143. package/next/font/next-font-desc.ts +27 -27
  144. package/next/font/pages-router-font-vars.tsx +18 -18
  145. package/next/head-metadata/from-next/metadata-types.ts +158 -158
  146. package/next/head-metadata/from-next/opengraph-types.ts +267 -267
  147. package/next/head-metadata/from-next/twitter-types.ts +92 -92
  148. package/next/head-metadata/index.tsx +208 -208
  149. package/next/middleware/determine-device-mw.ts +16 -16
  150. package/package.json +79 -79
  151. package/root-layout/WHY_THIS_IS_SEPARATE.txt +1 -1
  152. package/root-layout/index.tsx +112 -112
  153. package/server-actions/firebase-app.ts +14 -14
  154. package/server-actions/index.ts +5 -5
  155. package/server-actions/store-contact.ts +51 -51
  156. package/site-def/footer/community.tsx +67 -67
  157. package/site-def/footer/company.ts +37 -37
  158. package/site-def/footer/ecosystem.ts +37 -37
  159. package/site-def/footer/index.tsx +26 -26
  160. package/site-def/footer/legal.ts +28 -28
  161. package/site-def/footer/network.ts +45 -45
  162. package/site-def/footer/svg/warpcast-logo.svg +11 -11
  163. package/site-def/index.ts +2 -2
  164. package/site-def/main-nav.tsx +458 -458
  165. package/style/cart-animation.css +29 -29
  166. package/style/checkout-animation.css +23 -23
  167. package/style/drawer-handle-overrides.css +160 -160
  168. package/style/lux-colors.css +85 -85
  169. package/style/lux-global.css +50 -50
  170. package/tailwind/fontFamily.tailwind.lux.ts +18 -18
  171. package/tailwind/index.ts +2 -2
  172. package/tailwind/lux-tw-fonts.ts +39 -39
  173. package/tailwind/tailwind.config.lux-preset.ts +10 -10
  174. package/tsconfig.json +15 -15
  175. package/types/chatbot-config.ts +6 -6
  176. package/types/chatbot-suggested-question.ts +7 -7
  177. package/types/contact-info.ts +10 -10
  178. package/types/index.ts +4 -4
  179. package/types/site-def.ts +43 -43
  180. package/components/commerce/add-widget.tsx +0 -20
  181. package/components/commerce/checkout-panel/dt-checkout-panel.tsx +0 -85
  182. package/components/commerce/checkout-panel/links-row.tsx +0 -21
  183. package/components/commerce/checkout-panel/mb-checkout-panel.tsx +0 -55
@@ -1,92 +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)
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)
@@ -1,208 +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
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
@@ -1,16 +1,16 @@
1
- import { NextRequest, NextResponse, userAgent } from 'next/server'
2
- import { getSelectorsByUserAgent } from 'react-device-detect'
3
-
4
- // writed this way so they can be chained :)
5
- const determineDeviceMW = async (request: NextRequest) => {
6
-
7
- const ua = userAgent(request)
8
- const { isMobileOnly, isTablet, isDesktop } = getSelectorsByUserAgent(ua.ua)
9
- const agent = isMobileOnly ? 'phone' : (isTablet ? 'tablet' : (isDesktop ? 'desktop' : 'unknown'))
10
- const { nextUrl: url } = request
11
- //console.log(`\n=== from ${url.href} on a *${agent && agent.toUpperCase()}* device. ===\n`)
12
- url.searchParams.set('agent', agent)
13
- return NextResponse.rewrite(url)
14
- }
15
-
16
- export default determineDeviceMW
1
+ import { NextRequest, NextResponse, userAgent } from 'next/server'
2
+ import { getSelectorsByUserAgent } from 'react-device-detect'
3
+
4
+ // writed this way so they can be chained :)
5
+ const determineDeviceMW = async (request: NextRequest) => {
6
+
7
+ const ua = userAgent(request)
8
+ const { isMobileOnly, isTablet, isDesktop } = getSelectorsByUserAgent(ua.ua)
9
+ const agent = isMobileOnly ? 'phone' : (isTablet ? 'tablet' : (isDesktop ? 'desktop' : 'unknown'))
10
+ const { nextUrl: url } = request
11
+ //console.log(`\n=== from ${url.href} on a *${agent && agent.toUpperCase()}* device. ===\n`)
12
+ url.searchParams.set('agent', agent)
13
+ return NextResponse.rewrite(url)
14
+ }
15
+
16
+ export default determineDeviceMW