@nous-research/ui 0.15.0 → 0.17.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.
- package/CHANGELOG.md +266 -0
- package/README.md +24 -4
- package/dist/fonts.js +1 -0
- package/dist/hooks/use-below-breakpoint.d.ts +2 -0
- package/dist/hooks/use-below-breakpoint.js +17 -0
- package/dist/hooks/use-capped-frame.js +1 -0
- package/dist/hooks/use-confirm-delete.d.ts +10 -0
- package/dist/hooks/use-confirm-delete.js +35 -0
- package/dist/hooks/use-css-var-dims.js +1 -0
- package/dist/hooks/use-gpu-tier.js +1 -0
- package/dist/hooks/use-render-loop.js +1 -0
- package/dist/hooks/use-smooth-controls.js +1 -0
- package/dist/hooks/use-toast.d.ts +7 -0
- package/dist/hooks/use-toast.js +21 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.js +23 -1
- package/dist/ui/basic-page.js +1 -0
- package/dist/ui/components/animated-count.js +1 -0
- package/dist/ui/components/ascii.js +1 -0
- package/dist/ui/components/badge.js +2 -1
- package/dist/ui/components/badges/nous-girl.js +1 -0
- package/dist/ui/components/blend-mode.js +1 -0
- package/dist/ui/components/blink.js +1 -0
- package/dist/ui/components/bottom-sheet.d.ts +15 -0
- package/dist/ui/components/bottom-sheet.js +192 -0
- package/dist/ui/components/button.js +2 -1
- package/dist/ui/components/card.d.ts +5 -0
- package/dist/ui/components/card.js +74 -0
- package/dist/ui/components/checkbox.d.ts +1 -1
- package/dist/ui/components/checkbox.js +2 -1
- package/dist/ui/components/command-block.js +4 -3
- package/dist/ui/components/confirm-dialog.d.ts +13 -0
- package/dist/ui/components/confirm-dialog.js +113 -0
- package/dist/ui/components/cursor.js +1 -0
- package/dist/ui/components/dialog.d.ts +15 -0
- package/dist/ui/components/dialog.js +171 -0
- package/dist/ui/components/dropdown-menu.js +1 -0
- package/dist/ui/components/fit-text/index.js +1 -0
- package/dist/ui/components/graphs/bar-chart.js +1 -0
- package/dist/ui/components/graphs/index.js +1 -0
- package/dist/ui/components/graphs/line-chart.js +1 -0
- package/dist/ui/components/graphs/utils.js +1 -0
- package/dist/ui/components/grid/index.js +1 -0
- package/dist/ui/components/hover-bg.js +1 -0
- package/dist/ui/components/icons/arrow.js +1 -0
- package/dist/ui/components/icons/check.js +1 -0
- package/dist/ui/components/icons/chevron.js +1 -0
- package/dist/ui/components/icons/discord.js +1 -0
- package/dist/ui/components/icons/eye.js +1 -0
- package/dist/ui/components/icons/gear.js +1 -0
- package/dist/ui/components/icons/github.js +1 -0
- package/dist/ui/components/icons/hamburger.js +1 -0
- package/dist/ui/components/icons/heart.js +1 -0
- package/dist/ui/components/icons/index.js +1 -0
- package/dist/ui/components/icons/link.js +1 -0
- package/dist/ui/components/icons/minus.js +1 -0
- package/dist/ui/components/icons/search.js +1 -0
- package/dist/ui/components/image-distortion.js +1 -0
- package/dist/ui/components/input.d.ts +1 -0
- package/dist/ui/components/input.js +21 -0
- package/dist/ui/components/label.d.ts +1 -0
- package/dist/ui/components/label.js +18 -0
- package/dist/ui/components/leva-client.js +1 -0
- package/dist/ui/components/list-item.js +3 -2
- package/dist/ui/components/overlays/blend-modes.js +1 -0
- package/dist/ui/components/overlays/glitch.js +1 -0
- package/dist/ui/components/overlays/greys.js +1 -0
- package/dist/ui/components/overlays/index.js +1 -0
- package/dist/ui/components/overlays/lens-layers.js +1 -0
- package/dist/ui/components/overlays/lens.js +1 -0
- package/dist/ui/components/overlays/noise.js +1 -0
- package/dist/ui/components/overlays/vignette.js +1 -0
- package/dist/ui/components/poster.js +1 -0
- package/dist/ui/components/progress.js +1 -0
- package/dist/ui/components/scene-canvas.js +1 -0
- package/dist/ui/components/scramble.js +1 -0
- package/dist/ui/components/segmented.js +5 -4
- package/dist/ui/components/select.js +1 -0
- package/dist/ui/components/selection-switcher.js +1 -0
- package/dist/ui/components/separator.d.ts +5 -0
- package/dist/ui/components/separator.js +22 -0
- package/dist/ui/components/shader.js +1 -0
- package/dist/ui/components/socials.js +1 -0
- package/dist/ui/components/spinner.js +1 -0
- package/dist/ui/components/stats.js +2 -1
- package/dist/ui/components/switch.js +1 -0
- package/dist/ui/components/tabs.js +4 -3
- package/dist/ui/components/terminal-demo.js +2 -1
- package/dist/ui/components/theme-toggle.js +1 -0
- package/dist/ui/components/tier-card.js +2 -1
- package/dist/ui/components/toast.d.ts +8 -0
- package/dist/ui/components/toast.js +39 -0
- package/dist/ui/components/tv.js +1 -0
- package/dist/ui/components/typography/h1.js +1 -0
- package/dist/ui/components/typography/h2.js +1 -0
- package/dist/ui/components/typography/index.js +1 -0
- package/dist/ui/components/typography/legend.js +1 -0
- package/dist/ui/components/typography/small.js +1 -0
- package/dist/ui/components/watchlist.js +2 -1
- package/dist/ui/footer.js +1 -0
- package/dist/ui/globals.css +47 -3
- package/dist/ui/header.js +1 -0
- package/dist/ui/layout-wrapper.js +2 -1
- package/dist/utils/color.js +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/poly.js +1 -0
- package/package.json +5 -3
- package/src/assets/filler-bg0.webp +0 -0
- package/src/assets.d.ts +38 -0
- package/src/fonts/Collapse-Bold.woff2 +0 -0
- package/src/fonts/Collapse-BoldItalic.woff2 +0 -0
- package/src/fonts/Collapse-Italic.woff2 +0 -0
- package/src/fonts/Collapse-Light.woff2 +0 -0
- package/src/fonts/Collapse-LightItalic.woff2 +0 -0
- package/src/fonts/Collapse-Regular.woff2 +0 -0
- package/src/fonts/Collapse-Thin.woff2 +0 -0
- package/src/fonts/Collapse-ThinItalic.woff2 +0 -0
- package/src/fonts/Mondwest-Regular.woff2 +0 -0
- package/src/fonts/Neuebit-Bold.woff2 +0 -0
- package/src/fonts/RulesCompressed-Medium.woff2 +0 -0
- package/src/fonts/RulesCompressed-Regular.woff2 +0 -0
- package/src/fonts/RulesExpanded-Bold.woff2 +0 -0
- package/src/fonts/RulesExpanded-Regular.woff2 +0 -0
- package/src/fonts.ts +6 -0
- package/src/hooks/use-below-breakpoint.ts +21 -0
- package/src/hooks/use-capped-frame.ts +18 -0
- package/src/hooks/use-confirm-delete.ts +43 -0
- package/src/hooks/use-css-var-dims.ts +39 -0
- package/src/hooks/use-gpu-tier.ts +165 -0
- package/src/hooks/use-render-loop.ts +121 -0
- package/src/hooks/use-smooth-controls.ts +318 -0
- package/src/hooks/use-toast.ts +29 -0
- package/src/index.ts +130 -0
- package/src/ui/basic-page.tsx +34 -0
- package/src/ui/build.css +4 -0
- package/src/ui/components/animated-count.stories.tsx +67 -0
- package/src/ui/components/animated-count.tsx +168 -0
- package/src/ui/components/ascii.stories.tsx +30 -0
- package/src/ui/components/ascii.tsx +110 -0
- package/src/ui/components/badge.stories.tsx +31 -0
- package/src/ui/components/badge.tsx +60 -0
- package/src/ui/components/badges/nous-girl.tsx +52 -0
- package/src/ui/components/blend-mode.stories.tsx +33 -0
- package/src/ui/components/blend-mode.tsx +129 -0
- package/src/ui/components/blink.stories.tsx +32 -0
- package/src/ui/components/blink.tsx +21 -0
- package/src/ui/components/bottom-sheet.stories.tsx +43 -0
- package/src/ui/components/bottom-sheet.tsx +227 -0
- package/src/ui/components/button.stories.tsx +68 -0
- package/src/ui/components/button.tsx +170 -0
- package/src/ui/components/card.stories.tsx +63 -0
- package/src/ui/components/card.tsx +85 -0
- package/src/ui/components/checkbox.stories.tsx +113 -0
- package/src/ui/components/checkbox.tsx +36 -0
- package/src/ui/components/command-block.stories.tsx +52 -0
- package/src/ui/components/command-block.tsx +86 -0
- package/src/ui/components/confirm-dialog.stories.tsx +91 -0
- package/src/ui/components/confirm-dialog.tsx +130 -0
- package/src/ui/components/cursor.tsx +115 -0
- package/src/ui/components/dialog.stories.tsx +169 -0
- package/src/ui/components/dialog.tsx +177 -0
- package/src/ui/components/dropdown-menu.stories.tsx +52 -0
- package/src/ui/components/dropdown-menu.tsx +117 -0
- package/src/ui/components/fit-text/fit-text.css +42 -0
- package/src/ui/components/fit-text/index.stories.tsx +33 -0
- package/src/ui/components/fit-text/index.tsx +45 -0
- package/src/ui/components/forms.stories.tsx +173 -0
- package/src/ui/components/graphs/bar-chart.tsx +153 -0
- package/src/ui/components/graphs/index.stories.tsx +64 -0
- package/src/ui/components/graphs/index.tsx +4 -0
- package/src/ui/components/graphs/line-chart.tsx +213 -0
- package/src/ui/components/graphs/utils.tsx +265 -0
- package/src/ui/components/grid/grid.css +79 -0
- package/src/ui/components/grid/index.tsx +19 -0
- package/src/ui/components/hover-bg.stories.tsx +29 -0
- package/src/ui/components/hover-bg.tsx +15 -0
- package/src/ui/components/icons/arrow.tsx +42 -0
- package/src/ui/components/icons/check.tsx +14 -0
- package/src/ui/components/icons/chevron.tsx +45 -0
- package/src/ui/components/icons/discord.tsx +16 -0
- package/src/ui/components/icons/eye.tsx +12 -0
- package/src/ui/components/icons/gear.tsx +51 -0
- package/src/ui/components/icons/github.tsx +16 -0
- package/src/ui/components/icons/hamburger.tsx +52 -0
- package/src/ui/components/icons/heart.tsx +12 -0
- package/src/ui/components/icons/index.ts +12 -0
- package/src/ui/components/icons/link.tsx +14 -0
- package/src/ui/components/icons/minus.tsx +14 -0
- package/src/ui/components/icons/search.tsx +28 -0
- package/src/ui/components/image-distortion.stories.tsx +120 -0
- package/src/ui/components/image-distortion.tsx +498 -0
- package/src/ui/components/input.stories.tsx +39 -0
- package/src/ui/components/input.tsx +20 -0
- package/src/ui/components/label.stories.tsx +26 -0
- package/src/ui/components/label.tsx +16 -0
- package/src/ui/components/leva-client.tsx +14 -0
- package/src/ui/components/list-item.stories.tsx +83 -0
- package/src/ui/components/list-item.tsx +37 -0
- package/src/ui/components/overlays/blend-modes.ts +13 -0
- package/src/ui/components/overlays/glitch.tsx +243 -0
- package/src/ui/components/overlays/greys.tsx +386 -0
- package/src/ui/components/overlays/index.tsx +47 -0
- package/src/ui/components/overlays/lens-layers.tsx +119 -0
- package/src/ui/components/overlays/lens.ts +91 -0
- package/src/ui/components/overlays/noise.tsx +174 -0
- package/src/ui/components/overlays/vignette.tsx +60 -0
- package/src/ui/components/poster.stories.tsx +513 -0
- package/src/ui/components/poster.tsx +411 -0
- package/src/ui/components/progress.stories.tsx +48 -0
- package/src/ui/components/progress.tsx +56 -0
- package/src/ui/components/scene-canvas.tsx +254 -0
- package/src/ui/components/scramble.stories.tsx +49 -0
- package/src/ui/components/scramble.tsx +95 -0
- package/src/ui/components/segmented.stories.tsx +101 -0
- package/src/ui/components/segmented.tsx +81 -0
- package/src/ui/components/select.stories.tsx +88 -0
- package/src/ui/components/select.tsx +267 -0
- package/src/ui/components/selection-switcher.tsx +44 -0
- package/src/ui/components/separator.stories.tsx +33 -0
- package/src/ui/components/separator.tsx +24 -0
- package/src/ui/components/shader.tsx +83 -0
- package/src/ui/components/socials.tsx +42 -0
- package/src/ui/components/spinner.stories.tsx +101 -0
- package/src/ui/components/spinner.tsx +60 -0
- package/src/ui/components/stats.stories.tsx +24 -0
- package/src/ui/components/stats.tsx +53 -0
- package/src/ui/components/switch.stories.tsx +77 -0
- package/src/ui/components/switch.tsx +48 -0
- package/src/ui/components/tabs.stories.tsx +101 -0
- package/src/ui/components/tabs.tsx +66 -0
- package/src/ui/components/terminal-demo.stories.tsx +67 -0
- package/src/ui/components/terminal-demo.tsx +189 -0
- package/src/ui/components/theme-toggle.stories.tsx +47 -0
- package/src/ui/components/theme-toggle.tsx +66 -0
- package/src/ui/components/tier-card.stories.tsx +217 -0
- package/src/ui/components/tier-card.tsx +190 -0
- package/src/ui/components/toast.stories.tsx +55 -0
- package/src/ui/components/toast.tsx +49 -0
- package/src/ui/components/tv.stories.tsx +37 -0
- package/src/ui/components/tv.tsx +257 -0
- package/src/ui/components/typography/h1.tsx +18 -0
- package/src/ui/components/typography/h2.tsx +18 -0
- package/src/ui/components/typography/index.tsx +54 -0
- package/src/ui/components/typography/legend.tsx +24 -0
- package/src/ui/components/typography/small.tsx +11 -0
- package/src/ui/components/watchlist.stories.tsx +33 -0
- package/src/ui/components/watchlist.tsx +105 -0
- package/src/ui/fonts.css +63 -0
- package/src/ui/footer.tsx +111 -0
- package/src/ui/globals.css +395 -0
- package/src/ui/header.tsx +398 -0
- package/src/ui/layout-wrapper.tsx +11 -0
- package/src/utils/color.ts +21 -0
- package/src/utils/index.ts +62 -0
- package/src/utils/poly.ts +26 -0
- package/dist/ui/components/modal/index.d.ts +0 -8
- package/dist/ui/components/modal/index.js +0 -34
- package/dist/ui/components/modal/modal.css +0 -36
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type ComponentType,
|
|
5
|
+
type HTMLAttributes,
|
|
6
|
+
type RefObject,
|
|
7
|
+
useEffect,
|
|
8
|
+
useState
|
|
9
|
+
} from 'react'
|
|
10
|
+
|
|
11
|
+
import { useSmoothControls } from '../../../hooks/use-smooth-controls'
|
|
12
|
+
import {
|
|
13
|
+
type BlendColors,
|
|
14
|
+
type BlendModeProps
|
|
15
|
+
} from '../blend-mode'
|
|
16
|
+
|
|
17
|
+
export const accessor = <T, R>(key: ((d: T) => R) | keyof T) =>
|
|
18
|
+
typeof key === 'function' ? key : (d: T) => d[key] as R
|
|
19
|
+
|
|
20
|
+
export const CHART_MARGINS = {
|
|
21
|
+
marginBottom: 24,
|
|
22
|
+
marginLeft: 36,
|
|
23
|
+
marginRight: 12,
|
|
24
|
+
marginTop: 8
|
|
25
|
+
} as const
|
|
26
|
+
|
|
27
|
+
export const CHART_STYLE = {
|
|
28
|
+
background: 'transparent',
|
|
29
|
+
color: 'var(--midground)',
|
|
30
|
+
fontFamily: 'var(--font-mono), monospace',
|
|
31
|
+
fontSize: '11px',
|
|
32
|
+
overflow: 'hidden'
|
|
33
|
+
} as const
|
|
34
|
+
|
|
35
|
+
export const stylePlot = (plot: HTMLElement) => {
|
|
36
|
+
plot.querySelectorAll('[aria-label*="grid"] line').forEach(el =>
|
|
37
|
+
Object.assign((el as SVGLineElement).style, {
|
|
38
|
+
stroke: 'currentColor',
|
|
39
|
+
strokeDasharray: '2,4',
|
|
40
|
+
strokeOpacity: '0.3'
|
|
41
|
+
})
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
plot.querySelectorAll('text').forEach(el =>
|
|
45
|
+
Object.assign((el as SVGTextElement).style, {
|
|
46
|
+
fontSize: '11px',
|
|
47
|
+
fontWeight: '600'
|
|
48
|
+
})
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
plot
|
|
52
|
+
.querySelectorAll('[aria-label*="label"] text')
|
|
53
|
+
.forEach(el => ((el as SVGTextElement).style.opacity = '0.4'))
|
|
54
|
+
|
|
55
|
+
const svg = plot.querySelector('svg')
|
|
56
|
+
svg && (svg.style.display = 'block')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const useDims = (ref: RefObject<HTMLElement | null>) => {
|
|
60
|
+
const [dims, setDims] = useState({ h: 0, w: 0 })
|
|
61
|
+
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (!ref.current) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const update = () => {
|
|
68
|
+
const { height: h, width: w } = ref.current!.getBoundingClientRect()
|
|
69
|
+
const [rh, rw] = [Math.round(h), Math.round(w)]
|
|
70
|
+
|
|
71
|
+
rh &&
|
|
72
|
+
rw &&
|
|
73
|
+
setDims(st => (st.h === rh && st.w === rw ? st : { h: rh, w: rw }))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
update()
|
|
77
|
+
|
|
78
|
+
const ro = new ResizeObserver(update)
|
|
79
|
+
ro.observe(ref.current)
|
|
80
|
+
|
|
81
|
+
return () => ro.disconnect()
|
|
82
|
+
}, [ref])
|
|
83
|
+
|
|
84
|
+
return dims
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const Crosshair = ({
|
|
88
|
+
color = 'var(--foreground)',
|
|
89
|
+
containerWidth,
|
|
90
|
+
height,
|
|
91
|
+
points,
|
|
92
|
+
x
|
|
93
|
+
}: CrosshairState & {
|
|
94
|
+
color?: string
|
|
95
|
+
containerWidth: number
|
|
96
|
+
height: number
|
|
97
|
+
}) => {
|
|
98
|
+
if (x === null) {
|
|
99
|
+
return null
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const nearRight = x > containerWidth * 0.7
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<>
|
|
106
|
+
<div
|
|
107
|
+
className="pointer-events-none absolute top-0 w-px"
|
|
108
|
+
style={{ background: color, height, left: x, opacity: 0.4 }}
|
|
109
|
+
/>
|
|
110
|
+
|
|
111
|
+
{points?.map((pt, i) => (
|
|
112
|
+
<div
|
|
113
|
+
className="pointer-events-none absolute size-2 -translate-x-1/2 -translate-y-1/2 rounded-full"
|
|
114
|
+
key={i}
|
|
115
|
+
style={{ background: color, left: x, top: pt.dotY }}
|
|
116
|
+
/>
|
|
117
|
+
))}
|
|
118
|
+
|
|
119
|
+
{points?.map((pt, i) => (
|
|
120
|
+
<div
|
|
121
|
+
className="tooltip absolute -translate-y-1/2"
|
|
122
|
+
key={i}
|
|
123
|
+
style={{
|
|
124
|
+
left: nearRight ? undefined : x + 12,
|
|
125
|
+
right: nearRight ? containerWidth - x + 12 : undefined,
|
|
126
|
+
top: pt.dotY
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
{pt.tooltip}
|
|
130
|
+
</div>
|
|
131
|
+
))}
|
|
132
|
+
</>
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export const setupCrosshair = <T extends DataPoint>(
|
|
137
|
+
container: HTMLElement,
|
|
138
|
+
data: T[],
|
|
139
|
+
getX: (d: T) => number,
|
|
140
|
+
getY: (d: T) => number,
|
|
141
|
+
yDomain: [number, number],
|
|
142
|
+
formatTooltip: (d: T) => string,
|
|
143
|
+
onUpdate: (state: CrosshairState) => void,
|
|
144
|
+
getZ?: (d: T) => unknown
|
|
145
|
+
) => {
|
|
146
|
+
if (!data.length) {
|
|
147
|
+
return () => {}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const { marginBottom, marginLeft, marginRight, marginTop } = CHART_MARGINS
|
|
151
|
+
|
|
152
|
+
const seriesMap = data.reduce((m, d) => {
|
|
153
|
+
const key = getZ?.(d) ?? '__single__'
|
|
154
|
+
m.set(key, [...(m.get(key) ?? []), d])
|
|
155
|
+
|
|
156
|
+
return m
|
|
157
|
+
}, new Map<unknown, T[]>())
|
|
158
|
+
|
|
159
|
+
const sortedSeries = [...seriesMap.values()].map(s =>
|
|
160
|
+
[...s].sort((a, b) => getX(a) - getX(b))
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
const allX = data.map(getX)
|
|
164
|
+
const [xMin, xMax] = [Math.min(...allX), Math.max(...allX)]
|
|
165
|
+
|
|
166
|
+
const onMove = (e: MouseEvent) => {
|
|
167
|
+
const rect = container.getBoundingClientRect()
|
|
168
|
+
const [localX, localY] = [e.clientX - rect.left, e.clientY - rect.top]
|
|
169
|
+
|
|
170
|
+
if (
|
|
171
|
+
localX < 0 ||
|
|
172
|
+
localX > rect.width ||
|
|
173
|
+
localY < 0 ||
|
|
174
|
+
localY > rect.height
|
|
175
|
+
) {
|
|
176
|
+
return onUpdate({ x: null })
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const [chartLeft, chartRight] = [marginLeft, rect.width - marginRight]
|
|
180
|
+
const [chartTop, chartBottom] = [marginTop, rect.height - marginBottom]
|
|
181
|
+
|
|
182
|
+
if (localX < chartLeft || localX > chartRight) {
|
|
183
|
+
return onUpdate({ x: null })
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const pct = (localX - chartLeft) / (chartRight - chartLeft)
|
|
187
|
+
const xVal = xMin + pct * (xMax - xMin)
|
|
188
|
+
|
|
189
|
+
const points = sortedSeries.map(sorted => {
|
|
190
|
+
const idx = sorted.findIndex(d => getX(d) >= xVal)
|
|
191
|
+
|
|
192
|
+
const [closest, yVal] =
|
|
193
|
+
idx <= 0
|
|
194
|
+
? [sorted[0], getY(sorted[0])]
|
|
195
|
+
: idx >= sorted.length
|
|
196
|
+
? [sorted.at(-1)!, getY(sorted.at(-1)!)]
|
|
197
|
+
: (() => {
|
|
198
|
+
const [left, right] = [sorted[idx - 1], sorted[idx]]
|
|
199
|
+
const t = (xVal - getX(left)) / (getX(right) - getX(left))
|
|
200
|
+
|
|
201
|
+
return [
|
|
202
|
+
t < 0.5 ? left : right,
|
|
203
|
+
getY(left) + t * (getY(right) - getY(left))
|
|
204
|
+
] as const
|
|
205
|
+
})()
|
|
206
|
+
|
|
207
|
+
const yPct = (yVal - yDomain[0]) / (yDomain[1] - yDomain[0])
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
dotY: chartBottom - yPct * (chartBottom - chartTop),
|
|
211
|
+
tooltip: formatTooltip(closest)
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
onUpdate({ points, x: localX })
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
document.addEventListener('mousemove', onMove)
|
|
219
|
+
|
|
220
|
+
return () => document.removeEventListener('mousemove', onMove)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export const withChartBlend = <P extends BlendModeProps>(
|
|
224
|
+
Component: ComponentType<P>
|
|
225
|
+
) => {
|
|
226
|
+
const Wrapped = (props: Omit<P, keyof BlendColors>) => {
|
|
227
|
+
const { color } = useSmoothControls(
|
|
228
|
+
'Charts',
|
|
229
|
+
{ color: { value: '#709fea' } },
|
|
230
|
+
{ collapsed: true }
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
return <Component {...(props as P)} color={color} />
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
Wrapped.displayName = `withChartBlend(${Component.displayName ?? Component.name})`
|
|
237
|
+
|
|
238
|
+
return Wrapped
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export type DataPoint = Record<string, unknown>
|
|
242
|
+
|
|
243
|
+
export interface CrosshairPoint {
|
|
244
|
+
dotY: number
|
|
245
|
+
tooltip: string
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export interface CrosshairState {
|
|
249
|
+
points?: CrosshairPoint[]
|
|
250
|
+
x: null | number
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export interface ChartProps<T = DataPoint>
|
|
254
|
+
extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
255
|
+
data?: T[]
|
|
256
|
+
formatTooltip?: (d: T) => string
|
|
257
|
+
formatX?: (v: unknown) => string
|
|
258
|
+
formatY?: (v: number) => string
|
|
259
|
+
height?: number
|
|
260
|
+
x?: ((d: T) => unknown) | keyof T
|
|
261
|
+
xTicks?: number | number[]
|
|
262
|
+
y?: ((d: T) => number) | keyof T
|
|
263
|
+
yDomain?: [number, number]
|
|
264
|
+
yTicks?: number | number[]
|
|
265
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
.g {
|
|
2
|
+
@apply grid grid-cols-1 border-l border-current/20;
|
|
3
|
+
|
|
4
|
+
&:has(> .gc:nth-child(3)):not(:has(> .gc:nth-child(4))) > .gc:nth-child(2) {
|
|
5
|
+
@apply -order-1;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@media (width >= 40rem) {
|
|
9
|
+
&:has(> .gc:nth-child(2)) {
|
|
10
|
+
@apply grid-cols-2;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
&:has(> .gc:nth-child(3)):not(:has(> .gc:nth-child(4)))
|
|
14
|
+
> .gc:nth-child(2) {
|
|
15
|
+
@apply -order-1 col-span-full;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@media (width >= 64rem) {
|
|
20
|
+
&:has(> .gc:nth-child(3)) {
|
|
21
|
+
@apply grid-cols-3;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&:has(> .gc:nth-child(4)) {
|
|
25
|
+
@apply grid-cols-4;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&:has(> .gc:nth-child(5)) {
|
|
29
|
+
@apply grid-cols-5;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&:has(> .gc:nth-child(6)) {
|
|
33
|
+
@apply grid-cols-6;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&:has(> .gc:nth-child(3)):not(:has(> .gc:nth-child(4))) {
|
|
37
|
+
grid-template-columns: 1fr 2fr 1fr;
|
|
38
|
+
|
|
39
|
+
> .gc:nth-child(2) {
|
|
40
|
+
@apply order-none col-auto;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&:last-child {
|
|
46
|
+
@apply border-b;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&:first-child,
|
|
50
|
+
+ .g > .gc,
|
|
51
|
+
> .g {
|
|
52
|
+
@apply border-t;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.g {
|
|
56
|
+
@apply border-l-0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
&:not(:last-child) .gc:last-child {
|
|
60
|
+
@apply border-b-0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.gc {
|
|
64
|
+
min-width: 0;
|
|
65
|
+
@apply border-r border-inherit p-4;
|
|
66
|
+
|
|
67
|
+
&:has(> .gc) {
|
|
68
|
+
@apply p-0;
|
|
69
|
+
|
|
70
|
+
> .gc {
|
|
71
|
+
@apply border-r-0 not-first:border-t last:border-b-0;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.post.gc {
|
|
77
|
+
@apply lg:p-12;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createElement } from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn, polyRef } from '../../../utils'
|
|
4
|
+
|
|
5
|
+
export const Grid = polyRef<'div'>(({ as, className, ...rest }, ref) =>
|
|
6
|
+
createElement((as ?? 'div') as React.ElementType, {
|
|
7
|
+
...rest,
|
|
8
|
+
className: cn('g', className),
|
|
9
|
+
ref
|
|
10
|
+
})
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
export const Cell = polyRef<'div'>(({ as, className, ...rest }, ref) =>
|
|
14
|
+
createElement((as ?? 'div') as React.ElementType, {
|
|
15
|
+
...rest,
|
|
16
|
+
className: cn('gc', className),
|
|
17
|
+
ref
|
|
18
|
+
})
|
|
19
|
+
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
|
|
3
|
+
import { HoverBg } from './hover-bg'
|
|
4
|
+
import { Typography } from './typography'
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
component: HoverBg,
|
|
8
|
+
title: 'Components/Layout/HoverBg'
|
|
9
|
+
} satisfies Meta<typeof HoverBg>
|
|
10
|
+
|
|
11
|
+
export default meta
|
|
12
|
+
|
|
13
|
+
type Story = StoryObj<typeof meta>
|
|
14
|
+
|
|
15
|
+
export const Row: Story = {
|
|
16
|
+
render: () => (
|
|
17
|
+
<div className="flex gap-2">
|
|
18
|
+
{['Alpha', 'Beta', 'Gamma'].map(label => (
|
|
19
|
+
<div
|
|
20
|
+
className="group relative flex items-center justify-center px-6 py-3"
|
|
21
|
+
key={label}
|
|
22
|
+
>
|
|
23
|
+
<Typography mono>{label}</Typography>
|
|
24
|
+
<HoverBg />
|
|
25
|
+
</div>
|
|
26
|
+
))}
|
|
27
|
+
</div>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createElement } from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn, polyRef } from '../../utils'
|
|
4
|
+
|
|
5
|
+
export const HoverBg = polyRef<'span'>(({ as, className, ...rest }, ref) =>
|
|
6
|
+
createElement((as ?? 'span') as React.ElementType, {
|
|
7
|
+
...rest,
|
|
8
|
+
className: cn(
|
|
9
|
+
'absolute inset-1 bg-midground pointer-events-none',
|
|
10
|
+
'opacity-5 transition-opacity duration-250 group-hover:opacity-5 opacity-0 group-hover:duration-0',
|
|
11
|
+
className
|
|
12
|
+
),
|
|
13
|
+
ref
|
|
14
|
+
})
|
|
15
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { SVGProps } from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../../utils'
|
|
4
|
+
|
|
5
|
+
export function ArrowIcon({
|
|
6
|
+
className,
|
|
7
|
+
direction = 'down',
|
|
8
|
+
...props
|
|
9
|
+
}: ArrowIconProps) {
|
|
10
|
+
return (
|
|
11
|
+
<svg
|
|
12
|
+
className={cn(
|
|
13
|
+
direction === 'up' && 'rotate-180',
|
|
14
|
+
direction === 'left' && 'rotate-90',
|
|
15
|
+
direction === 'right' && '-rotate-90',
|
|
16
|
+
'origin-center',
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
19
|
+
fill="none"
|
|
20
|
+
viewBox="0 0 13 15"
|
|
21
|
+
{...props}
|
|
22
|
+
>
|
|
23
|
+
<path
|
|
24
|
+
clipRule="evenodd"
|
|
25
|
+
d="M5 15V0h2.50075v15z"
|
|
26
|
+
fill="currentColor"
|
|
27
|
+
fillRule="evenodd"
|
|
28
|
+
/>
|
|
29
|
+
|
|
30
|
+
<path
|
|
31
|
+
clipRule="evenodd"
|
|
32
|
+
d="M10 12.5007H2.5V9.99998H10zM12.4976 9.99951H9.99805v-2.4996h2.49955zM2.4996 9.99951H0v-2.4996h2.4996z"
|
|
33
|
+
fill="currentColor"
|
|
34
|
+
fillRule="evenodd"
|
|
35
|
+
/>
|
|
36
|
+
</svg>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface ArrowIconProps extends SVGProps<SVGSVGElement> {
|
|
41
|
+
direction?: 'down' | 'left' | 'right' | 'up'
|
|
42
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SVGProps } from 'react'
|
|
2
|
+
|
|
3
|
+
export function CheckIcon(props: SVGProps<SVGSVGElement>) {
|
|
4
|
+
return (
|
|
5
|
+
<svg fill="none" viewBox="0 0 12 12" {...props}>
|
|
6
|
+
<path
|
|
7
|
+
clipRule="evenodd"
|
|
8
|
+
d="M10.28 2.22a.75.75 0 0 1 0 1.06l-5.25 5.25a.75.75 0 0 1-1.06 0L1.72 6.28a.75.75 0 1 1 1.06-1.06L4.5 6.94l4.72-4.72a.75.75 0 0 1 1.06 0Z"
|
|
9
|
+
fill="currentColor"
|
|
10
|
+
fillRule="evenodd"
|
|
11
|
+
/>
|
|
12
|
+
</svg>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { SVGProps } from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../../utils'
|
|
4
|
+
|
|
5
|
+
export function ChevronIcon({
|
|
6
|
+
className,
|
|
7
|
+
direction = 'left',
|
|
8
|
+
...props
|
|
9
|
+
}: ChevronIconProps) {
|
|
10
|
+
return (
|
|
11
|
+
<svg
|
|
12
|
+
className={cn(
|
|
13
|
+
direction === 'left' && 'rotate-90',
|
|
14
|
+
direction === 'right' && '-rotate-90',
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
17
|
+
fill="none"
|
|
18
|
+
viewBox="0 0 8 13"
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
<path
|
|
22
|
+
clipRule="evenodd"
|
|
23
|
+
d="M0 7.49765h5V4.9969H1e-7z"
|
|
24
|
+
fill="currentColor"
|
|
25
|
+
fillRule="evenodd"
|
|
26
|
+
/>
|
|
27
|
+
<path
|
|
28
|
+
clipRule="evenodd"
|
|
29
|
+
d="M2.5 2.49765v7.5h2.50075v-7.5z"
|
|
30
|
+
fill="currentColor"
|
|
31
|
+
fillRule="evenodd"
|
|
32
|
+
/>
|
|
33
|
+
<path
|
|
34
|
+
clipRule="evenodd"
|
|
35
|
+
d="M5 .0000031V2.4996h2.4996V.0000032zM5 9.99805v2.49965h2.4996V9.99805z"
|
|
36
|
+
fill="currentColor"
|
|
37
|
+
fillRule="evenodd"
|
|
38
|
+
/>
|
|
39
|
+
</svg>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ChevronIconProps extends SVGProps<SVGSVGElement> {
|
|
44
|
+
direction?: 'left' | 'right'
|
|
45
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SVGProps } from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../../utils'
|
|
4
|
+
|
|
5
|
+
export function DiscordIcon({ className, ...props }: SVGProps<SVGSVGElement>) {
|
|
6
|
+
return (
|
|
7
|
+
<svg
|
|
8
|
+
className={cn('size-4', className)}
|
|
9
|
+
fill="currentColor"
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
{...props}
|
|
12
|
+
>
|
|
13
|
+
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z" />
|
|
14
|
+
</svg>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SVGProps } from 'react'
|
|
2
|
+
|
|
3
|
+
export function EyeIcon(props: SVGProps<SVGSVGElement>) {
|
|
4
|
+
return (
|
|
5
|
+
<svg fill="none" viewBox="0 0 26 17" {...props}>
|
|
6
|
+
<g clipRule="evenodd" fill="currentColor" fillRule="evenodd">
|
|
7
|
+
<path d="M2.36308 9.45484H0V7.09067h2.36308zM23.6387 9.45484h2.3631V7.09067h-2.3631zM4.73047 2.36462h3.54519v2.36309H4.73047zM8.27539 0h9.45451v2.36417H8.27539zM8.27539 14.1808h9.45451v2.3641H8.27539zM4.73047 14.1808h3.54519v-2.3631H4.73047zM21.2718 2.36462h-3.5452v2.36309h3.5452zM21.2718 14.1808h-3.5452v-2.3631h3.5452zM2.36719 4.72751h2.36308v2.36308H2.36719zM2.36719 11.8179h2.36308V9.45486H2.36719z" />
|
|
8
|
+
<path d="M23.6346 4.72751h-2.3631v2.36308h2.3631zM23.6346 11.8179h-2.3631V9.45486h2.3631zM14.7716 6.50014h-3.5452V4.13705h3.5452zm0 0v3.54516h-3.5452v2.3631h3.5452v-2.3631h2.363V6.50014zm-3.5452 0v3.54516H8.86328V6.50014z" />
|
|
9
|
+
</g>
|
|
10
|
+
</svg>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isValidElement,
|
|
3
|
+
type PropsWithChildren,
|
|
4
|
+
type ReactNode,
|
|
5
|
+
type SVGProps
|
|
6
|
+
} from 'react'
|
|
7
|
+
|
|
8
|
+
const VIEWBOX = '0 0 34 38'
|
|
9
|
+
|
|
10
|
+
const GEAR_PATH =
|
|
11
|
+
'M10.1249 3.37446h5.0624v3.37446h-5.0624zM23.6262 3.37446h-5.0625v3.37446h5.0625zM18.5637 0v3.37446h-3.3764L15.1877 0zM3.3762 6.74879l6.7487.00013.0003 3.37588h-6.749zM30.3748 6.74879l-6.7486.00013-.0003 3.37588h6.7489zM0 26.9988v-16.874h3.3762l-.00019 16.874zM33.7505 26.9988v-16.874h-3.3757l-.0003 16.874zM10.1248 30.3751H3.37586l.00015-3.3763 6.74879.0003zM23.6262 30.3751h6.749l-.0007-3.3763-6.7483.0003zM15.1873 33.7495h-5.0624l-.0001-3.3744 5.0625-.0001zM18.5637 33.7495h5.0625v-3.3744l-5.0625-.0001zM15.1874 37.1245l-.0001-3.375h3.3764l-.0003 3.375z'
|
|
12
|
+
|
|
13
|
+
export function GearIcon({
|
|
14
|
+
children,
|
|
15
|
+
innerScale = 0.55,
|
|
16
|
+
...props
|
|
17
|
+
}: GearIconProps) {
|
|
18
|
+
const isSvg = isValidElement(children) && children.type === 'svg'
|
|
19
|
+
|
|
20
|
+
const viewBox = isSvg
|
|
21
|
+
? ((children.props as { viewBox?: string }).viewBox ?? VIEWBOX)
|
|
22
|
+
: VIEWBOX
|
|
23
|
+
|
|
24
|
+
const inner = isSvg
|
|
25
|
+
? (children.props as { children?: ReactNode }).children
|
|
26
|
+
: children
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<svg fill="none" viewBox={VIEWBOX} {...props}>
|
|
30
|
+
<g clipRule="evenodd" fill="currentColor" fillRule="evenodd">
|
|
31
|
+
<path d={GEAR_PATH} />
|
|
32
|
+
</g>
|
|
33
|
+
|
|
34
|
+
{children && (
|
|
35
|
+
<svg
|
|
36
|
+
height={26 * innerScale}
|
|
37
|
+
width={26 * innerScale}
|
|
38
|
+
x={17 - (26 * innerScale) / 2}
|
|
39
|
+
y={19 - (26 * innerScale) / 2}
|
|
40
|
+
{...{ viewBox }}
|
|
41
|
+
>
|
|
42
|
+
{inner}
|
|
43
|
+
</svg>
|
|
44
|
+
)}
|
|
45
|
+
</svg>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface GearIconProps extends PropsWithChildren<SVGProps<SVGSVGElement>> {
|
|
50
|
+
innerScale?: number
|
|
51
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SVGProps } from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../../utils'
|
|
4
|
+
|
|
5
|
+
export function GitHubIcon({ className, ...props }: SVGProps<SVGSVGElement>) {
|
|
6
|
+
return (
|
|
7
|
+
<svg
|
|
8
|
+
className={cn('size-4', className)}
|
|
9
|
+
fill="currentColor"
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
{...props}
|
|
12
|
+
>
|
|
13
|
+
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />
|
|
14
|
+
</svg>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { SVGProps } from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../../utils'
|
|
4
|
+
|
|
5
|
+
export function HamburgerIcon({
|
|
6
|
+
className,
|
|
7
|
+
open = false,
|
|
8
|
+
...props
|
|
9
|
+
}: HamburgerIconProps) {
|
|
10
|
+
return (
|
|
11
|
+
<svg
|
|
12
|
+
className={cn('size-5', className)}
|
|
13
|
+
fill="none"
|
|
14
|
+
stroke="currentColor"
|
|
15
|
+
strokeLinecap="round"
|
|
16
|
+
strokeWidth={1.5}
|
|
17
|
+
viewBox="0 0 24 24"
|
|
18
|
+
{...props}
|
|
19
|
+
>
|
|
20
|
+
<line
|
|
21
|
+
className="origin-center transition-transform duration-200 ease-out"
|
|
22
|
+
style={{ transform: open ? 'rotate(45deg)' : 'translateY(-4px)' }}
|
|
23
|
+
x1={4}
|
|
24
|
+
x2={20}
|
|
25
|
+
y1={12}
|
|
26
|
+
y2={12}
|
|
27
|
+
/>
|
|
28
|
+
|
|
29
|
+
<line
|
|
30
|
+
className="transition-opacity duration-200 ease-out"
|
|
31
|
+
style={{ opacity: open ? 0 : 1 }}
|
|
32
|
+
x1={4}
|
|
33
|
+
x2={20}
|
|
34
|
+
y1={12}
|
|
35
|
+
y2={12}
|
|
36
|
+
/>
|
|
37
|
+
|
|
38
|
+
<line
|
|
39
|
+
className="origin-center transition-transform duration-200 ease-out"
|
|
40
|
+
style={{ transform: open ? 'rotate(-45deg)' : 'translateY(4px)' }}
|
|
41
|
+
x1={4}
|
|
42
|
+
x2={20}
|
|
43
|
+
y1={12}
|
|
44
|
+
y2={12}
|
|
45
|
+
/>
|
|
46
|
+
</svg>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface HamburgerIconProps extends SVGProps<SVGSVGElement> {
|
|
51
|
+
open?: boolean
|
|
52
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SVGProps } from 'react'
|
|
2
|
+
|
|
3
|
+
export function HeartIcon(props: SVGProps<SVGSVGElement>) {
|
|
4
|
+
return (
|
|
5
|
+
<svg fill="none" viewBox="0 0 14 12" {...props}>
|
|
6
|
+
<path
|
|
7
|
+
d="M13.2 0v5.65714h-1.8857v1.88572H9.42857v1.88571H7.54286v1.88573H5.65714V9.42857H3.77143V7.54286H1.88571V5.65714H0V0h5.65714v1.88571h1.88572V0z"
|
|
8
|
+
fill="currentColor"
|
|
9
|
+
/>
|
|
10
|
+
</svg>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './arrow'
|
|
2
|
+
export * from './check'
|
|
3
|
+
export * from './chevron'
|
|
4
|
+
export * from './discord'
|
|
5
|
+
export * from './eye'
|
|
6
|
+
export * from './gear'
|
|
7
|
+
export * from './github'
|
|
8
|
+
export * from './hamburger'
|
|
9
|
+
export * from './heart'
|
|
10
|
+
export * from './link'
|
|
11
|
+
export * from './minus'
|
|
12
|
+
export * from './search'
|