├── .DS_Store ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github └── FUNDING.yml ├── .gitignore ├── .gitmodules ├── .npmrc ├── .prettierignore ├── .prettierrc ├── .vscode └── extensions.json ├── LICENSE ├── README.md ├── compile_model.sh ├── components.json ├── docker-compose.yml ├── icon.png ├── index.html ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── shims.vue.d.ts ├── src ├── App.spec.ts ├── App.vue ├── assets │ └── css │ │ └── tailwind.css ├── components │ ├── dark-toggle │ │ └── DarkToggle.vue │ ├── domain │ │ └── bot │ │ │ ├── CreateBotForm.vue │ │ │ └── UpdateBotForm.vue │ └── ui │ │ ├── alert-dialog │ │ ├── AlertDialog.vue │ │ ├── AlertDialogAction.vue │ │ ├── AlertDialogCancel.vue │ │ ├── AlertDialogContent.vue │ │ ├── AlertDialogDescription.vue │ │ ├── AlertDialogFooter.vue │ │ ├── AlertDialogHeader.vue │ │ ├── AlertDialogTitle.vue │ │ ├── AlertDialogTrigger.vue │ │ └── index.ts │ │ ├── badge │ │ ├── Badge.vue │ │ └── index.ts │ │ ├── button │ │ ├── Button.vue │ │ └── index.ts │ │ ├── card │ │ ├── Card.vue │ │ ├── CardContent.vue │ │ ├── CardDescription.vue │ │ ├── CardFooter.vue │ │ ├── CardHeader.vue │ │ ├── CardTitle.vue │ │ └── index.ts │ │ ├── chat │ │ └── ChatMessage.vue │ │ ├── command │ │ ├── Command.vue │ │ ├── CommandDialog.vue │ │ ├── CommandEmpty.vue │ │ ├── CommandGroup.vue │ │ ├── CommandInput.vue │ │ ├── CommandItem.vue │ │ ├── CommandList.vue │ │ ├── CommandSeparator.vue │ │ ├── CommandShortcut.vue │ │ └── index.ts │ │ ├── dialog │ │ ├── Dialog.vue │ │ ├── DialogClose.vue │ │ ├── DialogContent.vue │ │ ├── DialogDescription.vue │ │ ├── DialogFooter.vue │ │ ├── DialogHeader.vue │ │ ├── DialogTitle.vue │ │ ├── DialogTrigger.vue │ │ └── index.ts │ │ ├── form │ │ ├── FormControl.vue │ │ ├── FormDescription.vue │ │ ├── FormItem.vue │ │ ├── FormLabel.vue │ │ ├── FormMessage.vue │ │ ├── index.ts │ │ └── useFormField.ts │ │ ├── input │ │ ├── Input.vue │ │ └── index.ts │ │ ├── loading │ │ └── Loading.vue │ │ ├── menu-item │ │ └── MenuItem.vue │ │ ├── popover │ │ ├── Popover.vue │ │ ├── PopoverContent.vue │ │ ├── PopoverTrigger.vue │ │ └── index.ts │ │ ├── skeleton │ │ ├── Skeleton.vue │ │ └── index.ts │ │ ├── slider │ │ ├── Slider.vue │ │ └── index.ts │ │ ├── switch │ │ ├── Switch.vue │ │ └── index.ts │ │ ├── table │ │ ├── Table.vue │ │ ├── TableBody.vue │ │ ├── TableCaption.vue │ │ ├── TableCell.vue │ │ ├── TableEmpty.vue │ │ ├── TableFooter.vue │ │ ├── TableHead.vue │ │ ├── TableHeader.vue │ │ ├── TableRow.vue │ │ └── index.ts │ │ ├── text │ │ ├── Text.vue │ │ └── index.ts │ │ ├── textarea │ │ ├── Textarea.vue │ │ └── index.ts │ │ ├── toast │ │ ├── Toast.vue │ │ ├── ToastAction.vue │ │ ├── ToastClose.vue │ │ ├── ToastDescription.vue │ │ ├── ToastProvider.vue │ │ ├── ToastTitle.vue │ │ ├── ToastViewport.vue │ │ ├── Toaster.vue │ │ ├── index.ts │ │ └── use-toast.ts │ │ └── tooltip │ │ ├── QuestionMark.vue │ │ ├── Tooltip.vue │ │ ├── TooltipContent.vue │ │ ├── TooltipProvider.vue │ │ ├── TooltipTrigger.vue │ │ └── index.ts ├── composables │ ├── useDb.ts │ ├── useLLM.ts │ ├── useModel.ts │ └── useWebGPU.ts ├── lib │ └── utils.ts ├── main.ts ├── router │ └── index.ts ├── store │ ├── chat.ts │ └── main.ts ├── styles.css ├── types.ts ├── views │ ├── Home.vue │ ├── Models.vue │ └── Prompts.vue └── web-worker.ts ├── static └── logo.png ├── tailwind.config.js ├── todo.md ├── tsconfig.app.json ├── tsconfig.base.json ├── tsconfig.json ├── tsconfig.spec.json └── vite.config.ts /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zuramai/ChatLLM/ef347adf68d62abf7d138b5e07deb8f4bc7ab053/.DS_Store -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nx"], 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx", "*.vue"], 8 | "rules": { 9 | "@nx/enforce-module-boundaries": [ 10 | "error", 11 | { 12 | "enforceBuildableLibDependency": true, 13 | "allow": [], 14 | "depConstraints": [ 15 | { 16 | "sourceTag": "*", 17 | "onlyDependOnLibsWithTags": ["*"] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | }, 24 | { 25 | "files": ["*.ts", "*.tsx"], 26 | "extends": ["plugin:@nx/typescript"], 27 | "rules": {} 28 | }, 29 | { 30 | "files": ["*.js", "*.jsx"], 31 | "extends": ["plugin:@nx/javascript"], 32 | "rules": {} 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: zuramai # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: saugi # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | dist 5 | dev-dist 6 | tmp 7 | /out-tsc 8 | 9 | # dependencies 10 | node_modules 11 | 12 | # IDEs and editors 13 | /.idea 14 | .project 15 | .classpath 16 | .c9/ 17 | *.launch 18 | .settings/ 19 | *.sublime-workspace 20 | 21 | # IDE - VSCode 22 | .vscode/* 23 | !.vscode/settings.json 24 | !.vscode/tasks.json 25 | !.vscode/launch.json 26 | !.vscode/extensions.json 27 | 28 | # misc 29 | /.sass-cache 30 | /connect.lock 31 | /coverage 32 | /libpeerconnection.log 33 | npm-debug.log 34 | yarn-error.log 35 | testem.log 36 | /typings 37 | 38 | # System Files 39 | .DS_Store 40 | Thumbs.db 41 | 42 | .nx/cache 43 | 44 | .yarn/* 45 | !.yarn/releases 46 | !.yarn/plugins 47 | .pnp.* 48 | cache -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "frontend/libs/web-llm"] 2 | path = libs/web-llm 3 | url = https://github.com/zuramai/web-llm 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | strict-peer-dependencies=false 2 | auto-install-peers=true 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | /dist 3 | /coverage 4 | /.nx/cache -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "nrwl.angular-console", 4 | "esbenp.prettier-vscode", 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Saugi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChatLLM 2 | 3 | Chat with LLM directly in your browser using your own GPU (powered by WebGPU) 4 | 5 | ![Screenshot 2024-10-02 at 20 43 18](https://github.com/user-attachments/assets/fd1e372e-55ed-4678-8004-cef3abe030dc) 6 | 7 | 1. Clone the repository 8 | ``` 9 | git clone https://github.com/zuramai/ChatLLM --recursive 10 | cd ChatLLM 11 | ``` 12 | 13 | 2. Install 14 | ``` 15 | pnpm install 16 | ``` 17 | 18 | 3. Run 19 | ``` 20 | pnpm run dev 21 | ``` 22 | 23 | # License 24 | This project is under MIT License 25 | -------------------------------------------------------------------------------- /compile_model.sh: -------------------------------------------------------------------------------- 1 | mlc_llm convert_weight ../models/orca_mini_3b --quantization q4f32_1 -o dist/orca_mini_3b-q4f32_1 2 | mlc_llm compile dist/orca_mini_3b-q4f32_1/mlc-chat-config.json --device webgpu -o dist/orca_mini_3b-q4f32_1/orca_mini_3b-q4f32_1.wasm 3 | mlc_llm gen_config ../models/orca_mini_3b --quantization q4f32_1 -o dist/orca_mini_3b-q4f32_1 --conv-template wizardlm_7b -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "style": "default", 3 | "typescript": true, 4 | "tailwind": { 5 | "config": "tailwind.config.js", 6 | "css": "src/assets/index.css", 7 | "baseColor": "slate", 8 | "cssVariables": true 9 | }, 10 | "framework": "vite", 11 | "aliases": { 12 | "components": "src/components", 13 | "utils": "src/lib/utils" 14 | } 15 | } -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | pg: 5 | container_name: pg 6 | image: postgres 7 | restart: always 8 | volumes: 9 | - db-data:/var/lib/postgresql/data 10 | environment: 11 | POSTGRES_PASSWORD: postgres 12 | POSTGRES_USER: postgres 13 | ports: 14 | - 5432:5432 15 | app: 16 | build: 17 | context: ./frontend 18 | dockerfile: Dockerfile 19 | container_name: llm-frontend 20 | command: pnpm run dev & pnpm run llm:dev 21 | ports: 22 | - '3000:3000' 23 | volumes: 24 | - ./frontend:/app 25 | - /app/node_modules 26 | 27 | volumes: 28 | db-data: -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zuramai/ChatLLM/ef347adf68d62abf7d138b5e07deb8f4bc7ab053/icon.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ChatLLM 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "llmchat", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vue-tsc --noEmit && vite build", 8 | "preview": "vite preview" 9 | }, 10 | "private": true, 11 | "dependencies": { 12 | "@mlc-ai/web-llm": "^0.2.50", 13 | "@swc/helpers": "~0.5.12", 14 | "@vee-validate/zod": "^4.13.2", 15 | "@vueuse/core": "^10.11.0", 16 | "class-variance-authority": "^0.7.0", 17 | "clsx": "^2.1.1", 18 | "esbuild": "^0.21.5", 19 | "localforage": "^1.10.0", 20 | "lucide-vue-next": "^0.292.0", 21 | "pdfjs-dist": "^4.4.168", 22 | "pinia": "^2.1.7", 23 | "radix-vue": "^1.9.1", 24 | "rollup": "^4.18.1", 25 | "tailwind-merge": "^2.4.0", 26 | "tailwindcss-animate": "^1.0.7", 27 | "vee-validate": "^4.13.2", 28 | "vue": "^3.4.31", 29 | "vue-router": "^4.4.0", 30 | "zod": "^3.23.8" 31 | }, 32 | "devDependencies": { 33 | "@swc-node/register": "~1.6.8", 34 | "@swc/cli": "~0.1.65", 35 | "@swc/core": "~1.3.107", 36 | "@types/node": "18.7.1", 37 | "@typescript-eslint/eslint-plugin": "^6.21.0", 38 | "@typescript-eslint/parser": "^6.21.0", 39 | "@vitejs/plugin-vue": "^4.6.2", 40 | "@vitest/coverage-v8": "~0.32.4", 41 | "@vitest/ui": "~0.32.4", 42 | "@vue/eslint-config-prettier": "7.1.0", 43 | "@vue/eslint-config-typescript": "^11.0.3", 44 | "@vue/test-utils": "^2.4.6", 45 | "@vue/tsconfig": "^0.4.0", 46 | "autoprefixer": "^10.4.19", 47 | "eslint": "~8.46.0", 48 | "eslint-config-prettier": "^9.1.0", 49 | "eslint-plugin-vue": "^9.27.0", 50 | "jsdom": "~22.1.0", 51 | "loglevel": "^1.9.1", 52 | "postcss": "^8.4.39", 53 | "prettier": "^2.8.8", 54 | "tailwindcss": "^3.4.5", 55 | "tslib": "^2.6.3", 56 | "typescript": "~5.2.2", 57 | "vite": "~4.3.9", 58 | "vite-plugin-dts": "~2.3.0", 59 | "vite-plugin-pwa": "^0.17.5", 60 | "vite-plugin-top-level-await": "^1.4.1", 61 | "vitest": "~0.32.4", 62 | "vue-tsc": "^1.8.27" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /shims.vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue'; 2 | -------------------------------------------------------------------------------- /src/App.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | import { mount } from '@vue/test-utils'; 4 | import App from './App.vue'; 5 | 6 | describe('App', () => { 7 | it('renders properly', () => { 8 | const wrapper = mount(App, {}); 9 | expect(wrapper.text()).toContain('Welcome frontend 👋'); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 68 | 69 | -------------------------------------------------------------------------------- /src/assets/css/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: white; 8 | --foreground: black; 9 | --main-bg: rgba(244, 246, 251, 0.592); 10 | 11 | --scrollbarBG: #f7f7f7; 12 | --thumbBG: #90A4AE; 13 | 14 | --heading-color: hsl(0, 0%, 2%); 15 | 16 | --muted: hsl(210 40% 96.1%); 17 | --muted-foreground: hsl(215.4 16.3% 46.9%); 18 | 19 | --popover: hsl(0 0% 100%); 20 | --popover-foreground: hsl(222.2 84% 4.9%); 21 | 22 | --card: hsl(0 0% 100%); 23 | --card-foreground: hsl(222.2 84% 4.9%); 24 | 25 | --border: hsl(214.3 31.8% 91.4%); 26 | --input: hsl(213, 27%, 92%); 27 | 28 | --primary: rgb(70, 154, 196); 29 | --primary-foreground: hsl(210 40% 98%); 30 | 31 | --secondary: hsl(210, 27%, 94%); 32 | --secondary-foreground: hsl(222.2 47.4% 11.2%); 33 | 34 | --accent: hsl(210 40% 96.1%); 35 | --accent-foreground: hsl(222.2 47.4% 11.2%); 36 | 37 | --destructive: hsl(348 100% 57%); 38 | --destructive-foreground: hsl(210 40% 98%); 39 | 40 | --success: hsl(167.26deg 52.66% 48.79%); 41 | --success-foreground: hsl(136, 0%, 100%); 42 | 43 | --ring: hsl(222.2 84% 4.9%); 44 | 45 | --radius: 0.5rem; 46 | } 47 | 48 | } 49 | 50 | .dark { 51 | --background: hsl(180, 31%, 6%); 52 | --foreground: hsl(218 11% 65%); 53 | --main-bg: rgba(24, 28, 40, 0.481);; 54 | 55 | --scrollbarBG: #1b1e2f; 56 | --thumbBG: #90A4AE; 57 | 58 | --muted: hsl(217.2 32.6% 17.5%); 59 | --muted-foreground: hsl(215 20.2% 65.1%); 60 | 61 | --popover: hsl(222.2 84% 4.9%); 62 | --popover-foreground: hsl(210 40% 98%); 63 | 64 | --card: hsl(222.2 84% 4.9%); 65 | --card-foreground: hsl(218 11% 65%); 66 | --border: hsl(217.2 32.6% 17.5%); 67 | --input: hsl(217.2 32.6% 17.5%); 68 | 69 | --primary: rgb(70, 154, 196); 70 | --primary-foreground: hsl(210 40% 98%); 71 | 72 | --secondary: hsl(217.2 32.6% 17.5%); 73 | --secondary-foreground: hsl(210 40% 98%); 74 | 75 | --accent: hsl(217.2 32.6% 17.5%); 76 | --accent-foreground: hsl(210 40% 98%); 77 | 78 | --destructive: hsl(350 70% 56%); 79 | --destructive-foreground: hsl(210 40% 98%); 80 | 81 | --ring: hsl(212.7 26.8% 83.9%); 82 | --heading-color: hsl(210 40% 98%); 83 | } 84 | .chat-messages { 85 | scrollbar-width: thin; 86 | } 87 | html { 88 | --scrollbarBG: #1b1e2f; 89 | --thumbBG: #90A4AE; 90 | } 91 | .chat-messages::-webkit-scrollbar { 92 | width: 11px; 93 | } 94 | .chat-messages { 95 | scrollbar-width: thin; 96 | scrollbar-color: var(--thumbBG) var(--scrollbarBG); 97 | } 98 | .chat-messages::-webkit-scrollbar-track { 99 | background: var(--scrollbarBG); 100 | } 101 | .chat-messages::-webkit-scrollbar-thumb { 102 | background-color: var(--thumbBG) ; 103 | border-radius: 6px; 104 | border: 3px solid var(--scrollbarBG); 105 | } 106 | .body-content main { 107 | background: var(--main-bg); 108 | } 109 | @layer base { 110 | * { 111 | @apply border-border; 112 | } 113 | body { 114 | @apply bg-background text-foreground; 115 | } 116 | h1,h2,h3,h4,h5,h6 { 117 | color: var(--heading-color); 118 | } 119 | } -------------------------------------------------------------------------------- /src/components/dark-toggle/DarkToggle.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /src/components/domain/bot/CreateBotForm.vue: -------------------------------------------------------------------------------- 1 | 101 | -------------------------------------------------------------------------------- /src/components/domain/bot/UpdateBotForm.vue: -------------------------------------------------------------------------------- 1 | 106 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialog.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogAction.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogCancel.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogContent.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 36 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogDescription.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogFooter.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogHeader.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogTitle.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/AlertDialogTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/alert-dialog/index.ts: -------------------------------------------------------------------------------- 1 | export { default as AlertDialog } from './AlertDialog.vue' 2 | export { default as AlertDialogTrigger } from './AlertDialogTrigger.vue' 3 | export { default as AlertDialogContent } from './AlertDialogContent.vue' 4 | export { default as AlertDialogHeader } from './AlertDialogHeader.vue' 5 | export { default as AlertDialogTitle } from './AlertDialogTitle.vue' 6 | export { default as AlertDialogDescription } from './AlertDialogDescription.vue' 7 | export { default as AlertDialogFooter } from './AlertDialogFooter.vue' 8 | export { default as AlertDialogAction } from './AlertDialogAction.vue' 9 | export { default as AlertDialogCancel } from './AlertDialogCancel.vue' 10 | -------------------------------------------------------------------------------- /src/components/ui/badge/Badge.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/components/ui/badge/index.ts: -------------------------------------------------------------------------------- 1 | import { type VariantProps, cva } from 'class-variance-authority' 2 | 3 | export { default as Badge } from './Badge.vue' 4 | 5 | export const badgeVariants = cva( 6 | 'inline-flex items-center rounded-full 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', 7 | { 8 | variants: { 9 | variant: { 10 | default: 11 | 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80', 12 | secondary: 13 | 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', 14 | destructive: 15 | 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', 16 | outline: 'text-foreground', 17 | }, 18 | }, 19 | defaultVariants: { 20 | variant: 'default', 21 | }, 22 | }, 23 | ) 24 | 25 | export type BadgeVariants = VariantProps 26 | -------------------------------------------------------------------------------- /src/components/ui/button/Button.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | -------------------------------------------------------------------------------- /src/components/ui/button/index.ts: -------------------------------------------------------------------------------- 1 | import { cva } from 'class-variance-authority' 2 | 3 | export { default as Button } from './Button.vue' 4 | 5 | export const buttonVariants = cva( 6 | 'inline-flex items-center justify-center 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', 7 | { 8 | variants: { 9 | variant: { 10 | default: 'bg-primary text-primary-foreground hover:bg-primary/90', 11 | destructive: 12 | 'bg-destructive text-destructive-foreground hover:bg-destructive/90', 13 | danger: 14 | 'bg-destructive text-destructive-foreground hover:bg-destructive/90', 15 | 'outline-danger': 16 | 'bg-transparent border-destructive border text-destructive hover:bg-destructive/90 hover:text-white', 17 | outline: 18 | 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', 19 | secondary: 20 | 'bg-secondary text-secondary-foreground hover:bg-secondary/80', 21 | ghost: 'hover:bg-accent hover:text-accent-foreground', 22 | link: 'text-primary underline-offset-4 hover:underline', 23 | }, 24 | size: { 25 | default: 'h-10 px-4 py-2', 26 | sm: 'h-9 rounded-md px-3', 27 | lg: 'h-11 rounded-md px-8', 28 | icon: 'h-10 w-10', 29 | }, 30 | }, 31 | defaultVariants: { 32 | variant: 'default', 33 | size: 'default', 34 | }, 35 | }, 36 | ) 37 | -------------------------------------------------------------------------------- /src/components/ui/card/Card.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | -------------------------------------------------------------------------------- /src/components/ui/card/CardContent.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/components/ui/card/CardDescription.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/components/ui/card/CardFooter.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/components/ui/card/CardHeader.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/components/ui/card/CardTitle.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 21 | -------------------------------------------------------------------------------- /src/components/ui/card/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Card } from './Card.vue' 2 | export { default as CardHeader } from './CardHeader.vue' 3 | export { default as CardTitle } from './CardTitle.vue' 4 | export { default as CardDescription } from './CardDescription.vue' 5 | export { default as CardContent } from './CardContent.vue' 6 | export { default as CardFooter } from './CardFooter.vue' 7 | -------------------------------------------------------------------------------- /src/components/ui/chat/ChatMessage.vue: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /src/components/ui/command/Command.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 22 | -------------------------------------------------------------------------------- /src/components/ui/command/CommandDialog.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 22 | -------------------------------------------------------------------------------- /src/components/ui/command/CommandEmpty.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /src/components/ui/command/CommandGroup.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 22 | -------------------------------------------------------------------------------- /src/components/ui/command/CommandInput.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 25 | -------------------------------------------------------------------------------- /src/components/ui/command/CommandItem.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 21 | -------------------------------------------------------------------------------- /src/components/ui/command/CommandList.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /src/components/ui/command/CommandSeparator.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | -------------------------------------------------------------------------------- /src/components/ui/command/CommandShortcut.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /src/components/ui/command/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Command } from './Command.vue' 2 | export { default as CommandDialog } from './CommandDialog.vue' 3 | export { default as CommandEmpty } from './CommandEmpty.vue' 4 | export { default as CommandGroup } from './CommandGroup.vue' 5 | export { default as CommandInput } from './CommandInput.vue' 6 | export { default as CommandItem } from './CommandItem.vue' 7 | export { default as CommandList } from './CommandList.vue' 8 | export { default as CommandSeparator } from './CommandSeparator.vue' 9 | export { default as CommandShortcut } from './CommandShortcut.vue' 10 | -------------------------------------------------------------------------------- /src/components/ui/dialog/Dialog.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 25 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogClose.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogContent.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 50 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogDescription.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogFooter.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogHeader.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogTitle.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 21 | -------------------------------------------------------------------------------- /src/components/ui/dialog/DialogTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/dialog/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Dialog } from './Dialog.vue' 2 | export { default as DialogClose } from './DialogClose.vue' 3 | export { default as DialogTrigger } from './DialogTrigger.vue' 4 | export { default as DialogHeader } from './DialogHeader.vue' 5 | export { default as DialogTitle } from './DialogTitle.vue' 6 | export { default as DialogDescription } from './DialogDescription.vue' 7 | export { default as DialogContent } from './DialogContent.vue' 8 | export { default as DialogFooter } from './DialogFooter.vue' 9 | -------------------------------------------------------------------------------- /src/components/ui/form/FormControl.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 17 | -------------------------------------------------------------------------------- /src/components/ui/form/FormDescription.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /src/components/ui/form/FormItem.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 22 | 23 | 28 | -------------------------------------------------------------------------------- /src/components/ui/form/FormLabel.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 29 | -------------------------------------------------------------------------------- /src/components/ui/form/FormMessage.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | -------------------------------------------------------------------------------- /src/components/ui/form/index.ts: -------------------------------------------------------------------------------- 1 | export { Form, Field as FormField } from 'vee-validate' 2 | export { default as FormItem } from './FormItem.vue' 3 | export { default as FormLabel } from './FormLabel.vue' 4 | export { default as FormControl } from './FormControl.vue' 5 | export { default as FormMessage } from './FormMessage.vue' 6 | export { default as FormDescription } from './FormDescription.vue' 7 | -------------------------------------------------------------------------------- /src/components/ui/form/useFormField.ts: -------------------------------------------------------------------------------- 1 | import { FieldContextKey, useFieldError, useIsFieldDirty, useIsFieldTouched, useIsFieldValid } from 'vee-validate' 2 | import { inject } from 'vue' 3 | import { FORM_ITEM_INJECTION_KEY } from './FormItem.vue' 4 | 5 | export function useFormField() { 6 | const fieldContext = inject(FieldContextKey) 7 | const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY) 8 | 9 | const fieldState = { 10 | valid: useIsFieldValid(), 11 | isDirty: useIsFieldDirty(), 12 | isTouched: useIsFieldTouched(), 13 | error: useFieldError(), 14 | } 15 | 16 | if (!fieldContext) 17 | throw new Error('useFormField should be used within ') 18 | 19 | const { name } = fieldContext 20 | const id = fieldItemContext 21 | 22 | return { 23 | id, 24 | name, 25 | formItemId: `${id}-form-item`, 26 | formDescriptionId: `${id}-form-item-description`, 27 | formMessageId: `${id}-form-item-message`, 28 | ...fieldState, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/ui/input/Input.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /src/components/ui/input/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Input } from './Input.vue' 2 | -------------------------------------------------------------------------------- /src/components/ui/loading/Loading.vue: -------------------------------------------------------------------------------- 1 | 6 | 11 | -------------------------------------------------------------------------------- /src/components/ui/menu-item/MenuItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 11 | -------------------------------------------------------------------------------- /src/components/ui/popover/Popover.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/ui/popover/PopoverContent.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 37 | -------------------------------------------------------------------------------- /src/components/ui/popover/PopoverTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/popover/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Popover } from './Popover.vue' 2 | export { default as PopoverTrigger } from './PopoverTrigger.vue' 3 | export { default as PopoverContent } from './PopoverContent.vue' 4 | -------------------------------------------------------------------------------- /src/components/ui/skeleton/Skeleton.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/components/ui/skeleton/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Skeleton } from './Skeleton.vue' 2 | -------------------------------------------------------------------------------- /src/components/ui/slider/Slider.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 26 | -------------------------------------------------------------------------------- /src/components/ui/slider/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Slider } from './Slider.vue' 2 | -------------------------------------------------------------------------------- /src/components/ui/switch/Switch.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 38 | -------------------------------------------------------------------------------- /src/components/ui/switch/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Switch } from './Switch.vue' 2 | -------------------------------------------------------------------------------- /src/components/ui/table/Table.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /src/components/ui/table/TableBody.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/table/TableCaption.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/table/TableCell.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | -------------------------------------------------------------------------------- /src/components/ui/table/TableEmpty.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 34 | -------------------------------------------------------------------------------- /src/components/ui/table/TableFooter.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/table/TableHead.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/table/TableHeader.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/table/TableRow.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/ui/table/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Table } from './Table.vue' 2 | export { default as TableBody } from './TableBody.vue' 3 | export { default as TableCell } from './TableCell.vue' 4 | export { default as TableHead } from './TableHead.vue' 5 | export { default as TableHeader } from './TableHeader.vue' 6 | export { default as TableRow } from './TableRow.vue' 7 | export { default as TableCaption } from './TableCaption.vue' 8 | export { default as TableEmpty } from './TableEmpty.vue' 9 | -------------------------------------------------------------------------------- /src/components/ui/text/Text.vue: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /src/components/ui/text/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Text } from './Text.vue' 2 | -------------------------------------------------------------------------------- /src/components/ui/textarea/Textarea.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 |