diff --git a/components.json b/components.json
index a78ad5d..c3cc1db 100644
--- a/components.json
+++ b/components.json
@@ -1,6 +1,6 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
- "style": "new-york",
+ "style": "base-nova",
"rsc": false,
"tsx": true,
"tailwind": {
diff --git a/package.json b/package.json
index 49837c1..1ae0e2b 100644
--- a/package.json
+++ b/package.json
@@ -20,10 +20,12 @@
"@ai-sdk/anthropic": "^3.0.38",
"@ai-sdk/openai": "^3.0.26",
"@ai-sdk/openai-compatible": "^2.0.28",
- "@kevisual/cnb": "^0.0.19",
+ "@base-ui/react": "^1.1.0",
+ "@kevisual/cnb": "^0.0.20",
"@kevisual/context": "^0.0.4",
"@kevisual/router": "0.0.70",
"@radix-ui/react-avatar": "^1.1.11",
+ "@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "^2.1.8",
@@ -31,7 +33,7 @@
"@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-tabs": "^1.1.13",
- "@tanstack/react-router": "^1.158.1",
+ "@tanstack/react-router": "^1.158.4",
"ai": "^6.0.77",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -51,21 +53,21 @@
"access": "public"
},
"devDependencies": {
- "@kevisual/query": "0.0.39",
+ "@kevisual/query": "0.0.40",
"@kevisual/types": "^0.0.12",
"@tailwindcss/vite": "^4.1.18",
- "@tanstack/react-router-devtools": "^1.158.1",
- "@tanstack/router-plugin": "^1.158.1",
- "@types/node": "^25.2.1",
+ "@tanstack/react-router-devtools": "^1.158.4",
+ "@tanstack/router-plugin": "^1.158.4",
+ "@types/node": "^25.2.2",
"@types/react": "^19.2.13",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.3",
- "dotenv": "^17.2.3",
+ "dotenv": "^17.2.4",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18",
"tw-animate-css": "^1.4.0",
"typescript": "^5.9.3",
"vite": "^8.0.0-beta.13"
},
- "packageManager": "pnpm@10.28.2"
+ "packageManager": "pnpm@10.29.1"
}
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7854d07..2ca8991 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,9 +17,12 @@ importers:
'@ai-sdk/openai-compatible':
specifier: ^2.0.28
version: 2.0.28(zod@4.3.6)
+ '@base-ui/react':
+ specifier: ^1.1.0
+ version: 1.1.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@kevisual/cnb':
- specifier: ^0.0.19
- version: 0.0.19(dotenv@17.2.3)(idb-keyval@6.2.1)
+ specifier: ^0.0.20
+ version: 0.0.20(dotenv@17.2.4)(idb-keyval@6.2.1)
'@kevisual/context':
specifier: ^0.0.4
version: 0.0.4
@@ -29,6 +32,9 @@ importers:
'@radix-ui/react-avatar':
specifier: ^1.1.11
version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@radix-ui/react-checkbox':
+ specifier: ^1.3.3
+ version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@radix-ui/react-dialog':
specifier: ^1.1.15
version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
@@ -51,8 +57,8 @@ importers:
specifier: ^1.1.13
version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@tanstack/react-router':
- specifier: ^1.158.1
- version: 1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ specifier: ^1.158.4
+ version: 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
ai:
specifier: ^6.0.77
version: 6.0.77(zod@4.3.6)
@@ -97,23 +103,23 @@ importers:
version: 5.0.11(@types/react@19.2.13)(immer@10.1.1)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4))
devDependencies:
'@kevisual/query':
- specifier: 0.0.39
- version: 0.0.39
+ specifier: 0.0.40
+ version: 0.0.40
'@kevisual/types':
specifier: ^0.0.12
version: 0.0.12
'@tailwindcss/vite':
specifier: ^4.1.18
- version: 4.1.18(vite@8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))
+ version: 4.1.18(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))
'@tanstack/react-router-devtools':
- specifier: ^1.158.1
- version: 1.158.1(@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.1)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ specifier: ^1.158.4
+ version: 1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.4)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@tanstack/router-plugin':
- specifier: ^1.158.1
- version: 1.158.1(@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))
+ specifier: ^1.158.4
+ version: 1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))
'@types/node':
- specifier: ^25.2.1
- version: 25.2.1
+ specifier: ^25.2.2
+ version: 25.2.2
'@types/react':
specifier: ^19.2.13
version: 19.2.13
@@ -122,10 +128,10 @@ importers:
version: 19.2.3(@types/react@19.2.13)
'@vitejs/plugin-react':
specifier: ^5.1.3
- version: 5.1.3(vite@8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))
+ version: 5.1.3(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))
dotenv:
- specifier: ^17.2.3
- version: 17.2.3
+ specifier: ^17.2.4
+ version: 17.2.4
tailwind-merge:
specifier: ^3.4.0
version: 3.4.0
@@ -140,7 +146,7 @@ importers:
version: 5.9.3
vite:
specifier: ^8.0.0-beta.13
- version: 8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1)
+ version: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1)
packages/components:
dependencies:
@@ -339,6 +345,10 @@ packages:
resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==}
engines: {node: '>=6.9.0'}
+ '@babel/runtime@7.28.6':
+ resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/template@7.25.9':
resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==}
engines: {node: '>=6.9.0'}
@@ -367,6 +377,27 @@ packages:
resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
engines: {node: '>=6.9.0'}
+ '@base-ui/react@1.1.0':
+ resolution: {integrity: sha512-ikcJRNj1mOiF2HZ5jQHrXoVoHcNHdBU5ejJljcBl+VTLoYXR6FidjTN86GjO6hyshi6TZFuNvv0dEOgaOFv6Lw==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@types/react': ^17 || ^18 || ^19
+ react: ^17 || ^18 || ^19
+ react-dom: ^17 || ^18 || ^19
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@base-ui/utils@0.2.4':
+ resolution: {integrity: sha512-smZwpMhjO29v+jrZusBSc5T+IJ3vBb9cjIiBjtKcvWmRj9Z4DWGVR3efr1eHR56/bqY5a4qyY9ElkOY5ljo3ng==}
+ peerDependencies:
+ '@types/react': ^17 || ^18 || ^19
+ react: ^17 || ^18 || ^19
+ react-dom: ^17 || ^18 || ^19
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@emnapi/core@1.8.1':
resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==}
@@ -634,8 +665,8 @@ packages:
'@kevisual/cache@0.0.2':
resolution: {integrity: sha512-2Cl5KF2Gi27uLfhO6CdTMFnRzx9vYnqevAo7d9ab3rOaqTgF8tLeAXglXyRbaWW3WUbHU2XaOb4r98uUsqIQQw==}
- '@kevisual/cnb@0.0.19':
- resolution: {integrity: sha512-SyO1C5yGsySsslSKr2BtwsxXzualNUJVH5HKE4FQga4dX/uxepBnSoDtdczbOWf3RgsQFZNzR0cihkgtWwkmtQ==}
+ '@kevisual/cnb@0.0.20':
+ resolution: {integrity: sha512-3ODGAT8vEnU90X/6SUeqMK1ZJCcvyn44bMsC7Joz0kvDKhntstbf/nZIm5TRhngvPEcOPyc+KROchTweC/qcNA==}
'@kevisual/context@0.0.4':
resolution: {integrity: sha512-HJeLeZQLU+7tCluSfOyvkgKLs0HjCZrdJlZgEgKRSa8XTwZfMAUt6J7qZTbrZAHBlPtX68EPu/PI8JMCeu3WAQ==}
@@ -651,8 +682,8 @@ packages:
'@kevisual/query@0.0.28':
resolution: {integrity: sha512-ijgKhfYzrNEoRuQOVD/ed8fqo+MKcNdvNFCBFHiBLVtyUrnSVNeEeyoM3eEw9iASBCltR1L4yoVn4Rls2jvpFA==}
- '@kevisual/query@0.0.39':
- resolution: {integrity: sha512-3UEPBIvtdykNkrby3hvrgrHdgd17Uq+Pnr4zs+JBzATkU2eKaOqtTUJqdyIEwuySCwzGTxrnlUzWP4tziDQDLQ==}
+ '@kevisual/query@0.0.40':
+ resolution: {integrity: sha512-7m5BgDzd01m51hCHUId6ugQHdwgrLTb6fI7DSuMY17VjWb0+zGnkYmvRBqkTXzoIjjYbP5iwtRnrooEoToQfhg==}
'@kevisual/router@0.0.70':
resolution: {integrity: sha512-vXlIj9jRufhcIfeuPWemjSI+dxdzSmIBq5eRxQzqEfAJ7k+mBPhoI4KxH8vHnwyL30bqm8EdODL/p6Wg8uBw3g==}
@@ -798,6 +829,19 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-checkbox@1.3.3':
+ resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-collection@1.1.7':
resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==}
peerDependencies:
@@ -1503,20 +1547,20 @@ packages:
resolution: {integrity: sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA==}
engines: {node: '>=12'}
- '@tanstack/react-router-devtools@1.158.1':
- resolution: {integrity: sha512-H0iTfsLNkadF/JhJnu/pUxlxOiLjE0866vFqXK/7EYVcyYwx2uWQuGxEkyF7a04oXXrbEImAOoXDRBQcZ9T5Zw==}
+ '@tanstack/react-router-devtools@1.158.4':
+ resolution: {integrity: sha512-/EkrrJGTPC7MwLfcYYmZM71ANDMLbwcYvBtDA+48LqHUKal8mpWlaodiWdFFnVQ7ny/unbUxljgdrNV9YZiyFQ==}
engines: {node: '>=12'}
peerDependencies:
- '@tanstack/react-router': ^1.158.1
- '@tanstack/router-core': ^1.158.1
+ '@tanstack/react-router': ^1.158.4
+ '@tanstack/router-core': ^1.158.4
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
peerDependenciesMeta:
'@tanstack/router-core':
optional: true
- '@tanstack/react-router@1.158.1':
- resolution: {integrity: sha512-ZRBhs0tJDPeYGVrBhXPkGs+mOKqKKMM4OfvYSNvWIYZGfs8KQcqxPaN8OnUvKsnAGtzwusVWDpBipqVZWJd0lA==}
+ '@tanstack/react-router@1.158.4':
+ resolution: {integrity: sha512-i15xXumgvpuM+4NSuIwgouGezuj9eHjZsgpTZSQ7E9pa8rYmhZbWnf8xU68qaLmaKIol/e75o/YzVH2QWHs3iQ==}
engines: {node: '>=12'}
peerDependencies:
react: '>=18.0.0 || >=19.0.0'
@@ -1528,30 +1572,30 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- '@tanstack/router-core@1.158.1':
- resolution: {integrity: sha512-8B9X3GzN1JWsqa+OTgg2k+LrayLQYmgtv26b96difyrRS32DaDBvEpU3xXDaLNmi/+zoqG1ffAcDT4D6tyC2hw==}
+ '@tanstack/router-core@1.158.4':
+ resolution: {integrity: sha512-KikgYdyrEFqsjjgv9pMhDTMmASMAyFRvUiKFdQPQtXq3aD1qv/zck4CbA4bfzp9N9nYu/qvWwU1mlYU4u5JeXg==}
engines: {node: '>=12'}
- '@tanstack/router-devtools-core@1.158.1':
- resolution: {integrity: sha512-iGCqmIJ5NXMIuyFwJgfikEmRrceT3tmynMTMSuVxFiv9+Dlk1tsp8bsYS+UGhyY4beoASsRnlikAeNAMsCjhwA==}
+ '@tanstack/router-devtools-core@1.158.4':
+ resolution: {integrity: sha512-9MKzstYp/6sNRSwJY2b9ipVW8b8/x1iSFNfLhOJur2tnjB3RhwCDfy0u+to70BrRpBEWeq7jvJoVdP029gzUUg==}
engines: {node: '>=12'}
peerDependencies:
- '@tanstack/router-core': ^1.158.1
+ '@tanstack/router-core': ^1.158.4
csstype: ^3.0.10
peerDependenciesMeta:
csstype:
optional: true
- '@tanstack/router-generator@1.158.1':
- resolution: {integrity: sha512-geBpsIxJNvdjw2kt/Ii/j68hIUvfGnra0HKlGrDZw8/Ny4AJ2nnOcszUlZRbuQyxByk05r4lneOShKy5V5MUCQ==}
+ '@tanstack/router-generator@1.158.4':
+ resolution: {integrity: sha512-RQmqMTT0oV8dS/3Glcq9SPzDZqOPyKb/LVFUkNoTfMwW88WyGnQcYqZAkmVk/CGBWWDfwObOUZoGq5jTF7bG8w==}
engines: {node: '>=12'}
- '@tanstack/router-plugin@1.158.1':
- resolution: {integrity: sha512-IPCnf1CBc0jnczuy65+3iBaoABv5TKhOJ1YLzwel4kb9D8Abcq0vF8ooR5FiPmaGnree/z3SvjgHe5eQtgcsSQ==}
+ '@tanstack/router-plugin@1.158.4':
+ resolution: {integrity: sha512-g2sytAhljw6Jd6Klu37OZ75+o+vhiGdbWtnBy/4rYLC4NN6hSnjgJQRI3+h1CI1KQ4EUgsZYZr/hgE1KHoiWYQ==}
engines: {node: '>=12'}
peerDependencies:
'@rsbuild/core': '>=1.0.2'
- '@tanstack/react-router': ^1.158.1
+ '@tanstack/react-router': ^1.158.4
vite: '>=5.0.0 || >=6.0.0 || >=7.0.0'
vite-plugin-solid: ^2.11.10
webpack: '>=5.92.0'
@@ -1599,8 +1643,8 @@ packages:
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
- '@types/node@25.2.1':
- resolution: {integrity: sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg==}
+ '@types/node@25.2.2':
+ resolution: {integrity: sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ==}
'@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
@@ -1778,8 +1822,8 @@ packages:
resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==}
engines: {node: '>=12'}
- dotenv@17.2.3:
- resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
+ dotenv@17.2.4:
+ resolution: {integrity: sha512-mudtfb4zRB4bVvdj0xRo+e6duH1csJRM8IukBqfTRvHotn9+LBXB8ynAidP9zHqoRC/fsllXgk4kCKlR21fIhw==}
engines: {node: '>=12'}
electron-to-chromium@1.5.65:
@@ -2366,6 +2410,9 @@ packages:
regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
+ reselect@5.1.1:
+ resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
+
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -2444,6 +2491,9 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
+ tabbable@6.4.0:
+ resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==}
+
tailwind-merge@3.3.0:
resolution: {integrity: sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==}
@@ -2872,6 +2922,8 @@ snapshots:
'@babel/runtime@7.27.1': {}
+ '@babel/runtime@7.28.6': {}
+
'@babel/template@7.25.9':
dependencies:
'@babel/code-frame': 7.26.2
@@ -2923,6 +2975,31 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
+ '@base-ui/react@1.1.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
+ dependencies:
+ '@babel/runtime': 7.28.6
+ '@base-ui/utils': 0.2.4(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@floating-ui/react-dom': 2.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@floating-ui/utils': 0.2.10
+ react: 19.2.4
+ react-dom: 19.2.4(react@19.2.4)
+ reselect: 5.1.1
+ tabbable: 6.4.0
+ use-sync-external-store: 1.6.0(react@19.2.4)
+ optionalDependencies:
+ '@types/react': 19.2.13
+
+ '@base-ui/utils@0.2.4(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
+ dependencies:
+ '@babel/runtime': 7.28.6
+ '@floating-ui/utils': 0.2.10
+ react: 19.2.4
+ react-dom: 19.2.4(react@19.2.4)
+ reselect: 5.1.1
+ use-sync-external-store: 1.6.0(react@19.2.4)
+ optionalDependencies:
+ '@types/react': 19.2.13
+
'@emnapi/core@1.8.1':
dependencies:
'@emnapi/wasi-threads': 1.1.0
@@ -3163,11 +3240,11 @@ snapshots:
- tslib
- typescript
- '@kevisual/cnb@0.0.19(dotenv@17.2.3)(idb-keyval@6.2.1)':
+ '@kevisual/cnb@0.0.20(dotenv@17.2.4)(idb-keyval@6.2.1)':
dependencies:
- '@kevisual/query': 0.0.39
+ '@kevisual/query': 0.0.40
'@kevisual/router': 0.0.70
- '@kevisual/use-config': 1.0.30(dotenv@17.2.3)
+ '@kevisual/use-config': 1.0.30(dotenv@17.2.4)
es-toolkit: 1.44.0
nanoid: 5.1.6
unstorage: 1.17.4(idb-keyval@6.2.1)
@@ -3218,7 +3295,7 @@ snapshots:
- ws
- zod
- '@kevisual/query@0.0.39':
+ '@kevisual/query@0.0.40':
dependencies:
tslib: 2.8.1
@@ -3228,10 +3305,10 @@ snapshots:
'@kevisual/types@0.0.12': {}
- '@kevisual/use-config@1.0.30(dotenv@17.2.3)':
+ '@kevisual/use-config@1.0.30(dotenv@17.2.4)':
dependencies:
'@kevisual/load': 0.0.6
- dotenv: 17.2.3
+ dotenv: 17.2.4
'@kevisual/ws@8.19.0': {}
@@ -3355,6 +3432,22 @@ snapshots:
'@types/react': 19.2.13
'@types/react-dom': 19.2.3(@types/react@19.2.13)
+ '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4)
+ '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4)
+ '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.13)(react@19.2.4)
+ '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.13)(react@19.2.4)
+ react: 19.2.4
+ react-dom: 19.2.4(react@19.2.4)
+ optionalDependencies:
+ '@types/react': 19.2.13
+ '@types/react-dom': 19.2.3(@types/react@19.2.13)
+
'@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4)
@@ -3919,31 +4012,31 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
'@tailwindcss/oxide-win32-x64-msvc': 4.1.18
- '@tailwindcss/vite@4.1.18(vite@8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))':
+ '@tailwindcss/vite@4.1.18(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))':
dependencies:
'@tailwindcss/node': 4.1.18
'@tailwindcss/oxide': 4.1.18
tailwindcss: 4.1.18
- vite: 8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1)
+ vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1)
'@tanstack/history@1.154.14': {}
- '@tanstack/react-router-devtools@1.158.1(@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.1)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
+ '@tanstack/react-router-devtools@1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.4)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
- '@tanstack/react-router': 1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- '@tanstack/router-devtools-core': 1.158.1(@tanstack/router-core@1.158.1)(csstype@3.2.3)
+ '@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@tanstack/router-devtools-core': 1.158.4(@tanstack/router-core@1.158.4)(csstype@3.2.3)
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
optionalDependencies:
- '@tanstack/router-core': 1.158.1
+ '@tanstack/router-core': 1.158.4
transitivePeerDependencies:
- csstype
- '@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
+ '@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
'@tanstack/history': 1.154.14
'@tanstack/react-store': 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- '@tanstack/router-core': 1.158.1
+ '@tanstack/router-core': 1.158.4
isbot: 5.1.34
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
@@ -3957,7 +4050,7 @@ snapshots:
react-dom: 19.2.4(react@19.2.4)
use-sync-external-store: 1.6.0(react@19.2.4)
- '@tanstack/router-core@1.158.1':
+ '@tanstack/router-core@1.158.4':
dependencies:
'@tanstack/history': 1.154.14
'@tanstack/store': 0.8.0
@@ -3967,18 +4060,18 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- '@tanstack/router-devtools-core@1.158.1(@tanstack/router-core@1.158.1)(csstype@3.2.3)':
+ '@tanstack/router-devtools-core@1.158.4(@tanstack/router-core@1.158.4)(csstype@3.2.3)':
dependencies:
- '@tanstack/router-core': 1.158.1
+ '@tanstack/router-core': 1.158.4
clsx: 2.1.1
goober: 2.1.18(csstype@3.2.3)
tiny-invariant: 1.3.3
optionalDependencies:
csstype: 3.2.3
- '@tanstack/router-generator@1.158.1':
+ '@tanstack/router-generator@1.158.4':
dependencies:
- '@tanstack/router-core': 1.158.1
+ '@tanstack/router-core': 1.158.4
'@tanstack/router-utils': 1.158.0
'@tanstack/virtual-file-routes': 1.154.7
prettier: 3.8.1
@@ -3989,7 +4082,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@tanstack/router-plugin@1.158.1(@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))':
+ '@tanstack/router-plugin@1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))':
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0)
@@ -3997,16 +4090,16 @@ snapshots:
'@babel/template': 7.28.6
'@babel/traverse': 7.29.0
'@babel/types': 7.29.0
- '@tanstack/router-core': 1.158.1
- '@tanstack/router-generator': 1.158.1
+ '@tanstack/router-core': 1.158.4
+ '@tanstack/router-generator': 1.158.4
'@tanstack/router-utils': 1.158.0
'@tanstack/virtual-file-routes': 1.154.7
chokidar: 3.6.0
unplugin: 2.3.11
zod: 3.25.76
optionalDependencies:
- '@tanstack/react-router': 1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- vite: 8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1)
+ '@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1)
transitivePeerDependencies:
- supports-color
@@ -4058,7 +4151,7 @@ snapshots:
'@types/estree@1.0.8': {}
- '@types/node@25.2.1':
+ '@types/node@25.2.2':
dependencies:
undici-types: 7.16.0
@@ -4086,7 +4179,7 @@ snapshots:
'@vercel/oidc@3.1.0': {}
- '@vitejs/plugin-react@5.1.3(vite@8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))':
+ '@vitejs/plugin-react@5.1.3(vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1))':
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0)
@@ -4094,7 +4187,7 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-rc.2
'@types/babel__core': 7.20.5
react-refresh: 0.18.0
- vite: 8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1)
+ vite: 8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1)
transitivePeerDependencies:
- supports-color
@@ -4230,7 +4323,7 @@ snapshots:
dotenv@16.5.0: {}
- dotenv@17.2.3: {}
+ dotenv@17.2.4: {}
electron-to-chromium@1.5.65: {}
@@ -4703,6 +4796,8 @@ snapshots:
regenerator-runtime@0.14.1: {}
+ reselect@5.1.1: {}
+
resolve-from@4.0.0: {}
resolve-pkg-maps@1.0.0: {}
@@ -4795,6 +4890,8 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
+ tabbable@6.4.0: {}
+
tailwind-merge@3.3.0: {}
tailwind-merge@3.4.0: {}
@@ -4882,7 +4979,7 @@ snapshots:
dependencies:
react: 19.2.4
- vite@8.0.0-beta.13(@types/node@25.2.1)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1):
+ vite@8.0.0-beta.13(@types/node@25.2.2)(esbuild@0.27.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.5.1):
dependencies:
'@oxc-project/runtime': 0.112.0
fdir: 6.5.0(picomatch@4.0.3)
@@ -4892,7 +4989,7 @@ snapshots:
rolldown: 1.0.0-rc.3
tinyglobby: 0.2.15
optionalDependencies:
- '@types/node': 25.2.1
+ '@types/node': 25.2.2
esbuild: 0.27.2
fsevents: 2.3.3
jiti: 2.6.1
diff --git a/src/app/config/page.tsx b/src/app/config/page.tsx
index 33e6c1f..3ea7c29 100644
--- a/src/app/config/page.tsx
+++ b/src/app/config/page.tsx
@@ -3,6 +3,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Button } from '@/components/ui/button';
+import { Checkbox } from '@/components/ui/checkbox';
import { configSchema } from './store/schema';
export const ConfigPage = () => {
@@ -19,7 +20,7 @@ export const ConfigPage = () => {
}
};
- const handleChange = (field: keyof typeof config, value: string) => {
+ const handleChange = (field: keyof typeof config, value: string | boolean) => {
setConfig({ [field]: value });
};
@@ -67,6 +68,17 @@ export const ConfigPage = () => {
/>
+
+ handleChange('ENABLE_CORS', checked === true)}
+ />
+
+
+
{
CNB_API_KEY: '',
CNB_COOKIE: '',
CNB_CORS_URL: 'https://cors.kevisual.cn',
+ ENABLE_CORS: true,
AI_BASE_URL: '',
AI_MODEL: '',
AI_API_KEY: ''
@@ -43,6 +44,7 @@ export const useConfigStore = create
()(
CNB_API_KEY: '',
CNB_COOKIE: '',
CNB_CORS_URL: 'https://cors.kevisual.cn',
+ ENABLE_CORS: true,
AI_BASE_URL: 'https://api.cnb.cool/kevisual/cnb-ai/-/ai/',
AI_MODEL: 'CNB-Models',
AI_API_KEY: ''
diff --git a/src/app/config/store/schema.ts b/src/app/config/store/schema.ts
index d04ae7a..68f8cbc 100644
--- a/src/app/config/store/schema.ts
+++ b/src/app/config/store/schema.ts
@@ -4,6 +4,7 @@ export const configSchema = z.object({
CNB_API_KEY: z.string().min(1, 'API Key is required'),
CNB_COOKIE: z.string().min(1, 'Cookie is required'),
CNB_CORS_URL: z.url('Must be a valid URL'),
+ ENABLE_CORS: z.boolean(),
AI_BASE_URL: z.url('Must be a valid URL'),
AI_MODEL: z.string().min(1, 'AI Model is required'),
AI_API_KEY: z.string().min(1, 'AI API Key is required'),
@@ -15,6 +16,7 @@ export const defaultConfig: Config = {
CNB_API_KEY: '',
CNB_COOKIE: '',
CNB_CORS_URL: 'https://cors.kevisual.cn',
+ ENABLE_CORS: true,
AI_BASE_URL: '',
AI_MODEL: '',
AI_API_KEY: ''
diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx
index 991f56e..2871ad1 100644
--- a/src/components/ui/avatar.tsx
+++ b/src/components/ui/avatar.tsx
@@ -1,48 +1,104 @@
import * as React from "react"
-import * as AvatarPrimitive from "@radix-ui/react-avatar"
+import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar"
import { cn } from "@/lib/utils"
-const Avatar = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-Avatar.displayName = AvatarPrimitive.Root.displayName
+function Avatar({
+ className,
+ size = "default",
+ ...props
+}: AvatarPrimitive.Root.Props & {
+ size?: "default" | "sm" | "lg"
+}) {
+ return (
+
+ )
+}
-const AvatarImage = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-AvatarImage.displayName = AvatarPrimitive.Image.displayName
+function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) {
+ return (
+
+ )
+}
-const AvatarFallback = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
+function AvatarFallback({
+ className,
+ ...props
+}: AvatarPrimitive.Fallback.Props) {
+ return (
+
+ )
+}
-export { Avatar, AvatarImage, AvatarFallback }
+function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
+ return (
+ svg]:hidden",
+ "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
+ "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
+ className
+ )}
+ {...props}
+ />
+ )
+}
+
+function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function AvatarGroupCount({
+ className,
+ ...props
+}: React.ComponentProps<"div">) {
+ return (
+ svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3 ring-background relative flex shrink-0 items-center justify-center ring-2", className)}
+ {...props}
+ />
+ )
+}
+
+export {
+ Avatar,
+ AvatarImage,
+ AvatarFallback,
+ AvatarGroup,
+ AvatarGroupCount,
+ AvatarBadge,
+}
diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx
index e87d62b..c0d4ad8 100644
--- a/src/components/ui/badge.tsx
+++ b/src/components/ui/badge.tsx
@@ -1,20 +1,20 @@
-import * as React from "react"
+import { mergeProps } from "@base-ui/react/merge-props"
+import { useRender } from "@base-ui/react/use-render"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const badgeVariants = cva(
- "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",
+ "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive overflow-hidden group/badge",
{
variants: {
variant: {
- default:
- "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
- secondary:
- "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
- destructive:
- "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
- outline: "text-foreground",
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
+ secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
+ destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
+ outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
+ ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
+ link: "text-primary underline-offset-4 hover:underline",
},
},
defaultVariants: {
@@ -23,14 +23,26 @@ const badgeVariants = cva(
}
)
-export interface BadgeProps
- extends React.HTMLAttributes
,
- VariantProps {}
-
-function Badge({ className, variant, ...props }: BadgeProps) {
- return (
-
- )
+function Badge({
+ className,
+ variant = "default",
+ render,
+ ...props
+}: useRender.ComponentProps<"span"> & VariantProps) {
+ return useRender({
+ defaultTagName: "span",
+ props: mergeProps<"span">(
+ {
+ className: cn(badgeVariants({ className, variant })),
+ },
+ props
+ ),
+ render,
+ state: {
+ slot: "badge",
+ variant,
+ },
+ })
}
export { Badge, badgeVariants }
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index 65d4fcd..e38fd55 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -1,30 +1,31 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
+"use client"
+
+import { Button as ButtonPrimitive } from "@base-ui/react/button"
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",
+ "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-lg border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
{
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",
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
+ outline: "border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground",
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
+ ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
+ destructive: "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
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",
+ default: "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
+ sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
+ icon: "size-8",
+ "icon-xs": "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
+ "icon-sm": "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
+ "icon-lg": "size-9",
},
},
defaultVariants: {
@@ -34,24 +35,19 @@ const buttonVariants = cva(
}
)
-export interface ButtonProps
- extends React.ButtonHTMLAttributes,
- VariantProps {
- asChild?: boolean
+function Button({
+ className,
+ variant = "default",
+ size = "default",
+ ...props
+}: ButtonPrimitive.Props & VariantProps) {
+ return (
+
+ )
}
-const Button = React.forwardRef(
- ({ className, variant, size, asChild = false, ...props }, ref) => {
- const Comp = asChild ? Slot : "button"
- return (
-
- )
- }
-)
-Button.displayName = "Button"
-
export { Button, buttonVariants }
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
index cabfbfc..84bfaa4 100644
--- a/src/components/ui/card.tsx
+++ b/src/components/ui/card.tsx
@@ -2,75 +2,93 @@ import * as React from "react"
import { cn } from "@/lib/utils"
-const Card = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-))
-Card.displayName = "Card"
+function Card({
+ className,
+ size = "default",
+ ...props
+}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
+ return (
+ img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl group/card flex flex-col", className)}
+ {...props}
+ />
+ )
+}
-const CardHeader = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-))
-CardHeader.displayName = "CardHeader"
+function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
-const CardTitle = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-))
-CardTitle.displayName = "CardTitle"
+function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
-const CardDescription = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-))
-CardDescription.displayName = "CardDescription"
+function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
-const CardContent = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-))
-CardContent.displayName = "CardContent"
+function CardAction({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
-const CardFooter = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-))
-CardFooter.displayName = "CardFooter"
+function CardContent({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
-export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
+function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardAction,
+ CardDescription,
+ CardContent,
+}
diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx
new file mode 100644
index 0000000..e010fd9
--- /dev/null
+++ b/src/components/ui/checkbox.tsx
@@ -0,0 +1,27 @@
+import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
+
+import { cn } from "@/lib/utils"
+import { CheckIcon } from "lucide-react"
+
+function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
+ return (
+
+
+
+
+
+ )
+}
+
+export { Checkbox }
diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx
index 9dbeaa0..c509160 100644
--- a/src/components/ui/dialog.tsx
+++ b/src/components/ui/dialog.tsx
@@ -1,120 +1,151 @@
+"use client"
+
import * as React from "react"
-import * as DialogPrimitive from "@radix-ui/react-dialog"
-import { X } from "lucide-react"
+import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import { XIcon } from "lucide-react"
-const Dialog = DialogPrimitive.Root
+function Dialog({ ...props }: DialogPrimitive.Root.Props) {
+ return
+}
-const DialogTrigger = DialogPrimitive.Trigger
+function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
+ return
+}
-const DialogPortal = DialogPrimitive.Portal
+function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
+ return
+}
-const DialogClose = DialogPrimitive.Close
+function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
+ return
+}
-const DialogOverlay = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
+function DialogOverlay({
+ className,
+ ...props
+}: DialogPrimitive.Backdrop.Props) {
+ return (
+
+ )
+}
-const DialogContent = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, children, ...props }, ref) => (
-
-
-
+
+
+ {children}
+ {showCloseButton && (
+
+ }
+ >
+
+ Close
+
+ )}
+
+
+ )
+}
+
+function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+function DialogFooter({
+ className,
+ showCloseButton = false,
+ children,
+ ...props
+}: React.ComponentProps<"div"> & {
+ showCloseButton?: boolean
+}) {
+ return (
+
{children}
-
-
- Close
-
-
-
-))
-DialogContent.displayName = DialogPrimitive.Content.displayName
+ {showCloseButton && (
+ }>
+ Close
+
+ )}
+
+ )
+}
-const DialogHeader = ({
+function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
+ return (
+
+ )
+}
+
+function DialogDescription({
className,
...props
-}: React.HTMLAttributes) => (
-
-)
-DialogHeader.displayName = "DialogHeader"
-
-const DialogFooter = ({
- className,
- ...props
-}: React.HTMLAttributes) => (
-
-)
-DialogFooter.displayName = "DialogFooter"
-
-const DialogTitle = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-DialogTitle.displayName = DialogPrimitive.Title.displayName
-
-const DialogDescription = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-DialogDescription.displayName = DialogPrimitive.Description.displayName
+}: DialogPrimitive.Description.Props) {
+ return (
+
+ )
+}
export {
Dialog,
- DialogPortal,
- DialogOverlay,
- DialogTrigger,
DialogClose,
DialogContent,
- DialogHeader,
- DialogFooter,
- DialogTitle,
DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogOverlay,
+ DialogPortal,
+ DialogTitle,
+ DialogTrigger,
}
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
index 69b64fb..981e825 100644
--- a/src/components/ui/input.tsx
+++ b/src/components/ui/input.tsx
@@ -1,22 +1,20 @@
import * as React from "react"
+import { Input as InputPrimitive } from "@base-ui/react/input"
import { cn } from "@/lib/utils"
-const Input = React.forwardRef>(
- ({ className, type, ...props }, ref) => {
- return (
-
- )
- }
-)
-Input.displayName = "Input"
+function Input({ className, type, ...props }: React.ComponentProps<"input">) {
+ return (
+
+ )
+}
export { Input }
diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx
index 683faa7..5ac813e 100644
--- a/src/components/ui/label.tsx
+++ b/src/components/ui/label.tsx
@@ -1,24 +1,20 @@
+"use client"
+
import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
-import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
-const labelVariants = cva(
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
-)
-
-const Label = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef &
- VariantProps
->(({ className, ...props }, ref) => (
-
-))
-Label.displayName = LabelPrimitive.Root.displayName
+function Label({ className, ...props }: React.ComponentProps<"label">) {
+ return (
+
+ )
+}
export { Label }
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
index 2ca1df8..231daaa 100644
--- a/src/components/ui/select.tsx
+++ b/src/components/ui/select.tsx
@@ -1,157 +1,191 @@
import * as React from "react"
-import * as SelectPrimitive from "@radix-ui/react-select"
-import { Check, ChevronDown, ChevronUp } from "lucide-react"
+import { Select as SelectPrimitive } from "@base-ui/react/select"
import { cn } from "@/lib/utils"
+import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
const Select = SelectPrimitive.Root
-const SelectGroup = SelectPrimitive.Group
+function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
+ return (
+
+ )
+}
-const SelectValue = SelectPrimitive.Value
+function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {
+ return (
+
+ )
+}
-const SelectTrigger = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, children, ...props }, ref) => (
- span]:line-clamp-1",
- className
- )}
- {...props}
- >
- {children}
-
-
-
-
-))
-SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
-
-const SelectScrollUpButton = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-
-
-))
-SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
-
-const SelectScrollDownButton = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-
-
-))
-SelectScrollDownButton.displayName =
- SelectPrimitive.ScrollDownButton.displayName
-
-const SelectContent = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, children, position = "popper", ...props }, ref) => (
-
-
-
-
+ }
+ />
+
+ )
+}
+
+function SelectContent({
+ className,
+ children,
+ side = "bottom",
+ sideOffset = 4,
+ align = "center",
+ alignOffset = 0,
+ alignItemWithTrigger = true,
+ ...props
+}: SelectPrimitive.Popup.Props &
+ Pick<
+ SelectPrimitive.Positioner.Props,
+ "align" | "alignOffset" | "side" | "sideOffset" | "alignItemWithTrigger"
+ >) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ )
+}
+
+function SelectLabel({
+ className,
+ ...props
+}: SelectPrimitive.GroupLabel.Props) {
+ return (
+
+ )
+}
+
+function SelectItem({
+ className,
+ children,
+ ...props
+}: SelectPrimitive.Item.Props) {
+ return (
+
+
{children}
-
-
-
-
-))
-SelectContent.displayName = SelectPrimitive.Content.displayName
-
-const SelectLabel = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-SelectLabel.displayName = SelectPrimitive.Label.displayName
-
-const SelectItem = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, children, ...props }, ref) => (
-
-
-
-
+
+ }
+ >
+
-
- {children}
-
-))
-SelectItem.displayName = SelectPrimitive.Item.displayName
+
+ )
+}
-const SelectSeparator = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-SelectSeparator.displayName = SelectPrimitive.Separator.displayName
+function SelectSeparator({
+ className,
+ ...props
+}: SelectPrimitive.Separator.Props) {
+ return (
+
+ )
+}
+
+function SelectScrollUpButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
+
+function SelectScrollDownButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ )
+}
export {
Select,
- SelectGroup,
- SelectValue,
- SelectTrigger,
SelectContent,
- SelectLabel,
+ SelectGroup,
SelectItem,
- SelectSeparator,
- SelectScrollUpButton,
+ SelectLabel,
SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
}
diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx
index 12d81c4..32b6ff2 100644
--- a/src/components/ui/separator.tsx
+++ b/src/components/ui/separator.tsx
@@ -1,31 +1,25 @@
"use client"
-import * as React from "react"
-import * as SeparatorPrimitive from "@radix-ui/react-separator"
+import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
import { cn } from "@/lib/utils"
-const Separator = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(
- (
- { className, orientation = "horizontal", decorative = true, ...props },
- ref
- ) => (
-
)
-)
-Separator.displayName = SeparatorPrimitive.Root.displayName
+}
export { Separator }
diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx
index 1128edf..9772eb2 100644
--- a/src/components/ui/sonner.tsx
+++ b/src/components/ui/sonner.tsx
@@ -1,7 +1,6 @@
import { useTheme } from "next-themes"
-import { Toaster as Sonner } from "sonner"
-
-type ToasterProps = React.ComponentProps
+import { Toaster as Sonner, type ToasterProps } from "sonner"
+import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon } from "lucide-react"
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
@@ -10,15 +9,34 @@ const Toaster = ({ ...props }: ToasterProps) => {
+ ),
+ info: (
+
+ ),
+ warning: (
+
+ ),
+ error: (
+
+ ),
+ loading: (
+
+ ),
+ }}
+ style={
+ {
+ "--normal-bg": "var(--popover)",
+ "--normal-text": "var(--popover-foreground)",
+ "--normal-border": "var(--border)",
+ "--border-radius": "var(--radius)",
+ } as React.CSSProperties
+ }
toastOptions={{
classNames: {
- toast:
- "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
- description: "group-[.toast]:text-muted-foreground",
- actionButton:
- "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
- cancelButton:
- "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
+ toast: "cn-toast",
},
}}
{...props}
diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx
index c0df655..6b715c3 100644
--- a/src/components/ui/table.tsx
+++ b/src/components/ui/table.tsx
@@ -1,112 +1,93 @@
+"use client"
+
import * as React from "react"
import { cn } from "@/lib/utils"
-const Table = React.forwardRef<
- HTMLTableElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-
) {
+ return (
+
+ )
+}
+
+function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
+ return (
+
-
-))
-Table.displayName = "Table"
+ )
+}
-const TableHeader = React.forwardRef<
- HTMLTableSectionElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-))
-TableHeader.displayName = "TableHeader"
+function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
+ return (
+
+ )
+}
-const TableBody = React.forwardRef<
- HTMLTableSectionElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-))
-TableBody.displayName = "TableBody"
+function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
+ return (
+ tr]:last:border-b-0", className)}
+ {...props}
+ />
+ )
+}
-const TableFooter = React.forwardRef<
- HTMLTableSectionElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
- tr]:last:border-b-0",
- className
- )}
- {...props}
- />
-))
-TableFooter.displayName = "TableFooter"
+function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
+ return (
+
+ )
+}
-const TableRow = React.forwardRef<
- HTMLTableRowElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-))
-TableRow.displayName = "TableRow"
+function TableHead({ className, ...props }: React.ComponentProps<"th">) {
+ return (
+ |
+ )
+}
-const TableHead = React.forwardRef<
- HTMLTableCellElement,
- React.ThHTMLAttributes
->(({ className, ...props }, ref) => (
- [role=checkbox]]:translate-y-[2px]",
- className
- )}
- {...props}
- />
-))
-TableHead.displayName = "TableHead"
+function TableCell({ className, ...props }: React.ComponentProps<"td">) {
+ return (
+ | |
+ )
+}
-const TableCell = React.forwardRef<
- HTMLTableCellElement,
- React.TdHTMLAttributes
->(({ className, ...props }, ref) => (
- [role=checkbox]]:translate-y-[2px]",
- className
- )}
- {...props}
- />
-))
-TableCell.displayName = "TableCell"
-
-const TableCaption = React.forwardRef<
- HTMLTableCaptionElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
-
-))
-TableCaption.displayName = "TableCaption"
+function TableCaption({
+ className,
+ ...props
+}: React.ComponentProps<"caption">) {
+ return (
+
+ )
+}
export {
Table,
diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx
index 85d83be..b4be30c 100644
--- a/src/components/ui/tabs.tsx
+++ b/src/components/ui/tabs.tsx
@@ -1,53 +1,80 @@
-import * as React from "react"
-import * as TabsPrimitive from "@radix-ui/react-tabs"
+import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"
+import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
-const Tabs = TabsPrimitive.Root
+function Tabs({
+ className,
+ orientation = "horizontal",
+ ...props
+}: TabsPrimitive.Root.Props) {
+ return (
+
+ )
+}
-const TabsList = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-TabsList.displayName = TabsPrimitive.List.displayName
+const tabsListVariants = cva(
+ "rounded-lg p-[3px] group-data-horizontal/tabs:h-8 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col",
+ {
+ variants: {
+ variant: {
+ default: "bg-muted",
+ line: "gap-1 bg-transparent",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
-const TabsTrigger = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
+function TabsList({
+ className,
+ variant = "default",
+ ...props
+}: TabsPrimitive.List.Props & VariantProps) {
+ return (
+
+ )
+}
-const TabsContent = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-))
-TabsContent.displayName = TabsPrimitive.Content.displayName
+function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
+ return (
+
+ )
+}
-export { Tabs, TabsList, TabsTrigger, TabsContent }
+function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
+ return (
+
+ )
+}
+
+export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
|