feat: add shadcn ui config (#954)

* feat: add shadcn ui config

* chore: tailwind config
This commit is contained in:
BiggerRain
2025-10-29 10:38:52 +08:00
committed by GitHub
parent c879c63b17
commit 1996298f0c
8 changed files with 299 additions and 28 deletions

22
components.json Normal file
View File

@@ -0,0 +1,22 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/main.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}

View File

@@ -19,6 +19,7 @@
}, },
"dependencies": { "dependencies": {
"@headlessui/react": "^2.2.2", "@headlessui/react": "^2.2.2",
"@radix-ui/react-slot": "^1.2.3",
"@tauri-apps/api": "^2.5.0", "@tauri-apps/api": "^2.5.0",
"@tauri-apps/plugin-autostart": "~2.2.0", "@tauri-apps/plugin-autostart": "~2.2.0",
"@tauri-apps/plugin-deep-link": "^2.2.1", "@tauri-apps/plugin-deep-link": "^2.2.1",
@@ -35,6 +36,7 @@
"@wavesurfer/react": "^1.0.11", "@wavesurfer/react": "^1.0.11",
"ahooks": "^3.8.4", "ahooks": "^3.8.4",
"axios": "^1.12.0", "axios": "^1.12.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"dotenv": "^16.5.0", "dotenv": "^16.5.0",
@@ -59,6 +61,7 @@
"remark-gfm": "^4.0.1", "remark-gfm": "^4.0.1",
"remark-math": "^6.0.0", "remark-math": "^6.0.0",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"tauri-plugin-fs-pro-api": "^2.4.0", "tauri-plugin-fs-pro-api": "^2.4.0",
"tauri-plugin-macos-permissions-api": "^2.3.0", "tauri-plugin-macos-permissions-api": "^2.3.0",
"tauri-plugin-screenshots-api": "^2.2.0", "tauri-plugin-screenshots-api": "^2.2.0",

56
pnpm-lock.yaml generated
View File

@@ -11,6 +11,9 @@ importers:
'@headlessui/react': '@headlessui/react':
specifier: ^2.2.2 specifier: ^2.2.2
version: 2.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 2.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot':
specifier: ^1.2.3
version: 1.2.3(@types/react@18.3.26)(react@18.3.1)
'@tauri-apps/api': '@tauri-apps/api':
specifier: ^2.5.0 specifier: ^2.5.0
version: 2.9.0 version: 2.9.0
@@ -59,6 +62,9 @@ importers:
axios: axios:
specifier: ^1.12.0 specifier: ^1.12.0
version: 1.12.0 version: 1.12.0
class-variance-authority:
specifier: ^0.7.1
version: 0.7.1
clsx: clsx:
specifier: ^2.1.1 specifier: ^2.1.1
version: 2.1.1 version: 2.1.1
@@ -131,6 +137,9 @@ importers:
tailwind-merge: tailwind-merge:
specifier: ^3.3.1 specifier: ^3.3.1
version: 3.3.1 version: 3.3.1
tailwindcss-animate:
specifier: ^1.0.7
version: 1.0.7(tailwindcss@3.4.18)
tauri-plugin-fs-pro-api: tauri-plugin-fs-pro-api:
specifier: ^2.4.0 specifier: ^2.4.0
version: 2.4.0 version: 2.4.0
@@ -1011,6 +1020,24 @@ packages:
resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==}
engines: {node: '>=12'} engines: {node: '>=12'}
'@radix-ui/react-compose-refs@1.1.2':
resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-slot@1.2.3':
resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@react-aria/focus@3.20.2': '@react-aria/focus@3.20.2':
resolution: {integrity: sha512-Q3rouk/rzoF/3TuH6FzoAIKrl+kzZi9LHmr8S5EqLAOyP9TXIKG34x2j42dZsAhrw7TbF9gA8tBKwnCNH4ZV+Q==} resolution: {integrity: sha512-Q3rouk/rzoF/3TuH6FzoAIKrl+kzZi9LHmr8S5EqLAOyP9TXIKG34x2j42dZsAhrw7TbF9gA8tBKwnCNH4ZV+Q==}
peerDependencies: peerDependencies:
@@ -1694,6 +1721,9 @@ packages:
resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==}
engines: {node: '>=8'} engines: {node: '>=8'}
class-variance-authority@0.7.1:
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
cli-boxes@3.0.0: cli-boxes@3.0.0:
resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -3481,6 +3511,11 @@ packages:
tailwind-merge@3.3.1: tailwind-merge@3.3.1:
resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==}
tailwindcss-animate@1.0.7:
resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders'
tailwindcss@3.4.18: tailwindcss@3.4.18:
resolution: {integrity: sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==} resolution: {integrity: sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
@@ -4512,6 +4547,19 @@ snapshots:
'@pnpm/network.ca-file': 1.0.2 '@pnpm/network.ca-file': 1.0.2
config-chain: 1.1.13 config-chain: 1.1.13
'@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.26)(react@18.3.1)':
dependencies:
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.26
'@radix-ui/react-slot@1.2.3(@types/react@18.3.26)(react@18.3.1)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@18.3.1)
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.26
'@react-aria/focus@3.20.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@react-aria/focus@3.20.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@react-aria/interactions': 3.25.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@react-aria/interactions': 3.25.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -5185,6 +5233,10 @@ snapshots:
ci-info@4.2.0: {} ci-info@4.2.0: {}
class-variance-authority@0.7.1:
dependencies:
clsx: 2.1.1
cli-boxes@3.0.0: {} cli-boxes@3.0.0: {}
cli-cursor@5.0.0: cli-cursor@5.0.0:
@@ -7322,6 +7374,10 @@ snapshots:
tailwind-merge@3.3.1: {} tailwind-merge@3.3.1: {}
tailwindcss-animate@1.0.7(tailwindcss@3.4.18):
dependencies:
tailwindcss: 3.4.18
tailwindcss@3.4.18: tailwindcss@3.4.18:
dependencies: dependencies:
'@alloc/quick-lru': 5.2.0 '@alloc/quick-lru': 5.2.0

View File

@@ -0,0 +1,57 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 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 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }

6
src/lib/utils.ts Normal file
View File

@@ -0,0 +1,6 @@
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}

View File

@@ -106,6 +106,59 @@
fill: currentColor; fill: currentColor;
overflow: hidden; overflow: hidden;
} }
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
--radius: 0.5rem;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
} }
/* Component styles */ /* Component styles */
@@ -261,3 +314,12 @@
display: none; /* Chrome/Safari */ display: none; /* Chrome/Safari */
} }
} }
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}

View File

@@ -35,7 +35,6 @@ function MainApp() {
<> <>
<SearchChat isTauri={true} hasModules={["search", "chat"]} /> <SearchChat isTauri={true} hasModules={["search", "chat"]} />
<UpdateApp /> <UpdateApp />
{synthesizeItem && <Synthesize />} {synthesizeItem && <Synthesize />}
</> </>
); );

View File

@@ -1,4 +1,5 @@
/** @type {import('tailwindcss').Config} */ import animate from "tailwindcss-animate";
export default { export default {
content: [ content: [
"./index.html", "./index.html",
@@ -9,11 +10,11 @@ export default {
theme: { theme: {
extend: { extend: {
backgroundColor: { backgroundColor: {
primary: "rgb(var(--color-primary) / <alpha-value>)", primary: 'rgb(var(--color-primary) / <alpha-value>)',
secondary: "rgb(var(--color-secondary) / <alpha-value>)", secondary: 'rgb(var(--color-secondary) / <alpha-value>)',
background: "rgb(var(--color-background) / <alpha-value>)", background: 'rgb(var(--color-background) / <alpha-value>)',
foreground: "rgb(var(--color-foreground) / <alpha-value>)", foreground: 'rgb(var(--color-foreground) / <alpha-value>)',
separator: "rgb(var(--color-separator) / <alpha-value>)", separator: 'rgb(var(--color-separator) / <alpha-value>)'
}, },
backgroundImage: { backgroundImage: {
chat_bg_light: "url('./assets/chat_bg_light.png')", chat_bg_light: "url('./assets/chat_bg_light.png')",
@@ -24,43 +25,108 @@ export default {
inputbox_bg_dark: "url('./assets/inputbox_bg_dark.png')", inputbox_bg_dark: "url('./assets/inputbox_bg_dark.png')",
}, },
textColor: { textColor: {
primary: "rgb(var(--color-foreground) / <alpha-value>)", primary: 'rgb(var(--color-foreground) / <alpha-value>)'
}, },
animation: { animation: {
"fade-in": "fade-in 0.2s ease-in-out", 'fade-in': 'fade-in 0.2s ease-in-out',
typing: "typing 1.5s ease-in-out infinite", typing: 'typing 1.5s ease-in-out infinite',
shake: "shake 0.5s ease-in-out", shake: 'shake 0.5s ease-in-out'
}, },
keyframes: { keyframes: {
"fade-in": { 'fade-in': {
"0%": { opacity: "0" }, '0%': {
"100%": { opacity: "1" }, opacity: '0'
},
'100%': {
opacity: '1'
}
}, },
typing: { typing: {
"0%": { opacity: "0.3" }, '0%': {
"50%": { opacity: "1" }, opacity: '0.3'
"100%": { opacity: "0.3" }, },
'50%': {
opacity: '1'
},
'100%': {
opacity: '0.3'
}
}, },
shake: { shake: {
"0%, 100%": { transform: "rotate(0deg)" }, '0%, 100%': {
"25%": { transform: "rotate(-20deg)" }, transform: 'rotate(0deg)'
"75%": { transform: "rotate(20deg)" }, },
}, '25%': {
transform: 'rotate(-20deg)'
},
'75%': {
transform: 'rotate(20deg)'
}
}
}, },
boxShadow: { boxShadow: {
"window-custom": "0px 16px 32px 0px rgba(0,0,0,0.3)", 'window-custom': '0px 16px 32px 0px rgba(0,0,0,0.3)'
}, },
zIndex: { zIndex: {
100: "100", '100': '100',
1000: "1000", '1000': '1000',
2000: "2000", '2000': '2000'
}, },
screens: { screens: {
mobile: { max: "679px" }, mobile: {
max: '679px'
}
}, },
}, borderRadius: {
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)'
},
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
card: {
DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))'
},
popover: {
DEFAULT: 'hsl(var(--popover))',
foreground: 'hsl(var(--popover-foreground))'
},
primary: {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))'
},
secondary: {
DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))'
},
muted: {
DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))'
},
accent: {
DEFAULT: 'hsl(var(--accent))',
foreground: 'hsl(var(--accent-foreground))'
},
destructive: {
DEFAULT: 'hsl(var(--destructive))',
foreground: 'hsl(var(--destructive-foreground))'
},
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
chart: {
'1': 'hsl(var(--chart-1))',
'2': 'hsl(var(--chart-2))',
'3': 'hsl(var(--chart-3))',
'4': 'hsl(var(--chart-4))',
'5': 'hsl(var(--chart-5))'
}
}
}
}, },
plugins: [], plugins: [animate],
mode: "jit", mode: "jit",
darkMode: ["class", '[data-theme="dark"]'], darkMode: ["class", '[data-theme="dark"]'],
safelist: ["bg-[green]", "bg-[red]", "bg-[yellow]"], safelist: ["bg-[green]", "bg-[red]", "bg-[yellow]"],