@hanzo/ui 2.0.4 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/assets/lux-site-icons/android-chrome-192x192.png +0 -0
  2. package/assets/lux-site-icons/android-chrome-512x512.png +0 -0
  3. package/assets/lux-site-icons/apple-touch-icon.png +0 -0
  4. package/assets/lux-site-icons/favicon-16x16.png +0 -0
  5. package/assets/lux-site-icons/favicon-32x32.png +0 -0
  6. package/assets/lux-site-icons/favicon.ico +0 -0
  7. package/assets/standard-docs/LUX-NFT-Terms-and-Conditions.pdf +0 -0
  8. package/assets/standard-docs/LUX-Privacy-Policy.pdf +0 -0
  9. package/blocks/components/card-block.tsx +1 -1
  10. package/blocks/components/screenful-block/index.tsx +11 -1
  11. package/common/chat-widget.tsx +75 -0
  12. package/common/contact-dialog/contact-form.tsx +111 -0
  13. package/common/contact-dialog/disclaimer.tsx +13 -0
  14. package/common/contact-dialog/index.tsx +48 -0
  15. package/common/copyright.tsx +21 -0
  16. package/common/drawer-menu.tsx +54 -0
  17. package/common/footer.tsx +77 -0
  18. package/common/head-metadata/from-next/metadata-types.ts +158 -0
  19. package/common/head-metadata/from-next/opengraph-types.ts +267 -0
  20. package/common/head-metadata/from-next/twitter-types.ts +92 -0
  21. package/common/head-metadata/index.tsx +208 -0
  22. package/common/header/index.tsx +66 -0
  23. package/common/header/mobile-nav.tsx +72 -0
  24. package/common/header/theme-toggle.tsx +26 -0
  25. package/common/icons/index.tsx +34 -0
  26. package/common/icons/lux-logo.tsx +10 -0
  27. package/common/icons/secure-delivery.tsx +13 -0
  28. package/common/icons/social-icon.tsx +35 -0
  29. package/common/index.ts +14 -0
  30. package/common/logo.tsx +71 -0
  31. package/common/mini-chart/index.tsx +8 -0
  32. package/common/mini-chart/mini-chart-props.ts +44 -0
  33. package/common/mini-chart/mini-chart.tsx +76 -0
  34. package/common/mini-chart/wrapper.tsx +23 -0
  35. package/context-providers/index.ts +1 -0
  36. package/{style → context-providers}/theme-provider.tsx +2 -2
  37. package/next/README.md +11 -0
  38. package/next/analytics/fpixel.ts +18 -0
  39. package/next/analytics/pixel-analytics.tsx +55 -0
  40. package/next/determine-device-middleware.ts +16 -0
  41. package/next/fonts/DrukTextWide-Bold-Trial.otf +0 -0
  42. package/next/fonts/DrukTextWide-Heavy-Trial.otf +0 -0
  43. package/next/fonts/DrukTextWide-Medium-Trial.otf +0 -0
  44. package/next/fonts/DrukWide-Bold-Trial.otf +0 -0
  45. package/next/fonts/DrukWide-Heavy-Trial.otf +0 -0
  46. package/next/fonts/DrukWide-Medium-Trial.otf +0 -0
  47. package/next/get-app-router-font-classes.ts +12 -0
  48. package/next/load-and-return-lux-next-fonts-on-import.ts +94 -0
  49. package/next/next-font-desc.ts +28 -0
  50. package/next/not-found-content.mdx +5 -0
  51. package/next/not-found.tsx +23 -0
  52. package/next/pages-router-font-vars.tsx +18 -0
  53. package/next/root-layout.tsx +62 -0
  54. package/package.json +12 -9
  55. package/primitives/carousel.tsx +263 -0
  56. package/primitives/index.ts +8 -1
  57. package/primitives/toggle-group.tsx +1 -1
  58. package/primitives/youtube-embed.tsx +1 -1
  59. package/siteDef/footer/community.tsx +67 -0
  60. package/siteDef/footer/company.ts +37 -0
  61. package/siteDef/footer/ecosystem.ts +37 -0
  62. package/siteDef/footer/index.tsx +26 -0
  63. package/siteDef/footer/legal.ts +28 -0
  64. package/siteDef/footer/network.ts +37 -0
  65. package/siteDef/footer/svg/warpcast-logo.svg +12 -0
  66. package/siteDef/main-nav.ts +35 -0
  67. package/style/hanzo-default-colors.css +2 -2
  68. package/style/social-svg.css +3 -0
  69. package/tailwind/{fontSize.tailwind.ts → fonts.tailwind.ts} +19 -1
  70. package/tailwind/index.ts +15 -4
  71. package/tailwind/lux-tw-fonts.ts +37 -0
  72. package/tailwind/{tailwind.config.hanzo-preset.js → tailwind.config.base.js} +2 -4
  73. package/tailwind/typo-plugin/get-plugin-styles.js +42 -42
  74. package/tailwind/typography-test.mdx +1 -1
  75. package/types/index.ts +15 -5
  76. package/types/site-def.ts +36 -0
  77. package/primitives/icons/index.ts +0 -18
  78. package/tailwind/fontFamily.tailwind.ts +0 -7
  79. package/tailwind/tailwind.config.hanzo-preset.d.ts +0 -5
  80. /package/{primitives → common}/icons/github.tsx +0 -0
  81. /package/{primitives → common}/icons/youtube-logo.tsx +0 -0
@@ -0,0 +1,26 @@
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+ import { Moon, Sun } from 'lucide-react'
5
+ import { useTheme } from 'next-themes'
6
+
7
+ import { Button } from '../../primitives'
8
+
9
+ const ThemeToggle: React.FC = () => {
10
+
11
+ const { setTheme, theme } = useTheme()
12
+
13
+ return (
14
+ <Button
15
+ variant='ghost'
16
+ size='icon'
17
+ onClick={() => {setTheme(theme === 'light' ? 'dark' : 'light')}}
18
+ >
19
+ <Sun className='h-[1.5rem] w-[1.3rem] dark:hidden' />
20
+ <Moon className='hidden h-5 w-5 dark:block' />
21
+ <span className='sr-only'>Toggle theme</span>
22
+ </Button>
23
+ )
24
+ }
25
+
26
+ export default ThemeToggle
@@ -0,0 +1,34 @@
1
+ import {
2
+ Moon as moon,
3
+ SunMedium as sun,
4
+ Menu as burger,
5
+ ArrowUpRight as linkOut,
6
+ type XIcon as LucideIcon,
7
+ } from 'lucide-react'
8
+
9
+ import gitHub from './github'
10
+ import logo from './lux-logo'
11
+ import youtube from './youtube-logo'
12
+ import secureDelivery from './secure-delivery'
13
+
14
+ import {
15
+ type SocialIconProps,
16
+ default as SocialIcon
17
+ } from './social-icon'
18
+
19
+ export { type LucideIcon as Icon, type SocialIconProps }
20
+
21
+
22
+ export {
23
+ sun,
24
+ moon,
25
+ logo,
26
+ burger,
27
+ gitHub,
28
+ linkOut,
29
+ youtube,
30
+ secureDelivery,
31
+ SocialIcon,
32
+ }
33
+
34
+
@@ -0,0 +1,10 @@
1
+ import React from 'react'
2
+ import { type LucideProps } from 'lucide-react'
3
+
4
+ const LuxLogo: React.FC<LucideProps> = (props: LucideProps) => (
5
+ <svg fill='currentColor' viewBox="0 0 260 260" xmlns="http://www.w3.org/2000/svg" {...props}>
6
+ <path d="M5,5H265L135,230"/>
7
+ </svg>
8
+ )
9
+
10
+ export default LuxLogo
@@ -0,0 +1,13 @@
1
+ import React from 'react'
2
+ import { type LucideProps } from 'lucide-react'
3
+
4
+ // width="52" height="36"
5
+ const SecureDelivery: React.FC<LucideProps> = (props: LucideProps) => (
6
+ <svg fill="currentColor" viewBox="0 0 52 36" xmlns="http://www.w3.org/2000/svg" {...props}>
7
+ <path d="M47.7611 24.5439H42.822L39.5293 14.9971H12.0732L8.7805 24.5439H2.96342L0 36.0001H51.7127L47.7611 24.5439ZM38.4147 16.9064L41.0488 24.5439H28.0049L25.3708 16.9064H38.4147ZM13.1879 16.9064H23.5976L26.2317 24.5439H10.5528L13.1879 16.9064ZM2.21225 34.0907L4.18786 26.4532H14.4865L16.4621 34.0907H2.21225ZM17.6804 32.1537L16.2061 26.4531H19.646L17.6804 32.1537ZM28.2706 34.0907H18.7854L21.4196 26.4532H31.8293L34.4634 34.0907H28.2706ZM36.2367 34.0907L33.6025 26.4532H46.6473L49.2814 34.0907H36.2367Z" />
8
+ <path d="M10.0843 0.108973C10.1056 -0.0363242 10.2915 -0.0363242 10.3128 0.108973L10.5061 1.43021C10.9095 4.18489 12.8287 6.34425 15.2772 6.79764L16.4515 7.01512C16.5808 7.03912 16.5808 7.24823 16.4515 7.27223L15.2772 7.4897C12.8286 7.94345 10.9091 10.1026 10.5061 12.8571L10.3128 14.1782C10.2915 14.3237 10.1056 14.3237 10.0843 14.1782L9.89096 12.8571C9.48763 10.1025 7.56837 7.9431 5.11989 7.4897L3.94562 7.27223C3.8163 7.24823 3.8163 7.03912 3.94562 7.01512L5.11989 6.79764C7.5685 6.3439 9.48794 4.18475 9.89096 1.43021L10.0843 0.108973Z" />
9
+ <path d="M22.034 0.0726485C22.0473 -0.0242162 22.1635 -0.0242162 22.1768 0.0726485L22.2977 0.953473C22.5497 2.78993 23.7493 4.2295 25.2796 4.53176L26.0135 4.67675C26.0943 4.69275 26.0943 4.83215 26.0135 4.84815L25.2796 4.99314C23.7492 5.29563 22.5495 6.73507 22.2977 8.57142L22.1768 9.45212C22.1635 9.54911 22.0473 9.54911 22.034 9.45212L21.9132 8.57142C21.6611 6.73497 20.4616 5.2954 18.9313 4.99314L18.1973 4.84815C18.1165 4.83215 18.1165 4.69275 18.1973 4.67675L18.9313 4.53176C20.4616 4.22926 21.6613 2.78983 21.9132 0.953473L22.034 0.0726485Z" />
10
+ </svg>
11
+ )
12
+
13
+ export default SecureDelivery
@@ -0,0 +1,35 @@
1
+ import React from 'react'
2
+
3
+ import { SocialIcon as BaseSocialIcon } from 'react-social-icons'
4
+
5
+ import { cn } from '../../util'
6
+ import '../../style/social-svg.css'
7
+
8
+ interface SocialIconProps {
9
+ // one of these: https://github.com/couetilc/react-social-icons/tree/main/db
10
+ network: string
11
+ size: number
12
+ className?: string
13
+ }
14
+
15
+ const SocialIcon: React.FC<SocialIconProps> = ({
16
+ network,
17
+ size,
18
+ className = ''
19
+ }) => (
20
+ <BaseSocialIcon
21
+ network={network}
22
+ as='div'
23
+ // This is set up so the enclosing element sets the color.
24
+ // For example, something like 'color-foreground hover:color-muted-1'
25
+ className={cn('color-inherit', className)}
26
+ bgColor='transparent'
27
+ fgColor='currentColor'
28
+ style={{height: size, width: size}}
29
+ />
30
+ )
31
+
32
+ export {
33
+ type SocialIconProps,
34
+ SocialIcon as default
35
+ }
@@ -0,0 +1,14 @@
1
+ export { default as ChatWidget } from './chat-widget'
2
+ export { default as ContactDialog } from './contact-dialog'
3
+ export { default as Copyright} from './copyright'
4
+ export { default as DrawerMenu } from './drawer-menu'
5
+ export { default as Footer } from './footer'
6
+ export { default as Header } from './header'
7
+ export {
8
+ default as HeadMetadata,
9
+ getTitleFromTemplateString,
10
+ TwitterComponent
11
+ } from './head-metadata'
12
+ export * as Icons from './icons'
13
+ export { default as Logo } from './logo'
14
+ export { default as MiniChart } from './mini-chart'
@@ -0,0 +1,71 @@
1
+ import React from 'react'
2
+ import Link from 'next/link'
3
+
4
+ import { type TShirtSize } from '../types'
5
+ import { cn } from '../util'
6
+ import { Icons } from '.'
7
+
8
+ const Logo: React.FC<{
9
+ size?: TShirtSize
10
+ logoOnly?: boolean
11
+ href?: string
12
+ className?: string
13
+ }> = ({
14
+ size,
15
+ href, // no default please!
16
+ className='',
17
+ logoOnly=false
18
+ }) => {
19
+ let classes: any = {}
20
+ const toAdd = (logoOnly) ? {
21
+ span: ' hidden',
22
+ icon: ' mr-r'
23
+ } : {
24
+ span: '',
25
+ icon: ''
26
+ }
27
+ if (size === 'lg' || size === 'xl' ) { // for safety
28
+ classes.icon = 'h-10 w-10 mr-4 color-inherit' + toAdd.icon
29
+ classes.span = 'text-3xl' + toAdd.span
30
+ }
31
+ // match lux.network
32
+ else if (size === 'md') {
33
+ classes.icon = 'h-[32px] w-[32px] mr-[12px] color-inherit' + toAdd.icon
34
+ classes.span = 'text-[26px]/[26px] tracking-tighter' + toAdd.span
35
+ }
36
+ else if (size === 'sm' ) {
37
+ classes.icon = 'h-6 w-6 mr-2 color-inherit' + toAdd.icon
38
+ classes.span = 'text-lg' + toAdd.span
39
+ }
40
+ // xs
41
+ else {
42
+ classes.icon = 'h-4 w-4 mr-1 color-inherit' + toAdd.icon
43
+ classes.span = 'text-base' + toAdd.span
44
+ }
45
+
46
+ const outerClasses = 'flex flex-row items-center ' + className
47
+ const spanClasses = 'inline-block font-bold font-heading '
48
+ + (href ? 'hover:text-accent ' : 'cursor-default ')
49
+ + classes.span
50
+
51
+ const Inner: React.FC = () => (<>
52
+ <Icons.logo className={classes.icon} />
53
+ <span className={cn(spanClasses, ' text-inherit')}>LUX</span>
54
+ </>)
55
+
56
+
57
+ return (
58
+ href ? (
59
+ <Link href={href} className={outerClasses} >
60
+ <Inner />
61
+ </Link>
62
+
63
+ ) : (
64
+ <span className={outerClasses} >
65
+ <Inner />
66
+ </span>
67
+ )
68
+ )
69
+ }
70
+
71
+ export default Logo
@@ -0,0 +1,8 @@
1
+ import MiniChart from './wrapper'
2
+ // import { type MiniChartProps, type MiniChartDateRanges } from './mini-chart-props'
3
+
4
+ export {
5
+ MiniChart as default,
6
+ // type MiniChartProps,
7
+ // type MiniChartDateRanges
8
+ }
@@ -0,0 +1,44 @@
1
+ import type { CSSProperties } from 'react'
2
+
3
+ // https://www.typescriptlang.org/docs/handbook/enums.html#enums-at-runtime
4
+ const enum MiniChartDateRangesValues {
5
+ '1D',
6
+ '1M',
7
+ '3M',
8
+ '12M',
9
+ '60M',
10
+ 'ALL',
11
+ }
12
+
13
+ type MiniChartDateRanges = keyof typeof MiniChartDateRangesValues
14
+
15
+ interface MiniChartBaseProps {
16
+ symbol: string
17
+ exchange?: string
18
+ dateRange: MiniChartDateRanges
19
+ noTimeScale?: boolean
20
+ width?: number | string
21
+ height?: number | string
22
+ locale?: string
23
+ colorTheme?: "light" | "dark"
24
+ // @ts-ignore // TODO
25
+ lineColor?: CSSProperties["color"]
26
+ // @ts-ignore // TODO
27
+ topGradientColor?: CSSProperties["color"]
28
+ // @ts-ignore // TODO
29
+ bottomGradientColor?: CSSProperties["color"]
30
+ isTransparent?: boolean
31
+ autosize?: boolean
32
+ chartOnly?: boolean
33
+ largeChartUrl?: string
34
+ }
35
+
36
+ type MiniChartProps = {
37
+ widgetProps: MiniChartBaseProps
38
+ containerStyles?: CSSProperties
39
+ }
40
+
41
+ export {
42
+ type MiniChartProps,
43
+ type MiniChartDateRanges
44
+ }
@@ -0,0 +1,76 @@
1
+ 'use client'
2
+
3
+ import React, { useEffect, useRef } from 'react'
4
+ import { type MiniChartProps } from './mini-chart-props'
5
+
6
+ const MiniChart: React.FC<MiniChartProps> = ({
7
+ widgetProps,
8
+ containerStyles = {}
9
+ }) => {
10
+
11
+ const {
12
+ symbol,
13
+ exchange,
14
+ lineColor,
15
+ topGradientColor,
16
+ bottomGradientColor,
17
+ width,
18
+ height,
19
+ autosize,
20
+ locale,
21
+ ...rest
22
+ } = widgetProps
23
+
24
+ const symbolString = (exchange) ? `${exchange}:${symbol}` : symbol
25
+
26
+ const containerRef = useRef<HTMLDivElement | null>(null)
27
+
28
+ useEffect(() => {
29
+ if (!containerRef.current) {
30
+ return
31
+ }
32
+ const script = document.createElement('script')
33
+ script.type = 'text/javascript'
34
+ script.src = 'https://s3.tradingview.com/external-embedding/embed-widget-mini-symbol-overview.js'
35
+ script.async = true
36
+ script.onload = async () => {
37
+ const iframe = containerRef.current?.querySelector('iframe')
38
+ if (iframe && iframe instanceof Element) iframe.style.colorScheme = 'normal'
39
+
40
+ const copyDiv = document.querySelector('.tradingview-widget-copyright')
41
+ if (copyDiv) {
42
+ setTimeout(() => {
43
+ copyDiv.classList.remove('invisible')
44
+ }, 1200) // from experimentation
45
+ }
46
+ }
47
+ const config = JSON.stringify({
48
+ symbol: symbolString,
49
+ width: autosize ? '100%' : (width || 350),
50
+ height: autosize ? '100%' : (height || 220),
51
+ locale: locale ?? 'en',
52
+ isTransparent: 'true',
53
+ trendLineColor: lineColor || 'rgba(41, 98, 255, 1)',
54
+ underLineColor: topGradientColor || 'rgba(41, 98, 255, 0.3)',
55
+ underLineBottomColor: bottomGradientColor || 'rgba(41, 98, 255, 0)',
56
+ ...rest,
57
+ })
58
+ script.innerHTML = config
59
+ containerRef.current.appendChild(script)
60
+ return () => {
61
+ while (containerRef.current?.firstChild) {
62
+ containerRef.current.removeChild(containerRef.current.firstChild)
63
+ }
64
+ }
65
+ }, [ JSON.stringify(widgetProps) ])
66
+
67
+ return (<>
68
+ <div style={containerStyles} className='tradingview-widget-container h-[150px]' ref={containerRef} />
69
+ <div className='tradingview-widget-copyright border-t w-full invisible'>
70
+ <a href={`https://www.tradingview.com/symbols/${symbol}${exchange ? `/?exchange=${exchange}` : '' }`} rel="noopener" target="_blank">
71
+ <span className="text-[--secondary-2]">{symbol} quotes</span></a>&nbsp;by TradingView
72
+ </div>
73
+ </>)
74
+ }
75
+
76
+ export default MiniChart
@@ -0,0 +1,23 @@
1
+ import React from 'react'
2
+
3
+ import BaseChart from './mini-chart'
4
+
5
+ const Wrapper: React.FC<{
6
+ symbol: string,
7
+ exchange?: string
8
+ }> = ({
9
+ symbol,
10
+ exchange
11
+ }) => (
12
+ <BaseChart widgetProps ={{
13
+ symbol,
14
+ exchange,
15
+ autosize: true,
16
+ colorTheme: 'dark',
17
+ lineColor: "rgb(114, 27, 228)",
18
+ bottomGradientColor: "rgba(255, 255, 255, 0.1)",
19
+ dateRange: '60M',
20
+ }}/>
21
+ )
22
+
23
+ export default Wrapper
@@ -0,0 +1 @@
1
+ export { default as ThemeProvider } from './theme-provider'
@@ -9,8 +9,8 @@ const ThemeProvider: React.FC<ThemeProviderProps> = ({ children, ...props }) =>
9
9
  attribute="class"
10
10
  {...props}
11
11
  value={{
12
- light: 'hanzo-ui-light-theme',
13
- dark: 'hanzo-ui-dark-theme'
12
+ light: 'lux-light-theme',
13
+ dark: 'lux-dark-theme'
14
14
  }}
15
15
  >
16
16
  {children}
package/next/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # Next related Lux helpers
2
+
3
+ ### no `index.ts` file, and `load-and-return-lux-next-fonts-on-import.ts`
4
+
5
+ Next font loading requires the fonts to be assigned to const's in module scope (ie, loaded when the module is evaluated, exactly once).
6
+
7
+ If there was an `index.ts` "barrel file", and the client code imported anything from this package, it would have resulted in evaluting all the packages imported including the that loaded the fonts. Without the index, the client code knows what modules import it and thus when it happens.
8
+
9
+ tl;dr: See [this article from Vercel](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js) about this issue.
10
+
11
+ (Previously, not having this safegaurd caused a serious bug becuase the fonts were loaded far too early.)
@@ -0,0 +1,18 @@
1
+ declare global {
2
+ interface Window {
3
+ fbq: Function;
4
+ }
5
+ }
6
+
7
+ export const FB_PIXEL_ID = process.env.NEXT_PUBLIC_FACEBOOK_PIXEL_ID
8
+
9
+ export const pageview = () => {
10
+ // @ts-ignore
11
+ window.fbq('track', 'PageView')
12
+ }
13
+
14
+ // https://developers.facebook.com/docs/facebook-pixel/advanced/
15
+ export const event = (name: string, options = {}) => {
16
+ // @ts-ignore
17
+ window.fbq('track', name, options)
18
+ }
@@ -0,0 +1,55 @@
1
+ 'use client'
2
+
3
+ import { usePathname } from 'next/navigation'
4
+ import Script from 'next/script'
5
+ import { useEffect, useState } from 'react'
6
+ import * as fbq from './fpixel'
7
+
8
+ const FacebookPixelHead = () => {
9
+ return (
10
+ <noscript>
11
+ <img
12
+ height='1'
13
+ width='1'
14
+ style={{ display: 'none' }}
15
+ src={`https://www.facebook.com/tr?id=${fbq.FB_PIXEL_ID}&ev=PageView&noscript=1`}
16
+ />
17
+ </noscript>
18
+ )
19
+ }
20
+
21
+ const FacebookPixel = () => {
22
+ const [loaded, setLoaded] = useState(false)
23
+ const pathname = usePathname()
24
+
25
+ useEffect(() => {
26
+ if (!loaded) return
27
+
28
+ fbq.pageview()
29
+ }, [pathname, loaded])
30
+
31
+ return (
32
+ <div>
33
+ <Script
34
+ id='fb-pixel'
35
+ strategy='afterInteractive'
36
+ onLoad={() => setLoaded(true)}
37
+ dangerouslySetInnerHTML={{
38
+ __html: `
39
+ !function(f,b,e,v,n,t,s)
40
+ {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
41
+ n.callMethod.apply(n,arguments):n.queue.push(arguments)};
42
+ if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
43
+ n.queue=[];t=b.createElement(e);t.async=!0;
44
+ t.src=v;s=b.getElementsByTagName(e)[0];
45
+ s.parentNode.insertBefore(t,s)}(window, document,'script',
46
+ 'https://connect.facebook.net/en_US/fbevents.js');
47
+ fbq('init', ${fbq.FB_PIXEL_ID});
48
+ `,
49
+ }}
50
+ />
51
+ </div>
52
+ )
53
+ }
54
+
55
+ export {FacebookPixelHead, FacebookPixel}
@@ -0,0 +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 determineDeviceMiddleware = 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 determineDeviceMiddleware
@@ -0,0 +1,12 @@
1
+ import nextFonts from './load-and-return-lux-next-fonts-on-import'
2
+ import type NextFontDesc from './next-font-desc'
3
+
4
+ // These will be injected for <body> in app router app that uses our RootLayout
5
+
6
+ // First is assumed to be mapped to the default font and is injected into <body>
7
+ // as a normal tw font family class.
8
+ export default () => (
9
+ nextFonts.map(
10
+ (desc: NextFontDesc) => (desc.nextFont!.variable)
11
+ ).join(' ') + ` font-${nextFonts[0].twName}`
12
+ )
@@ -0,0 +1,94 @@
1
+ import { Inter } from 'next/font/google'
2
+ import localFont from 'next/font/local'
3
+
4
+ import type NextFontDesc from './next-font-desc'
5
+ import type TwFontDesc from '../tailwind/tw-font-desc'
6
+
7
+ import twFonts from '../tailwind/lux-tw-fonts'
8
+
9
+ /*
10
+ Creating NextFontDesc's and TwFontDesc's has to be seperated because they are needed
11
+ at different times during the next compile / build. Otherwise a nasty
12
+ race condition happens!
13
+
14
+ Also, requires that "Font loaders must be called and assigned to a const in the module scope"
15
+
16
+ */
17
+
18
+ const drukTextWide = localFont({
19
+ src: [
20
+ {
21
+ path: './fonts/DrukTextWide-Medium-Trial.otf',
22
+ weight: '500',
23
+ style: 'normal'
24
+ },
25
+ {
26
+ path: './fonts/DrukTextWide-Bold-Trial.otf',
27
+ weight: '700',
28
+ style: 'normal'
29
+ },
30
+ {
31
+ path: './fonts/DrukTextWide-Heavy-Trial.otf',
32
+ weight: '800',
33
+ style: 'normal',
34
+ },
35
+ ],
36
+ display: 'swap',
37
+ variable: '--font-druk-text-wide' ,
38
+ })
39
+
40
+ const drukWide = localFont({
41
+ src: [
42
+ {
43
+ path: './fonts/DrukWide-Medium-Trial.otf',
44
+ weight: '500',
45
+ style: 'normal'
46
+ },
47
+ {
48
+ path: './fonts/DrukWide-Bold-Trial.otf',
49
+ weight: '700',
50
+ style: 'normal'
51
+ },
52
+ {
53
+ path: './fonts/DrukWide-Heavy-Trial.otf',
54
+ weight: '500',
55
+ style: 'normal',
56
+ },
57
+ ],
58
+ display: 'swap',
59
+ variable: '--font-druk-wide' ,
60
+ })
61
+
62
+ const inter = Inter({
63
+ subsets: ["latin"],
64
+ variable: "--font-inter",
65
+ })
66
+
67
+ export default [
68
+ {
69
+ font: inter,
70
+ twName: 'sans'
71
+ },
72
+ {
73
+ font: drukTextWide,
74
+ twName: 'nav'
75
+ },
76
+ {
77
+ font: drukWide,
78
+ twName: 'heading'
79
+ }
80
+ ].map (
81
+ (el) => {
82
+ const twFont: TwFontDesc | undefined = twFonts.find((twf: TwFontDesc) => (el.twName === twf.twName))
83
+ if (!twFont) {
84
+ throw new Error('lux-next-fonts: Next font is not paired to a TW font!')
85
+ }
86
+
87
+ return ({
88
+ ...twFont,
89
+ nextFont: el.font,
90
+ })
91
+ }
92
+ ) as NextFontDesc[]
93
+
94
+
@@ -0,0 +1,28 @@
1
+ import type TwFontDesc from '../tailwind/tw-font-desc'
2
+
3
+ // from next repo
4
+ type NextFont = {
5
+ className: string
6
+ style: { fontFamily: string; fontWeight?: number; fontStyle?: string }
7
+ }
8
+
9
+ // from next repo
10
+ type NextFontWithVariable = NextFont & {
11
+ variable: string
12
+ }
13
+
14
+
15
+ /*
16
+ NextFontDesc and TwFontDesc have to be seperate because they are needed
17
+ at different times during the next compile / build. Otherwise a nasty
18
+ race condition happens! That's why they are in different files.
19
+ */
20
+
21
+ interface NextFontDesc extends TwFontDesc {
22
+ nextFont: NextFontWithVariable
23
+ }
24
+
25
+ export {
26
+ type NextFontDesc as default,
27
+ type NextFontWithVariable,
28
+ }
@@ -0,0 +1,5 @@
1
+ ### ...Huh?
2
+ #### Sorry, we're fresh out of those.
3
+ <br/>
4
+ #### ...try something from the [Home Page](/)?
5
+
@@ -0,0 +1,23 @@
1
+ import React from 'react'
2
+
3
+ import Main from '../primitives/main'
4
+ import Footer from '../common/footer'
5
+ import { ApplyTypography } from '../primitives'
6
+
7
+ import NotFoundMDX from './not-found-content.mdx'
8
+ import type { SiteDef } from '../types'
9
+
10
+ const NotFound: React.FC<{
11
+ siteDef: SiteDef
12
+ }> = ({
13
+ siteDef
14
+ }) => (<>
15
+ <Main className='xs:h-[100svh] xs:px-8 sm:px-10 sm:h-[700px]'>
16
+ <ApplyTypography className='mt-[200px] flex flex-col md:gap-8 '>
17
+ <NotFoundMDX />
18
+ </ApplyTypography>
19
+ </Main>
20
+ <Footer siteDef={siteDef}/>
21
+ </>)
22
+
23
+ export default NotFound