langwatch 0.0.1
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/.eslintrc.cjs +37 -0
- package/README.md +3 -0
- package/dist/chunk-GOA2HL4A.mjs +269 -0
- package/dist/chunk-GOA2HL4A.mjs.map +1 -0
- package/dist/index.d.mts +82 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +940 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +666 -0
- package/dist/index.mjs.map +1 -0
- package/dist/utils-s3gGR6vj.d.mts +209 -0
- package/dist/utils-s3gGR6vj.d.ts +209 -0
- package/dist/utils.d.mts +3 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +263 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.mjs +7 -0
- package/dist/utils.mjs.map +1 -0
- package/example/.env.example +12 -0
- package/example/.eslintrc.json +26 -0
- package/example/LICENSE +13 -0
- package/example/README.md +10 -0
- package/example/app/(chat)/chat/[id]/page.tsx +60 -0
- package/example/app/(chat)/layout.tsx +14 -0
- package/example/app/(chat)/page.tsx +22 -0
- package/example/app/actions.ts +156 -0
- package/example/app/globals.css +76 -0
- package/example/app/layout.tsx +64 -0
- package/example/app/login/actions.ts +71 -0
- package/example/app/login/page.tsx +18 -0
- package/example/app/new/page.tsx +5 -0
- package/example/app/opengraph-image.png +0 -0
- package/example/app/share/[id]/page.tsx +58 -0
- package/example/app/signup/actions.ts +111 -0
- package/example/app/signup/page.tsx +18 -0
- package/example/app/twitter-image.png +0 -0
- package/example/auth.config.ts +42 -0
- package/example/auth.ts +45 -0
- package/example/components/button-scroll-to-bottom.tsx +36 -0
- package/example/components/chat-history.tsx +49 -0
- package/example/components/chat-list.tsx +52 -0
- package/example/components/chat-message-actions.tsx +40 -0
- package/example/components/chat-message.tsx +80 -0
- package/example/components/chat-panel.tsx +139 -0
- package/example/components/chat-share-dialog.tsx +95 -0
- package/example/components/chat.tsx +84 -0
- package/example/components/clear-history.tsx +75 -0
- package/example/components/empty-screen.tsx +38 -0
- package/example/components/external-link.tsx +29 -0
- package/example/components/footer.tsx +19 -0
- package/example/components/header.tsx +80 -0
- package/example/components/login-button.tsx +42 -0
- package/example/components/login-form.tsx +97 -0
- package/example/components/markdown.tsx +9 -0
- package/example/components/prompt-form.tsx +115 -0
- package/example/components/providers.tsx +17 -0
- package/example/components/sidebar-actions.tsx +125 -0
- package/example/components/sidebar-desktop.tsx +19 -0
- package/example/components/sidebar-footer.tsx +16 -0
- package/example/components/sidebar-item.tsx +124 -0
- package/example/components/sidebar-items.tsx +42 -0
- package/example/components/sidebar-list.tsx +38 -0
- package/example/components/sidebar-mobile.tsx +31 -0
- package/example/components/sidebar-toggle.tsx +24 -0
- package/example/components/sidebar.tsx +21 -0
- package/example/components/signup-form.tsx +95 -0
- package/example/components/stocks/events-skeleton.tsx +31 -0
- package/example/components/stocks/events.tsx +30 -0
- package/example/components/stocks/index.tsx +36 -0
- package/example/components/stocks/message.tsx +134 -0
- package/example/components/stocks/spinner.tsx +16 -0
- package/example/components/stocks/stock-purchase.tsx +146 -0
- package/example/components/stocks/stock-skeleton.tsx +22 -0
- package/example/components/stocks/stock.tsx +210 -0
- package/example/components/stocks/stocks-skeleton.tsx +9 -0
- package/example/components/stocks/stocks.tsx +67 -0
- package/example/components/tailwind-indicator.tsx +14 -0
- package/example/components/theme-toggle.tsx +31 -0
- package/example/components/ui/alert-dialog.tsx +141 -0
- package/example/components/ui/badge.tsx +36 -0
- package/example/components/ui/button.tsx +57 -0
- package/example/components/ui/codeblock.tsx +148 -0
- package/example/components/ui/dialog.tsx +122 -0
- package/example/components/ui/dropdown-menu.tsx +205 -0
- package/example/components/ui/icons.tsx +507 -0
- package/example/components/ui/input.tsx +25 -0
- package/example/components/ui/label.tsx +26 -0
- package/example/components/ui/select.tsx +164 -0
- package/example/components/ui/separator.tsx +31 -0
- package/example/components/ui/sheet.tsx +140 -0
- package/example/components/ui/sonner.tsx +31 -0
- package/example/components/ui/switch.tsx +29 -0
- package/example/components/ui/textarea.tsx +24 -0
- package/example/components/ui/tooltip.tsx +30 -0
- package/example/components/user-menu.tsx +53 -0
- package/example/components.json +17 -0
- package/example/lib/chat/actions.tsx +606 -0
- package/example/lib/hooks/use-copy-to-clipboard.tsx +33 -0
- package/example/lib/hooks/use-enter-submit.tsx +23 -0
- package/example/lib/hooks/use-local-storage.ts +24 -0
- package/example/lib/hooks/use-scroll-anchor.tsx +86 -0
- package/example/lib/hooks/use-sidebar.tsx +60 -0
- package/example/lib/hooks/use-streamable-text.ts +25 -0
- package/example/lib/types.ts +41 -0
- package/example/lib/utils.ts +89 -0
- package/example/middleware.ts +8 -0
- package/example/next-env.d.ts +5 -0
- package/example/next.config.js +13 -0
- package/example/package-lock.json +9249 -0
- package/example/package.json +77 -0
- package/example/pnpm-lock.yaml +5712 -0
- package/example/postcss.config.js +6 -0
- package/example/prettier.config.cjs +34 -0
- package/example/public/apple-touch-icon.png +0 -0
- package/example/public/favicon-16x16.png +0 -0
- package/example/public/favicon.ico +0 -0
- package/example/public/next.svg +1 -0
- package/example/public/thirteen.svg +1 -0
- package/example/public/vercel.svg +1 -0
- package/example/tailwind.config.ts +81 -0
- package/example/tsconfig.json +35 -0
- package/package.json +45 -0
- package/src/helpers.ts +64 -0
- package/src/index.test.ts +255 -0
- package/src/index.ts +397 -0
- package/src/server/types/.gitkeep +0 -0
- package/src/types.ts +69 -0
- package/src/utils.ts +134 -0
- package/ts-to-zod.config.js +18 -0
- package/tsconfig.json +32 -0
- package/tsup.config.ts +10 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState, useRef, useEffect, useId } from 'react'
|
|
4
|
+
import { scaleLinear } from 'd3-scale'
|
|
5
|
+
import { subMonths, format } from 'date-fns'
|
|
6
|
+
import { useResizeObserver } from 'usehooks-ts'
|
|
7
|
+
import { useAIState } from 'ai/rsc'
|
|
8
|
+
|
|
9
|
+
interface Stock {
|
|
10
|
+
symbol: string
|
|
11
|
+
price: number
|
|
12
|
+
delta: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function Stock({ props: { symbol, price, delta } }: { props: Stock }) {
|
|
16
|
+
const [aiState, setAIState] = useAIState()
|
|
17
|
+
const id = useId()
|
|
18
|
+
|
|
19
|
+
const [priceAtTime, setPriceAtTime] = useState({
|
|
20
|
+
time: '00:00',
|
|
21
|
+
value: price.toFixed(2),
|
|
22
|
+
x: 0
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const [startHighlight, setStartHighlight] = useState(0)
|
|
26
|
+
const [endHighlight, setEndHighlight] = useState(0)
|
|
27
|
+
|
|
28
|
+
const chartRef = useRef<HTMLDivElement>(null)
|
|
29
|
+
const { width = 0 } = useResizeObserver({
|
|
30
|
+
ref: chartRef,
|
|
31
|
+
box: 'border-box'
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const xToDate = scaleLinear(
|
|
35
|
+
[0, width],
|
|
36
|
+
[subMonths(new Date(), 6), new Date()]
|
|
37
|
+
)
|
|
38
|
+
const xToValue = scaleLinear(
|
|
39
|
+
[0, width],
|
|
40
|
+
[price - price / 2, price + price / 2]
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (startHighlight && endHighlight) {
|
|
45
|
+
const message = {
|
|
46
|
+
id,
|
|
47
|
+
role: 'system' as const,
|
|
48
|
+
content: `[User has highlighted dates between between ${format(
|
|
49
|
+
xToDate(startHighlight),
|
|
50
|
+
'd LLL'
|
|
51
|
+
)} and ${format(xToDate(endHighlight), 'd LLL, yyyy')}`
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (aiState.messages[aiState.messages.length - 1]?.id === id) {
|
|
55
|
+
setAIState({
|
|
56
|
+
...aiState,
|
|
57
|
+
messages: [...aiState.messages.slice(0, -1), message]
|
|
58
|
+
})
|
|
59
|
+
} else {
|
|
60
|
+
setAIState({
|
|
61
|
+
...aiState,
|
|
62
|
+
messages: [...aiState.messages, message]
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}, [startHighlight, endHighlight])
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div className="rounded-xl border bg-zinc-950 p-4 text-green-400">
|
|
70
|
+
<div className="float-right inline-block rounded-full bg-white/10 px-2 py-1 text-xs">
|
|
71
|
+
{`${delta > 0 ? '+' : ''}${((delta / price) * 100).toFixed(2)}% ${
|
|
72
|
+
delta > 0 ? '↑' : '↓'
|
|
73
|
+
}`}
|
|
74
|
+
</div>
|
|
75
|
+
<div className="text-lg text-zinc-300">{symbol}</div>
|
|
76
|
+
<div className="text-3xl font-bold">${price}</div>
|
|
77
|
+
<div className="text mt-1 text-xs text-zinc-500">
|
|
78
|
+
Closed: Feb 27, 4:59 PM EST
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div
|
|
82
|
+
className="relative -mx-4 cursor-col-resize"
|
|
83
|
+
onPointerDown={event => {
|
|
84
|
+
if (chartRef.current) {
|
|
85
|
+
const { clientX } = event
|
|
86
|
+
const { left } = chartRef.current.getBoundingClientRect()
|
|
87
|
+
|
|
88
|
+
setStartHighlight(clientX - left)
|
|
89
|
+
setEndHighlight(0)
|
|
90
|
+
|
|
91
|
+
setPriceAtTime({
|
|
92
|
+
time: format(xToDate(clientX), 'dd LLL yy'),
|
|
93
|
+
value: xToValue(clientX).toFixed(2),
|
|
94
|
+
x: clientX - left
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
}}
|
|
98
|
+
onPointerUp={event => {
|
|
99
|
+
if (chartRef.current) {
|
|
100
|
+
const { clientX } = event
|
|
101
|
+
const { left } = chartRef.current.getBoundingClientRect()
|
|
102
|
+
|
|
103
|
+
setEndHighlight(clientX - left)
|
|
104
|
+
}
|
|
105
|
+
}}
|
|
106
|
+
onPointerMove={event => {
|
|
107
|
+
if (chartRef.current) {
|
|
108
|
+
const { clientX } = event
|
|
109
|
+
const { left } = chartRef.current.getBoundingClientRect()
|
|
110
|
+
|
|
111
|
+
setPriceAtTime({
|
|
112
|
+
time: format(xToDate(clientX), 'dd LLL yy'),
|
|
113
|
+
value: xToValue(clientX).toFixed(2),
|
|
114
|
+
x: clientX - left
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
}}
|
|
118
|
+
onPointerLeave={() => {
|
|
119
|
+
setPriceAtTime({
|
|
120
|
+
time: '00:00',
|
|
121
|
+
value: price.toFixed(2),
|
|
122
|
+
x: 0
|
|
123
|
+
})
|
|
124
|
+
}}
|
|
125
|
+
ref={chartRef}
|
|
126
|
+
>
|
|
127
|
+
{priceAtTime.x > 0 ? (
|
|
128
|
+
<div
|
|
129
|
+
className="pointer-events-none absolute z-10 flex w-fit select-none gap-2 rounded-md bg-zinc-800 p-2"
|
|
130
|
+
style={{
|
|
131
|
+
left: priceAtTime.x - 124 / 2,
|
|
132
|
+
top: 30
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
<div className="text-xs tabular-nums">${priceAtTime.value}</div>
|
|
136
|
+
<div className="text-xs tabular-nums text-zinc-400">
|
|
137
|
+
{priceAtTime.time}
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
) : null}
|
|
141
|
+
|
|
142
|
+
{startHighlight ? (
|
|
143
|
+
<div
|
|
144
|
+
className="pointer-events-none absolute h-32 w-5 select-none rounded-md border border-zinc-500 bg-zinc-500/20"
|
|
145
|
+
style={{
|
|
146
|
+
left: startHighlight,
|
|
147
|
+
width: endHighlight
|
|
148
|
+
? endHighlight - startHighlight
|
|
149
|
+
: priceAtTime.x - startHighlight,
|
|
150
|
+
bottom: 0
|
|
151
|
+
}}
|
|
152
|
+
></div>
|
|
153
|
+
) : null}
|
|
154
|
+
|
|
155
|
+
<svg
|
|
156
|
+
viewBox="0 0 250.0 168.0"
|
|
157
|
+
height="150"
|
|
158
|
+
width="100%"
|
|
159
|
+
preserveAspectRatio="none"
|
|
160
|
+
>
|
|
161
|
+
<defs>
|
|
162
|
+
<linearGradient
|
|
163
|
+
id="fill-id-tsuid_31"
|
|
164
|
+
x1="0%"
|
|
165
|
+
x2="0%"
|
|
166
|
+
y1="0%"
|
|
167
|
+
y2="100%"
|
|
168
|
+
>
|
|
169
|
+
<stop offset="0%" stopColor="#34a853" stopOpacity="0.38"></stop>
|
|
170
|
+
<stop offset="13%" stopColor="#e6f4ea" stopOpacity="0"></stop>
|
|
171
|
+
</linearGradient>
|
|
172
|
+
<clipPath id="range-id-tsuid_31">
|
|
173
|
+
<rect height="100%" width="0" x="0" y="0"></rect>
|
|
174
|
+
</clipPath>
|
|
175
|
+
<defs>
|
|
176
|
+
<linearGradient
|
|
177
|
+
id="chart-grad-_f1bJZYLUHqWpxc8Prs2meA_33"
|
|
178
|
+
x1="0%"
|
|
179
|
+
x2="0%"
|
|
180
|
+
y1="0%"
|
|
181
|
+
y2="100%"
|
|
182
|
+
>
|
|
183
|
+
<stop offset="0%" stopColor="#34a853" stopOpacity="0.38"></stop>
|
|
184
|
+
<stop offset="13%" stopColor="#e6f4ea" stopOpacity="0"></stop>
|
|
185
|
+
</linearGradient>
|
|
186
|
+
</defs>
|
|
187
|
+
<clipPath id="mask-_f1bJZYLUHqWpxc8Prs2meA_32">
|
|
188
|
+
<rect height="218" width="250" x="0" y="-5"></rect>
|
|
189
|
+
</clipPath>
|
|
190
|
+
</defs>
|
|
191
|
+
<path
|
|
192
|
+
d="M 0 42.86 L 0.89 46.26 L 1.78 44.3 L 2.68 44.24 L 3.57 42 L 4.46 43.42 L 5.35 43.62 L 6.25 47 L 7.14 47.65 L 8.03 47.69 L 8.92 45.55 L 9.82 43.19 L 10.71 43.9 L 11.6 42.83 L 12.49 42.81 L 13.39 46.75 L 14.28 43.06 L 15.17 40.8 L 16.06 39.72 L 16.96 39.77 L 17.85 45.77 L 18.74 44.93 L 19.63 44.35 L 20.53 40.29 L 21.42 42.77 L 22.31 42.12 L 23.2 43.4 L 24.1 47.95 L 24.99 50.15 L 25.88 48.59 L 26.77 42.18 L 27.67 44.1 L 28.56 39.91 L 29.45 44.92 L 30.34 47.62 L 31.24 48.06 L 32.13 47.67 L 33.02 56.47 L 33.91 57.74 L 34.8 65.48 L 35.7 64.47 L 36.59 47.25 L 37.48 58.26 L 38.37 52.04 L 39.27 55.8 L 40.16 92.92 L 41.05 105.2 L 41.94 102 L 42.84 106.14 L 43.73 78.71 L 44.62 104.6 L 45.51 96.58 L 46.41 67.56 L 47.3 69.53 L 48.19 69.99 L 49.08 66.75 L 49.98 69.72 L 50.87 70.13 L 51.76 71.3 L 52.65 70.03 L 53.55 67.92 L 54.44 66.41 L 55.33 97.12 L 56.22 95.93 L 57.12 95.03 L 58.01 95.09 L 58.9 65.56 L 59.79 65.12 L 60.69 82.42 L 61.58 74.7 L 62.47 71.13 L 63.36 82.43 L 64.26 96.02 L 65.15 100.36 L 66.04 98.6 L 66.93 103.37 L 67.82 102.12 L 68.72 97.08 L 69.61 89.74 L 70.5 90.7 L 71.39 93.46 L 72.29 94.24 L 73.18 97.8 L 74.07 97.88 L 74.96 96.63 L 75.86 96.27 L 76.75 97.15 L 77.64 100.12 L 78.53 100.51 L 79.43 106.59 L 80.32 104.54 L 81.21 100.31 L 82.1 118.76 L 83 106.24 L 83.89 114.8 L 84.78 174.89 L 85.67 122.28 L 86.57 149.25 L 87.46 151.47 L 88.35 153.38 L 89.24 153.5 L 90.14 149.24 L 91.03 122.44 L 91.92 122.08 L 92.81 147.16 L 93.71 147.46 L 94.6 119.13 L 95.49 117.97 L 96.38 122.22 L 97.28 116.38 L 98.17 119.53 L 99.06 119.65 L 99.95 120.15 L 100.84 120.22 L 101.74 121.28 L 102.63 121.4 L 103.52 122.97 L 104.41 122.15 L 105.31 120.6 L 106.2 116.55 L 107.09 122.23 L 107.98 120.96 L 108.88 119.54 L 109.77 120.19 L 110.66 120.99 L 111.55 119.92 L 112.45 115.69 L 113.34 116.33 L 114.23 116.07 L 115.12 115.34 L 116.02 111.34 L 116.91 107.23 L 117.8 113.21 L 118.69 98.77 L 119.59 97.04 L 120.48 96.56 L 121.37 96.36 L 122.26 99.7 L 123.16 103.33 L 124.05 100.38 L 124.94 99.68 L 125.83 99.02 L 126.73 102.56 L 127.62 103.25 L 128.51 103.38 L 129.4 104.89 L 130.3 118.07 L 131.19 100.82 L 132.08 103.06 L 132.97 103.47 L 133.86 99.8 L 134.76 111.28 L 135.65 107.73 L 136.54 107.46 L 137.43 108.08 L 138.33 109.82 L 139.22 110.94 L 140.11 111.3 L 141 108.14 L 141.9 109.35 L 142.79 108.38 L 143.68 99.08 L 144.57 99.02 L 145.47 98.61 L 146.36 99.07 L 147.25 99.26 L 148.14 95.1 L 149.04 92.08 L 149.93 92.76 L 150.82 92.87 L 151.71 83.31 L 152.61 82.93 L 153.5 84.86 L 154.39 84.12 L 155.28 94.08 L 156.18 93.31 L 157.07 94.23 L 157.96 94.58 L 158.85 99.33 L 159.75 80 L 160.64 90.28 L 161.53 84.07 L 162.42 68.37 L 163.32 76.88 L 164.21 81.78 L 165.1 80.72 L 165.99 73.89 L 166.88 77.14 L 167.78 67.58 L 168.67 59.82 L 169.56 61.91 L 170.45 61.07 L 171.35 73.74 L 172.24 77.02 L 173.13 78.61 L 174.02 71.59 L 174.92 68.24 L 175.81 72.14 L 176.7 65.37 L 177.59 76.73 L 178.49 88.02 L 179.38 88.01 L 180.27 88.27 L 181.16 86.23 L 182.06 86.14 L 182.95 89.54 L 183.84 94.16 L 184.73 97.72 L 185.63 81.52 L 186.52 92.85 L 187.41 94.14 L 188.3 93.06 L 189.2 92.64 L 190.09 92.44 L 190.98 91.75 L 191.87 90.53 L 192.77 88.27 L 193.66 85.44 L 194.55 82.26 L 195.44 85.08 L 196.34 85.65 L 197.23 53.43 L 198.12 72.01 L 199.01 38.37 L 199.9 69.43 L 200.8 74.46 L 201.69 74.22 L 202.58 82.46 L 203.47 77.01 L 204.37 87.8 L 205.26 91.56 L 206.15 76.69 L 207.04 76.46 L 207.94 78.13 L 208.83 80.06 L 209.72 92.79 L 210.61 87.74 L 211.51 88.21 L 212.4 88.47 L 213.29 87.35 L 214.18 89.69 L 215.08 77.37 L 215.97 87.95 L 216.86 75.16 L 217.75 70.47 L 218.65 85.11 L 219.54 88.1 L 220.43 88.06 L 221.32 86.34 L 222.22 76.91 L 223.11 75.33 L 224 73.6 L 224.89 25.31 L 225.79 44.14 L 226.68 43.93 L 227.57 45.13 L 228.46 44.03 L 229.36 35.73 L 230.25 33.65 L 231.14 34.81 L 232.03 17.64 L 232.92 21.13 L 233.82 19.37 L 234.71 24.66 L 235.6 23.87 L 236.49 22.56 L 237.39 28.48 L 238.28 25.33 L 239.17 28.51 L 240.06 30.83 L 240.96 35.79 L 241.85 34.6 L 242.74 31.2 L 243.63 32.97 L 244.53 33.01 L 245.42 31.38 L 246.31 30.21 L 247.2 27.75 L 248.1 25.27 L 248.99 23 L 249.88 23 L 250 23 L 2000 0 L 2000 1000 L -1000 1000"
|
|
193
|
+
clipPath="url(#range-id-tsuid_31)"
|
|
194
|
+
vectorEffect="non-scaling-stroke"
|
|
195
|
+
stroke="none"
|
|
196
|
+
strokeWidth={2}
|
|
197
|
+
fill='url("#fill-id-tsuid_31")'
|
|
198
|
+
></path>
|
|
199
|
+
<path
|
|
200
|
+
clipPath="url(#mask-_f1bJZYLUHqWpxc8Prs2meA_32)"
|
|
201
|
+
d="M 0 42.86 L 0.89 46.26 L 1.78 44.3 L 2.68 44.24 L 3.57 42 L 4.46 43.42 L 5.35 43.62 L 6.25 47 L 7.14 47.65 L 8.03 47.69 L 8.92 45.55 L 9.82 43.19 L 10.71 43.9 L 11.6 42.83 L 12.49 42.81 L 13.39 46.75 L 14.28 43.06 L 15.17 40.8 L 16.06 39.72 L 16.96 39.77 L 17.85 45.77 L 18.74 44.93 L 19.63 44.35 L 20.53 40.29 L 21.42 42.77 L 22.31 42.12 L 23.2 43.4 L 24.1 47.95 L 24.99 50.15 L 25.88 48.59 L 26.77 42.18 L 27.67 44.1 L 28.56 39.91 L 29.45 44.92 L 30.34 47.62 L 31.24 48.06 L 32.13 47.67 L 33.02 56.47 L 33.91 57.74 L 34.8 65.48 L 35.7 64.47 L 36.59 47.25 L 37.48 58.26 L 38.37 52.04 L 39.27 55.8 L 40.16 92.92 L 41.05 105.2 L 41.94 102 L 42.84 106.14 L 43.73 78.71 L 44.62 104.6 L 45.51 96.58 L 46.41 67.56 L 47.3 69.53 L 48.19 69.99 L 49.08 66.75 L 49.98 69.72 L 50.87 70.13 L 51.76 71.3 L 52.65 70.03 L 53.55 67.92 L 54.44 66.41 L 55.33 97.12 L 56.22 95.93 L 57.12 95.03 L 58.01 95.09 L 58.9 65.56 L 59.79 65.12 L 60.69 82.42 L 61.58 74.7 L 62.47 71.13 L 63.36 82.43 L 64.26 96.02 L 65.15 100.36 L 66.04 98.6 L 66.93 103.37 L 67.82 102.12 L 68.72 97.08 L 69.61 89.74 L 70.5 90.7 L 71.39 93.46 L 72.29 94.24 L 73.18 97.8 L 74.07 97.88 L 74.96 96.63 L 75.86 96.27 L 76.75 97.15 L 77.64 100.12 L 78.53 100.51 L 79.43 106.59 L 80.32 104.54 L 81.21 100.31 L 82.1 118.76 L 83 106.24 L 83.89 114.8 L 84.78 174.89 L 85.67 122.28 L 86.57 149.25 L 87.46 151.47 L 88.35 153.38 L 89.24 153.5 L 90.14 149.24 L 91.03 122.44 L 91.92 122.08 L 92.81 147.16 L 93.71 147.46 L 94.6 119.13 L 95.49 117.97 L 96.38 122.22 L 97.28 116.38 L 98.17 119.53 L 99.06 119.65 L 99.95 120.15 L 100.84 120.22 L 101.74 121.28 L 102.63 121.4 L 103.52 122.97 L 104.41 122.15 L 105.31 120.6 L 106.2 116.55 L 107.09 122.23 L 107.98 120.96 L 108.88 119.54 L 109.77 120.19 L 110.66 120.99 L 111.55 119.92 L 112.45 115.69 L 113.34 116.33 L 114.23 116.07 L 115.12 115.34 L 116.02 111.34 L 116.91 107.23 L 117.8 113.21 L 118.69 98.77 L 119.59 97.04 L 120.48 96.56 L 121.37 96.36 L 122.26 99.7 L 123.16 103.33 L 124.05 100.38 L 124.94 99.68 L 125.83 99.02 L 126.73 102.56 L 127.62 103.25 L 128.51 103.38 L 129.4 104.89 L 130.3 118.07 L 131.19 100.82 L 132.08 103.06 L 132.97 103.47 L 133.86 99.8 L 134.76 111.28 L 135.65 107.73 L 136.54 107.46 L 137.43 108.08 L 138.33 109.82 L 139.22 110.94 L 140.11 111.3 L 141 108.14 L 141.9 109.35 L 142.79 108.38 L 143.68 99.08 L 144.57 99.02 L 145.47 98.61 L 146.36 99.07 L 147.25 99.26 L 148.14 95.1 L 149.04 92.08 L 149.93 92.76 L 150.82 92.87 L 151.71 83.31 L 152.61 82.93 L 153.5 84.86 L 154.39 84.12 L 155.28 94.08 L 156.18 93.31 L 157.07 94.23 L 157.96 94.58 L 158.85 99.33 L 159.75 80 L 160.64 90.28 L 161.53 84.07 L 162.42 68.37 L 163.32 76.88 L 164.21 81.78 L 165.1 80.72 L 165.99 73.89 L 166.88 77.14 L 167.78 67.58 L 168.67 59.82 L 169.56 61.91 L 170.45 61.07 L 171.35 73.74 L 172.24 77.02 L 173.13 78.61 L 174.02 71.59 L 174.92 68.24 L 175.81 72.14 L 176.7 65.37 L 177.59 76.73 L 178.49 88.02 L 179.38 88.01 L 180.27 88.27 L 181.16 86.23 L 182.06 86.14 L 182.95 89.54 L 183.84 94.16 L 184.73 97.72 L 185.63 81.52 L 186.52 92.85 L 187.41 94.14 L 188.3 93.06 L 189.2 92.64 L 190.09 92.44 L 190.98 91.75 L 191.87 90.53 L 192.77 88.27 L 193.66 85.44 L 194.55 82.26 L 195.44 85.08 L 196.34 85.65 L 197.23 53.43 L 198.12 72.01 L 199.01 38.37 L 199.9 69.43 L 200.8 74.46 L 201.69 74.22 L 202.58 82.46 L 203.47 77.01 L 204.37 87.8 L 205.26 91.56 L 206.15 76.69 L 207.04 76.46 L 207.94 78.13 L 208.83 80.06 L 209.72 92.79 L 210.61 87.74 L 211.51 88.21 L 212.4 88.47 L 213.29 87.35 L 214.18 89.69 L 215.08 77.37 L 215.97 87.95 L 216.86 75.16 L 217.75 70.47 L 218.65 85.11 L 219.54 88.1 L 220.43 88.06 L 221.32 86.34 L 222.22 76.91 L 223.11 75.33 L 224 73.6 L 224.89 25.31 L 225.79 44.14 L 226.68 43.93 L 227.57 45.13 L 228.46 44.03 L 229.36 35.73 L 230.25 33.65 L 231.14 34.81 L 232.03 17.64 L 232.92 21.13 L 233.82 19.37 L 234.71 24.66 L 235.6 23.87 L 236.49 22.56 L 237.39 28.48 L 238.28 25.33 L 239.17 28.51 L 240.06 30.83 L 240.96 35.79 L 241.85 34.6 L 242.74 31.2 L 243.63 32.97 L 244.53 33.01 L 245.42 31.38 L 246.31 30.21 L 247.2 27.75 L 248.1 25.27 L 248.99 23 L 249.88 23 L 250 23 L 2000 0 L 2000 1000 L -1000 1000"
|
|
202
|
+
vectorEffect="non-scaling-stroke"
|
|
203
|
+
stroke="#34a853"
|
|
204
|
+
style={{ fill: 'url(#chart-grad-_f1bJZYLUHqWpxc8Prs2meA_33)' }}
|
|
205
|
+
></path>
|
|
206
|
+
</svg>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
)
|
|
210
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const StocksSkeleton = () => {
|
|
2
|
+
return (
|
|
3
|
+
<div className="mb-4 flex flex-col gap-2 overflow-y-scroll pb-4 text-sm sm:flex-row">
|
|
4
|
+
<div className="flex h-[60px] w-full cursor-pointer flex-row gap-2 rounded-lg bg-zinc-800 p-2 text-left hover:bg-zinc-800 sm:w-[208px]"></div>
|
|
5
|
+
<div className="flex h-[60px] w-full cursor-pointer flex-row gap-2 rounded-lg bg-zinc-800 p-2 text-left hover:bg-zinc-800 sm:w-[208px]"></div>
|
|
6
|
+
<div className="flex h-[60px] w-full cursor-pointer flex-row gap-2 rounded-lg bg-zinc-800 p-2 text-left hover:bg-zinc-800 sm:w-[208px]"></div>
|
|
7
|
+
</div>
|
|
8
|
+
)
|
|
9
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useActions, useUIState } from 'ai/rsc'
|
|
4
|
+
|
|
5
|
+
import type { AI } from '@/lib/chat/actions'
|
|
6
|
+
|
|
7
|
+
interface Stock {
|
|
8
|
+
symbol: string
|
|
9
|
+
price: number
|
|
10
|
+
delta: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function Stocks({ props: stocks }: { props: Stock[] }) {
|
|
14
|
+
const [, setMessages] = useUIState<typeof AI>()
|
|
15
|
+
const { submitUserMessage } = useActions()
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div>
|
|
19
|
+
<div className="mb-4 flex flex-col gap-2 overflow-y-scroll pb-4 text-sm sm:flex-row">
|
|
20
|
+
{stocks.map(stock => (
|
|
21
|
+
<button
|
|
22
|
+
key={stock.symbol}
|
|
23
|
+
className="flex cursor-pointer flex-row gap-2 rounded-lg bg-zinc-800 p-2 text-left hover:bg-zinc-700 sm:w-52"
|
|
24
|
+
onClick={async () => {
|
|
25
|
+
const response = await submitUserMessage(`View ${stock.symbol}`)
|
|
26
|
+
setMessages(currentMessages => [...currentMessages, response])
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
<div
|
|
30
|
+
className={`text-xl ${
|
|
31
|
+
stock.delta > 0 ? 'text-green-600' : 'text-red-600'
|
|
32
|
+
} flex w-11 flex-row justify-center rounded-md bg-white/10 p-2`}
|
|
33
|
+
>
|
|
34
|
+
{stock.delta > 0 ? '↑' : '↓'}
|
|
35
|
+
</div>
|
|
36
|
+
<div className="flex flex-col">
|
|
37
|
+
<div className="bold uppercase text-zinc-300">{stock.symbol}</div>
|
|
38
|
+
<div className="text-base text-zinc-500">
|
|
39
|
+
${stock.price.toExponential(1)}
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
<div className="ml-auto flex flex-col">
|
|
43
|
+
<div
|
|
44
|
+
className={`${
|
|
45
|
+
stock.delta > 0 ? 'text-green-600' : 'text-red-600'
|
|
46
|
+
} bold text-right uppercase`}
|
|
47
|
+
>
|
|
48
|
+
{` ${((stock.delta / stock.price) * 100).toExponential(1)}%`}
|
|
49
|
+
</div>
|
|
50
|
+
<div
|
|
51
|
+
className={`${
|
|
52
|
+
stock.delta > 0 ? 'text-green-700' : 'text-red-700'
|
|
53
|
+
} text-right text-base`}
|
|
54
|
+
>
|
|
55
|
+
{stock.delta.toExponential(1)}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</button>
|
|
59
|
+
))}
|
|
60
|
+
</div>
|
|
61
|
+
<div className="p-4 text-center text-sm text-zinc-500">
|
|
62
|
+
Note: Data and latency are simulated for illustrative purposes and
|
|
63
|
+
should not be considered as financial advice.
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function TailwindIndicator() {
|
|
2
|
+
if (process.env.NODE_ENV === 'production') return null
|
|
3
|
+
|
|
4
|
+
return (
|
|
5
|
+
<div className="fixed bottom-1 left-1 z-50 flex size-6 items-center justify-center rounded-full bg-gray-800 p-3 font-mono text-xs text-white">
|
|
6
|
+
<div className="block sm:hidden">xs</div>
|
|
7
|
+
<div className="hidden sm:block md:hidden">sm</div>
|
|
8
|
+
<div className="hidden md:block lg:hidden">md</div>
|
|
9
|
+
<div className="hidden lg:block xl:hidden">lg</div>
|
|
10
|
+
<div className="hidden xl:block 2xl:hidden">xl</div>
|
|
11
|
+
<div className="hidden 2xl:block">2xl</div>
|
|
12
|
+
</div>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { useTheme } from 'next-themes'
|
|
5
|
+
|
|
6
|
+
import { Button } from '@/components/ui/button'
|
|
7
|
+
import { IconMoon, IconSun } from '@/components/ui/icons'
|
|
8
|
+
|
|
9
|
+
export function ThemeToggle() {
|
|
10
|
+
const { setTheme, theme } = useTheme()
|
|
11
|
+
const [_, startTransition] = React.useTransition()
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Button
|
|
15
|
+
variant="ghost"
|
|
16
|
+
size="icon"
|
|
17
|
+
onClick={() => {
|
|
18
|
+
startTransition(() => {
|
|
19
|
+
setTheme(theme === 'light' ? 'dark' : 'light')
|
|
20
|
+
})
|
|
21
|
+
}}
|
|
22
|
+
>
|
|
23
|
+
{!theme ? null : theme === 'dark' ? (
|
|
24
|
+
<IconMoon className="transition-all" />
|
|
25
|
+
) : (
|
|
26
|
+
<IconSun className="transition-all" />
|
|
27
|
+
)}
|
|
28
|
+
<span className="sr-only">Toggle theme</span>
|
|
29
|
+
</Button>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
import { buttonVariants } from "@/components/ui/button"
|
|
8
|
+
|
|
9
|
+
const AlertDialog = AlertDialogPrimitive.Root
|
|
10
|
+
|
|
11
|
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
|
|
12
|
+
|
|
13
|
+
const AlertDialogPortal = AlertDialogPrimitive.Portal
|
|
14
|
+
|
|
15
|
+
const AlertDialogOverlay = React.forwardRef<
|
|
16
|
+
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
|
17
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
|
18
|
+
>(({ className, ...props }, ref) => (
|
|
19
|
+
<AlertDialogPrimitive.Overlay
|
|
20
|
+
className={cn(
|
|
21
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
22
|
+
className
|
|
23
|
+
)}
|
|
24
|
+
{...props}
|
|
25
|
+
ref={ref}
|
|
26
|
+
/>
|
|
27
|
+
))
|
|
28
|
+
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
|
|
29
|
+
|
|
30
|
+
const AlertDialogContent = React.forwardRef<
|
|
31
|
+
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
|
32
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
|
33
|
+
>(({ className, ...props }, ref) => (
|
|
34
|
+
<AlertDialogPortal>
|
|
35
|
+
<AlertDialogOverlay />
|
|
36
|
+
<AlertDialogPrimitive.Content
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn(
|
|
39
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
|
40
|
+
className
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
</AlertDialogPortal>
|
|
45
|
+
))
|
|
46
|
+
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
|
47
|
+
|
|
48
|
+
const AlertDialogHeader = ({
|
|
49
|
+
className,
|
|
50
|
+
...props
|
|
51
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
52
|
+
<div
|
|
53
|
+
className={cn(
|
|
54
|
+
"flex flex-col space-y-2 text-center sm:text-left",
|
|
55
|
+
className
|
|
56
|
+
)}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
)
|
|
60
|
+
AlertDialogHeader.displayName = "AlertDialogHeader"
|
|
61
|
+
|
|
62
|
+
const AlertDialogFooter = ({
|
|
63
|
+
className,
|
|
64
|
+
...props
|
|
65
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
66
|
+
<div
|
|
67
|
+
className={cn(
|
|
68
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
69
|
+
className
|
|
70
|
+
)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
)
|
|
74
|
+
AlertDialogFooter.displayName = "AlertDialogFooter"
|
|
75
|
+
|
|
76
|
+
const AlertDialogTitle = React.forwardRef<
|
|
77
|
+
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
|
78
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
|
79
|
+
>(({ className, ...props }, ref) => (
|
|
80
|
+
<AlertDialogPrimitive.Title
|
|
81
|
+
ref={ref}
|
|
82
|
+
className={cn("text-lg font-semibold", className)}
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
))
|
|
86
|
+
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
|
87
|
+
|
|
88
|
+
const AlertDialogDescription = React.forwardRef<
|
|
89
|
+
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
|
90
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
|
91
|
+
>(({ className, ...props }, ref) => (
|
|
92
|
+
<AlertDialogPrimitive.Description
|
|
93
|
+
ref={ref}
|
|
94
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
95
|
+
{...props}
|
|
96
|
+
/>
|
|
97
|
+
))
|
|
98
|
+
AlertDialogDescription.displayName =
|
|
99
|
+
AlertDialogPrimitive.Description.displayName
|
|
100
|
+
|
|
101
|
+
const AlertDialogAction = React.forwardRef<
|
|
102
|
+
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
|
103
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
|
104
|
+
>(({ className, ...props }, ref) => (
|
|
105
|
+
<AlertDialogPrimitive.Action
|
|
106
|
+
ref={ref}
|
|
107
|
+
className={cn(buttonVariants(), className)}
|
|
108
|
+
{...props}
|
|
109
|
+
/>
|
|
110
|
+
))
|
|
111
|
+
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
|
|
112
|
+
|
|
113
|
+
const AlertDialogCancel = React.forwardRef<
|
|
114
|
+
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
|
115
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
|
116
|
+
>(({ className, ...props }, ref) => (
|
|
117
|
+
<AlertDialogPrimitive.Cancel
|
|
118
|
+
ref={ref}
|
|
119
|
+
className={cn(
|
|
120
|
+
buttonVariants({ variant: "outline" }),
|
|
121
|
+
"mt-2 sm:mt-0",
|
|
122
|
+
className
|
|
123
|
+
)}
|
|
124
|
+
{...props}
|
|
125
|
+
/>
|
|
126
|
+
))
|
|
127
|
+
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
|
128
|
+
|
|
129
|
+
export {
|
|
130
|
+
AlertDialog,
|
|
131
|
+
AlertDialogPortal,
|
|
132
|
+
AlertDialogOverlay,
|
|
133
|
+
AlertDialogTrigger,
|
|
134
|
+
AlertDialogContent,
|
|
135
|
+
AlertDialogHeader,
|
|
136
|
+
AlertDialogFooter,
|
|
137
|
+
AlertDialogTitle,
|
|
138
|
+
AlertDialogDescription,
|
|
139
|
+
AlertDialogAction,
|
|
140
|
+
AlertDialogCancel,
|
|
141
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
const badgeVariants = cva(
|
|
7
|
+
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default:
|
|
12
|
+
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
|
13
|
+
secondary:
|
|
14
|
+
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
15
|
+
destructive:
|
|
16
|
+
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
|
17
|
+
outline: "text-foreground",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: "default",
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
export interface BadgeProps
|
|
27
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
28
|
+
VariantProps<typeof badgeVariants> {}
|
|
29
|
+
|
|
30
|
+
function Badge({ className, variant, ...props }: BadgeProps) {
|
|
31
|
+
return (
|
|
32
|
+
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { Badge, badgeVariants }
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot'
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
4
|
+
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
'bg-primary text-primary-foreground shadow hover:bg-primary/90',
|
|
14
|
+
destructive:
|
|
15
|
+
'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
|
|
16
|
+
outline:
|
|
17
|
+
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
|
|
18
|
+
secondary:
|
|
19
|
+
'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
|
|
20
|
+
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
21
|
+
link: 'text-primary underline-offset-4 hover:underline'
|
|
22
|
+
},
|
|
23
|
+
size: {
|
|
24
|
+
default: 'h-9 px-4 py-2',
|
|
25
|
+
sm: 'h-8 rounded-md px-3 text-xs',
|
|
26
|
+
lg: 'h-10 rounded-md px-8',
|
|
27
|
+
icon: 'size-9'
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
defaultVariants: {
|
|
31
|
+
variant: 'default',
|
|
32
|
+
size: 'default'
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
export interface ButtonProps
|
|
38
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
39
|
+
VariantProps<typeof buttonVariants> {
|
|
40
|
+
asChild?: boolean
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
44
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
45
|
+
const Comp = asChild ? Slot : 'button'
|
|
46
|
+
return (
|
|
47
|
+
<Comp
|
|
48
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
49
|
+
ref={ref}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
Button.displayName = 'Button'
|
|
56
|
+
|
|
57
|
+
export { Button, buttonVariants }
|