@hanzogui/logo 2.0.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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/GuiLogo.cjs +55 -0
  3. package/dist/cjs/GuiLogo.native.js +61 -0
  4. package/dist/cjs/GuiLogo.native.js.map +1 -0
  5. package/dist/cjs/GuiLogoSvg.cjs +72 -0
  6. package/dist/cjs/GuiLogoSvg.native.js +78 -0
  7. package/dist/cjs/GuiLogoSvg.native.js.map +1 -0
  8. package/dist/cjs/LogoIcon.cjs +47 -0
  9. package/dist/cjs/LogoIcon.native.js +53 -0
  10. package/dist/cjs/LogoIcon.native.js.map +1 -0
  11. package/dist/cjs/LogoWords.cjs +143 -0
  12. package/dist/cjs/LogoWords.native.js +175 -0
  13. package/dist/cjs/LogoWords.native.js.map +1 -0
  14. package/dist/cjs/SeasonProvider.cjs +41 -0
  15. package/dist/cjs/SeasonProvider.native.js +52 -0
  16. package/dist/cjs/SeasonProvider.native.js.map +1 -0
  17. package/dist/cjs/ThemeTint.cjs +54 -0
  18. package/dist/cjs/ThemeTint.native.js +60 -0
  19. package/dist/cjs/ThemeTint.native.js.map +1 -0
  20. package/dist/cjs/index.cjs +24 -0
  21. package/dist/cjs/index.native.js +27 -0
  22. package/dist/cjs/index.native.js.map +1 -0
  23. package/dist/cjs/tints.cjs +88 -0
  24. package/dist/cjs/tints.native.js +97 -0
  25. package/dist/cjs/tints.native.js.map +1 -0
  26. package/dist/cjs/useTint.cjs +103 -0
  27. package/dist/cjs/useTint.native.js +119 -0
  28. package/dist/cjs/useTint.native.js.map +1 -0
  29. package/dist/esm/GuiLogo.mjs +32 -0
  30. package/dist/esm/GuiLogo.mjs.map +1 -0
  31. package/dist/esm/GuiLogo.native.js +35 -0
  32. package/dist/esm/GuiLogo.native.js.map +1 -0
  33. package/dist/esm/GuiLogoSvg.mjs +49 -0
  34. package/dist/esm/GuiLogoSvg.mjs.map +1 -0
  35. package/dist/esm/GuiLogoSvg.native.js +52 -0
  36. package/dist/esm/GuiLogoSvg.native.js.map +1 -0
  37. package/dist/esm/LogoIcon.mjs +24 -0
  38. package/dist/esm/LogoIcon.mjs.map +1 -0
  39. package/dist/esm/LogoIcon.native.js +27 -0
  40. package/dist/esm/LogoIcon.native.js.map +1 -0
  41. package/dist/esm/LogoWords.mjs +109 -0
  42. package/dist/esm/LogoWords.mjs.map +1 -0
  43. package/dist/esm/LogoWords.native.js +138 -0
  44. package/dist/esm/LogoWords.native.js.map +1 -0
  45. package/dist/esm/SeasonProvider.mjs +18 -0
  46. package/dist/esm/SeasonProvider.mjs.map +1 -0
  47. package/dist/esm/SeasonProvider.native.js +26 -0
  48. package/dist/esm/SeasonProvider.native.js.map +1 -0
  49. package/dist/esm/ThemeTint.mjs +30 -0
  50. package/dist/esm/ThemeTint.mjs.map +1 -0
  51. package/dist/esm/ThemeTint.native.js +33 -0
  52. package/dist/esm/ThemeTint.native.js.map +1 -0
  53. package/dist/esm/index.js +8 -0
  54. package/dist/esm/index.js.map +1 -0
  55. package/dist/esm/index.mjs +8 -0
  56. package/dist/esm/index.mjs.map +1 -0
  57. package/dist/esm/index.native.js +8 -0
  58. package/dist/esm/index.native.js.map +1 -0
  59. package/dist/esm/tints.mjs +50 -0
  60. package/dist/esm/tints.mjs.map +1 -0
  61. package/dist/esm/tints.native.js +56 -0
  62. package/dist/esm/tints.native.js.map +1 -0
  63. package/dist/esm/useTint.mjs +63 -0
  64. package/dist/esm/useTint.mjs.map +1 -0
  65. package/dist/esm/useTint.native.js +76 -0
  66. package/dist/esm/useTint.native.js.map +1 -0
  67. package/icon/index.js +1 -0
  68. package/icon/index.native.js +1 -0
  69. package/icon.cjs +1 -0
  70. package/package.json +58 -0
  71. package/src/GuiLogo.tsx +40 -0
  72. package/src/GuiLogoSvg.tsx +27 -0
  73. package/src/LogoIcon.tsx +31 -0
  74. package/src/LogoWords.tsx +186 -0
  75. package/src/SeasonProvider.tsx +57 -0
  76. package/src/ThemeTint.tsx +32 -0
  77. package/src/index.tsx +7 -0
  78. package/src/tints.tsx +112 -0
  79. package/src/useTint.tsx +116 -0
  80. package/types/GuiLogo.d.ts +13 -0
  81. package/types/GuiLogo.d.ts.map +11 -0
  82. package/types/GuiLogoSvg.d.ts +8 -0
  83. package/types/GuiLogoSvg.d.ts.map +11 -0
  84. package/types/LogoIcon.d.ts +7 -0
  85. package/types/LogoIcon.d.ts.map +11 -0
  86. package/types/LogoWords.d.ts +8 -0
  87. package/types/LogoWords.d.ts.map +11 -0
  88. package/types/SeasonProvider.d.ts +6 -0
  89. package/types/SeasonProvider.d.ts.map +11 -0
  90. package/types/ThemeTint.d.ts +11 -0
  91. package/types/ThemeTint.d.ts.map +11 -0
  92. package/types/index.d.ts +9 -0
  93. package/types/index.d.ts.map +11 -0
  94. package/types/tints.d.ts +31 -0
  95. package/types/tints.d.ts.map +11 -0
  96. package/types/useTint.d.ts +31 -0
  97. package/types/useTint.d.ts.map +11 -0
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@hanzogui/logo",
3
+ "version": "2.0.0",
4
+ "source": "src/index.tsx",
5
+ "files": [
6
+ "src",
7
+ "types",
8
+ "dist",
9
+ "*.cjs",
10
+ "icon"
11
+ ],
12
+ "type": "module",
13
+ "main": "dist/cjs",
14
+ "module": "dist/esm",
15
+ "types": "./types/index.d.ts",
16
+ "exports": {
17
+ "./package.json": "./package.json",
18
+ ".": {
19
+ "types": "./types/index.d.ts",
20
+ "react-native": "./dist/esm/index.native.js",
21
+ "browser": "./dist/esm/index.mjs",
22
+ "module": "./dist/esm/index.mjs",
23
+ "import": "./dist/esm/index.mjs",
24
+ "require": "./dist/cjs/index.cjs",
25
+ "default": "./dist/esm/index.mjs"
26
+ },
27
+ "./icon": {
28
+ "types": "./types/LogoIcon.d.ts",
29
+ "react-native": "./dist/esm/LogoIcon.native.js",
30
+ "browser": "./dist/esm/LogoIcon.mjs",
31
+ "module": "./dist/esm/LogoIcon.mjs",
32
+ "import": "./dist/esm/LogoIcon.mjs",
33
+ "require": "./dist/cjs/LogoIcon.cjs",
34
+ "default": "./dist/cjs/LogoIcon.native.js"
35
+ }
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "scripts": {
41
+ "build": "hanzo-gui-build",
42
+ "watch": "hanzo-gui-build --watch",
43
+ "clean": "hanzo-gui-build clean",
44
+ "clean:build": "hanzo-gui-build clean:build"
45
+ },
46
+ "dependencies": {
47
+ "@hanzogui/use-element-layout": "workspace:*",
48
+ "@hanzogui/web": "workspace:*",
49
+ "@hanzo/gui": "workspace:*"
50
+ },
51
+ "devDependencies": {
52
+ "@hanzogui/build": "workspace:*",
53
+ "react": ">=19"
54
+ },
55
+ "peerDependencies": {
56
+ "react": ">=19"
57
+ }
58
+ }
@@ -0,0 +1,40 @@
1
+ import type { JSX } from 'react/jsx-runtime'
2
+ import type { XStackProps } from '@hanzo/gui'
3
+ import { XStack, YStack } from '@hanzo/gui'
4
+ import { LogoIcon } from './LogoIcon'
5
+ import { LogoWords } from './LogoWords'
6
+
7
+ type LogoProps = {
8
+ showWords?: boolean
9
+ downscale?: number
10
+ animated?: boolean
11
+ color?: string
12
+ ref?: any
13
+ } & XStackProps
14
+
15
+ export const GuiLogo = ({
16
+ showWords,
17
+ downscale,
18
+ animated,
19
+ color,
20
+ ref,
21
+ ...props
22
+ }: LogoProps): JSX.Element => {
23
+ return (
24
+ <XStack
25
+ render="span"
26
+ ref={ref}
27
+ alignItems="center"
28
+ justifyContent="center"
29
+ gap="$5"
30
+ {...props}
31
+ >
32
+ <LogoIcon downscale={(downscale ?? 1) * (showWords ? 2 : 1.5)} color={color} />
33
+ {showWords && (
34
+ <YStack render="span" marginBottom={-4}>
35
+ <LogoWords animated={animated} downscale={downscale ?? 2} />
36
+ </YStack>
37
+ )}
38
+ </XStack>
39
+ )
40
+ }
@@ -0,0 +1,27 @@
1
+ import type { JSX } from 'react/jsx-runtime'
2
+
3
+ type GuiIconSvgProps = React.SVGProps<SVGSVGElement> & {
4
+ color?: string
5
+ }
6
+
7
+ export const GuiIconSvg = ({
8
+ color = '#ECD20A',
9
+ ...props
10
+ }: GuiIconSvgProps): JSX.Element => (
11
+ <svg width="160px" height="160px" viewBox="0 0 160 160" {...props}>
12
+ <g id="duck" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
13
+ <circle id="Oval" cx="80" cy="80" r="145"></circle>
14
+ <g id="Group-Copy-5">
15
+ <path
16
+ d="M10,110 L10,100 L20,100 L20,90 L30,90 L30,80 L40,80 L40,30 L50,30 L50,10 L70,10 L70,0 L120,0 L120,10 L130,10 L130,20 L140,20 L140,40 L160,40 L160,50 L150,50 L150,60 L160,60 L160,70 L150,70 L150,80 L140,80 L140,100 L150,100 L150,110 L160,110 L160,140 L150,140 L150,150 L130,150 L130,160 L40,160 L40,150 L20,150 L20,140 L10,140 L10,130 L0,130 L0,110 L10,110 Z M90,40 L80,40 L80,50 L90,50 L90,40 Z M120,30 L110,30 L110,40 L120,40 L120,30 Z"
17
+ id="Combined-Shape"
18
+ fill={color}
19
+ ></path>
20
+ <g id="Group" transform="translate(80, 30)" fill="#000000">
21
+ <rect id="Rectangle-Copy-117" x="0" y="10" width="10" height="10"></rect>
22
+ <rect id="Rectangle-Copy-141" x="30" y="0" width="10" height="10"></rect>
23
+ </g>
24
+ </g>
25
+ </g>
26
+ </svg>
27
+ )
@@ -0,0 +1,31 @@
1
+ import { YStack } from '@hanzo/gui'
2
+ import { GuiIconSvg } from './GuiLogoSvg'
3
+ import type { JSX } from 'react/jsx-runtime'
4
+
5
+ export const LogoIcon = ({
6
+ downscale = 2,
7
+ color,
8
+ }: {
9
+ downscale?: number
10
+ color?: string
11
+ }): JSX.Element => {
12
+ return (
13
+ <YStack
14
+ render="span"
15
+ className="unselectable"
16
+ alignSelf="center"
17
+ marginVertical={-10}
18
+ pressStyle={{
19
+ opacity: 0.7,
20
+ scaleX: -1,
21
+ }}
22
+ >
23
+ <GuiIconSvg
24
+ className="gui-icon"
25
+ width={450 / 8 / downscale}
26
+ height={420 / 8 / downscale}
27
+ color={color}
28
+ />
29
+ </YStack>
30
+ )
31
+ }
@@ -0,0 +1,186 @@
1
+ import type { LayoutValue } from '@hanzogui/use-element-layout'
2
+ import React, { useEffect, useState } from 'react'
3
+ import type { XStackProps } from '@hanzo/gui'
4
+ import { Circle, XStack } from '@hanzo/gui'
5
+ import { useTint } from './useTint'
6
+
7
+ // T A M A G U I
8
+ // default: white white white white red green blue
9
+ // hover: yellow yellow yellow color12 red green blue
10
+ const defaultColors = [
11
+ 'var(--color12)',
12
+ 'var(--color12)',
13
+ 'var(--color12)',
14
+ 'var(--color12)',
15
+ 'var(--red9)',
16
+ 'var(--green9)',
17
+ 'var(--blue9)',
18
+ ]
19
+
20
+ const hoveredColors = [
21
+ 'var(--yellow9)',
22
+ 'var(--yellow9)',
23
+ 'var(--yellow9)',
24
+ 'var(--color12)',
25
+ 'var(--red9)',
26
+ 'var(--green9)',
27
+ 'var(--blue9)',
28
+ ]
29
+
30
+ export const LogoWords: React.MemoExoticComponent<
31
+ ({
32
+ downscale,
33
+ animated,
34
+ ...props
35
+ }: XStackProps & {
36
+ downscale?: number
37
+ animated?: boolean
38
+ }) => import('react/jsx-runtime').JSX.Element
39
+ > = React.memo(({ downscale = 1, animated, ...props }) => {
40
+ const Tint = useTint()
41
+ const [hovered, setHovered] = React.useState(false)
42
+ const [mounted, setMounted] = React.useState<'start' | 'animate' | 'done'>('start')
43
+
44
+ const { tintIndex: index } = Tint
45
+
46
+ useEffect(() => {
47
+ const idle = window.requestIdleCallback || setTimeout
48
+ idle(() => {
49
+ setTimeout(() => {
50
+ setMounted('animate')
51
+ }, 50)
52
+
53
+ setTimeout(() => {
54
+ setMounted('done')
55
+ }, 1500)
56
+ })
57
+ }, [])
58
+
59
+ useEffect(() => {
60
+ const handleKeyDown = (event: KeyboardEvent) => {
61
+ const index = Number.parseInt(event.key, 10) - 1 // Convert key to index (0-based)
62
+ if (!Number.isNaN(index) && index >= 0 && index < Tint.tints.length) {
63
+ Tint.setTintIndex(index)
64
+ }
65
+ }
66
+
67
+ window.addEventListener('keydown', handleKeyDown)
68
+
69
+ return () => {
70
+ window.removeEventListener('keydown', handleKeyDown)
71
+ }
72
+ }, [Tint])
73
+
74
+ const getColor = (i: number) => {
75
+ if (hovered) return `var(--${Tint.tints[i]}9)`
76
+ return defaultColors[i]
77
+ }
78
+
79
+ const x = Math.round(
80
+ index * 18.5 + (18 / 2) * (index / defaultColors.length) + 3 + (index === 6 ? -3 : 0)
81
+ )
82
+
83
+ const [layout, setLayout] = useState<LayoutValue>()
84
+
85
+ return (
86
+ <XStack
87
+ onMouseEnter={() => setHovered(true)}
88
+ onMouseLeave={() => setHovered(false)}
89
+ paddingVertical="$2"
90
+ data-tauri-drag-region
91
+ marginVertical="$-2"
92
+ position="relative"
93
+ className="logo-words"
94
+ onLayout={(e) => {
95
+ setLayout(e.nativeEvent.layout as any)
96
+ }}
97
+ // @ts-ignore
98
+ onMouseMove={(e: MouseEvent) => {
99
+ if (!layout) return
100
+ const x = e.clientX - layout.pageX
101
+ // Total width divided into 7 sections (one for each letter)
102
+ const sectionWidth = layout.width / 7
103
+ // Calculate which section we're in (0-6)
104
+ const section = Math.min(6, Math.floor(x / sectionWidth))
105
+ Tint.setTintIndex(section)
106
+ }}
107
+ {...props}
108
+ >
109
+ {animated && (
110
+ <Circle
111
+ transition="medium"
112
+ position="absolute"
113
+ top={0}
114
+ left={0}
115
+ y={mounted === 'start' ? -30 : -4}
116
+ // the last i is less wide
117
+ x={x}
118
+ size={4}
119
+ backgroundColor="$color12"
120
+ />
121
+ )}
122
+
123
+ <svg
124
+ data-tauri-drag-region
125
+ width={373 * (1 / downscale) * 0.3333333}
126
+ height={41 * (1 / downscale) * 0.3333333}
127
+ viewBox="0 0 373 41"
128
+ >
129
+ <polygon
130
+ data-tauri-drag-region
131
+ shapeRendering="crispEdges"
132
+ fill={getColor(0)}
133
+ points="24.3870968 40.1612903 24.3870968 8.67741935 32.2580645 8.67741935 32.2580645 0.806451613 0.774193548 0.806451613 0.774193548 8.67741935 8.64516129 8.67741935 8.64516129 40.1612903"
134
+ // onMouseEnter={() => Tint.setTintIndex(0)}
135
+ />
136
+
137
+ <path
138
+ shapeRendering="crispEdges"
139
+ fill={getColor(1)}
140
+ d="M87.3548387,0.806451613 L87.3548387,8.67741935 L95.2258065,8.67741935 L95.2258065,40.1612903 L79.483871,40.1612903 L79.483871,24.4193548 L71.6129032,24.4193548 L71.6129032,40.1612903 L55.8709677,40.1612903 L55.8709677,8.67741935 L63.7419355,8.67741935 L63.7419355,0.806451613 L87.3548387,0.806451613 Z M79.483871,8.67741935 L71.6129032,8.67741935 L71.6129032,16.5483871 L79.483871,16.5483871 L79.483871,8.67741935 Z"
141
+ fillRule="nonzero"
142
+ // onMouseEnter={() => Tint.setTintIndex(1)}
143
+ />
144
+
145
+ <polygon
146
+ data-tauri-drag-region
147
+ shapeRendering="crispEdges"
148
+ fill={getColor(2)}
149
+ points="130.645161 40.1612903 130.645161 22.4516129 138.516129 22.4516129 138.516129 40.1612903 154.258065 40.1612903 154.258065 0.806451613 142.451613 0.806451613 142.451613 8.67741935 126.709677 8.67741935 126.709677 0.806451613 114.903226 0.806451613 114.903226 40.1612903"
150
+ // onMouseEnter={() => Tint.setTintIndex(2)}
151
+ />
152
+
153
+ <path
154
+ fill={getColor(3)}
155
+ d="M205.419355,0.806451613 L205.419355,8.67741935 L213.290323,8.67741935 L213.290323,40.1612903 L197.548387,40.1612903 L197.548387,24.4193548 L189.677419,24.4193548 L189.677419,40.1612903 L173.935484,40.1612903 L173.935484,8.67741935 L181.806452,8.67741935 L181.806452,0.806451613 L205.419355,0.806451613 Z M197.548387,8.67741935 L189.677419,8.67741935 L189.677419,16.5483871 L197.548387,16.5483871 L197.548387,8.67741935 Z"
156
+ fillRule="nonzero"
157
+ // onMouseEnter={() => Tint.setTintIndex(3)}
158
+ />
159
+
160
+ <polygon
161
+ data-tauri-drag-region
162
+ shapeRendering="crispEdges"
163
+ fill={getColor(4)}
164
+ points="264.451613 40.1612903 264.451613 32.2903226 272.322581 32.2903226 272.322581 16.5483871 256.580645 16.5483871 256.580645 32.2903226 248.709677 32.2903226 248.709677 8.67741935 272.322581 8.67741935 272.322581 0.806451613 240.83871 0.806451613 240.83871 8.67741935 232.967742 8.67741935 232.967742 32.2903226 240.83871 32.2903226 240.83871 40.1612903"
165
+ // onMouseEnter={() => Tint.setTintIndex(4)}
166
+ />
167
+
168
+ <polygon
169
+ data-tauri-drag-region
170
+ shapeRendering="crispEdges"
171
+ fill={getColor(5)}
172
+ points="323.483871 40.1612903 323.483871 32.2903226 331.354839 32.2903226 331.354839 0.806451613 315.612903 0.806451613 315.612903 32.2903226 307.741935 32.2903226 307.741935 0.806451613 292 0.806451613 292 32.2903226 299.870968 32.2903226 299.870968 40.1612903"
173
+ // onMouseEnter={() => Tint.setTintIndex(5)}
174
+ />
175
+
176
+ <polygon
177
+ data-tauri-drag-region
178
+ shapeRendering="crispEdges"
179
+ fill={getColor(6)}
180
+ points="372.677419 40.1612903 372.677419 0.806451613 356.935484 0.806451613 356.935484 40.1612903"
181
+ // onMouseEnter={() => Tint.setTintIndex(6)}
182
+ />
183
+ </svg>
184
+ </XStack>
185
+ )
186
+ })
@@ -0,0 +1,57 @@
1
+ import type React from 'react'
2
+ import { useEffect } from 'react'
3
+ import { setTintFamily, type TintFamily } from './tints'
4
+
5
+ // inline script that runs before hydration to set season class on html
6
+ // auto-detects season from current date
7
+ function getInlineScript() {
8
+ return `(function(){
9
+ var d = new Date();
10
+ var m = d.getMonth();
11
+ var day = d.getDate();
12
+ var season = '@hanzo/gui';
13
+
14
+ if (m === 11 && day >= 14) season = 'xmas';
15
+ else if (m === 9 && day >= 20) season = 'halloween';
16
+ else if (m === 2 && day >= 10 && day <= 17) season = 'stpatricks';
17
+ else if (m === 2 && day >= 30 || m === 3 && day <= 20) season = 'easter';
18
+ else if (m === 1 && day >= 7 && day <= 14) season = 'valentine';
19
+ else if (m === 0 && day >= 20 || m === 1 && day <= 12) season = 'lunar';
20
+
21
+ if (season !== '@hanzo/gui') {
22
+ document.documentElement.classList.add(season + '-season');
23
+ }
24
+ window.__HANZO_GUI_SEASON__ = season;
25
+ })();`
26
+ }
27
+
28
+ // syncs the tint family with the value computed by the inline script
29
+ function useSeasonSync() {
30
+ useEffect(() => {
31
+ const computed = (window as any).__HANZO_GUI_SEASON__ as TintFamily | undefined
32
+ if (computed) {
33
+ setTintFamily(computed)
34
+ }
35
+ }, [])
36
+ }
37
+
38
+ export function SeasonProvider({
39
+ children,
40
+ }: {
41
+ children: React.ReactNode
42
+ }): React.ReactNode {
43
+ useSeasonSync()
44
+
45
+ return (
46
+ <>
47
+ {/* disabled because were launchig v2 and its lunar new year */}
48
+ {/* <script
49
+ suppressHydrationWarning
50
+ dangerouslySetInnerHTML={{
51
+ __html: getInlineScript(),
52
+ }}
53
+ /> */}
54
+ {children}
55
+ </>
56
+ )
57
+ }
@@ -0,0 +1,32 @@
1
+ import { type ThemeProps, Theme } from '@hanzogui/web'
2
+ import type { JSX } from 'react/jsx-runtime'
3
+ import { useTint } from './useTint'
4
+
5
+ export const ThemeTint = ({
6
+ disable,
7
+ children,
8
+ ...rest
9
+ }: ThemeProps & { disable?: boolean }): JSX.Element => {
10
+ const curTint = useTint().tint
11
+
12
+ return (
13
+ <Theme {...rest} name={disable ? null : curTint}>
14
+ {children}
15
+ </Theme>
16
+ )
17
+ }
18
+
19
+ export const ThemeTintAlt = ({
20
+ children,
21
+ disable,
22
+ offset = 1,
23
+ ...rest
24
+ }: ThemeProps & { disable?: boolean; offset?: number }): JSX.Element => {
25
+ const curTint = useTint(offset).tintAlt
26
+ const name = disable ? null : curTint
27
+ return (
28
+ <Theme name={name} {...rest}>
29
+ {children}
30
+ </Theme>
31
+ )
32
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,7 @@
1
+ export * from './GuiLogo'
2
+ export * from './LogoWords'
3
+ export * from './LogoIcon'
4
+ export * from './tints'
5
+ export * from './useTint'
6
+ export * from './ThemeTint'
7
+ export * from './SeasonProvider'
package/src/tints.tsx ADDED
@@ -0,0 +1,112 @@
1
+ import React from 'react'
2
+ import type { ThemeName } from '@hanzo/gui'
3
+
4
+ type ChangeHandler = (next: TintFamily) => void
5
+
6
+ const listeners = new Set<ChangeHandler>()
7
+
8
+ // T A M A G U I
9
+ // Maps to logo letters - index 3 (A) is the "none" theme position
10
+ const familiesValues = {
11
+ gui: ['yellow', 'yellow', 'yellow', 'gray', 'red', 'green', 'blue'] as ThemeName[],
12
+ xmas: ['red', 'green', 'red', 'green', 'red', 'green', 'red'] as ThemeName[],
13
+ easter: [
14
+ 'yellow',
15
+ 'yellow',
16
+ 'yellow',
17
+ 'yellow',
18
+ 'yellow',
19
+ 'yellow',
20
+ 'yellow',
21
+ ] as ThemeName[],
22
+ halloween: [
23
+ 'yellow',
24
+ 'gray',
25
+ 'yellow',
26
+ 'gray',
27
+ 'yellow',
28
+ 'gray',
29
+ 'yellow',
30
+ ] as ThemeName[],
31
+ valentine: ['red', 'red', 'red', 'red', 'red', 'red', 'red'] as ThemeName[],
32
+ lunar: ['yellow', 'red', 'red', 'red', 'red', 'red', 'yellow'] as ThemeName[],
33
+ stpatricks: ['green', 'teal', 'green', 'teal', 'green', 'teal', 'green'] as ThemeName[],
34
+ }
35
+
36
+ type Family = keyof typeof familiesValues
37
+
38
+ const DEFAULT_FAMILY: Family = '@hanzo/gui'
39
+
40
+ const familiesNames = Object.keys(familiesValues) as any as Family[]
41
+
42
+ type Families = { [key in Family]: ThemeName[] }
43
+ const families = familiesValues as Families
44
+
45
+ export type TintFamily = keyof typeof families
46
+
47
+ let fam: TintFamily = DEFAULT_FAMILY
48
+
49
+ export function getTints(): {
50
+ name: string
51
+ tints: ThemeName[]
52
+ families: Families
53
+ } {
54
+ return {
55
+ name: fam || DEFAULT_FAMILY,
56
+ tints: families[fam] || families.gui,
57
+ families,
58
+ }
59
+ }
60
+
61
+ export function useTints(): {
62
+ name: string
63
+ tints: ThemeName[]
64
+ families: Families
65
+ } {
66
+ const [val, setVal] = React.useState(getTints())
67
+
68
+ React.useEffect(() => {
69
+ return onTintFamilyChange(() => {
70
+ React.startTransition(() => {
71
+ setVal(getTints())
72
+ })
73
+ })
74
+ }, [])
75
+
76
+ return val
77
+ }
78
+
79
+ export function setTintFamily(next: TintFamily): void {
80
+ if (!families[next]) throw `impossible`
81
+ fam = next
82
+
83
+ // update DOM class for CSS-based styling (e.g., rainbow gradients)
84
+ if (typeof document !== 'undefined') {
85
+ const root = document.documentElement.classList
86
+ // remove all season classes
87
+ familiesNames.forEach((s) => {
88
+ if (s !== '@hanzo/gui') {
89
+ root.remove(`${s}-season`)
90
+ }
91
+ })
92
+ // add the new one if not gui
93
+ if (next !== '@hanzo/gui') {
94
+ root.add(`${next}-season`)
95
+ }
96
+ }
97
+
98
+ React.startTransition(() => {
99
+ listeners.forEach((l) => l(next))
100
+ })
101
+ }
102
+
103
+ export const setNextTintFamily = (): void => {
104
+ setTintFamily(familiesNames[(familiesNames.indexOf(fam) + 1) % familiesNames.length])
105
+ }
106
+
107
+ export const onTintFamilyChange = (cb: ChangeHandler) => {
108
+ listeners.add(cb)
109
+ return (): void => {
110
+ listeners.delete(cb)
111
+ }
112
+ }
@@ -0,0 +1,116 @@
1
+ import React, { createContext, useContext, useEffect, useState } from 'react'
2
+ import { useDidFinishSSR, type ThemeName } from '@hanzo/gui'
3
+ import { getTints, setNextTintFamily, useTints } from './tints'
4
+
5
+ let current = 3
6
+ let disableTintTheme = false
7
+
8
+ const listeners = new Set<Function>()
9
+ const disableListeners = new Set<Function>()
10
+
11
+ export const onTintChange = (listener: (cur: number) => void) => {
12
+ listeners.add(listener)
13
+ return (): void => {
14
+ listeners.delete(listener)
15
+ }
16
+ }
17
+
18
+ const numTints = getTints().tints.length
19
+
20
+ export const setTintIndex = (next: number): void => {
21
+ const val = Math.max(0, next % numTints)
22
+ if (val === current) return
23
+ current = val
24
+ listeners.forEach((x) => x(val))
25
+ }
26
+
27
+ // when true, useTint returns null for tint/tintAlt so ThemeTint doesn't apply sub-themes
28
+ export const setDisableTintTheme = (disable: boolean): void => {
29
+ if (disable === disableTintTheme) return
30
+ disableTintTheme = disable
31
+ disableListeners.forEach((x) => x(disable))
32
+ }
33
+
34
+ export const getDisableTintTheme = (): boolean => disableTintTheme
35
+
36
+ export function getDocsSection(pathname: string): 'compiler' | 'ui' | 'core' | null {
37
+ return pathname === '/docs/intro/compiler-install' ||
38
+ pathname === '/docs/intro/benchmarks' ||
39
+ pathname === '/docs/intro/why-a-compiler'
40
+ ? 'compiler'
41
+ : pathname.startsWith('/ui/')
42
+ ? 'ui'
43
+ : pathname.startsWith('/docs/')
44
+ ? 'core'
45
+ : null
46
+ }
47
+
48
+ export const InitialPathContext: React.Context<number> = createContext(3)
49
+
50
+ export const useTint = (
51
+ altOffset = -1
52
+ ): {
53
+ tints: ThemeName[]
54
+ tintIndex: number
55
+ tintAltIndex: number
56
+ tint: ThemeName
57
+ tintAlt: ThemeName
58
+ setTintIndex: (next: number) => void
59
+ setNextTintFamily: () => void
60
+ setNextTint: () => void
61
+ setDisableTintTheme: (disable: boolean) => void
62
+ disableTintTheme: boolean
63
+ name: string
64
+ families: {
65
+ gui: string[]
66
+ xmas: string[]
67
+ easter: string[]
68
+ halloween: string[]
69
+ valentine: string[]
70
+ lunar: string[]
71
+ }
72
+ } => {
73
+ const initial = useContext(InitialPathContext)
74
+ const didHydrate = useDidFinishSSR()
75
+ const [index, setIndex] = useState(didHydrate ? current : initial)
76
+ const [disabled, setDisabled] = useState(disableTintTheme)
77
+ const tintsContext = useTints()
78
+ const { tints } = tintsContext
79
+ const tintAltIndex = Math.abs((index + altOffset) % tints.length)
80
+
81
+ useEffect(() => {
82
+ return onTintChange((cur) => {
83
+ setIndex(cur)
84
+ })
85
+ }, [])
86
+
87
+ useEffect(() => {
88
+ const cb = (val: boolean) => setDisabled(val)
89
+ disableListeners.add(cb)
90
+ return () => {
91
+ disableListeners.delete(cb)
92
+ }
93
+ }, [])
94
+
95
+ // return null for tint when disabled or at the "none" position (index 3)
96
+ const tint = disabled || index === 3 ? null : tints[index]
97
+ const tintAlt = disabled || tintAltIndex === 3 ? null : tints[tintAltIndex]
98
+
99
+ return {
100
+ ...tintsContext,
101
+ tints: tintsContext.tints as ThemeName[],
102
+ tintIndex: index,
103
+ tintAltIndex,
104
+ tint: tint as ThemeName,
105
+ tintAlt: tintAlt as ThemeName,
106
+ setTintIndex,
107
+ setNextTintFamily,
108
+ setDisableTintTheme,
109
+ disableTintTheme: disabled,
110
+ setNextTint: () => {
111
+ React.startTransition(() => {
112
+ setTintIndex(index + 1)
113
+ })
114
+ },
115
+ } as const
116
+ }
@@ -0,0 +1,13 @@
1
+ import type { JSX } from "react/jsx-runtime";
2
+ import type { XStackProps } from "@hanzo/gui";
3
+ type LogoProps = {
4
+ showWords?: boolean;
5
+ downscale?: number;
6
+ animated?: boolean;
7
+ color?: string;
8
+ ref?: any;
9
+ } & XStackProps;
10
+ export declare const GuiLogo: ({ showWords, downscale, animated, color, ref, ...props }: LogoProps) => JSX.Element;
11
+ export {};
12
+
13
+ //# sourceMappingURL=GuiLogo.d.ts.map