├── .gitignore
├── LICENSE
├── README.md
├── components.json
├── eslint.config.js
├── ignore
├── index.html
├── package-lock.json
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── src
├── App.css
├── App.tsx
├── components
│ ├── ui
│ │ ├── accordion.tsx
│ │ ├── alert-dialog.tsx
│ │ ├── alert.tsx
│ │ ├── aspect-ratio.tsx
│ │ ├── avatar.tsx
│ │ ├── badge.tsx
│ │ ├── breadcrumb.tsx
│ │ ├── button.tsx
│ │ ├── calendar.tsx
│ │ ├── card.tsx
│ │ ├── carousel.tsx
│ │ ├── chart.tsx
│ │ ├── checkbox.tsx
│ │ ├── collapsible.tsx
│ │ ├── command.tsx
│ │ ├── context-menu.tsx
│ │ ├── dialog.tsx
│ │ ├── drawer.tsx
│ │ ├── dropdown-menu.tsx
│ │ ├── form.tsx
│ │ ├── hover-card.tsx
│ │ ├── input-otp.tsx
│ │ ├── input.tsx
│ │ ├── label.tsx
│ │ ├── menubar.tsx
│ │ ├── navigation-menu.tsx
│ │ ├── pagination.tsx
│ │ ├── popover.tsx
│ │ ├── progress.tsx
│ │ ├── radio-group.tsx
│ │ ├── resizable.tsx
│ │ ├── scroll-area.tsx
│ │ ├── select.tsx
│ │ ├── separator.tsx
│ │ ├── sheet.tsx
│ │ ├── skeleton.tsx
│ │ ├── slider.tsx
│ │ ├── sonner.tsx
│ │ ├── switch.tsx
│ │ ├── table.tsx
│ │ ├── tabs.tsx
│ │ ├── textarea.tsx
│ │ ├── toast.tsx
│ │ ├── toaster.tsx
│ │ ├── toggle-group.tsx
│ │ ├── toggle.tsx
│ │ └── tooltip.tsx
│ └── voice-call
│ │ ├── StreamPlayer.ts
│ │ ├── VoiceCall.tsx
│ │ ├── VoiceCallService.ts
│ │ ├── audio
│ │ ├── AudioAnalyzer.tsx
│ │ ├── AudioWaveform.tsx
│ │ ├── CallAudioWaveform.tsx
│ │ └── index.ts
│ │ ├── components
│ │ ├── AvatarFrame.tsx
│ │ ├── CallButton.tsx
│ │ ├── CallDialButton.tsx
│ │ ├── ChatTextInput.tsx
│ │ ├── InputModeSwitch.tsx
│ │ ├── RecordingPulseButton.tsx
│ │ ├── VoiceInputWaveform.tsx
│ │ └── index.ts
│ │ ├── index.ts
│ │ ├── speech
│ │ ├── SpeechRecognition.ts
│ │ └── index.ts
│ │ └── utils.ts
├── hooks
│ └── use-toast.ts
├── index.css
├── lib
│ └── utils.ts
├── main.tsx
└── vite-env.d.ts
├── tailwind.config.js
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # StarLover - AI Voice Call Web App
2 |
3 | StarLover is a voice call web app built with React and TypeScript, providing an experience of voice interaction with AI virtual characters. It uses Vite as the build tool and integrates a modern UI component library.
4 |
5 | ## Features
6 |
7 | - 📞 Simulate voice call experience with AI virtual characters
8 | - 🎙️ Voice recognition and text-to-speech functionality
9 | - 💬 Support voice and text dual input modes
10 | - 📱 Responsive design, suitable for different device screens
11 | - 🎨 Beautiful user interface design, including audio waveform animation
12 | - 🔄 Streaming response, real-time display of AI replies
13 |
14 | ## Tech Stack
15 |
16 | - React 18.3
17 | - TypeScript 5.5
18 | - Vite 5.4
19 | - Tailwind CSS
20 | - Framer Motion (animation)
21 | - Radix UI
22 | - Web Speech API (voice recognition)
23 |
24 | ## Quick Start
25 |
26 | ### Prerequisites
27 |
28 | - Node.js 16.x or higher
29 | - npm or yarn package manager
30 |
31 | ### Installation
32 |
33 | 1. Clone the repository
34 |
35 | ```bash
36 | git clone https://github.com/starlover/starlover.git
37 | cd starlover
38 | ```
39 |
40 | 2. Install dependencies
41 |
42 | ```bash
43 | npm install
44 | # or
45 | yarn install
46 | ```
47 |
48 | 3. Start the development server
49 |
50 | ```bash
51 | npm run dev
52 | # or
53 | yarn dev
54 | ```
55 |
56 | The application will run on `http://localhost:5173`.
57 |
58 | ### Build the production version
59 |
60 | ```bash
61 | npm run build
62 | # or
63 | yarn build
64 | ```
65 |
66 | ## Usage Guide
67 |
68 | StarLover application provides a simple and intuitive user interface:
69 |
70 | 1. After entering the application, you will see a call interface, click the answer button to start the call
71 | 2. After the call is connected, you can interact with the AI in the following ways:
72 | - Use voice mode: click the microphone button to start voice input
73 | - Use text mode: switch to text input mode, input text and send
74 | 3. AI will reply to your questions through voice and text
75 |
76 | ## Custom Configuration
77 |
78 | You can customize the application behavior by using the props of the `VoiceCall` component:
79 |
80 | ```jsx
81 |
91 | ```
92 |
93 | ## API Endpoints
94 |
95 | The application uses the following API endpoints by default:
96 |
97 | - Call status: `/api/chat/call-status`
98 | - Chat stream: `/api/chat/stream`
99 |
100 | You can use your own backend service by modifying the `apiUrl` configuration in `App.tsx`.
101 |
102 | ## License
103 |
104 | This project is licensed under the Apache License 2.0. See [LICENSE](LICENSE) for details.
105 |
106 | ## Contribution Guidelines
107 |
108 | Welcome to contribute code, report issues, or suggest improvements. Please follow the steps below:
109 |
110 | 1. Fork the project repository
111 | 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
112 | 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
113 | 4. Push to the branch (`git push origin feature/amazing-feature`)
114 | 5. Submit a Pull Request
115 |
116 | ## Contact
117 |
118 | If you have any questions or suggestions, please contact us through Issues.
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": false,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.js",
8 | "css": "src/index.css",
9 | "baseColor": "neutral",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils",
16 | "ui": "@/components/ui",
17 | "lib": "@/lib",
18 | "hooks": "@/hooks"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js';
2 | import globals from 'globals';
3 | import reactHooks from 'eslint-plugin-react-hooks';
4 | import reactRefresh from 'eslint-plugin-react-refresh';
5 | import tseslint from 'typescript-eslint';
6 |
7 | export default tseslint.config(
8 | { ignores: ['dist'] },
9 | {
10 | extends: [js.configs.recommended, ...tseslint.configs.recommended],
11 | files: ['**/*.{ts,tsx}'],
12 | languageOptions: {
13 | ecmaVersion: 2020,
14 | globals: globals.browser,
15 | },
16 | plugins: {
17 | 'react-hooks': reactHooks,
18 | 'react-refresh': reactRefresh,
19 | },
20 | rules: {
21 | ...reactHooks.configs.recommended.rules,
22 | 'react-refresh/only-export-components': [
23 | 'warn',
24 | { allowConstantExport: true },
25 | ],
26 | },
27 | }
28 | );
29 |
--------------------------------------------------------------------------------
/ignore:
--------------------------------------------------------------------------------
1 | src/components/ui/*
2 | hooks/use-toast.ts
3 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ⚡️ Bolt.new + Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-react-typescript-starter",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc -b && vite build",
9 | "lint": "eslint .",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@hookform/resolvers": "^3.9.0",
14 | "@radix-ui/react-accordion": "^1.2.0",
15 | "@radix-ui/react-alert-dialog": "^1.1.1",
16 | "@radix-ui/react-aspect-ratio": "^1.1.0",
17 | "@radix-ui/react-avatar": "^1.1.0",
18 | "@radix-ui/react-checkbox": "^1.1.1",
19 | "@radix-ui/react-collapsible": "^1.1.0",
20 | "@radix-ui/react-context-menu": "^2.2.1",
21 | "@radix-ui/react-dialog": "^1.1.1",
22 | "@radix-ui/react-dropdown-menu": "^2.1.1",
23 | "@radix-ui/react-hover-card": "^1.1.1",
24 | "@radix-ui/react-icons": "^1.3.0",
25 | "@radix-ui/react-label": "^2.1.0",
26 | "@radix-ui/react-menubar": "^1.1.1",
27 | "@radix-ui/react-navigation-menu": "^1.2.0",
28 | "@radix-ui/react-popover": "^1.1.1",
29 | "@radix-ui/react-progress": "^1.1.0",
30 | "@radix-ui/react-radio-group": "^1.2.0",
31 | "@radix-ui/react-scroll-area": "^1.1.0",
32 | "@radix-ui/react-select": "^2.1.1",
33 | "@radix-ui/react-separator": "^1.1.0",
34 | "@radix-ui/react-slider": "^1.2.0",
35 | "@radix-ui/react-slot": "^1.1.0",
36 | "@radix-ui/react-switch": "^1.1.0",
37 | "@radix-ui/react-tabs": "^1.1.0",
38 | "@radix-ui/react-toast": "^1.2.1",
39 | "@radix-ui/react-toggle": "^1.1.0",
40 | "@radix-ui/react-toggle-group": "^1.1.0",
41 | "@radix-ui/react-tooltip": "^1.1.2",
42 | "class-variance-authority": "^0.7.0",
43 | "clsx": "^2.1.1",
44 | "cmdk": "^1.0.0",
45 | "date-fns": "^3.6.0",
46 | "embla-carousel-react": "^8.3.0",
47 | "framer-motion": "^11.0.8",
48 | "input-otp": "^1.2.4",
49 | "lucide-react": "^0.446.0",
50 | "next-themes": "^0.3.0",
51 | "react": "^18.3.1",
52 | "react-day-picker": "^8.10.1",
53 | "react-dom": "^18.3.1",
54 | "react-hook-form": "^7.53.0",
55 | "react-resizable-panels": "^2.1.3",
56 | "recharts": "^2.12.7",
57 | "sonner": "^1.5.0",
58 | "tailwind-merge": "^2.5.2",
59 | "tailwindcss-animate": "^1.0.7",
60 | "vaul": "^1.0.0",
61 | "zod": "^3.23.8"
62 | },
63 | "devDependencies": {
64 | "@eslint/js": "^9.11.1",
65 | "@types/node": "^22.7.3",
66 | "@types/react": "^18.3.9",
67 | "@types/react-dom": "^18.3.0",
68 | "@vitejs/plugin-react": "^4.3.1",
69 | "autoprefixer": "^10.4.20",
70 | "eslint": "^9.11.1",
71 | "eslint-plugin-react-hooks": "^5.1.0-rc.0",
72 | "eslint-plugin-react-refresh": "^0.4.12",
73 | "globals": "^15.9.0",
74 | "postcss": "^8.4.47",
75 | "tailwindcss": "^3.4.13",
76 | "typescript": "^5.5.3",
77 | "typescript-eslint": "^8.7.0",
78 | "vite": "^5.4.8"
79 | },
80 | "packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b"
81 | }
82 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import VoiceCall from './components/voice-call/VoiceCall';
2 |
3 | function App() {
4 | const apiUrl = {
5 | callStatus: "https://voice.hydramcp.xyz/api/chat/call-status",
6 | chatStream: "https://voice.hydramcp.xyz/api/chat/stream"
7 | }
8 | return (
9 |
10 | );
11 | }
12 |
13 | export default App;
14 |
--------------------------------------------------------------------------------
/src/components/ui/accordion.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as AccordionPrimitive from '@radix-ui/react-accordion';
3 | import { ChevronDownIcon } from '@radix-ui/react-icons';
4 |
5 | import { cn } from '@/lib/utils';
6 |
7 | const Accordion = AccordionPrimitive.Root;
8 |
9 | const AccordionItem = React.forwardRef<
10 | React.ElementRef,
11 | React.ComponentPropsWithoutRef
12 | >(({ className, ...props }, ref) => (
13 |
18 | ));
19 | AccordionItem.displayName = 'AccordionItem';
20 |
21 | const AccordionTrigger = React.forwardRef<
22 | React.ElementRef,
23 | React.ComponentPropsWithoutRef
24 | >(({ className, children, ...props }, ref) => (
25 |
26 | svg]:rotate-180',
30 | className
31 | )}
32 | {...props}
33 | >
34 | {children}
35 |
36 |
37 |
38 | ));
39 | AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
40 |
41 | const AccordionContent = React.forwardRef<
42 | React.ElementRef,
43 | React.ComponentPropsWithoutRef
44 | >(({ className, children, ...props }, ref) => (
45 |
50 | {children}
51 |
52 | ));
53 | AccordionContent.displayName = AccordionPrimitive.Content.displayName;
54 |
55 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
56 |
--------------------------------------------------------------------------------
/src/components/ui/alert-dialog.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
3 |
4 | import { cn } from '@/lib/utils';
5 | import { buttonVariants } from '@/components/ui/button';
6 |
7 | const AlertDialog = AlertDialogPrimitive.Root;
8 |
9 | const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
10 |
11 | const AlertDialogPortal = AlertDialogPrimitive.Portal;
12 |
13 | const AlertDialogOverlay = React.forwardRef<
14 | React.ElementRef,
15 | React.ComponentPropsWithoutRef
16 | >(({ className, ...props }, ref) => (
17 |
25 | ));
26 | AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
27 |
28 | const AlertDialogContent = React.forwardRef<
29 | React.ElementRef,
30 | React.ComponentPropsWithoutRef
31 | >(({ className, ...props }, ref) => (
32 |
33 |
34 |
42 |
43 | ));
44 | AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
45 |
46 | const AlertDialogHeader = ({
47 | className,
48 | ...props
49 | }: React.HTMLAttributes) => (
50 |
57 | );
58 | AlertDialogHeader.displayName = 'AlertDialogHeader';
59 |
60 | const AlertDialogFooter = ({
61 | className,
62 | ...props
63 | }: React.HTMLAttributes) => (
64 |
71 | );
72 | AlertDialogFooter.displayName = 'AlertDialogFooter';
73 |
74 | const AlertDialogTitle = React.forwardRef<
75 | React.ElementRef,
76 | React.ComponentPropsWithoutRef
77 | >(({ className, ...props }, ref) => (
78 |
83 | ));
84 | AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
85 |
86 | const AlertDialogDescription = React.forwardRef<
87 | React.ElementRef,
88 | React.ComponentPropsWithoutRef
89 | >(({ className, ...props }, ref) => (
90 |
95 | ));
96 | AlertDialogDescription.displayName =
97 | AlertDialogPrimitive.Description.displayName;
98 |
99 | const AlertDialogAction = React.forwardRef<
100 | React.ElementRef,
101 | React.ComponentPropsWithoutRef
102 | >(({ className, ...props }, ref) => (
103 |
108 | ));
109 | AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
110 |
111 | const AlertDialogCancel = React.forwardRef<
112 | React.ElementRef,
113 | React.ComponentPropsWithoutRef
114 | >(({ className, ...props }, ref) => (
115 |
124 | ));
125 | AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
126 |
127 | export {
128 | AlertDialog,
129 | AlertDialogPortal,
130 | AlertDialogOverlay,
131 | AlertDialogTrigger,
132 | AlertDialogContent,
133 | AlertDialogHeader,
134 | AlertDialogFooter,
135 | AlertDialogTitle,
136 | AlertDialogDescription,
137 | AlertDialogAction,
138 | AlertDialogCancel,
139 | };
140 |
--------------------------------------------------------------------------------
/src/components/ui/alert.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { cva, type VariantProps } from 'class-variance-authority';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const alertVariants = cva(
7 | 'relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7',
8 | {
9 | variants: {
10 | variant: {
11 | default: 'bg-background text-foreground',
12 | destructive:
13 | 'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
14 | },
15 | },
16 | defaultVariants: {
17 | variant: 'default',
18 | },
19 | }
20 | );
21 |
22 | const Alert = React.forwardRef<
23 | HTMLDivElement,
24 | React.HTMLAttributes & VariantProps
25 | >(({ className, variant, ...props }, ref) => (
26 |
32 | ));
33 | Alert.displayName = 'Alert';
34 |
35 | const AlertTitle = React.forwardRef<
36 | HTMLParagraphElement,
37 | React.HTMLAttributes
38 | >(({ className, ...props }, ref) => (
39 |
44 | ));
45 | AlertTitle.displayName = 'AlertTitle';
46 |
47 | const AlertDescription = React.forwardRef<
48 | HTMLParagraphElement,
49 | React.HTMLAttributes
50 | >(({ className, ...props }, ref) => (
51 |
56 | ));
57 | AlertDescription.displayName = 'AlertDescription';
58 |
59 | export { Alert, AlertTitle, AlertDescription };
60 |
--------------------------------------------------------------------------------
/src/components/ui/aspect-ratio.tsx:
--------------------------------------------------------------------------------
1 | import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio';
2 |
3 | const AspectRatio = AspectRatioPrimitive.Root;
4 |
5 | export { AspectRatio };
6 |
--------------------------------------------------------------------------------
/src/components/ui/avatar.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as AvatarPrimitive from '@radix-ui/react-avatar';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const Avatar = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(({ className, ...props }, ref) => (
10 |
18 | ));
19 | Avatar.displayName = AvatarPrimitive.Root.displayName;
20 |
21 | const AvatarImage = React.forwardRef<
22 | React.ElementRef,
23 | React.ComponentPropsWithoutRef
24 | >(({ className, ...props }, ref) => (
25 |
30 | ));
31 | AvatarImage.displayName = AvatarPrimitive.Image.displayName;
32 |
33 | const AvatarFallback = React.forwardRef<
34 | React.ElementRef,
35 | React.ComponentPropsWithoutRef
36 | >(({ className, ...props }, ref) => (
37 |
45 | ));
46 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
47 |
48 | export { Avatar, AvatarImage, AvatarFallback };
49 |
--------------------------------------------------------------------------------
/src/components/ui/badge.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { cva, type VariantProps } from 'class-variance-authority';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const badgeVariants = cva(
7 | 'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
8 | {
9 | variants: {
10 | variant: {
11 | default:
12 | 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
13 | secondary:
14 | 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
15 | destructive:
16 | 'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
17 | outline: 'text-foreground',
18 | },
19 | },
20 | defaultVariants: {
21 | variant: 'default',
22 | },
23 | }
24 | );
25 |
26 | export interface BadgeProps
27 | extends React.HTMLAttributes,
28 | VariantProps {}
29 |
30 | function Badge({ className, variant, ...props }: BadgeProps) {
31 | return (
32 |
33 | );
34 | }
35 |
36 | export { Badge, badgeVariants };
37 |
--------------------------------------------------------------------------------
/src/components/ui/breadcrumb.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { ChevronRightIcon, DotsHorizontalIcon } from '@radix-ui/react-icons';
3 | import { Slot } from '@radix-ui/react-slot';
4 |
5 | import { cn } from '@/lib/utils';
6 |
7 | const Breadcrumb = React.forwardRef<
8 | HTMLElement,
9 | React.ComponentPropsWithoutRef<'nav'> & {
10 | separator?: React.ReactNode;
11 | }
12 | >(({ ...props }, ref) => );
13 | Breadcrumb.displayName = 'Breadcrumb';
14 |
15 | const BreadcrumbList = React.forwardRef<
16 | HTMLOListElement,
17 | React.ComponentPropsWithoutRef<'ol'>
18 | >(({ className, ...props }, ref) => (
19 |
27 | ));
28 | BreadcrumbList.displayName = 'BreadcrumbList';
29 |
30 | const BreadcrumbItem = React.forwardRef<
31 | HTMLLIElement,
32 | React.ComponentPropsWithoutRef<'li'>
33 | >(({ className, ...props }, ref) => (
34 |
39 | ));
40 | BreadcrumbItem.displayName = 'BreadcrumbItem';
41 |
42 | const BreadcrumbLink = React.forwardRef<
43 | HTMLAnchorElement,
44 | React.ComponentPropsWithoutRef<'a'> & {
45 | asChild?: boolean;
46 | }
47 | >(({ asChild, className, ...props }, ref) => {
48 | const Comp = asChild ? Slot : 'a';
49 |
50 | return (
51 |
56 | );
57 | });
58 | BreadcrumbLink.displayName = 'BreadcrumbLink';
59 |
60 | const BreadcrumbPage = React.forwardRef<
61 | HTMLSpanElement,
62 | React.ComponentPropsWithoutRef<'span'>
63 | >(({ className, ...props }, ref) => (
64 |
72 | ));
73 | BreadcrumbPage.displayName = 'BreadcrumbPage';
74 |
75 | const BreadcrumbSeparator = ({
76 | children,
77 | className,
78 | ...props
79 | }: React.ComponentProps<'li'>) => (
80 | svg]:size-3.5', className)}
84 | {...props}
85 | >
86 | {children ?? }
87 |
88 | );
89 | BreadcrumbSeparator.displayName = 'BreadcrumbSeparator';
90 |
91 | const BreadcrumbEllipsis = ({
92 | className,
93 | ...props
94 | }: React.ComponentProps<'span'>) => (
95 |
101 |
102 | More
103 |
104 | );
105 | BreadcrumbEllipsis.displayName = 'BreadcrumbElipssis';
106 |
107 | export {
108 | Breadcrumb,
109 | BreadcrumbList,
110 | BreadcrumbItem,
111 | BreadcrumbLink,
112 | BreadcrumbPage,
113 | BreadcrumbSeparator,
114 | BreadcrumbEllipsis,
115 | };
116 |
--------------------------------------------------------------------------------
/src/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Slot } from '@radix-ui/react-slot';
3 | import { cva, type VariantProps } from 'class-variance-authority';
4 |
5 | import { cn } from '@/lib/utils';
6 |
7 | const buttonVariants = cva(
8 | 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
9 | {
10 | variants: {
11 | variant: {
12 | default:
13 | 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
14 | destructive:
15 | 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
16 | outline:
17 | 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
18 | secondary:
19 | 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
20 | ghost: 'hover:bg-accent hover:text-accent-foreground',
21 | link: 'text-primary underline-offset-4 hover:underline',
22 | },
23 | size: {
24 | default: 'h-9 px-4 py-2',
25 | sm: 'h-8 rounded-md px-3 text-xs',
26 | lg: 'h-10 rounded-md px-8',
27 | icon: 'h-9 w-9',
28 | },
29 | },
30 | defaultVariants: {
31 | variant: 'default',
32 | size: 'default',
33 | },
34 | }
35 | );
36 |
37 | export interface ButtonProps
38 | extends React.ButtonHTMLAttributes,
39 | VariantProps {
40 | asChild?: boolean;
41 | }
42 |
43 | const Button = React.forwardRef(
44 | ({ className, variant, size, asChild = false, ...props }, ref) => {
45 | const Comp = asChild ? Slot : 'button';
46 | return (
47 |
52 | );
53 | }
54 | );
55 | Button.displayName = 'Button';
56 |
57 | export { Button, buttonVariants };
58 |
--------------------------------------------------------------------------------
/src/components/ui/calendar.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { ChevronLeftIcon, ChevronRightIcon } from '@radix-ui/react-icons';
3 | import { DayPicker } from 'react-day-picker';
4 |
5 | import { cn } from '@/lib/utils';
6 | import { buttonVariants } from '@/components/ui/button';
7 |
8 | export type CalendarProps = React.ComponentProps;
9 |
10 | function Calendar({
11 | className,
12 | classNames,
13 | showOutsideDays = true,
14 | ...props
15 | }: CalendarProps) {
16 | return (
17 | .day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md'
41 | : '[&:has([aria-selected])]:rounded-md'
42 | ),
43 | day: cn(
44 | buttonVariants({ variant: 'ghost' }),
45 | 'h-8 w-8 p-0 font-normal aria-selected:opacity-100'
46 | ),
47 | day_range_start: 'day-range-start',
48 | day_range_end: 'day-range-end',
49 | day_selected:
50 | 'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
51 | day_today: 'bg-accent text-accent-foreground',
52 | day_outside:
53 | 'day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30',
54 | day_disabled: 'text-muted-foreground opacity-50',
55 | day_range_middle:
56 | 'aria-selected:bg-accent aria-selected:text-accent-foreground',
57 | day_hidden: 'invisible',
58 | ...classNames,
59 | }}
60 | components={{
61 | IconLeft: ({ ...props }) => ,
62 | IconRight: ({ ...props }) => ,
63 | }}
64 | {...props}
65 | />
66 | );
67 | }
68 | Calendar.displayName = 'Calendar';
69 |
70 | export { Calendar };
71 |
--------------------------------------------------------------------------------
/src/components/ui/card.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { cn } from '@/lib/utils';
4 |
5 | const Card = React.forwardRef<
6 | HTMLDivElement,
7 | React.HTMLAttributes
8 | >(({ className, ...props }, ref) => (
9 |
17 | ));
18 | Card.displayName = 'Card';
19 |
20 | const CardHeader = React.forwardRef<
21 | HTMLDivElement,
22 | React.HTMLAttributes
23 | >(({ className, ...props }, ref) => (
24 |
29 | ));
30 | CardHeader.displayName = 'CardHeader';
31 |
32 | const CardTitle = React.forwardRef<
33 | HTMLParagraphElement,
34 | React.HTMLAttributes
35 | >(({ className, ...props }, ref) => (
36 |
41 | ));
42 | CardTitle.displayName = 'CardTitle';
43 |
44 | const CardDescription = React.forwardRef<
45 | HTMLParagraphElement,
46 | React.HTMLAttributes
47 | >(({ className, ...props }, ref) => (
48 |
53 | ));
54 | CardDescription.displayName = 'CardDescription';
55 |
56 | const CardContent = React.forwardRef<
57 | HTMLDivElement,
58 | React.HTMLAttributes
59 | >(({ className, ...props }, ref) => (
60 |
61 | ));
62 | CardContent.displayName = 'CardContent';
63 |
64 | const CardFooter = React.forwardRef<
65 | HTMLDivElement,
66 | React.HTMLAttributes
67 | >(({ className, ...props }, ref) => (
68 |
73 | ));
74 | CardFooter.displayName = 'CardFooter';
75 |
76 | export {
77 | Card,
78 | CardHeader,
79 | CardFooter,
80 | CardTitle,
81 | CardDescription,
82 | CardContent,
83 | };
84 |
--------------------------------------------------------------------------------
/src/components/ui/carousel.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { ArrowLeftIcon, ArrowRightIcon } from '@radix-ui/react-icons';
3 | import useEmblaCarousel, {
4 | type UseEmblaCarouselType,
5 | } from 'embla-carousel-react';
6 |
7 | import { cn } from '@/lib/utils';
8 | import { Button } from '@/components/ui/button';
9 |
10 | type CarouselApi = UseEmblaCarouselType[1];
11 | type UseCarouselParameters = Parameters;
12 | type CarouselOptions = UseCarouselParameters[0];
13 | type CarouselPlugin = UseCarouselParameters[1];
14 |
15 | type CarouselProps = {
16 | opts?: CarouselOptions;
17 | plugins?: CarouselPlugin;
18 | orientation?: 'horizontal' | 'vertical';
19 | setApi?: (api: CarouselApi) => void;
20 | };
21 |
22 | type CarouselContextProps = {
23 | carouselRef: ReturnType[0];
24 | api: ReturnType[1];
25 | scrollPrev: () => void;
26 | scrollNext: () => void;
27 | canScrollPrev: boolean;
28 | canScrollNext: boolean;
29 | } & CarouselProps;
30 |
31 | const CarouselContext = React.createContext(null);
32 |
33 | function useCarousel() {
34 | const context = React.useContext(CarouselContext);
35 |
36 | if (!context) {
37 | throw new Error('useCarousel must be used within a ');
38 | }
39 |
40 | return context;
41 | }
42 |
43 | const Carousel = React.forwardRef<
44 | HTMLDivElement,
45 | React.HTMLAttributes & CarouselProps
46 | >(
47 | (
48 | {
49 | orientation = 'horizontal',
50 | opts,
51 | setApi,
52 | plugins,
53 | className,
54 | children,
55 | ...props
56 | },
57 | ref
58 | ) => {
59 | const [carouselRef, api] = useEmblaCarousel(
60 | {
61 | ...opts,
62 | axis: orientation === 'horizontal' ? 'x' : 'y',
63 | },
64 | plugins
65 | );
66 | const [canScrollPrev, setCanScrollPrev] = React.useState(false);
67 | const [canScrollNext, setCanScrollNext] = React.useState(false);
68 |
69 | const onSelect = React.useCallback((api: CarouselApi) => {
70 | if (!api) {
71 | return;
72 | }
73 |
74 | setCanScrollPrev(api.canScrollPrev());
75 | setCanScrollNext(api.canScrollNext());
76 | }, []);
77 |
78 | const scrollPrev = React.useCallback(() => {
79 | api?.scrollPrev();
80 | }, [api]);
81 |
82 | const scrollNext = React.useCallback(() => {
83 | api?.scrollNext();
84 | }, [api]);
85 |
86 | const handleKeyDown = React.useCallback(
87 | (event: React.KeyboardEvent) => {
88 | if (event.key === 'ArrowLeft') {
89 | event.preventDefault();
90 | scrollPrev();
91 | } else if (event.key === 'ArrowRight') {
92 | event.preventDefault();
93 | scrollNext();
94 | }
95 | },
96 | [scrollPrev, scrollNext]
97 | );
98 |
99 | React.useEffect(() => {
100 | if (!api || !setApi) {
101 | return;
102 | }
103 |
104 | setApi(api);
105 | }, [api, setApi]);
106 |
107 | React.useEffect(() => {
108 | if (!api) {
109 | return;
110 | }
111 |
112 | onSelect(api);
113 | api.on('reInit', onSelect);
114 | api.on('select', onSelect);
115 |
116 | return () => {
117 | api?.off('select', onSelect);
118 | };
119 | }, [api, onSelect]);
120 |
121 | return (
122 |
135 |
143 | {children}
144 |
145 |
146 | );
147 | }
148 | );
149 | Carousel.displayName = 'Carousel';
150 |
151 | const CarouselContent = React.forwardRef<
152 | HTMLDivElement,
153 | React.HTMLAttributes
154 | >(({ className, ...props }, ref) => {
155 | const { carouselRef, orientation } = useCarousel();
156 |
157 | return (
158 |
169 | );
170 | });
171 | CarouselContent.displayName = 'CarouselContent';
172 |
173 | const CarouselItem = React.forwardRef<
174 | HTMLDivElement,
175 | React.HTMLAttributes
176 | >(({ className, ...props }, ref) => {
177 | const { orientation } = useCarousel();
178 |
179 | return (
180 |
191 | );
192 | });
193 | CarouselItem.displayName = 'CarouselItem';
194 |
195 | const CarouselPrevious = React.forwardRef<
196 | HTMLButtonElement,
197 | React.ComponentProps
198 | >(({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
199 | const { orientation, scrollPrev, canScrollPrev } = useCarousel();
200 |
201 | return (
202 |
217 |
218 | Previous slide
219 |
220 | );
221 | });
222 | CarouselPrevious.displayName = 'CarouselPrevious';
223 |
224 | const CarouselNext = React.forwardRef<
225 | HTMLButtonElement,
226 | React.ComponentProps
227 | >(({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
228 | const { orientation, scrollNext, canScrollNext } = useCarousel();
229 |
230 | return (
231 |
246 |
247 | Next slide
248 |
249 | );
250 | });
251 | CarouselNext.displayName = 'CarouselNext';
252 |
253 | export {
254 | type CarouselApi,
255 | Carousel,
256 | CarouselContent,
257 | CarouselItem,
258 | CarouselPrevious,
259 | CarouselNext,
260 | };
261 |
--------------------------------------------------------------------------------
/src/components/ui/checkbox.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
3 | import { CheckIcon } from '@radix-ui/react-icons';
4 |
5 | import { cn } from '@/lib/utils';
6 |
7 | const Checkbox = React.forwardRef<
8 | React.ElementRef,
9 | React.ComponentPropsWithoutRef
10 | >(({ className, ...props }, ref) => (
11 |
19 |
22 |
23 |
24 |
25 | ));
26 | Checkbox.displayName = CheckboxPrimitive.Root.displayName;
27 |
28 | export { Checkbox };
29 |
--------------------------------------------------------------------------------
/src/components/ui/collapsible.tsx:
--------------------------------------------------------------------------------
1 | import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
2 |
3 | const Collapsible = CollapsiblePrimitive.Root;
4 |
5 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
6 |
7 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
8 |
9 | export { Collapsible, CollapsibleTrigger, CollapsibleContent };
10 |
--------------------------------------------------------------------------------
/src/components/ui/command.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { type DialogProps } from '@radix-ui/react-dialog';
3 | import { MagnifyingGlassIcon } from '@radix-ui/react-icons';
4 | import { Command as CommandPrimitive } from 'cmdk';
5 |
6 | import { cn } from '@/lib/utils';
7 | import { Dialog, DialogContent } from '@/components/ui/dialog';
8 |
9 | const Command = React.forwardRef<
10 | React.ElementRef,
11 | React.ComponentPropsWithoutRef
12 | >(({ className, ...props }, ref) => (
13 |
21 | ));
22 | Command.displayName = CommandPrimitive.displayName;
23 |
24 | interface CommandDialogProps extends DialogProps {}
25 |
26 | const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
27 | return (
28 |
29 |
30 |
31 | {children}
32 |
33 |
34 |
35 | );
36 | };
37 |
38 | const CommandInput = React.forwardRef<
39 | React.ElementRef,
40 | React.ComponentPropsWithoutRef
41 | >(({ className, ...props }, ref) => (
42 |
43 |
44 |
52 |
53 | ));
54 |
55 | CommandInput.displayName = CommandPrimitive.Input.displayName;
56 |
57 | const CommandList = React.forwardRef<
58 | React.ElementRef,
59 | React.ComponentPropsWithoutRef
60 | >(({ className, ...props }, ref) => (
61 |
66 | ));
67 |
68 | CommandList.displayName = CommandPrimitive.List.displayName;
69 |
70 | const CommandEmpty = React.forwardRef<
71 | React.ElementRef,
72 | React.ComponentPropsWithoutRef
73 | >((props, ref) => (
74 |
79 | ));
80 |
81 | CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
82 |
83 | const CommandGroup = React.forwardRef<
84 | React.ElementRef,
85 | React.ComponentPropsWithoutRef
86 | >(({ className, ...props }, ref) => (
87 |
95 | ));
96 |
97 | CommandGroup.displayName = CommandPrimitive.Group.displayName;
98 |
99 | const CommandSeparator = React.forwardRef<
100 | React.ElementRef,
101 | React.ComponentPropsWithoutRef
102 | >(({ className, ...props }, ref) => (
103 |
108 | ));
109 | CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
110 |
111 | const CommandItem = React.forwardRef<
112 | React.ElementRef,
113 | React.ComponentPropsWithoutRef
114 | >(({ className, ...props }, ref) => (
115 |
123 | ));
124 |
125 | CommandItem.displayName = CommandPrimitive.Item.displayName;
126 |
127 | const CommandShortcut = ({
128 | className,
129 | ...props
130 | }: React.HTMLAttributes) => {
131 | return (
132 |
139 | );
140 | };
141 | CommandShortcut.displayName = 'CommandShortcut';
142 |
143 | export {
144 | Command,
145 | CommandDialog,
146 | CommandInput,
147 | CommandList,
148 | CommandEmpty,
149 | CommandGroup,
150 | CommandItem,
151 | CommandShortcut,
152 | CommandSeparator,
153 | };
154 |
--------------------------------------------------------------------------------
/src/components/ui/context-menu.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ContextMenuPrimitive from '@radix-ui/react-context-menu';
3 | import {
4 | CheckIcon,
5 | ChevronRightIcon,
6 | DotFilledIcon,
7 | } from '@radix-ui/react-icons';
8 |
9 | import { cn } from '@/lib/utils';
10 |
11 | const ContextMenu = ContextMenuPrimitive.Root;
12 |
13 | const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
14 |
15 | const ContextMenuGroup = ContextMenuPrimitive.Group;
16 |
17 | const ContextMenuPortal = ContextMenuPrimitive.Portal;
18 |
19 | const ContextMenuSub = ContextMenuPrimitive.Sub;
20 |
21 | const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
22 |
23 | const ContextMenuSubTrigger = React.forwardRef<
24 | React.ElementRef,
25 | React.ComponentPropsWithoutRef & {
26 | inset?: boolean;
27 | }
28 | >(({ className, inset, children, ...props }, ref) => (
29 |
38 | {children}
39 |
40 |
41 | ));
42 | ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
43 |
44 | const ContextMenuSubContent = React.forwardRef<
45 | React.ElementRef,
46 | React.ComponentPropsWithoutRef
47 | >(({ className, ...props }, ref) => (
48 |
56 | ));
57 | ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
58 |
59 | const ContextMenuContent = React.forwardRef<
60 | React.ElementRef,
61 | React.ComponentPropsWithoutRef
62 | >(({ className, ...props }, ref) => (
63 |
64 |
72 |
73 | ));
74 | ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
75 |
76 | const ContextMenuItem = React.forwardRef<
77 | React.ElementRef,
78 | React.ComponentPropsWithoutRef & {
79 | inset?: boolean;
80 | }
81 | >(({ className, inset, ...props }, ref) => (
82 |
91 | ));
92 | ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
93 |
94 | const ContextMenuCheckboxItem = React.forwardRef<
95 | React.ElementRef,
96 | React.ComponentPropsWithoutRef
97 | >(({ className, children, checked, ...props }, ref) => (
98 |
107 |
108 |
109 |
110 |
111 |
112 | {children}
113 |
114 | ));
115 | ContextMenuCheckboxItem.displayName =
116 | ContextMenuPrimitive.CheckboxItem.displayName;
117 |
118 | const ContextMenuRadioItem = React.forwardRef<
119 | React.ElementRef,
120 | React.ComponentPropsWithoutRef
121 | >(({ className, children, ...props }, ref) => (
122 |
130 |
131 |
132 |
133 |
134 |
135 | {children}
136 |
137 | ));
138 | ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
139 |
140 | const ContextMenuLabel = React.forwardRef<
141 | React.ElementRef,
142 | React.ComponentPropsWithoutRef & {
143 | inset?: boolean;
144 | }
145 | >(({ className, inset, ...props }, ref) => (
146 |
155 | ));
156 | ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
157 |
158 | const ContextMenuSeparator = React.forwardRef<
159 | React.ElementRef,
160 | React.ComponentPropsWithoutRef
161 | >(({ className, ...props }, ref) => (
162 |
167 | ));
168 | ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
169 |
170 | const ContextMenuShortcut = ({
171 | className,
172 | ...props
173 | }: React.HTMLAttributes) => {
174 | return (
175 |
182 | );
183 | };
184 | ContextMenuShortcut.displayName = 'ContextMenuShortcut';
185 |
186 | export {
187 | ContextMenu,
188 | ContextMenuTrigger,
189 | ContextMenuContent,
190 | ContextMenuItem,
191 | ContextMenuCheckboxItem,
192 | ContextMenuRadioItem,
193 | ContextMenuLabel,
194 | ContextMenuSeparator,
195 | ContextMenuShortcut,
196 | ContextMenuGroup,
197 | ContextMenuPortal,
198 | ContextMenuSub,
199 | ContextMenuSubContent,
200 | ContextMenuSubTrigger,
201 | ContextMenuRadioGroup,
202 | };
203 |
--------------------------------------------------------------------------------
/src/components/ui/dialog.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as DialogPrimitive from '@radix-ui/react-dialog';
3 | import { Cross2Icon } from '@radix-ui/react-icons';
4 |
5 | import { cn } from '@/lib/utils';
6 |
7 | const Dialog = DialogPrimitive.Root;
8 |
9 | const DialogTrigger = DialogPrimitive.Trigger;
10 |
11 | const DialogPortal = DialogPrimitive.Portal;
12 |
13 | const DialogClose = DialogPrimitive.Close;
14 |
15 | const DialogOverlay = React.forwardRef<
16 | React.ElementRef,
17 | React.ComponentPropsWithoutRef
18 | >(({ className, ...props }, ref) => (
19 |
27 | ));
28 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
29 |
30 | const DialogContent = React.forwardRef<
31 | React.ElementRef,
32 | React.ComponentPropsWithoutRef
33 | >(({ className, children, ...props }, ref) => (
34 |
35 |
36 |
44 | {children}
45 |
46 |
47 | Close
48 |
49 |
50 |
51 | ));
52 | DialogContent.displayName = DialogPrimitive.Content.displayName;
53 |
54 | const DialogHeader = ({
55 | className,
56 | ...props
57 | }: React.HTMLAttributes) => (
58 |
65 | );
66 | DialogHeader.displayName = 'DialogHeader';
67 |
68 | const DialogFooter = ({
69 | className,
70 | ...props
71 | }: React.HTMLAttributes) => (
72 |
79 | );
80 | DialogFooter.displayName = 'DialogFooter';
81 |
82 | const DialogTitle = React.forwardRef<
83 | React.ElementRef,
84 | React.ComponentPropsWithoutRef
85 | >(({ className, ...props }, ref) => (
86 |
94 | ));
95 | DialogTitle.displayName = DialogPrimitive.Title.displayName;
96 |
97 | const DialogDescription = React.forwardRef<
98 | React.ElementRef,
99 | React.ComponentPropsWithoutRef
100 | >(({ className, ...props }, ref) => (
101 |
106 | ));
107 | DialogDescription.displayName = DialogPrimitive.Description.displayName;
108 |
109 | export {
110 | Dialog,
111 | DialogPortal,
112 | DialogOverlay,
113 | DialogTrigger,
114 | DialogClose,
115 | DialogContent,
116 | DialogHeader,
117 | DialogFooter,
118 | DialogTitle,
119 | DialogDescription,
120 | };
121 |
--------------------------------------------------------------------------------
/src/components/ui/drawer.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Drawer as DrawerPrimitive } from 'vaul';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const Drawer = ({
7 | shouldScaleBackground = true,
8 | ...props
9 | }: React.ComponentProps) => (
10 |
14 | );
15 | Drawer.displayName = 'Drawer';
16 |
17 | const DrawerTrigger = DrawerPrimitive.Trigger;
18 |
19 | const DrawerPortal = DrawerPrimitive.Portal;
20 |
21 | const DrawerClose = DrawerPrimitive.Close;
22 |
23 | const DrawerOverlay = React.forwardRef<
24 | React.ElementRef,
25 | React.ComponentPropsWithoutRef
26 | >(({ className, ...props }, ref) => (
27 |
32 | ));
33 | DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
34 |
35 | const DrawerContent = React.forwardRef<
36 | React.ElementRef,
37 | React.ComponentPropsWithoutRef
38 | >(({ className, children, ...props }, ref) => (
39 |
40 |
41 |
49 |
50 | {children}
51 |
52 |
53 | ));
54 | DrawerContent.displayName = 'DrawerContent';
55 |
56 | const DrawerHeader = ({
57 | className,
58 | ...props
59 | }: React.HTMLAttributes) => (
60 |
64 | );
65 | DrawerHeader.displayName = 'DrawerHeader';
66 |
67 | const DrawerFooter = ({
68 | className,
69 | ...props
70 | }: React.HTMLAttributes) => (
71 |
75 | );
76 | DrawerFooter.displayName = 'DrawerFooter';
77 |
78 | const DrawerTitle = React.forwardRef<
79 | React.ElementRef,
80 | React.ComponentPropsWithoutRef
81 | >(({ className, ...props }, ref) => (
82 |
90 | ));
91 | DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
92 |
93 | const DrawerDescription = React.forwardRef<
94 | React.ElementRef,
95 | React.ComponentPropsWithoutRef
96 | >(({ className, ...props }, ref) => (
97 |
102 | ));
103 | DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
104 |
105 | export {
106 | Drawer,
107 | DrawerPortal,
108 | DrawerOverlay,
109 | DrawerTrigger,
110 | DrawerClose,
111 | DrawerContent,
112 | DrawerHeader,
113 | DrawerFooter,
114 | DrawerTitle,
115 | DrawerDescription,
116 | };
117 |
--------------------------------------------------------------------------------
/src/components/ui/dropdown-menu.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
3 | import {
4 | CheckIcon,
5 | ChevronRightIcon,
6 | DotFilledIcon,
7 | } from '@radix-ui/react-icons';
8 |
9 | import { cn } from '@/lib/utils';
10 |
11 | const DropdownMenu = DropdownMenuPrimitive.Root;
12 |
13 | const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
14 |
15 | const DropdownMenuGroup = DropdownMenuPrimitive.Group;
16 |
17 | const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
18 |
19 | const DropdownMenuSub = DropdownMenuPrimitive.Sub;
20 |
21 | const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
22 |
23 | const DropdownMenuSubTrigger = React.forwardRef<
24 | React.ElementRef,
25 | React.ComponentPropsWithoutRef & {
26 | inset?: boolean;
27 | }
28 | >(({ className, inset, children, ...props }, ref) => (
29 |
38 | {children}
39 |
40 |
41 | ));
42 | DropdownMenuSubTrigger.displayName =
43 | DropdownMenuPrimitive.SubTrigger.displayName;
44 |
45 | const DropdownMenuSubContent = React.forwardRef<
46 | React.ElementRef,
47 | React.ComponentPropsWithoutRef
48 | >(({ className, ...props }, ref) => (
49 |
57 | ));
58 | DropdownMenuSubContent.displayName =
59 | DropdownMenuPrimitive.SubContent.displayName;
60 |
61 | const DropdownMenuContent = React.forwardRef<
62 | React.ElementRef,
63 | React.ComponentPropsWithoutRef
64 | >(({ className, sideOffset = 4, ...props }, ref) => (
65 |
66 |
76 |
77 | ));
78 | DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
79 |
80 | const DropdownMenuItem = React.forwardRef<
81 | React.ElementRef,
82 | React.ComponentPropsWithoutRef & {
83 | inset?: boolean;
84 | }
85 | >(({ className, inset, ...props }, ref) => (
86 |
95 | ));
96 | DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
97 |
98 | const DropdownMenuCheckboxItem = React.forwardRef<
99 | React.ElementRef,
100 | React.ComponentPropsWithoutRef
101 | >(({ className, children, checked, ...props }, ref) => (
102 |
111 |
112 |
113 |
114 |
115 |
116 | {children}
117 |
118 | ));
119 | DropdownMenuCheckboxItem.displayName =
120 | DropdownMenuPrimitive.CheckboxItem.displayName;
121 |
122 | const DropdownMenuRadioItem = React.forwardRef<
123 | React.ElementRef,
124 | React.ComponentPropsWithoutRef
125 | >(({ className, children, ...props }, ref) => (
126 |
134 |
135 |
136 |
137 |
138 |
139 | {children}
140 |
141 | ));
142 | DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
143 |
144 | const DropdownMenuLabel = React.forwardRef<
145 | React.ElementRef,
146 | React.ComponentPropsWithoutRef & {
147 | inset?: boolean;
148 | }
149 | >(({ className, inset, ...props }, ref) => (
150 |
159 | ));
160 | DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
161 |
162 | const DropdownMenuSeparator = React.forwardRef<
163 | React.ElementRef,
164 | React.ComponentPropsWithoutRef
165 | >(({ className, ...props }, ref) => (
166 |
171 | ));
172 | DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
173 |
174 | const DropdownMenuShortcut = ({
175 | className,
176 | ...props
177 | }: React.HTMLAttributes) => {
178 | return (
179 |
183 | );
184 | };
185 | DropdownMenuShortcut.displayName = 'DropdownMenuShortcut';
186 |
187 | export {
188 | DropdownMenu,
189 | DropdownMenuTrigger,
190 | DropdownMenuContent,
191 | DropdownMenuItem,
192 | DropdownMenuCheckboxItem,
193 | DropdownMenuRadioItem,
194 | DropdownMenuLabel,
195 | DropdownMenuSeparator,
196 | DropdownMenuShortcut,
197 | DropdownMenuGroup,
198 | DropdownMenuPortal,
199 | DropdownMenuSub,
200 | DropdownMenuSubContent,
201 | DropdownMenuSubTrigger,
202 | DropdownMenuRadioGroup,
203 | };
204 |
--------------------------------------------------------------------------------
/src/components/ui/form.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as LabelPrimitive from '@radix-ui/react-label';
3 | import { Slot } from '@radix-ui/react-slot';
4 | import {
5 | Controller,
6 | ControllerProps,
7 | FieldPath,
8 | FieldValues,
9 | FormProvider,
10 | useFormContext,
11 | } from 'react-hook-form';
12 |
13 | import { cn } from '@/lib/utils';
14 | import { Label } from '@/components/ui/label';
15 |
16 | const Form = FormProvider;
17 |
18 | type FormFieldContextValue<
19 | TFieldValues extends FieldValues = FieldValues,
20 | TName extends FieldPath = FieldPath
21 | > = {
22 | name: TName;
23 | };
24 |
25 | const FormFieldContext = React.createContext(
26 | {} as FormFieldContextValue
27 | );
28 |
29 | const FormField = <
30 | TFieldValues extends FieldValues = FieldValues,
31 | TName extends FieldPath = FieldPath
32 | >({
33 | ...props
34 | }: ControllerProps) => {
35 | return (
36 |
37 |
38 |
39 | );
40 | };
41 |
42 | const useFormField = () => {
43 | const fieldContext = React.useContext(FormFieldContext);
44 | const itemContext = React.useContext(FormItemContext);
45 | const { getFieldState, formState } = useFormContext();
46 |
47 | const fieldState = getFieldState(fieldContext.name, formState);
48 |
49 | if (!fieldContext) {
50 | throw new Error('useFormField should be used within ');
51 | }
52 |
53 | const { id } = itemContext;
54 |
55 | return {
56 | id,
57 | name: fieldContext.name,
58 | formItemId: `${id}-form-item`,
59 | formDescriptionId: `${id}-form-item-description`,
60 | formMessageId: `${id}-form-item-message`,
61 | ...fieldState,
62 | };
63 | };
64 |
65 | type FormItemContextValue = {
66 | id: string;
67 | };
68 |
69 | const FormItemContext = React.createContext(
70 | {} as FormItemContextValue
71 | );
72 |
73 | const FormItem = React.forwardRef<
74 | HTMLDivElement,
75 | React.HTMLAttributes
76 | >(({ className, ...props }, ref) => {
77 | const id = React.useId();
78 |
79 | return (
80 |
81 |
82 |
83 | );
84 | });
85 | FormItem.displayName = 'FormItem';
86 |
87 | const FormLabel = React.forwardRef<
88 | React.ElementRef,
89 | React.ComponentPropsWithoutRef
90 | >(({ className, ...props }, ref) => {
91 | const { error, formItemId } = useFormField();
92 |
93 | return (
94 |
100 | );
101 | });
102 | FormLabel.displayName = 'FormLabel';
103 |
104 | const FormControl = React.forwardRef<
105 | React.ElementRef,
106 | React.ComponentPropsWithoutRef
107 | >(({ ...props }, ref) => {
108 | const { error, formItemId, formDescriptionId, formMessageId } =
109 | useFormField();
110 |
111 | return (
112 |
123 | );
124 | });
125 | FormControl.displayName = 'FormControl';
126 |
127 | const FormDescription = React.forwardRef<
128 | HTMLParagraphElement,
129 | React.HTMLAttributes
130 | >(({ className, ...props }, ref) => {
131 | const { formDescriptionId } = useFormField();
132 |
133 | return (
134 |
140 | );
141 | });
142 | FormDescription.displayName = 'FormDescription';
143 |
144 | const FormMessage = React.forwardRef<
145 | HTMLParagraphElement,
146 | React.HTMLAttributes
147 | >(({ className, children, ...props }, ref) => {
148 | const { error, formMessageId } = useFormField();
149 | const body = error ? String(error?.message) : children;
150 |
151 | if (!body) {
152 | return null;
153 | }
154 |
155 | return (
156 |
162 | {body}
163 |
164 | );
165 | });
166 | FormMessage.displayName = 'FormMessage';
167 |
168 | export {
169 | useFormField,
170 | Form,
171 | FormItem,
172 | FormLabel,
173 | FormControl,
174 | FormDescription,
175 | FormMessage,
176 | FormField,
177 | };
178 |
--------------------------------------------------------------------------------
/src/components/ui/hover-card.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const HoverCard = HoverCardPrimitive.Root;
7 |
8 | const HoverCardTrigger = HoverCardPrimitive.Trigger;
9 |
10 | const HoverCardContent = React.forwardRef<
11 | React.ElementRef,
12 | React.ComponentPropsWithoutRef
13 | >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
14 |
24 | ));
25 | HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
26 |
27 | export { HoverCard, HoverCardTrigger, HoverCardContent };
28 |
--------------------------------------------------------------------------------
/src/components/ui/input-otp.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { DashIcon } from '@radix-ui/react-icons';
3 | import { OTPInput, OTPInputContext } from 'input-otp';
4 |
5 | import { cn } from '@/lib/utils';
6 |
7 | const InputOTP = React.forwardRef<
8 | React.ElementRef,
9 | React.ComponentPropsWithoutRef
10 | >(({ className, containerClassName, ...props }, ref) => (
11 |
20 | ));
21 | InputOTP.displayName = 'InputOTP';
22 |
23 | const InputOTPGroup = React.forwardRef<
24 | React.ElementRef<'div'>,
25 | React.ComponentPropsWithoutRef<'div'>
26 | >(({ className, ...props }, ref) => (
27 |
28 | ));
29 | InputOTPGroup.displayName = 'InputOTPGroup';
30 |
31 | const InputOTPSlot = React.forwardRef<
32 | React.ElementRef<'div'>,
33 | React.ComponentPropsWithoutRef<'div'> & { index: number }
34 | >(({ index, className, ...props }, ref) => {
35 | const inputOTPContext = React.useContext(OTPInputContext);
36 | const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
37 |
38 | return (
39 |
48 | {char}
49 | {hasFakeCaret && (
50 |
53 | )}
54 |
55 | );
56 | });
57 | InputOTPSlot.displayName = 'InputOTPSlot';
58 |
59 | const InputOTPSeparator = React.forwardRef<
60 | React.ElementRef<'div'>,
61 | React.ComponentPropsWithoutRef<'div'>
62 | >(({ ...props }, ref) => (
63 |
64 |
65 |
66 | ));
67 | InputOTPSeparator.displayName = 'InputOTPSeparator';
68 |
69 | export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
70 |
--------------------------------------------------------------------------------
/src/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { cn } from '@/lib/utils';
4 |
5 | export interface InputProps
6 | extends React.InputHTMLAttributes {}
7 |
8 | const Input = React.forwardRef(
9 | ({ className, type, ...props }, ref) => {
10 | return (
11 |
20 | );
21 | }
22 | );
23 | Input.displayName = 'Input';
24 |
25 | export { Input };
26 |
--------------------------------------------------------------------------------
/src/components/ui/label.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as LabelPrimitive from '@radix-ui/react-label';
3 | import { cva, type VariantProps } from 'class-variance-authority';
4 |
5 | import { cn } from '@/lib/utils';
6 |
7 | const labelVariants = cva(
8 | 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
9 | );
10 |
11 | const Label = React.forwardRef<
12 | React.ElementRef,
13 | React.ComponentPropsWithoutRef &
14 | VariantProps
15 | >(({ className, ...props }, ref) => (
16 |
21 | ));
22 | Label.displayName = LabelPrimitive.Root.displayName;
23 |
24 | export { Label };
25 |
--------------------------------------------------------------------------------
/src/components/ui/menubar.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {
3 | CheckIcon,
4 | ChevronRightIcon,
5 | DotFilledIcon,
6 | } from '@radix-ui/react-icons';
7 | import * as MenubarPrimitive from '@radix-ui/react-menubar';
8 |
9 | import { cn } from '@/lib/utils';
10 |
11 | const MenubarMenu = MenubarPrimitive.Menu;
12 |
13 | const MenubarGroup = MenubarPrimitive.Group;
14 |
15 | const MenubarPortal = MenubarPrimitive.Portal;
16 |
17 | const MenubarSub = MenubarPrimitive.Sub;
18 |
19 | const MenubarRadioGroup = MenubarPrimitive.RadioGroup;
20 |
21 | const Menubar = React.forwardRef<
22 | React.ElementRef,
23 | React.ComponentPropsWithoutRef
24 | >(({ className, ...props }, ref) => (
25 |
33 | ));
34 | Menubar.displayName = MenubarPrimitive.Root.displayName;
35 |
36 | const MenubarTrigger = React.forwardRef<
37 | React.ElementRef,
38 | React.ComponentPropsWithoutRef
39 | >(({ className, ...props }, ref) => (
40 |
48 | ));
49 | MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName;
50 |
51 | const MenubarSubTrigger = React.forwardRef<
52 | React.ElementRef,
53 | React.ComponentPropsWithoutRef & {
54 | inset?: boolean;
55 | }
56 | >(({ className, inset, children, ...props }, ref) => (
57 |
66 | {children}
67 |
68 |
69 | ));
70 | MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName;
71 |
72 | const MenubarSubContent = React.forwardRef<
73 | React.ElementRef,
74 | React.ComponentPropsWithoutRef
75 | >(({ className, ...props }, ref) => (
76 |
84 | ));
85 | MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;
86 |
87 | const MenubarContent = React.forwardRef<
88 | React.ElementRef,
89 | React.ComponentPropsWithoutRef
90 | >(
91 | (
92 | { className, align = 'start', alignOffset = -4, sideOffset = 8, ...props },
93 | ref
94 | ) => (
95 |
96 |
107 |
108 | )
109 | );
110 | MenubarContent.displayName = MenubarPrimitive.Content.displayName;
111 |
112 | const MenubarItem = React.forwardRef<
113 | React.ElementRef,
114 | React.ComponentPropsWithoutRef & {
115 | inset?: boolean;
116 | }
117 | >(({ className, inset, ...props }, ref) => (
118 |
127 | ));
128 | MenubarItem.displayName = MenubarPrimitive.Item.displayName;
129 |
130 | const MenubarCheckboxItem = React.forwardRef<
131 | React.ElementRef,
132 | React.ComponentPropsWithoutRef
133 | >(({ className, children, checked, ...props }, ref) => (
134 |
143 |
144 |
145 |
146 |
147 |
148 | {children}
149 |
150 | ));
151 | MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName;
152 |
153 | const MenubarRadioItem = React.forwardRef<
154 | React.ElementRef,
155 | React.ComponentPropsWithoutRef
156 | >(({ className, children, ...props }, ref) => (
157 |
165 |
166 |
167 |
168 |
169 |
170 | {children}
171 |
172 | ));
173 | MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName;
174 |
175 | const MenubarLabel = React.forwardRef<
176 | React.ElementRef,
177 | React.ComponentPropsWithoutRef & {
178 | inset?: boolean;
179 | }
180 | >(({ className, inset, ...props }, ref) => (
181 |
190 | ));
191 | MenubarLabel.displayName = MenubarPrimitive.Label.displayName;
192 |
193 | const MenubarSeparator = React.forwardRef<
194 | React.ElementRef,
195 | React.ComponentPropsWithoutRef
196 | >(({ className, ...props }, ref) => (
197 |
202 | ));
203 | MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName;
204 |
205 | const MenubarShortcut = ({
206 | className,
207 | ...props
208 | }: React.HTMLAttributes) => {
209 | return (
210 |
217 | );
218 | };
219 | MenubarShortcut.displayname = 'MenubarShortcut';
220 |
221 | export {
222 | Menubar,
223 | MenubarMenu,
224 | MenubarTrigger,
225 | MenubarContent,
226 | MenubarItem,
227 | MenubarSeparator,
228 | MenubarLabel,
229 | MenubarCheckboxItem,
230 | MenubarRadioGroup,
231 | MenubarRadioItem,
232 | MenubarPortal,
233 | MenubarSubContent,
234 | MenubarSubTrigger,
235 | MenubarGroup,
236 | MenubarSub,
237 | MenubarShortcut,
238 | };
239 |
--------------------------------------------------------------------------------
/src/components/ui/navigation-menu.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { ChevronDownIcon } from '@radix-ui/react-icons';
3 | import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu';
4 | import { cva } from 'class-variance-authority';
5 |
6 | import { cn } from '@/lib/utils';
7 |
8 | const NavigationMenu = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, children, ...props }, ref) => (
12 |
20 | {children}
21 |
22 |
23 | ));
24 | NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
25 |
26 | const NavigationMenuList = React.forwardRef<
27 | React.ElementRef,
28 | React.ComponentPropsWithoutRef
29 | >(({ className, ...props }, ref) => (
30 |
38 | ));
39 | NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
40 |
41 | const NavigationMenuItem = NavigationMenuPrimitive.Item;
42 |
43 | const navigationMenuTriggerStyle = cva(
44 | 'group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50'
45 | );
46 |
47 | const NavigationMenuTrigger = React.forwardRef<
48 | React.ElementRef,
49 | React.ComponentPropsWithoutRef
50 | >(({ className, children, ...props }, ref) => (
51 |
56 | {children}{' '}
57 |
61 |
62 | ));
63 | NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
64 |
65 | const NavigationMenuContent = React.forwardRef<
66 | React.ElementRef,
67 | React.ComponentPropsWithoutRef
68 | >(({ className, ...props }, ref) => (
69 |
77 | ));
78 | NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
79 |
80 | const NavigationMenuLink = NavigationMenuPrimitive.Link;
81 |
82 | const NavigationMenuViewport = React.forwardRef<
83 | React.ElementRef,
84 | React.ComponentPropsWithoutRef
85 | >(({ className, ...props }, ref) => (
86 |
87 |
95 |
96 | ));
97 | NavigationMenuViewport.displayName =
98 | NavigationMenuPrimitive.Viewport.displayName;
99 |
100 | const NavigationMenuIndicator = React.forwardRef<
101 | React.ElementRef,
102 | React.ComponentPropsWithoutRef
103 | >(({ className, ...props }, ref) => (
104 |
112 |
113 |
114 | ));
115 | NavigationMenuIndicator.displayName =
116 | NavigationMenuPrimitive.Indicator.displayName;
117 |
118 | export {
119 | navigationMenuTriggerStyle,
120 | NavigationMenu,
121 | NavigationMenuList,
122 | NavigationMenuItem,
123 | NavigationMenuContent,
124 | NavigationMenuTrigger,
125 | NavigationMenuLink,
126 | NavigationMenuIndicator,
127 | NavigationMenuViewport,
128 | };
129 |
--------------------------------------------------------------------------------
/src/components/ui/pagination.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {
3 | ChevronLeftIcon,
4 | ChevronRightIcon,
5 | DotsHorizontalIcon,
6 | } from '@radix-ui/react-icons';
7 |
8 | import { cn } from '@/lib/utils';
9 | import { ButtonProps, buttonVariants } from '@/components/ui/button';
10 |
11 | const Pagination = ({ className, ...props }: React.ComponentProps<'nav'>) => (
12 |
18 | );
19 | Pagination.displayName = 'Pagination';
20 |
21 | const PaginationContent = React.forwardRef<
22 | HTMLUListElement,
23 | React.ComponentProps<'ul'>
24 | >(({ className, ...props }, ref) => (
25 |
30 | ));
31 | PaginationContent.displayName = 'PaginationContent';
32 |
33 | const PaginationItem = React.forwardRef<
34 | HTMLLIElement,
35 | React.ComponentProps<'li'>
36 | >(({ className, ...props }, ref) => (
37 |
38 | ));
39 | PaginationItem.displayName = 'PaginationItem';
40 |
41 | type PaginationLinkProps = {
42 | isActive?: boolean;
43 | } & Pick &
44 | React.ComponentProps<'a'>;
45 |
46 | const PaginationLink = ({
47 | className,
48 | isActive,
49 | size = 'icon',
50 | ...props
51 | }: PaginationLinkProps) => (
52 |
63 | );
64 | PaginationLink.displayName = 'PaginationLink';
65 |
66 | const PaginationPrevious = ({
67 | className,
68 | ...props
69 | }: React.ComponentProps) => (
70 |
76 |
77 | Previous
78 |
79 | );
80 | PaginationPrevious.displayName = 'PaginationPrevious';
81 |
82 | const PaginationNext = ({
83 | className,
84 | ...props
85 | }: React.ComponentProps) => (
86 |
92 | Next
93 |
94 |
95 | );
96 | PaginationNext.displayName = 'PaginationNext';
97 |
98 | const PaginationEllipsis = ({
99 | className,
100 | ...props
101 | }: React.ComponentProps<'span'>) => (
102 |
107 |
108 | More pages
109 |
110 | );
111 | PaginationEllipsis.displayName = 'PaginationEllipsis';
112 |
113 | export {
114 | Pagination,
115 | PaginationContent,
116 | PaginationLink,
117 | PaginationItem,
118 | PaginationPrevious,
119 | PaginationNext,
120 | PaginationEllipsis,
121 | };
122 |
--------------------------------------------------------------------------------
/src/components/ui/popover.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as PopoverPrimitive from '@radix-ui/react-popover';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const Popover = PopoverPrimitive.Root;
7 |
8 | const PopoverTrigger = PopoverPrimitive.Trigger;
9 |
10 | const PopoverAnchor = PopoverPrimitive.Anchor;
11 |
12 | const PopoverContent = React.forwardRef<
13 | React.ElementRef,
14 | React.ComponentPropsWithoutRef
15 | >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
16 |
17 |
27 |
28 | ));
29 | PopoverContent.displayName = PopoverPrimitive.Content.displayName;
30 |
31 | export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
32 |
--------------------------------------------------------------------------------
/src/components/ui/progress.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ProgressPrimitive from '@radix-ui/react-progress';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const Progress = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(({ className, value, ...props }, ref) => (
10 |
18 |
22 |
23 | ));
24 | Progress.displayName = ProgressPrimitive.Root.displayName;
25 |
26 | export { Progress };
27 |
--------------------------------------------------------------------------------
/src/components/ui/radio-group.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { CheckIcon } from '@radix-ui/react-icons';
3 | import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
4 |
5 | import { cn } from '@/lib/utils';
6 |
7 | const RadioGroup = React.forwardRef<
8 | React.ElementRef,
9 | React.ComponentPropsWithoutRef
10 | >(({ className, ...props }, ref) => {
11 | return (
12 |
17 | );
18 | });
19 | RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
20 |
21 | const RadioGroupItem = React.forwardRef<
22 | React.ElementRef,
23 | React.ComponentPropsWithoutRef
24 | >(({ className, ...props }, ref) => {
25 | return (
26 |
34 |
35 |
36 |
37 |
38 | );
39 | });
40 | RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
41 |
42 | export { RadioGroup, RadioGroupItem };
43 |
--------------------------------------------------------------------------------
/src/components/ui/resizable.tsx:
--------------------------------------------------------------------------------
1 | import { DragHandleDots2Icon } from '@radix-ui/react-icons';
2 | import * as ResizablePrimitive from 'react-resizable-panels';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const ResizablePanelGroup = ({
7 | className,
8 | ...props
9 | }: React.ComponentProps) => (
10 |
17 | );
18 |
19 | const ResizablePanel = ResizablePrimitive.Panel;
20 |
21 | const ResizableHandle = ({
22 | withHandle,
23 | className,
24 | ...props
25 | }: React.ComponentProps & {
26 | withHandle?: boolean;
27 | }) => (
28 | div]:rotate-90',
31 | className
32 | )}
33 | {...props}
34 | >
35 | {withHandle && (
36 |
37 |
38 |
39 | )}
40 |
41 | );
42 |
43 | export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
44 |
--------------------------------------------------------------------------------
/src/components/ui/scroll-area.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const ScrollArea = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(({ className, children, ...props }, ref) => (
10 |
15 |
16 | {children}
17 |
18 |
19 |
20 |
21 | ));
22 | ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
23 |
24 | const ScrollBar = React.forwardRef<
25 | React.ElementRef,
26 | React.ComponentPropsWithoutRef
27 | >(({ className, orientation = 'vertical', ...props }, ref) => (
28 |
41 |
42 |
43 | ));
44 | ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
45 |
46 | export { ScrollArea, ScrollBar };
47 |
--------------------------------------------------------------------------------
/src/components/ui/select.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {
3 | CaretSortIcon,
4 | CheckIcon,
5 | ChevronDownIcon,
6 | ChevronUpIcon,
7 | } from '@radix-ui/react-icons';
8 | import * as SelectPrimitive from '@radix-ui/react-select';
9 |
10 | import { cn } from '@/lib/utils';
11 |
12 | const Select = SelectPrimitive.Root;
13 |
14 | const SelectGroup = SelectPrimitive.Group;
15 |
16 | const SelectValue = SelectPrimitive.Value;
17 |
18 | const SelectTrigger = React.forwardRef<
19 | React.ElementRef,
20 | React.ComponentPropsWithoutRef
21 | >(({ className, children, ...props }, ref) => (
22 | span]:line-clamp-1',
26 | className
27 | )}
28 | {...props}
29 | >
30 | {children}
31 |
32 |
33 |
34 |
35 | ));
36 | SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
37 |
38 | const SelectScrollUpButton = React.forwardRef<
39 | React.ElementRef,
40 | React.ComponentPropsWithoutRef
41 | >(({ className, ...props }, ref) => (
42 |
50 |
51 |
52 | ));
53 | SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
54 |
55 | const SelectScrollDownButton = React.forwardRef<
56 | React.ElementRef,
57 | React.ComponentPropsWithoutRef
58 | >(({ className, ...props }, ref) => (
59 |
67 |
68 |
69 | ));
70 | SelectScrollDownButton.displayName =
71 | SelectPrimitive.ScrollDownButton.displayName;
72 |
73 | const SelectContent = React.forwardRef<
74 | React.ElementRef,
75 | React.ComponentPropsWithoutRef
76 | >(({ className, children, position = 'popper', ...props }, ref) => (
77 |
78 |
89 |
90 |
97 | {children}
98 |
99 |
100 |
101 |
102 | ));
103 | SelectContent.displayName = SelectPrimitive.Content.displayName;
104 |
105 | const SelectLabel = React.forwardRef<
106 | React.ElementRef,
107 | React.ComponentPropsWithoutRef
108 | >(({ className, ...props }, ref) => (
109 |
114 | ));
115 | SelectLabel.displayName = SelectPrimitive.Label.displayName;
116 |
117 | const SelectItem = React.forwardRef<
118 | React.ElementRef,
119 | React.ComponentPropsWithoutRef
120 | >(({ className, children, ...props }, ref) => (
121 |
129 |
130 |
131 |
132 |
133 |
134 | {children}
135 |
136 | ));
137 | SelectItem.displayName = SelectPrimitive.Item.displayName;
138 |
139 | const SelectSeparator = React.forwardRef<
140 | React.ElementRef,
141 | React.ComponentPropsWithoutRef
142 | >(({ className, ...props }, ref) => (
143 |
148 | ));
149 | SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
150 |
151 | export {
152 | Select,
153 | SelectGroup,
154 | SelectValue,
155 | SelectTrigger,
156 | SelectContent,
157 | SelectLabel,
158 | SelectItem,
159 | SelectSeparator,
160 | SelectScrollUpButton,
161 | SelectScrollDownButton,
162 | };
163 |
--------------------------------------------------------------------------------
/src/components/ui/separator.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as SeparatorPrimitive from '@radix-ui/react-separator';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const Separator = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(
10 | (
11 | { className, orientation = 'horizontal', decorative = true, ...props },
12 | ref
13 | ) => (
14 |
25 | )
26 | );
27 | Separator.displayName = SeparatorPrimitive.Root.displayName;
28 |
29 | export { Separator };
30 |
--------------------------------------------------------------------------------
/src/components/ui/sheet.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as SheetPrimitive from '@radix-ui/react-dialog';
3 | import { Cross2Icon } from '@radix-ui/react-icons';
4 | import { cva, type VariantProps } from 'class-variance-authority';
5 |
6 | import { cn } from '@/lib/utils';
7 |
8 | const Sheet = SheetPrimitive.Root;
9 |
10 | const SheetTrigger = SheetPrimitive.Trigger;
11 |
12 | const SheetClose = SheetPrimitive.Close;
13 |
14 | const SheetPortal = SheetPrimitive.Portal;
15 |
16 | const SheetOverlay = React.forwardRef<
17 | React.ElementRef,
18 | React.ComponentPropsWithoutRef
19 | >(({ className, ...props }, ref) => (
20 |
28 | ));
29 | SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
30 |
31 | const sheetVariants = cva(
32 | 'fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out',
33 | {
34 | variants: {
35 | side: {
36 | top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
37 | bottom:
38 | 'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
39 | left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
40 | right:
41 | 'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
42 | },
43 | },
44 | defaultVariants: {
45 | side: 'right',
46 | },
47 | }
48 | );
49 |
50 | interface SheetContentProps
51 | extends React.ComponentPropsWithoutRef,
52 | VariantProps {}
53 |
54 | const SheetContent = React.forwardRef<
55 | React.ElementRef,
56 | SheetContentProps
57 | >(({ side = 'right', className, children, ...props }, ref) => (
58 |
59 |
60 |
65 |
66 |
67 | Close
68 |
69 | {children}
70 |
71 |
72 | ));
73 | SheetContent.displayName = SheetPrimitive.Content.displayName;
74 |
75 | const SheetHeader = ({
76 | className,
77 | ...props
78 | }: React.HTMLAttributes) => (
79 |
86 | );
87 | SheetHeader.displayName = 'SheetHeader';
88 |
89 | const SheetFooter = ({
90 | className,
91 | ...props
92 | }: React.HTMLAttributes) => (
93 |
100 | );
101 | SheetFooter.displayName = 'SheetFooter';
102 |
103 | const SheetTitle = React.forwardRef<
104 | React.ElementRef,
105 | React.ComponentPropsWithoutRef
106 | >(({ className, ...props }, ref) => (
107 |
112 | ));
113 | SheetTitle.displayName = SheetPrimitive.Title.displayName;
114 |
115 | const SheetDescription = React.forwardRef<
116 | React.ElementRef,
117 | React.ComponentPropsWithoutRef
118 | >(({ className, ...props }, ref) => (
119 |
124 | ));
125 | SheetDescription.displayName = SheetPrimitive.Description.displayName;
126 |
127 | export {
128 | Sheet,
129 | SheetPortal,
130 | SheetOverlay,
131 | SheetTrigger,
132 | SheetClose,
133 | SheetContent,
134 | SheetHeader,
135 | SheetFooter,
136 | SheetTitle,
137 | SheetDescription,
138 | };
139 |
--------------------------------------------------------------------------------
/src/components/ui/skeleton.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from '@/lib/utils';
2 |
3 | function Skeleton({
4 | className,
5 | ...props
6 | }: React.HTMLAttributes) {
7 | return (
8 |
12 | );
13 | }
14 |
15 | export { Skeleton };
16 |
--------------------------------------------------------------------------------
/src/components/ui/slider.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as SliderPrimitive from '@radix-ui/react-slider';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const Slider = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(({ className, ...props }, ref) => (
10 |
18 |
19 |
20 |
21 |
22 |
23 | ));
24 | Slider.displayName = SliderPrimitive.Root.displayName;
25 |
26 | export { Slider };
27 |
--------------------------------------------------------------------------------
/src/components/ui/sonner.tsx:
--------------------------------------------------------------------------------
1 | import { useTheme } from 'next-themes';
2 | import { Toaster as Sonner } from 'sonner';
3 |
4 | type ToasterProps = React.ComponentProps;
5 |
6 | const Toaster = ({ ...props }: ToasterProps) => {
7 | const { theme = 'system' } = useTheme();
8 |
9 | return (
10 |
26 | );
27 | };
28 |
29 | export { Toaster };
30 |
--------------------------------------------------------------------------------
/src/components/ui/switch.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as SwitchPrimitives from '@radix-ui/react-switch';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const Switch = React.forwardRef<
7 | React.ElementRef,
8 | React.ComponentPropsWithoutRef
9 | >(({ className, ...props }, ref) => (
10 |
18 |
23 |
24 | ));
25 | Switch.displayName = SwitchPrimitives.Root.displayName;
26 |
27 | export { Switch };
28 |
--------------------------------------------------------------------------------
/src/components/ui/table.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { cn } from '@/lib/utils';
4 |
5 | const Table = React.forwardRef<
6 | HTMLTableElement,
7 | React.HTMLAttributes
8 | >(({ className, ...props }, ref) => (
9 |
16 | ));
17 | Table.displayName = 'Table';
18 |
19 | const TableHeader = React.forwardRef<
20 | HTMLTableSectionElement,
21 | React.HTMLAttributes
22 | >(({ className, ...props }, ref) => (
23 |
24 | ));
25 | TableHeader.displayName = 'TableHeader';
26 |
27 | const TableBody = React.forwardRef<
28 | HTMLTableSectionElement,
29 | React.HTMLAttributes
30 | >(({ className, ...props }, ref) => (
31 |
36 | ));
37 | TableBody.displayName = 'TableBody';
38 |
39 | const TableFooter = React.forwardRef<
40 | HTMLTableSectionElement,
41 | React.HTMLAttributes
42 | >(({ className, ...props }, ref) => (
43 | tr]:last:border-b-0',
47 | className
48 | )}
49 | {...props}
50 | />
51 | ));
52 | TableFooter.displayName = 'TableFooter';
53 |
54 | const TableRow = React.forwardRef<
55 | HTMLTableRowElement,
56 | React.HTMLAttributes
57 | >(({ className, ...props }, ref) => (
58 |
66 | ));
67 | TableRow.displayName = 'TableRow';
68 |
69 | const TableHead = React.forwardRef<
70 | HTMLTableCellElement,
71 | React.ThHTMLAttributes
72 | >(({ className, ...props }, ref) => (
73 | [role=checkbox]]:translate-y-[2px]',
77 | className
78 | )}
79 | {...props}
80 | />
81 | ));
82 | TableHead.displayName = 'TableHead';
83 |
84 | const TableCell = React.forwardRef<
85 | HTMLTableCellElement,
86 | React.TdHTMLAttributes
87 | >(({ className, ...props }, ref) => (
88 | [role=checkbox]]:translate-y-[2px]',
92 | className
93 | )}
94 | {...props}
95 | />
96 | ));
97 | TableCell.displayName = 'TableCell';
98 |
99 | const TableCaption = React.forwardRef<
100 | HTMLTableCaptionElement,
101 | React.HTMLAttributes
102 | >(({ className, ...props }, ref) => (
103 |
108 | ));
109 | TableCaption.displayName = 'TableCaption';
110 |
111 | export {
112 | Table,
113 | TableHeader,
114 | TableBody,
115 | TableFooter,
116 | TableHead,
117 | TableRow,
118 | TableCell,
119 | TableCaption,
120 | };
121 |
--------------------------------------------------------------------------------
/src/components/ui/tabs.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as TabsPrimitive from '@radix-ui/react-tabs';
3 |
4 | import { cn } from '@/lib/utils';
5 |
6 | const Tabs = TabsPrimitive.Root;
7 |
8 | const TabsList = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, ...props }, ref) => (
12 |
20 | ));
21 | TabsList.displayName = TabsPrimitive.List.displayName;
22 |
23 | const TabsTrigger = React.forwardRef<
24 | React.ElementRef,
25 | React.ComponentPropsWithoutRef
26 | >(({ className, ...props }, ref) => (
27 |
35 | ));
36 | TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
37 |
38 | const TabsContent = React.forwardRef<
39 | React.ElementRef,
40 | React.ComponentPropsWithoutRef
41 | >(({ className, ...props }, ref) => (
42 |
50 | ));
51 | TabsContent.displayName = TabsPrimitive.Content.displayName;
52 |
53 | export { Tabs, TabsList, TabsTrigger, TabsContent };
54 |
--------------------------------------------------------------------------------
/src/components/ui/textarea.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { cn } from '@/lib/utils';
4 |
5 | export interface TextareaProps
6 | extends React.TextareaHTMLAttributes {}
7 |
8 | const Textarea = React.forwardRef(
9 | ({ className, ...props }, ref) => {
10 | return (
11 |
19 | );
20 | }
21 | );
22 | Textarea.displayName = 'Textarea';
23 |
24 | export { Textarea };
25 |
--------------------------------------------------------------------------------
/src/components/ui/toast.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Cross2Icon } from '@radix-ui/react-icons';
3 | import * as ToastPrimitives from '@radix-ui/react-toast';
4 | import { cva, type VariantProps } from 'class-variance-authority';
5 |
6 | import { cn } from '@/lib/utils';
7 |
8 | const ToastProvider = ToastPrimitives.Provider;
9 |
10 | const ToastViewport = React.forwardRef<
11 | React.ElementRef,
12 | React.ComponentPropsWithoutRef
13 | >(({ className, ...props }, ref) => (
14 |