├── .gitattributes ├── .gitignore ├── LICENSE ├── LLMModel.jsx ├── README.md ├── assets └── img │ └── demo_img.png └── my-app ├── .eslintrc.cjs ├── .gitignore ├── README.md ├── components.json ├── index.html ├── jsconfig.json ├── package-lock.json ├── package.json ├── postcss.config.js ├── public └── vite.svg ├── src ├── App.css ├── App.jsx ├── assets │ └── react.svg ├── components │ ├── LLMModel.jsx │ └── ui │ │ ├── button.jsx │ │ ├── card.jsx │ │ └── input.jsx ├── index.css ├── lib │ └── utils.js └── main.jsx ├── tailwind.config.js └── vite.config.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Benjamin Klieger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LLMModel.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" 3 | import { Button } from "@/components/ui/button" 4 | import { Input } from "@/components/ui/input" 5 | import { Boxes, Cpu, Network, Lightbulb, ArrowRight } from 'lucide-react' 6 | 7 | const LLMModel = () => { 8 | const [input, setInput] = useState(''); 9 | const [output, setOutput] = useState(''); 10 | const [step, setStep] = useState(0); 11 | 12 | const steps = [ 13 | { 14 | name: "Tokenization", 15 | icon: , 16 | description: "The input text is broken down into tokens (words or subwords). This process converts the raw text into a format the model can understand.", 17 | example: input ? input.split(' ').map((word, i) => {word}) : null 18 | }, 19 | { 20 | name: "Embedding", 21 | icon: , 22 | description: "Each token is converted into a numerical vector representation. This allows the model to process the text mathematically.", 23 | example:
24 | {input.split(' ').slice(0, 4).map((_, i) => 25 |
26 | [0.2, -0.5, 0.8, ...] 27 |
28 | )} 29 |
30 | }, 31 | { 32 | name: "Attention Mechanism", 33 | icon: , 34 | description: "The model calculates attention scores to understand the relationships between different parts of the input.", 35 | example:
36 | {input.split(' ').slice(0, 4).map((word, i) => 37 |
38 | {word} 39 | 40 | {(Math.random() * 0.5 + 0.5).toFixed(2)} 41 |
42 | )} 43 |
44 | }, 45 | { 46 | name: "Feed Forward", 47 | icon: , 48 | description: "The embedded and attention-weighted inputs are processed through multiple neural network layers.", 49 | example:
50 | 51 |
52 | }, 53 | { 54 | name: "Output Generation", 55 | icon: , 56 | description: "The model generates output tokens based on the processed input and the temperature setting.", 57 | example: output ?
{output}
: null 58 | } 59 | ]; 60 | 61 | const handleInputChange = (e) => { 62 | setInput(e.target.value); 63 | }; 64 | 65 | const handleNextStep = () => { 66 | if (step < steps.length - 1) { 67 | setStep(step + 1); 68 | } else { 69 | setOutput(generateOutput(input)); 70 | } 71 | }; 72 | 73 | const handleReset = () => { 74 | setInput(''); 75 | setOutput(''); 76 | setStep(0); 77 | }; 78 | 79 | const generateOutput = (input) => { 80 | // This is a simplified simulation of output generation 81 | const words = input.split(' '); 82 | const outputLength = Math.floor(Math.random() * 5) + words.length; 83 | let output = ''; 84 | for (let i = 0; i < outputLength; i++) { 85 | output += words[Math.floor(Math.random() * words.length)] + ' '; 86 | } 87 | return output.trim(); 88 | }; 89 | 90 | return ( 91 | 92 | 93 | Enhanced LLM Interactive Model 94 | Explore how LLMs process and generate text 95 | 96 | 97 |
98 |
99 | 100 | 105 |
106 |
107 |
108 | {steps[step].icon} 109 |

{steps[step].name}

110 |
111 |

{steps[step].description}

112 |
113 | {steps[step].example} 114 |
115 |
116 |
117 |
118 | 119 | 122 | 123 | 124 |
125 | ); 126 | }; 127 | 128 | export default LLMModel; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![License](https://img.shields.io/badge/license-MIT-green) 2 | 3 | # Claude React Artifact Tutorial 4 | 5 | Claude recently released Artifacts, which can compile code in a dedicated window. This tutorial helps beginners set up a React app to any React run code generated by Claude's Artifacts feature. 6 | 7 | [![Project Demo](https://img.youtube.com/vi/oRh_tVdgjB8/0.jpg)](https://www.youtube.com/watch?v=oRh_tVdgjB8) 8 | 9 | > Claude-React-Jumpstart: A step-by-step guide to running Claude-generated React code locally. 10 | 11 | --- 12 | 13 | ## Getting Started 14 | You can use the example provided to learn the process. Before beginning the following steps, remove the my-app folder so you can recreate it. 15 | 16 | ### Step 1: Create new React app with Vite 17 | 18 | ```bash 19 | npm create vite@latest my-app 20 | ✔ Select a framework: › React 21 | ✔ Select a variant: › JavaScript 22 | cd my-app 23 | npm install 24 | ``` 25 | 26 | ### Step 2: Install Tailwindcss and Shadcn 27 | 28 | From instructions: https://ui.shadcn.com/docs/installation/vite 29 | 30 | ```bash 31 | npm install -D tailwindcss postcss autoprefixer 32 | npx tailwindcss init -p 33 | ``` 34 | 35 | Update `vite.config.js`: 36 | 37 | ```javascript 38 | import { defineConfig } from 'vite' 39 | import react from '@vitejs/plugin-react' 40 | import path from 'path' 41 | 42 | export default defineConfig({ 43 | plugins: [react()], 44 | resolve: { 45 | alias: { 46 | '@': path.resolve(__dirname, './src'), 47 | }, 48 | }, 49 | }) 50 | ``` 51 | 52 | Create `jsconfig.json`: 53 | 54 | ```json 55 | { 56 | "compilerOptions": { 57 | "baseUrl": ".", 58 | "paths": { 59 | "@/*": ["src/*"] 60 | } 61 | }, 62 | "include": ["src/**/*"] 63 | } 64 | ``` 65 | 66 | ```bash 67 | npx shadcn-ui@latest init 68 | ``` 69 | 70 | ``` 71 | ✔ Would you like to use TypeScript (recommended)? no 72 | ✔ Which style would you like to use? › Default 73 | ✔ Which color would you like to use as base color? › Slate 74 | ✔ Where is your global CSS file? … src/index.css 75 | ✔ Would you like to use CSS variables for colors? … yes 76 | ✔ Are you using a custom tailwind prefix eg. tw-? (Leave blank if not) … 77 | ✔ Where is your tailwind.config.js located? … tailwind.config.js 78 | ✔ Configure the import alias for components: … @/components 79 | ✔ Configure the import alias for utils: … @/lib/utils 80 | ✔ Are you using React Server Components? … no 81 | ✔ Write configuration to components.json. Proceed? … yes 82 | ``` 83 | 84 | ### 3. Install Other Libraries and Components 85 | Choose your list of required components and libraries to download based upon the imports in your react file. 86 | ```bash 87 | npx shadcn-ui@latest add card button input 88 | npm install lucide-react 89 | ``` 90 | 91 | ### 4. Add Your Artifact Code 92 | 93 | `LLMModel.jsx` is an included artifact example. You can move the file to `src/components/LLMModel.jsx`. 94 | 95 | Then add it to your app by updating `App.jsx`: 96 | 97 | ```jsx 98 | import './App.css' 99 | import LLMModel from './components/LLMModel' 100 | 101 | function App() { 102 | return ( 103 | <> 104 | 105 | 106 | ) 107 | } 108 | 109 | export default App 110 | ``` 111 | 112 | ### 5. Run the App 113 | 114 | ```bash 115 | npm run dev 116 | ``` 117 | 118 | ![Example App Online](./assets/img/demo_img.png) 119 | Example App with LLMModel.jsx Online -------------------------------------------------------------------------------- /assets/img/demo_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bklieger/Claude-React-Jumpstart/ec7a179082892b92e97458fd9ba17fe3cb2f3323/assets/img/demo_img.png -------------------------------------------------------------------------------- /my-app/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react/jsx-no-target-blank': 'off', 16 | 'react-refresh/only-export-components': [ 17 | 'warn', 18 | { allowConstantExport: true }, 19 | ], 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /my-app/.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 | -------------------------------------------------------------------------------- /my-app/README.md: -------------------------------------------------------------------------------- 1 | # React + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | -------------------------------------------------------------------------------- /my-app/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": false, 5 | "tsx": false, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/index.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /my-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /my-app/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@/*": ["src/*"] 6 | } 7 | }, 8 | "include": ["src/**/*"] 9 | } -------------------------------------------------------------------------------- /my-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@radix-ui/react-slot": "^1.1.0", 14 | "class-variance-authority": "^0.7.0", 15 | "clsx": "^2.1.1", 16 | "lucide-react": "^0.396.0", 17 | "react": "^18.3.1", 18 | "react-dom": "^18.3.1", 19 | "tailwind-merge": "^2.3.0", 20 | "tailwindcss-animate": "^1.0.7" 21 | }, 22 | "devDependencies": { 23 | "@types/react": "^18.3.3", 24 | "@types/react-dom": "^18.3.0", 25 | "@vitejs/plugin-react": "^4.3.1", 26 | "autoprefixer": "^10.4.19", 27 | "eslint": "^8.57.0", 28 | "eslint-plugin-react": "^7.34.2", 29 | "eslint-plugin-react-hooks": "^4.6.2", 30 | "eslint-plugin-react-refresh": "^0.4.7", 31 | "postcss": "^8.4.38", 32 | "tailwindcss": "^3.4.4", 33 | "vite": "^5.3.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /my-app/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /my-app/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /my-app/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /my-app/src/App.jsx: -------------------------------------------------------------------------------- 1 | import './App.css' 2 | import LLMModel from './components/LLMModel' 3 | 4 | function App() { 5 | return ( 6 | <> 7 | 8 | 9 | ) 10 | } 11 | 12 | export default App -------------------------------------------------------------------------------- /my-app/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /my-app/src/components/LLMModel.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" 3 | import { Button } from "@/components/ui/button" 4 | import { Input } from "@/components/ui/input" 5 | import { Boxes, Cpu, Network, Lightbulb, ArrowRight } from 'lucide-react' 6 | 7 | const LLMModel = () => { 8 | const [input, setInput] = useState(''); 9 | const [output, setOutput] = useState(''); 10 | const [step, setStep] = useState(0); 11 | 12 | const steps = [ 13 | { 14 | name: "Tokenization", 15 | icon: , 16 | description: "The input text is broken down into tokens (words or subwords). This process converts the raw text into a format the model can understand.", 17 | example: input ? input.split(' ').map((word, i) => {word}) : null 18 | }, 19 | { 20 | name: "Embedding", 21 | icon: , 22 | description: "Each token is converted into a numerical vector representation. This allows the model to process the text mathematically.", 23 | example:
24 | {input.split(' ').slice(0, 4).map((_, i) => 25 |
26 | [0.2, -0.5, 0.8, ...] 27 |
28 | )} 29 |
30 | }, 31 | { 32 | name: "Attention Mechanism", 33 | icon: , 34 | description: "The model calculates attention scores to understand the relationships between different parts of the input.", 35 | example:
36 | {input.split(' ').slice(0, 4).map((word, i) => 37 |
38 | {word} 39 | 40 | {(Math.random() * 0.5 + 0.5).toFixed(2)} 41 |
42 | )} 43 |
44 | }, 45 | { 46 | name: "Feed Forward", 47 | icon: , 48 | description: "The embedded and attention-weighted inputs are processed through multiple neural network layers.", 49 | example:
50 | 51 |
52 | }, 53 | { 54 | name: "Output Generation", 55 | icon: , 56 | description: "The model generates output tokens based on the processed input and the temperature setting.", 57 | example: output ?
{output}
: null 58 | } 59 | ]; 60 | 61 | const handleInputChange = (e) => { 62 | setInput(e.target.value); 63 | }; 64 | 65 | const handleNextStep = () => { 66 | if (step < steps.length - 1) { 67 | setStep(step + 1); 68 | } else { 69 | setOutput(generateOutput(input)); 70 | } 71 | }; 72 | 73 | const handleReset = () => { 74 | setInput(''); 75 | setOutput(''); 76 | setStep(0); 77 | }; 78 | 79 | const generateOutput = (input) => { 80 | // This is a simplified simulation of output generation 81 | const words = input.split(' '); 82 | const outputLength = Math.floor(Math.random() * 5) + words.length; 83 | let output = ''; 84 | for (let i = 0; i < outputLength; i++) { 85 | output += words[Math.floor(Math.random() * words.length)] + ' '; 86 | } 87 | return output.trim(); 88 | }; 89 | 90 | return ( 91 | 92 | 93 | Enhanced LLM Interactive Model 94 | Explore how LLMs process and generate text 95 | 96 | 97 |
98 |
99 | 100 | 105 |
106 |
107 |
108 | {steps[step].icon} 109 |

{steps[step].name}

110 |
111 |

{steps[step].description}

112 |
113 | {steps[step].example} 114 |
115 |
116 |
117 |
118 | 119 | 122 | 123 | 124 |
125 | ); 126 | }; 127 | 128 | export default LLMModel; -------------------------------------------------------------------------------- /my-app/src/components/ui/button.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva } 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 ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", 9 | { 10 | variants: { 11 | variant: { 12 | default: "bg-primary text-primary-foreground hover:bg-primary/90", 13 | destructive: 14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90", 15 | outline: 16 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground", 17 | secondary: 18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80", 19 | ghost: "hover:bg-accent hover:text-accent-foreground", 20 | link: "text-primary underline-offset-4 hover:underline", 21 | }, 22 | size: { 23 | default: "h-10 px-4 py-2", 24 | sm: "h-9 rounded-md px-3", 25 | lg: "h-11 rounded-md px-8", 26 | icon: "h-10 w-10", 27 | }, 28 | }, 29 | defaultVariants: { 30 | variant: "default", 31 | size: "default", 32 | }, 33 | } 34 | ) 35 | 36 | const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => { 37 | const Comp = asChild ? Slot : "button" 38 | return ( 39 | () 43 | ); 44 | }) 45 | Button.displayName = "Button" 46 | 47 | export { Button, buttonVariants } 48 | -------------------------------------------------------------------------------- /my-app/src/components/ui/card.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Card = React.forwardRef(({ className, ...props }, ref) => ( 6 |
10 | )) 11 | Card.displayName = "Card" 12 | 13 | const CardHeader = React.forwardRef(({ className, ...props }, ref) => ( 14 |
18 | )) 19 | CardHeader.displayName = "CardHeader" 20 | 21 | const CardTitle = React.forwardRef(({ className, ...props }, ref) => ( 22 |

26 | )) 27 | CardTitle.displayName = "CardTitle" 28 | 29 | const CardDescription = React.forwardRef(({ className, ...props }, ref) => ( 30 |

34 | )) 35 | CardDescription.displayName = "CardDescription" 36 | 37 | const CardContent = React.forwardRef(({ className, ...props }, ref) => ( 38 |

39 | )) 40 | CardContent.displayName = "CardContent" 41 | 42 | const CardFooter = React.forwardRef(({ className, ...props }, ref) => ( 43 |
47 | )) 48 | CardFooter.displayName = "CardFooter" 49 | 50 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } 51 | -------------------------------------------------------------------------------- /my-app/src/components/ui/input.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Input = React.forwardRef(({ className, type, ...props }, ref) => { 6 | return ( 7 | () 15 | ); 16 | }) 17 | Input.displayName = "Input" 18 | 19 | export { Input } 20 | -------------------------------------------------------------------------------- /my-app/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 222.2 84% 4.9%; 9 | 10 | --card: 0 0% 100%; 11 | --card-foreground: 222.2 84% 4.9%; 12 | 13 | --popover: 0 0% 100%; 14 | --popover-foreground: 222.2 84% 4.9%; 15 | 16 | --primary: 222.2 47.4% 11.2%; 17 | --primary-foreground: 210 40% 98%; 18 | 19 | --secondary: 210 40% 96.1%; 20 | --secondary-foreground: 222.2 47.4% 11.2%; 21 | 22 | --muted: 210 40% 96.1%; 23 | --muted-foreground: 215.4 16.3% 46.9%; 24 | 25 | --accent: 210 40% 96.1%; 26 | --accent-foreground: 222.2 47.4% 11.2%; 27 | 28 | --destructive: 0 84.2% 60.2%; 29 | --destructive-foreground: 210 40% 98%; 30 | 31 | --border: 214.3 31.8% 91.4%; 32 | --input: 214.3 31.8% 91.4%; 33 | --ring: 222.2 84% 4.9%; 34 | 35 | --radius: 0.5rem; 36 | } 37 | 38 | .dark { 39 | --background: 222.2 84% 4.9%; 40 | --foreground: 210 40% 98%; 41 | 42 | --card: 222.2 84% 4.9%; 43 | --card-foreground: 210 40% 98%; 44 | 45 | --popover: 222.2 84% 4.9%; 46 | --popover-foreground: 210 40% 98%; 47 | 48 | --primary: 210 40% 98%; 49 | --primary-foreground: 222.2 47.4% 11.2%; 50 | 51 | --secondary: 217.2 32.6% 17.5%; 52 | --secondary-foreground: 210 40% 98%; 53 | 54 | --muted: 217.2 32.6% 17.5%; 55 | --muted-foreground: 215 20.2% 65.1%; 56 | 57 | --accent: 217.2 32.6% 17.5%; 58 | --accent-foreground: 210 40% 98%; 59 | 60 | --destructive: 0 62.8% 30.6%; 61 | --destructive-foreground: 210 40% 98%; 62 | 63 | --border: 217.2 32.6% 17.5%; 64 | --input: 217.2 32.6% 17.5%; 65 | --ring: 212.7 26.8% 83.9%; 66 | } 67 | } 68 | 69 | @layer base { 70 | * { 71 | @apply border-border; 72 | } 73 | body { 74 | @apply bg-background text-foreground; 75 | } 76 | } -------------------------------------------------------------------------------- /my-app/src/lib/utils.js: -------------------------------------------------------------------------------- 1 | import { clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /my-app/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.jsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /my-app/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | darkMode: ["class"], 4 | content: [ 5 | './pages/**/*.{js,jsx}', 6 | './components/**/*.{js,jsx}', 7 | './app/**/*.{js,jsx}', 8 | './src/**/*.{js,jsx}', 9 | ], 10 | prefix: "", 11 | theme: { 12 | container: { 13 | center: true, 14 | padding: "2rem", 15 | screens: { 16 | "2xl": "1400px", 17 | }, 18 | }, 19 | extend: { 20 | colors: { 21 | border: "hsl(var(--border))", 22 | input: "hsl(var(--input))", 23 | ring: "hsl(var(--ring))", 24 | background: "hsl(var(--background))", 25 | foreground: "hsl(var(--foreground))", 26 | primary: { 27 | DEFAULT: "hsl(var(--primary))", 28 | foreground: "hsl(var(--primary-foreground))", 29 | }, 30 | secondary: { 31 | DEFAULT: "hsl(var(--secondary))", 32 | foreground: "hsl(var(--secondary-foreground))", 33 | }, 34 | destructive: { 35 | DEFAULT: "hsl(var(--destructive))", 36 | foreground: "hsl(var(--destructive-foreground))", 37 | }, 38 | muted: { 39 | DEFAULT: "hsl(var(--muted))", 40 | foreground: "hsl(var(--muted-foreground))", 41 | }, 42 | accent: { 43 | DEFAULT: "hsl(var(--accent))", 44 | foreground: "hsl(var(--accent-foreground))", 45 | }, 46 | popover: { 47 | DEFAULT: "hsl(var(--popover))", 48 | foreground: "hsl(var(--popover-foreground))", 49 | }, 50 | card: { 51 | DEFAULT: "hsl(var(--card))", 52 | foreground: "hsl(var(--card-foreground))", 53 | }, 54 | }, 55 | borderRadius: { 56 | lg: "var(--radius)", 57 | md: "calc(var(--radius) - 2px)", 58 | sm: "calc(var(--radius) - 4px)", 59 | }, 60 | keyframes: { 61 | "accordion-down": { 62 | from: { height: "0" }, 63 | to: { height: "var(--radix-accordion-content-height)" }, 64 | }, 65 | "accordion-up": { 66 | from: { height: "var(--radix-accordion-content-height)" }, 67 | to: { height: "0" }, 68 | }, 69 | }, 70 | animation: { 71 | "accordion-down": "accordion-down 0.2s ease-out", 72 | "accordion-up": "accordion-up 0.2s ease-out", 73 | }, 74 | }, 75 | }, 76 | plugins: [require("tailwindcss-animate")], 77 | } -------------------------------------------------------------------------------- /my-app/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | import path from 'path' 4 | 5 | export default defineConfig({ 6 | plugins: [react()], 7 | resolve: { 8 | alias: { 9 | '@': path.resolve(__dirname, './src'), 10 | }, 11 | }, 12 | }) --------------------------------------------------------------------------------