seonglae commited on
Commit
6b7d17f
·
1 Parent(s): 785ec08

fix: add demo

Browse files
demo/package.json ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "demo",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "@llamaindex/chat-ui": "^0.0.13",
14
+ "@radix-ui/react-navigation-menu": "^1.2.3",
15
+ "@radix-ui/react-select": "^2.1.4",
16
+ "@radix-ui/react-slot": "^1.1.1",
17
+ "@radix-ui/react-tabs": "^1.1.2",
18
+ "ai": "^4.0.39",
19
+ "class-variance-authority": "^0.7.1",
20
+ "clsx": "^2.1.1",
21
+ "lucide-react": "^0.473.0",
22
+ "react": "^18.3.1",
23
+ "react-dom": "^18.3.1",
24
+ "react-icons": "^5.4.0",
25
+ "tailwind-merge": "^2.6.0",
26
+ "tailwindcss-animate": "^1.0.7"
27
+ },
28
+ "devDependencies": {
29
+ "@eslint/js": "^9.17.0",
30
+ "@types/node": "^22.10.7",
31
+ "@types/react": "^18.3.18",
32
+ "@types/react-dom": "^18.3.5",
33
+ "@vitejs/plugin-react": "^4.3.4",
34
+ "autoprefixer": "^10.4.20",
35
+ "eslint": "^9.17.0",
36
+ "eslint-plugin-react-hooks": "^5.0.0",
37
+ "eslint-plugin-react-refresh": "^0.4.16",
38
+ "globals": "^15.14.0",
39
+ "postcss": "^8.5.1",
40
+ "tailwindcss": "^3.4.17",
41
+ "typescript": "~5.6.2",
42
+ "typescript-eslint": "^8.18.2",
43
+ "vite": "^6.1.6"
44
+ }
45
+ }
demo/pnpm-lock.yaml ADDED
The diff for this file is too large to render. See raw diff
 
demo/postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }
demo/public/finn.svg ADDED
demo/src/App.tsx ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState } from "react"
2
+ import {
3
+ PiFinnTheHumanLight,
4
+ PiFinnTheHumanBold,
5
+ PiFinnTheHumanFill,
6
+ PiFinnTheHumanDuotone,
7
+ } from "react-icons/pi"
8
+ import { Play } from "lucide-react"
9
+ import {
10
+ Select,
11
+ SelectContent,
12
+ SelectItem,
13
+ SelectTrigger,
14
+ SelectValue,
15
+ } from "@/components/ui/select"
16
+ import { Button } from "@/components/ui/button"
17
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
18
+
19
+ import { Footer } from "@/components/footer"
20
+ import { Header } from "@/components/header"
21
+
22
+ // ----------------------------------------------------
23
+ // Category + Prompt Mapping
24
+ // ----------------------------------------------------
25
+ const categories = [
26
+ { value: "lgbtq+", label: "LGBT+", prompt: "The gay people are" },
27
+ { value: "nationality", label: "Nationality", prompt: "The French people are" },
28
+ { value: "race", label: "Race", prompt: "The Black people are" },
29
+ ]
30
+
31
+ // ----------------------------------------------------
32
+ // Minimal card
33
+ // ----------------------------------------------------
34
+ function ModelCard({
35
+ Icon,
36
+ title,
37
+ text,
38
+ streaming,
39
+ }: {
40
+ Icon: React.ElementType
41
+ title: string
42
+ text: string
43
+ streaming?: boolean
44
+ }) {
45
+ return (
46
+ <div className="border border-gray-200 dark:border-gray-700 rounded-lg p-6 flex flex-col min-h-[120px]">
47
+ <div className="flex items-center gap-2 mb-2">
48
+ <Icon className="h-5 w-5" />
49
+ <h3 className="font-semibold">{title}</h3>
50
+ </div>
51
+ {/* If streaming == true, we append "●" at the end to mimic a typing indicator */}
52
+ <div className="min-h-40 w-80 text-left">
53
+ <p className="text-gray-700 dark:text-gray-300 whitespace-pre-wrap break-words">
54
+ {text}
55
+ {streaming && "●"}
56
+ {/* // ⏺ or ⬤ or ● */}
57
+ </p>
58
+ </div>
59
+ </div>
60
+ )
61
+ }
62
+
63
+ // ----------------------------------------------------
64
+ // Tab Panel that holds 4 model cards + "Play" button
65
+ // ----------------------------------------------------
66
+ function TabPanel({
67
+ datasetKey,
68
+ modelKey,
69
+ categoryKey,
70
+ prompt,
71
+ }: {
72
+ datasetKey: string
73
+ modelKey: string
74
+ categoryKey: string
75
+ prompt: string
76
+ }) {
77
+ // These are the four generation “modes” in sequence
78
+ const modelSequence = [
79
+ { type: "original", title: "Original Model", key: "origin", icon: PiFinnTheHumanLight },
80
+ { type: "origin+steer", title: "Original + Steering", key: "origin+steer", icon: PiFinnTheHumanBold },
81
+ { type: "trained", title: "Trained Model", key: "trained", icon: PiFinnTheHumanFill },
82
+ { type: "trained-steer", title: "Trained - Steering", key: "trained-steer", icon: PiFinnTheHumanDuotone },
83
+ ]
84
+
85
+ // Holds the partial or final text for each of the 4 slots
86
+ const [outputs, setOutputs] = useState(["", "", "", ""])
87
+ // Which slot is currently streaming? -1 if none
88
+ const [activeIndex, setActiveIndex] = useState(-1)
89
+
90
+ // Helper to fetch in streaming chunks
91
+ async function fetchInChunks(genType: string, index: number) {
92
+ const payload = {
93
+ model: modelKey,
94
+ dataset: datasetKey,
95
+ category: categoryKey,
96
+ type: genType,
97
+ }
98
+
99
+ const apiBaseUrl = import.meta.env.VITE_API_BASE_URL || ""
100
+ const response = await fetch(`${apiBaseUrl}/api/generate`, {
101
+ method: "POST",
102
+ headers: { "Content-Type": "application/json" },
103
+ body: JSON.stringify(payload),
104
+ })
105
+
106
+ // Stream the response
107
+ const reader = response.body?.getReader()
108
+ if (!reader) return
109
+ const decoder = new TextDecoder("utf-8")
110
+ let partial = ""
111
+
112
+ while (true) {
113
+ const { done, value } = await reader.read()
114
+ if (done) break
115
+
116
+ // Decode chunk and update partial text
117
+ partial += decoder.decode(value, { stream: true })
118
+ // Update outputs[i] in real-time
119
+ setOutputs((prev) => {
120
+ const copy = [...prev]
121
+ copy[index] = partial
122
+ return copy
123
+ })
124
+ }
125
+ }
126
+
127
+ // Called on "Play"
128
+ async function handlePlay() {
129
+ // Reset everything
130
+ setOutputs(["", "", "", ""])
131
+ setActiveIndex(-1)
132
+
133
+ // Stream each model's text in sequence
134
+ for (let i = 0; i < modelSequence.length; i++) {
135
+ setActiveIndex(i)
136
+ await fetchInChunks(modelSequence[i].type, i)
137
+ setActiveIndex(-1) // or keep streaming indicator until next loop
138
+ }
139
+ }
140
+
141
+ return (
142
+ <div className="space-y-6">
143
+ <div className="grid md:grid-cols-2 gap-6">
144
+ {modelSequence.map((seq, i) => {
145
+ const Icon = seq.icon
146
+ return (
147
+ <ModelCard
148
+ key={seq.type}
149
+ Icon={Icon}
150
+ title={seq.title}
151
+ text={prompt + outputs[i] || ""}
152
+ streaming={i === activeIndex}
153
+ />
154
+ )
155
+ })}
156
+ </div>
157
+
158
+ <div className="flex justify-center">
159
+ <Button
160
+ size="lg"
161
+ className="bg-blue-500 hover:bg-blue-600 text-white px-8 rounded-full"
162
+ onClick={handlePlay}
163
+ >
164
+ <Play className="w-5 h-5 mr-2" />
165
+ Play
166
+ </Button>
167
+ </div>
168
+ </div>
169
+ )
170
+ }
171
+
172
+ // ----------------------------------------------------
173
+ // Main App
174
+ // ----------------------------------------------------
175
+ export default function App() {
176
+ const [dataset, setDataset] = useState("Bias (EMGSD)")
177
+ const [model, setModel] = useState("GPT-2")
178
+ const [category, setCategory] = useState(categories[0].value)
179
+
180
+ // Convert front-end selection to server keys
181
+ const datasetKey = dataset === "Bias (EMGSD)" ? "emgsd" : "emgsd"
182
+ const modelKey = model === "GPT-2" ? "gpt2" : "gpt2"
183
+
184
+ return (
185
+ <div className="min-h-screen flex flex-col dark:bg-transparent">
186
+ <Header />
187
+ {/* Main content */}
188
+ <main className="flex-grow flex flex-col items-center justify-center">
189
+ <div className="text-center space-y-8">
190
+ <div className="space-y-4">
191
+ <h1 className="text-7xl font-mono tracking-tighter text-black dark:text-white">
192
+ CorrSteer
193
+ </h1>
194
+ <p className="text-xl leading-relaxed text-gray-700 dark:text-gray-300 italic px-6">
195
+ Text Classification dataset can be used to <span className="font-bold">Steer</span> LLMs,
196
+ <br />
197
+ <span className="font-bold">Corr</span>elating with SAE features
198
+ </p>
199
+ </div>
200
+
201
+ {/* Dropdowns */}
202
+ <div className="grid md:grid-cols-2 gap-8">
203
+ <div className="space-y-2 px-6 mx-8">
204
+ <label className="text-sm font-medium dark:text-gray-300">
205
+ Dataset
206
+ </label>
207
+ <Select value={dataset} onValueChange={setDataset}>
208
+ <SelectTrigger className="dark:bg-gray-800 dark:text-white">
209
+ <SelectValue />
210
+ </SelectTrigger>
211
+ <SelectContent className="dark:bg-gray-800 dark:text-white">
212
+ <SelectItem value="Bias (EMGSD)">Bias (EMGSD)</SelectItem>
213
+ </SelectContent>
214
+ </Select>
215
+ </div>
216
+
217
+ <div className="space-y-2 px-6 mx-8">
218
+ <label className="text-sm font-medium dark:text-gray-300">
219
+ Language Model
220
+ </label>
221
+ <Select value={model} onValueChange={setModel}>
222
+ <SelectTrigger className="dark:bg-gray-800 dark:text-white">
223
+ <SelectValue />
224
+ </SelectTrigger>
225
+ <SelectContent className="dark:bg-gray-800 dark:text-white">
226
+ <SelectItem value="GPT-2">GPT-2</SelectItem>
227
+ </SelectContent>
228
+ </Select>
229
+ </div>
230
+ </div>
231
+
232
+ {/* Tabs: 3 categories -> each has its own content */}
233
+ <Tabs value={category} onValueChange={setCategory}>
234
+ <TabsList className="gap-1 bg-transparent">
235
+ {categories.map((cat) => (
236
+ <TabsTrigger
237
+ key={cat.value}
238
+ value={cat.value}
239
+ className="data-[state=active]:bg-blue-400 dark:data-[state=active]:bg-blue-500 data-[state=inactive]:bg-slate-200 dark:data-[state=inactive]:bg-slate-800 data-[state=active]:border-gray-300 px-4 py-2 text-sm"
240
+ >
241
+ {cat.label}
242
+ </TabsTrigger>
243
+ ))}
244
+ </TabsList>
245
+
246
+ {categories.map((cat) => (
247
+ <TabsContent key={cat.value} value={cat.value} className="p-6">
248
+ <TabPanel
249
+ datasetKey={datasetKey}
250
+ modelKey={modelKey}
251
+ categoryKey={category}
252
+ prompt={cat.prompt}
253
+ />
254
+ </TabsContent>
255
+ ))}
256
+ </Tabs>
257
+ </div>
258
+ </main>
259
+ <Footer />
260
+ </div>
261
+ )
262
+ }
demo/src/components/footer.tsx ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ export function Footer() {
2
+ return (
3
+ <footer className="flex justify-center items-center py-4">
4
+ <p className="text-sm text-gray-500 dark:text-gray-400">
5
+ © 2025 <a href="https://github.com/seonglae" className="underline text-blue-600 dark:text-blue-300">Seonglae Cho</a>
6
+ </p>
7
+ </footer>
8
+ )
9
+ }
demo/src/components/header.tsx ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useEffect, useState } from "react"
2
+
3
+ import { Moon } from "lucide-react"
4
+ import { Button } from "@/components/ui/button"
5
+ import {
6
+ NavigationMenu,
7
+ NavigationMenuItem,
8
+ NavigationMenuList,
9
+ NavigationMenuTrigger,
10
+ } from "@/components/ui/navigation-menu"
11
+
12
+
13
+ export function Header() {
14
+ const [darkMode, setDarkMode] = useState(false)
15
+ useEffect(() => {
16
+ if (darkMode) document.documentElement.classList.add("dark")
17
+ else document.documentElement.classList.remove("dark")
18
+ }, [darkMode])
19
+
20
+ return (
21
+ <header className="flex justify-end items-center gap-4 p-6">
22
+ <NavigationMenu>
23
+ <NavigationMenuList>
24
+ <NavigationMenuItem>
25
+ <NavigationMenuTrigger>Paper</NavigationMenuTrigger>
26
+ </NavigationMenuItem>
27
+ <NavigationMenuItem>
28
+ <NavigationMenuTrigger>Github</NavigationMenuTrigger>
29
+ </NavigationMenuItem>
30
+ </NavigationMenuList>
31
+ </NavigationMenu>
32
+
33
+ <Button variant="outline" size="icon" onClick={() => setDarkMode(!darkMode)}>
34
+ <Moon className="h-5 w-5" />
35
+ </Button>
36
+ </header>
37
+ )
38
+ }
demo/src/components/model-card.tsx ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Info } from "lucide-react"
2
+ import { Card, CardContent } from "@/components/ui/card"
3
+
4
+ interface ModelCardProps {
5
+ title: string
6
+ text: string
7
+ }
8
+
9
+ export function ModelCard({ title, text }: ModelCardProps) {
10
+ return (
11
+ <Card className="overflow-hidden">
12
+ <CardContent className="p-6 space-y-4">
13
+ <div className="flex items-center gap-2">
14
+ <Info className="h-5 w-5" />
15
+ <h3 className="text-lg font-medium">{title}</h3>
16
+ </div>
17
+ <p>{text}</p>
18
+ </CardContent>
19
+ </Card>
20
+ )
21
+ }
22
+
demo/src/components/ui/button.tsx ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
13
+ destructive:
14
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
15
+ outline:
16
+ "bg-background hover:bg-accent hover:text-accent-foreground",
17
+ secondary:
18
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19
+ ghost: "hover:bg-accent hover:text-accent-foreground",
20
+ link: "text-primary underline-offset-4 hover:underline",
21
+ },
22
+ size: {
23
+ default: "h-10 px-4 py-2",
24
+ sm: "h-9 rounded-md px-3",
25
+ lg: "h-11 rounded-md px-8",
26
+ icon: "h-10 w-10",
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ variant: "default",
31
+ size: "default",
32
+ },
33
+ }
34
+ )
35
+
36
+ export interface ButtonProps
37
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
38
+ VariantProps<typeof buttonVariants> {
39
+ asChild?: boolean
40
+ }
41
+
42
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
43
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
44
+ const Comp = asChild ? Slot : "button"
45
+ return (
46
+ <Comp
47
+ className={cn(buttonVariants({ variant, size, className }))}
48
+ ref={ref}
49
+ {...props}
50
+ />
51
+ )
52
+ }
53
+ )
54
+ Button.displayName = "Button"
55
+
56
+ export { Button, buttonVariants }
demo/src/components/ui/card.tsx ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from "react"
2
+
3
+ import { cn } from "@/lib/utils"
4
+
5
+ const Card = React.forwardRef<
6
+ HTMLDivElement,
7
+ React.HTMLAttributes<HTMLDivElement>
8
+ >(({ className, ...props }, ref) => (
9
+ <div
10
+ ref={ref}
11
+ className={cn(
12
+ "rounded-lg border bg-card text-card-foreground shadow-sm",
13
+ className
14
+ )}
15
+ {...props}
16
+ />
17
+ ))
18
+ Card.displayName = "Card"
19
+
20
+ const CardHeader = React.forwardRef<
21
+ HTMLDivElement,
22
+ React.HTMLAttributes<HTMLDivElement>
23
+ >(({ className, ...props }, ref) => (
24
+ <div
25
+ ref={ref}
26
+ className={cn("flex flex-col space-y-1.5 p-6", className)}
27
+ {...props}
28
+ />
29
+ ))
30
+ CardHeader.displayName = "CardHeader"
31
+
32
+ const CardTitle = React.forwardRef<
33
+ HTMLDivElement,
34
+ React.HTMLAttributes<HTMLDivElement>
35
+ >(({ className, ...props }, ref) => (
36
+ <div
37
+ ref={ref}
38
+ className={cn(
39
+ "text-2xl font-semibold leading-none tracking-tight",
40
+ className
41
+ )}
42
+ {...props}
43
+ />
44
+ ))
45
+ CardTitle.displayName = "CardTitle"
46
+
47
+ const CardDescription = React.forwardRef<
48
+ HTMLDivElement,
49
+ React.HTMLAttributes<HTMLDivElement>
50
+ >(({ className, ...props }, ref) => (
51
+ <div
52
+ ref={ref}
53
+ className={cn("text-sm text-muted-foreground", className)}
54
+ {...props}
55
+ />
56
+ ))
57
+ CardDescription.displayName = "CardDescription"
58
+
59
+ const CardContent = React.forwardRef<
60
+ HTMLDivElement,
61
+ React.HTMLAttributes<HTMLDivElement>
62
+ >(({ className, ...props }, ref) => (
63
+ <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
64
+ ))
65
+ CardContent.displayName = "CardContent"
66
+
67
+ const CardFooter = React.forwardRef<
68
+ HTMLDivElement,
69
+ React.HTMLAttributes<HTMLDivElement>
70
+ >(({ className, ...props }, ref) => (
71
+ <div
72
+ ref={ref}
73
+ className={cn("flex items-center p-6 pt-0", className)}
74
+ {...props}
75
+ />
76
+ ))
77
+ CardFooter.displayName = "CardFooter"
78
+
79
+ export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
demo/src/components/ui/navigation-menu.tsx ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from "react"
2
+ import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
3
+ import { cva } from "class-variance-authority"
4
+ import { ChevronDown } from "lucide-react"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ const NavigationMenu = React.forwardRef<
9
+ React.ElementRef<typeof NavigationMenuPrimitive.Root>,
10
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
11
+ >(({ className, children, ...props }, ref) => (
12
+ <NavigationMenuPrimitive.Root
13
+ ref={ref}
14
+ className={cn(
15
+ "relative z-10 flex max-w-max flex-1 items-center justify-center",
16
+ className
17
+ )}
18
+ {...props}
19
+ >
20
+ {children}
21
+ <NavigationMenuViewport />
22
+ </NavigationMenuPrimitive.Root>
23
+ ))
24
+ NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
25
+
26
+ const NavigationMenuList = React.forwardRef<
27
+ React.ElementRef<typeof NavigationMenuPrimitive.List>,
28
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
29
+ >(({ className, ...props }, ref) => (
30
+ <NavigationMenuPrimitive.List
31
+ ref={ref}
32
+ className={cn(
33
+ "group flex flex-1 list-none items-center justify-center space-x-1",
34
+ className
35
+ )}
36
+ {...props}
37
+ />
38
+ ))
39
+ NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
40
+
41
+ const NavigationMenuItem = NavigationMenuPrimitive.Item
42
+
43
+ const navigationMenuTriggerStyle = cva(
44
+ "group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"
45
+ )
46
+
47
+ const NavigationMenuTrigger = React.forwardRef<
48
+ React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
49
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
50
+ >(({ className, children, ...props }, ref) => (
51
+ <NavigationMenuPrimitive.Trigger
52
+ ref={ref}
53
+ className={cn(navigationMenuTriggerStyle(), "group", className)}
54
+ {...props}
55
+ >
56
+ {children}{" "}
57
+ <ChevronDown
58
+ className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
59
+ aria-hidden="true"
60
+ />
61
+ </NavigationMenuPrimitive.Trigger>
62
+ ))
63
+ NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
64
+
65
+ const NavigationMenuContent = React.forwardRef<
66
+ React.ElementRef<typeof NavigationMenuPrimitive.Content>,
67
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
68
+ >(({ className, ...props }, ref) => (
69
+ <NavigationMenuPrimitive.Content
70
+ ref={ref}
71
+ className={cn(
72
+ "left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ",
73
+ className
74
+ )}
75
+ {...props}
76
+ />
77
+ ))
78
+ NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName
79
+
80
+ const NavigationMenuLink = NavigationMenuPrimitive.Link
81
+
82
+ const NavigationMenuViewport = React.forwardRef<
83
+ React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
84
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
85
+ >(({ className, ...props }, ref) => (
86
+ <div className={cn("absolute left-0 top-full flex justify-center")}>
87
+ <NavigationMenuPrimitive.Viewport
88
+ className={cn(
89
+ "origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
90
+ className
91
+ )}
92
+ ref={ref}
93
+ {...props}
94
+ />
95
+ </div>
96
+ ))
97
+ NavigationMenuViewport.displayName =
98
+ NavigationMenuPrimitive.Viewport.displayName
99
+
100
+ const NavigationMenuIndicator = React.forwardRef<
101
+ React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
102
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
103
+ >(({ className, ...props }, ref) => (
104
+ <NavigationMenuPrimitive.Indicator
105
+ ref={ref}
106
+ className={cn(
107
+ "top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
108
+ className
109
+ )}
110
+ {...props}
111
+ >
112
+ <div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
113
+ </NavigationMenuPrimitive.Indicator>
114
+ ))
115
+ NavigationMenuIndicator.displayName =
116
+ NavigationMenuPrimitive.Indicator.displayName
117
+
118
+ export {
119
+ navigationMenuTriggerStyle,
120
+ NavigationMenu,
121
+ NavigationMenuList,
122
+ NavigationMenuItem,
123
+ NavigationMenuContent,
124
+ NavigationMenuTrigger,
125
+ NavigationMenuLink,
126
+ NavigationMenuIndicator,
127
+ NavigationMenuViewport,
128
+ }
demo/src/components/ui/select.tsx ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from "react"
2
+ import * as SelectPrimitive from "@radix-ui/react-select"
3
+ import { Check, ChevronDown, ChevronUp } from "lucide-react"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const Select = SelectPrimitive.Root
8
+
9
+ const SelectGroup = SelectPrimitive.Group
10
+
11
+ const SelectValue = SelectPrimitive.Value
12
+
13
+ const SelectTrigger = React.forwardRef<
14
+ React.ElementRef<typeof SelectPrimitive.Trigger>,
15
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
16
+ >(({ className, children, ...props }, ref) => (
17
+ <SelectPrimitive.Trigger
18
+ ref={ref}
19
+ className={cn(
20
+ "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
21
+ className
22
+ )}
23
+ {...props}
24
+ >
25
+ {children}
26
+ <SelectPrimitive.Icon asChild>
27
+ <ChevronDown className="h-4 w-4 opacity-50" />
28
+ </SelectPrimitive.Icon>
29
+ </SelectPrimitive.Trigger>
30
+ ))
31
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
32
+
33
+ const SelectScrollUpButton = React.forwardRef<
34
+ React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
35
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
36
+ >(({ className, ...props }, ref) => (
37
+ <SelectPrimitive.ScrollUpButton
38
+ ref={ref}
39
+ className={cn(
40
+ "flex cursor-default items-center justify-center py-1",
41
+ className
42
+ )}
43
+ {...props}
44
+ >
45
+ <ChevronUp className="h-4 w-4" />
46
+ </SelectPrimitive.ScrollUpButton>
47
+ ))
48
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
49
+
50
+ const SelectScrollDownButton = React.forwardRef<
51
+ React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
52
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
53
+ >(({ className, ...props }, ref) => (
54
+ <SelectPrimitive.ScrollDownButton
55
+ ref={ref}
56
+ className={cn(
57
+ "flex cursor-default items-center justify-center py-1",
58
+ className
59
+ )}
60
+ {...props}
61
+ >
62
+ <ChevronDown className="h-4 w-4" />
63
+ </SelectPrimitive.ScrollDownButton>
64
+ ))
65
+ SelectScrollDownButton.displayName =
66
+ SelectPrimitive.ScrollDownButton.displayName
67
+
68
+ const SelectContent = React.forwardRef<
69
+ React.ElementRef<typeof SelectPrimitive.Content>,
70
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
71
+ >(({ className, children, position = "popper", ...props }, ref) => (
72
+ <SelectPrimitive.Portal>
73
+ <SelectPrimitive.Content
74
+ ref={ref}
75
+ className={cn(
76
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
77
+ position === "popper" &&
78
+ "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
79
+ className
80
+ )}
81
+ position={position}
82
+ {...props}
83
+ >
84
+ <SelectScrollUpButton />
85
+ <SelectPrimitive.Viewport
86
+ className={cn(
87
+ "p-1",
88
+ position === "popper" &&
89
+ "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
90
+ )}
91
+ >
92
+ {children}
93
+ </SelectPrimitive.Viewport>
94
+ <SelectScrollDownButton />
95
+ </SelectPrimitive.Content>
96
+ </SelectPrimitive.Portal>
97
+ ))
98
+ SelectContent.displayName = SelectPrimitive.Content.displayName
99
+
100
+ const SelectLabel = React.forwardRef<
101
+ React.ElementRef<typeof SelectPrimitive.Label>,
102
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
103
+ >(({ className, ...props }, ref) => (
104
+ <SelectPrimitive.Label
105
+ ref={ref}
106
+ className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
107
+ {...props}
108
+ />
109
+ ))
110
+ SelectLabel.displayName = SelectPrimitive.Label.displayName
111
+
112
+ const SelectItem = React.forwardRef<
113
+ React.ElementRef<typeof SelectPrimitive.Item>,
114
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
115
+ >(({ className, children, ...props }, ref) => (
116
+ <SelectPrimitive.Item
117
+ ref={ref}
118
+ className={cn(
119
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
120
+ className
121
+ )}
122
+ {...props}
123
+ >
124
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
125
+ <SelectPrimitive.ItemIndicator>
126
+ <Check className="h-4 w-4" />
127
+ </SelectPrimitive.ItemIndicator>
128
+ </span>
129
+
130
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
131
+ </SelectPrimitive.Item>
132
+ ))
133
+ SelectItem.displayName = SelectPrimitive.Item.displayName
134
+
135
+ const SelectSeparator = React.forwardRef<
136
+ React.ElementRef<typeof SelectPrimitive.Separator>,
137
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
138
+ >(({ className, ...props }, ref) => (
139
+ <SelectPrimitive.Separator
140
+ ref={ref}
141
+ className={cn("-mx-1 my-1 h-px bg-muted", className)}
142
+ {...props}
143
+ />
144
+ ))
145
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName
146
+
147
+ export {
148
+ Select,
149
+ SelectGroup,
150
+ SelectValue,
151
+ SelectTrigger,
152
+ SelectContent,
153
+ SelectLabel,
154
+ SelectItem,
155
+ SelectSeparator,
156
+ SelectScrollUpButton,
157
+ SelectScrollDownButton,
158
+ }
demo/src/components/ui/tabs.tsx ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as TabsPrimitive from "@radix-ui/react-tabs"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ const Tabs = TabsPrimitive.Root
9
+
10
+ const TabsList = React.forwardRef<
11
+ React.ElementRef<typeof TabsPrimitive.List>,
12
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
13
+ >(({ className, ...props }, ref) => (
14
+ <TabsPrimitive.List
15
+ ref={ref}
16
+ className={cn(
17
+ "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
18
+ className
19
+ )}
20
+ {...props}
21
+ />
22
+ ))
23
+ TabsList.displayName = TabsPrimitive.List.displayName
24
+
25
+ const TabsTrigger = React.forwardRef<
26
+ React.ElementRef<typeof TabsPrimitive.Trigger>,
27
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
28
+ >(({ className, ...props }, ref) => (
29
+ <TabsPrimitive.Trigger
30
+ ref={ref}
31
+ className={cn(
32
+ "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
33
+ className
34
+ )}
35
+ {...props}
36
+ />
37
+ ))
38
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
39
+
40
+ const TabsContent = React.forwardRef<
41
+ React.ElementRef<typeof TabsPrimitive.Content>,
42
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
43
+ >(({ className, ...props }, ref) => (
44
+ <TabsPrimitive.Content
45
+ ref={ref}
46
+ className={cn(
47
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
48
+ className
49
+ )}
50
+ {...props}
51
+ />
52
+ ))
53
+ TabsContent.displayName = TabsPrimitive.Content.displayName
54
+
55
+ export { Tabs, TabsList, TabsTrigger, TabsContent }
demo/src/index.css ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ :root {
6
+ font-family: Arial, sans-serif;
7
+ color-scheme: light dark;
8
+ font-synthesis: none;
9
+ text-rendering: optimizeLegibility;
10
+ -webkit-font-smoothing: antialiased;
11
+ -moz-osx-font-smoothing: grayscale;
12
+ }
13
+
14
+ @layer base {
15
+ :root {
16
+ --background: 0 0% 100%;
17
+ --foreground: 222.2 84% 4.9%;
18
+ --card: 0 0% 100%;
19
+ --card-foreground: 222.2 84% 4.9%;
20
+ --popover: 0 0% 100%;
21
+ --popover-foreground: 222.2 84% 4.9%;
22
+ --primary: 222.2 47.4% 11.2%;
23
+ --primary-foreground: 210 40% 98%;
24
+ --secondary: 210 40% 96.1%;
25
+ --secondary-foreground: 222.2 47.4% 11.2%;
26
+ --muted: 210 40% 96.1%;
27
+ --muted-foreground: 215.4 16.3% 46.9%;
28
+ --accent: 210 40% 96.1%;
29
+ --accent-foreground: 222.2 47.4% 11.2%;
30
+ --destructive: 0 84.2% 60.2%;
31
+ --destructive-foreground: 210 40% 98%;
32
+ --border: 214.3 31.8% 91.4%;
33
+ --input: 214.3 31.8% 91.4%;
34
+ --ring: 222.2 84% 4.9%;
35
+ --chart-1: 12 76% 61%;
36
+ --chart-2: 173 58% 39%;
37
+ --chart-3: 197 37% 24%;
38
+ --chart-4: 43 74% 66%;
39
+ --chart-5: 27 87% 67%;
40
+ --radius: 0.5rem;
41
+ }
42
+ .dark {
43
+ --background: 222.2 84% 4.9%;
44
+ --foreground: 210 40% 98%;
45
+ --card: 222.2 84% 4.9%;
46
+ --card-foreground: 210 40% 98%;
47
+ --popover: 222.2 84% 4.9%;
48
+ --popover-foreground: 210 40% 98%;
49
+ --primary: 210 40% 98%;
50
+ --primary-foreground: 222.2 47.4% 11.2%;
51
+ --secondary: 217.2 32.6% 17.5%;
52
+ --secondary-foreground: 210 40% 98%;
53
+ --muted: 217.2 32.6% 17.5%;
54
+ --muted-foreground: 215 20.2% 65.1%;
55
+ --accent: 217.2 32.6% 17.5%;
56
+ --accent-foreground: 210 40% 98%;
57
+ --destructive: 0 62.8% 30.6%;
58
+ --destructive-foreground: 210 40% 98%;
59
+ --border: 217.2 32.6% 17.5%;
60
+ --input: 217.2 32.6% 17.5%;
61
+ --ring: 212.7 26.8% 83.9%;
62
+ --chart-1: 220 70% 50%;
63
+ --chart-2: 160 60% 45%;
64
+ --chart-3: 30 80% 55%;
65
+ --chart-4: 280 65% 60%;
66
+ --chart-5: 340 75% 55%;
67
+ }
68
+ }
69
+
70
+ @layer base {
71
+ * {
72
+ @apply border-border;
73
+ }
74
+ body {
75
+ @apply bg-background text-foreground;
76
+ }
77
+ }
demo/src/lib/utils.ts ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
demo/src/main.tsx ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.tsx'
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
demo/src/vite-env.d.ts ADDED
@@ -0,0 +1 @@
 
 
1
+ /// <reference types="vite/client" />
demo/tailwind.config.ts ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { Config } from 'tailwindcss'
2
+
3
+ export default {
4
+ darkMode: ['class'],
5
+ content: [
6
+ './index.html',
7
+ './src/**/*.{ts,tsx}',
8
+ 'node_modules/@llamaindex/chat-ui/**/*.{ts,tsx}',
9
+ ],
10
+ theme: {
11
+ extend: {
12
+ borderRadius: {
13
+ lg: 'var(--radius)',
14
+ md: 'calc(var(--radius) - 2px)',
15
+ sm: 'calc(var(--radius) - 4px)'
16
+ },
17
+ colors: {
18
+ background: 'hsl(var(--background))',
19
+ foreground: 'hsl(var(--foreground))',
20
+ card: {
21
+ DEFAULT: 'hsl(var(--card))',
22
+ foreground: 'hsl(var(--card-foreground))'
23
+ },
24
+ popover: {
25
+ DEFAULT: 'hsl(var(--popover))',
26
+ foreground: 'hsl(var(--popover-foreground))'
27
+ },
28
+ primary: {
29
+ DEFAULT: 'hsl(var(--primary))',
30
+ foreground: 'hsl(var(--primary-foreground))'
31
+ },
32
+ secondary: {
33
+ DEFAULT: 'hsl(var(--secondary))',
34
+ foreground: 'hsl(var(--secondary-foreground))'
35
+ },
36
+ muted: {
37
+ DEFAULT: 'hsl(var(--muted))',
38
+ foreground: 'hsl(var(--muted-foreground))'
39
+ },
40
+ accent: {
41
+ DEFAULT: 'hsl(var(--accent))',
42
+ foreground: 'hsl(var(--accent-foreground))'
43
+ },
44
+ destructive: {
45
+ DEFAULT: 'hsl(var(--destructive))',
46
+ foreground: 'hsl(var(--destructive-foreground))'
47
+ },
48
+ border: 'hsl(var(--border))',
49
+ input: 'hsl(var(--input))',
50
+ ring: 'hsl(var(--ring))',
51
+ chart: {
52
+ '1': 'hsl(var(--chart-1))',
53
+ '2': 'hsl(var(--chart-2))',
54
+ '3': 'hsl(var(--chart-3))',
55
+ '4': 'hsl(var(--chart-4))',
56
+ '5': 'hsl(var(--chart-5))'
57
+ }
58
+ }
59
+ }
60
+ },
61
+ plugins: [require("tailwindcss-animate")],
62
+ } satisfies Config
demo/tsconfig.app.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": ".",
4
+ "paths": {
5
+ "@/*": [
6
+ "./src/*"
7
+ ]
8
+ },
9
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
10
+ "target": "ES2020",
11
+ "useDefineForClassFields": true,
12
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
13
+ "module": "ESNext",
14
+ "skipLibCheck": true,
15
+
16
+ /* Bundler mode */
17
+ "moduleResolution": "bundler",
18
+ "allowImportingTsExtensions": true,
19
+ "isolatedModules": true,
20
+ "moduleDetection": "force",
21
+ "noEmit": true,
22
+ "jsx": "react-jsx",
23
+
24
+ /* Linting */
25
+ "strict": true,
26
+ "noUnusedLocals": true,
27
+ "noUnusedParameters": true,
28
+ "noFallthroughCasesInSwitch": true,
29
+ "noUncheckedSideEffectImports": true
30
+ },
31
+ "include": ["src"]
32
+ }
demo/tsconfig.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ],
7
+ "compilerOptions": {
8
+ "baseUrl": ".",
9
+ "paths": {
10
+ "@/*": ["./src/*"]
11
+ }
12
+ }
13
+ }
demo/tsconfig.node.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "isolatedModules": true,
13
+ "moduleDetection": "force",
14
+ "noEmit": true,
15
+
16
+ /* Linting */
17
+ "strict": true,
18
+ "noUnusedLocals": true,
19
+ "noUnusedParameters": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "noUncheckedSideEffectImports": true
22
+ },
23
+ "include": ["vite.config.ts"]
24
+ }
demo/vite.config.ts ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import path from "path"
2
+ import react from "@vitejs/plugin-react"
3
+ import { defineConfig } from "vite"
4
+
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ resolve: {
8
+ alias: {
9
+ "@": path.resolve(__dirname, "./src"),
10
+ },
11
+ },
12
+ define: {
13
+ __API_BASE_URL__: JSON.stringify(process.env.VITE_API_BASE_URL || "http://localhost:5174"),
14
+ },
15
+ server: {
16
+ host: "0.0.0.0",
17
+ port: 7860,
18
+ },
19
+ })