├── .gitignore ├── LICENSE ├── README.md ├── app.js ├── app ├── .gitignore ├── README.md ├── components.json ├── dist │ ├── .vite │ │ └── manifest.json │ ├── assets │ │ ├── css │ │ │ └── index-ChDpXTlT.css │ │ └── js │ │ │ └── index-DkcwcVaL.js │ └── index.html ├── index.html ├── jsconfig.json ├── package.json ├── postcss.config.js ├── src │ ├── App.jsx │ ├── components │ │ ├── LoadingScreen.jsx │ │ ├── PageTransition.jsx │ │ ├── layouts │ │ │ └── MainLayout.jsx │ │ └── ui │ │ │ ├── accordion.jsx │ │ │ ├── alert-dialog.jsx │ │ │ ├── alert.jsx │ │ │ ├── avatar.jsx │ │ │ ├── badge.jsx │ │ │ ├── breadcrumb.jsx │ │ │ ├── button.jsx │ │ │ ├── card.jsx │ │ │ ├── checkbox.jsx │ │ │ ├── collapsible.jsx │ │ │ ├── dialog.jsx │ │ │ ├── dropdown-menu.jsx │ │ │ ├── hover-card.jsx │ │ │ ├── input.jsx │ │ │ ├── label.jsx │ │ │ ├── progress.jsx │ │ │ ├── scroll-area.jsx │ │ │ ├── select.jsx │ │ │ ├── separator.jsx │ │ │ ├── sheet.jsx │ │ │ ├── sidebar.jsx │ │ │ ├── skeleton.jsx │ │ │ ├── table.jsx │ │ │ ├── tabs.jsx │ │ │ ├── textarea.jsx │ │ │ ├── toast.jsx │ │ │ ├── toaster.jsx │ │ │ └── tooltip.jsx │ ├── hooks │ │ ├── use-mobile.jsx │ │ └── use-toast.js │ ├── index.css │ ├── lib │ │ ├── api.js │ │ └── utils.js │ ├── main.jsx │ └── pages │ │ ├── Account.jsx │ │ ├── Auth.jsx │ │ ├── Dashboard.jsx │ │ ├── NotFound.jsx │ │ ├── Referrals.jsx │ │ ├── SupportTickets.jsx │ │ ├── admin │ │ ├── Nodes.jsx │ │ ├── Overview.jsx │ │ ├── Radar.jsx │ │ ├── Tickets.jsx │ │ └── Users.jsx │ │ ├── coins │ │ ├── AFKPage.jsx │ │ └── Store.jsx │ │ └── server │ │ ├── Backups.jsx │ │ ├── ConsolePage.jsx │ │ ├── FileManagerPage.jsx │ │ ├── Network.jsx │ │ ├── Overview.jsx │ │ ├── Players.jsx │ │ ├── PluginManagerPage.jsx │ │ ├── Settings.jsx │ │ └── UserManagerPage.jsx ├── tailwind.config.js └── vite.config.js ├── assets ├── MozillaHeadline-Variable.ttf ├── MozillaHeadline-Variable.woff ├── MozillaHeadline-Variable.woff2 ├── MozillaHeadlineItalic-Variable.ttf ├── MozillaHeadlineItalic-Variable.woff ├── MozillaHeadlineItalic-Variable.woff2 ├── MozillaText-Variable.ttf ├── MozillaText-Variable.woff ├── MozillaText-Variable.woff2 ├── MozillaTextItalic-Variable.ttf ├── MozillaTextItalic-Variable.woff ├── MozillaTextItalic-Variable.woff2 ├── tailwind.css └── tw.conf ├── db.js ├── example_config.toml ├── handlers ├── Client.js ├── Queue.js ├── afk.js ├── config.js ├── console.js ├── getPteroUser.js ├── getServers.js ├── log.js └── vpnCheck.js ├── modules ├── admin.js ├── api.js ├── auth.js ├── extras.js ├── referrals.js ├── routing.js ├── server:allocations.js ├── server:backups.js ├── server:core.js ├── server:files_delete.js ├── server:files_list.js ├── server:files_read.js ├── server:files_transfer.js ├── server:files_write.js ├── server:logs.js ├── server:players.js ├── server:players_ban.js ├── server:plugins.js ├── server:power.js ├── server:settings.js ├── server:startup.js ├── server:users.js ├── server:users_legacy.js ├── server:variables.js ├── server:websocket.js ├── server:workflow.js ├── server:worlds.js ├── server:worlds_import.js ├── servers.js ├── store.js └── support.js ├── package.json └── tailwind.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | backups/ 3 | logs/ 4 | *.log 5 | prism.* 6 | *.db 7 | *.sqlite 8 | storage/ 9 | temp/ 10 | *.lockb 11 | *.lock 12 | *.rdb 13 | package-lock.json 14 | config.toml 15 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # Prism Public Use License 2 | 3 | Copyright (c) 2025 Matt James 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 | 1. The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | 2. Any use of the Software must include prominent attribution to the original 16 | author(s). This attribution must appear in any documentation, software interfaces, 17 | and other materials that accompany or describe the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Prism 2 | 3 | The all-in-one dashboard built from the legacy of Heliactyl. A high performance user interface, full built-in panel for managing servers, coins system, resources store and more. 4 | 5 | ## Required: Edit your Wings configuration 6 | 7 | **Before deploying Prism, you must configure each node's Wings configuration!** 8 | 9 | 1. On each node, edit the Wings configuration file (usually at `/etc/pterodactyl/config.yml`) 10 | 2. Locate the `allowed-origins` section 11 | 3. Change: 12 | ```yaml 13 | allowed-origins: [] 14 | ``` 15 | to either: 16 | ```yaml 17 | allowed-origins: ['*'] # recommended for simplicity 18 | ``` 19 | or: 20 | ```yaml 21 | allowed-origins: ['https://your-dashboard-domain.com'] # more restrictive option 22 | ``` 23 | 24 | If you don't do this, Prism can't communicate with your nodes. 25 | 26 | ## Features 27 | 28 | - Modern, responsive user interface 29 | - Built-in panel, goodbye Pterodactyl 30 | - Integrated coins/credits system 31 | - User/password authentication 32 | - Resource allocation system 33 | - Real-time stats and charts 34 | - Support tickets *(pending reimplementation)* 35 | - Admin area with users, nodes and more 36 | 37 | ## Prerequisites 38 | 39 | - Bun v1.1.42 or higher 40 | - Node.js v18+ *(for frontend only, backend runs on Bun)* 41 | - Redis 42 | - Nginx 43 | - SSL certificate (recommended) 44 | 45 | ## 1. Prerequisites Installation 46 | 47 | 1. Install Redis: 48 | ```bash 49 | # For Ubuntu/Debian 50 | sudo apt update 51 | sudo apt install redis-server 52 | 53 | # For CentOS/RHEL 54 | sudo dnf install epel-release 55 | sudo dnf install redis 56 | 57 | # Start and enable Redis 58 | sudo systemctl start redis 59 | sudo systemctl enable redis 60 | ``` 61 | 62 | 2. Install Bun: 63 | ```bash 64 | # Install Bun 65 | curl -fsSL https://bun.sh/install | bash 66 | 67 | # Install Node.js 68 | # This depends on your system, find how to via https://nodejs.org 69 | 70 | # Upgrade to Bun Canary (important!) 71 | bun upgrade --canary 72 | 73 | # Reload shell configuration to use Bun 74 | source ~/.bashrc 75 | ``` 76 | 77 | ## 2. Prism Installation 78 | 79 | 1. Clone the repository: 80 | ```bash 81 | git clone https://github.com/PrismFOSS/Prism 82 | cd Prism 83 | ``` 84 | 85 | 2. Install dependencies: 86 | ```bash 87 | bun install 88 | ``` 89 | 90 | 3. Create configuration file: 91 | ```bash 92 | cp example_config.toml config.toml 93 | ``` 94 | 95 | 4. Configure your `config.toml` file 96 | 97 | 5. Build & Start Prism: 98 | ```bash 99 | cd app 100 | npm install 101 | npm run build 102 | cd ../ 103 | 104 | bun run app.js 105 | ``` 106 | 107 | ## Nginx Configuration 108 | 109 | This is required to host Prism on a public URL. 110 | 111 | ```nginx 112 | server { 113 | listen 80; 114 | listen [::]:80; 115 | server_name dashboard.yourdomain.com; 116 | 117 | # Redirect HTTP to HTTPS 118 | return 301 https://$server_name$request_uri; 119 | } 120 | 121 | server { 122 | listen 443 ssl http2; 123 | listen [::]:443 ssl http2; 124 | server_name dashboard.yourdomain.com; 125 | 126 | ssl_certificate /path/to/cert.pem; 127 | ssl_certificate_key /path/to/key.pem; 128 | 129 | # SSL configuration 130 | ssl_protocols TLSv1.2 TLSv1.3; 131 | ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; 132 | ssl_prefer_server_ciphers off; 133 | 134 | # HSTS (uncomment if you're using HTTPS) 135 | # add_header Strict-Transport-Security "max-age=63072000" always; 136 | 137 | location / { 138 | proxy_pass http://localhost:3000; 139 | proxy_http_version 1.1; 140 | proxy_set_header Upgrade $http_upgrade; 141 | proxy_set_header Connection 'upgrade'; 142 | proxy_set_header Host $host; 143 | proxy_cache_bypass $http_upgrade; 144 | proxy_set_header X-Real-IP $remote_addr; 145 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 146 | proxy_set_header X-Forwarded-Proto $scheme; 147 | } 148 | 149 | # WebSocket support 150 | location /ws { 151 | proxy_pass http://localhost:3000; 152 | proxy_http_version 1.1; 153 | proxy_set_header Upgrade $http_upgrade; 154 | proxy_set_header Connection "Upgrade"; 155 | proxy_set_header Host $host; 156 | proxy_cache_bypass $http_upgrade; 157 | proxy_set_header X-Real-IP $remote_addr; 158 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 159 | proxy_set_header X-Forwarded-Proto $scheme; 160 | 161 | # WebSocket specific settings 162 | proxy_read_timeout 86400; # Prevents timeout for long-lived connections 163 | proxy_send_timeout 86400; # Prevents timeout for long-lived connections 164 | proxy_buffering off; # Disable buffering for real-time communication 165 | } 166 | 167 | # Security headers 168 | add_header X-Frame-Options "SAMEORIGIN" always; 169 | add_header X-XSS-Protection "1; mode=block" always; 170 | add_header X-Content-Type-Options "nosniff" always; 171 | add_header Referrer-Policy "no-referrer-when-downgrade" always; 172 | 173 | # Optimize SSL 174 | ssl_session_timeout 1d; 175 | ssl_session_cache shared:SSL:50m; 176 | ssl_session_tickets off; 177 | } 178 | ``` 179 | 180 | ## License 181 | 182 | This project is licensed under the Prism Public Use License - see the LICENSE file for details. 183 | 184 | ## Support 185 | 186 | For support, please open an issue on the GitHub repository or join our Discord community. 187 | 188 | ## Security 189 | 190 | To report security vulnerabilities, please email security@xeh.sh 191 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | .DS_Store -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | # Prism Mono 2 | 3 | The brand new frontend for the Prism dashboard, built with shadcn/ui, Tailwind CSS and in React. 4 | 5 | ## Standalone build guide 6 | 7 | ``` 8 | npm install 9 | npm run build``` 10 | 11 | The files will now be accessible in `dist/`. If the app is located inside the Prism directory under `app` then Prism will serve `app/dist/` (as of Adelante 105) to the user. Have a look: `modules/routing.js`. -------------------------------------------------------------------------------- /app/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": false, 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 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /app/dist/.vite/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "index.html": { 3 | "file": "assets/js/index-DkcwcVaL.js", 4 | "name": "index", 5 | "src": "index.html", 6 | "isEntry": true, 7 | "css": [ 8 | "assets/css/index-ChDpXTlT.css" 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /app/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Prism 7 | 8 | 9 | 10 | 11 |
12 | 13 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Prism 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /app/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "~/*": ["./src/*"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@prism/mono", 3 | "private": true, 4 | "version": "0.1.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "watch": "vite build --watch", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@hookform/resolvers": "^3.9.1", 14 | "@monaco-editor/react": "^4.6.0", 15 | "@radix-ui/react-accordion": "^1.2.2", 16 | "@radix-ui/react-alert-dialog": "^1.1.4", 17 | "@radix-ui/react-avatar": "^1.1.2", 18 | "@radix-ui/react-checkbox": "^1.1.3", 19 | "@radix-ui/react-collapsible": "^1.1.2", 20 | "@radix-ui/react-dialog": "^1.1.4", 21 | "@radix-ui/react-dropdown-menu": "^2.1.4", 22 | "@radix-ui/react-hover-card": "^1.1.4", 23 | "@radix-ui/react-icons": "^1.3.2", 24 | "@radix-ui/react-label": "^2.1.1", 25 | "@radix-ui/react-progress": "^1.1.1", 26 | "@radix-ui/react-scroll-area": "^1.2.2", 27 | "@radix-ui/react-select": "^2.1.4", 28 | "@radix-ui/react-separator": "^1.1.1", 29 | "@radix-ui/react-slot": "^1.1.1", 30 | "@radix-ui/react-tabs": "^1.1.2", 31 | "@radix-ui/react-toast": "^1.2.4", 32 | "@radix-ui/react-tooltip": "^1.1.6", 33 | "@tanstack/react-query": "^5.62.10", 34 | "axios": "^1.7.9", 35 | "class-variance-authority": "^0.7.1", 36 | "clsx": "^2.1.1", 37 | "framer-motion": "^11.15.0", 38 | "js-cookie": "^3.0.5", 39 | "lucide-react": "^0.469.0", 40 | "react": "^18.3.1", 41 | "react-dom": "^18.3.1", 42 | "react-google-recaptcha": "^3.1.0", 43 | "react-hot-toast": "^2.4.1", 44 | "react-router-dom": "^6.28.1", 45 | "recharts": "^2.15.0", 46 | "sonner": "^1.7.1", 47 | "tailwind-merge": "^2.6.0", 48 | "tailwindcss-animate": "^1.0.7" 49 | }, 50 | "devDependencies": { 51 | "@types/react": "^18.2.43", 52 | "@types/react-dom": "^18.2.17", 53 | "@vitejs/plugin-react": "^4.2.1", 54 | "autoprefixer": "^10.4.20", 55 | "postcss": "^8.4.49", 56 | "tailwindcss": "^3.4.17", 57 | "vite": "^5.0.8" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /app/src/components/LoadingScreen.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Loader2 } from "lucide-react"; 3 | 4 | export default function LoadingScreen() { 5 | const [progress, setProgress] = useState(0); 6 | 7 | useEffect(() => { 8 | const timer = setTimeout(() => { 9 | setProgress(100); 10 | }, 100); 11 | 12 | return () => clearTimeout(timer); 13 | }, []); 14 | 15 | return ( 16 |
17 | {/* Top Progress Bar */} 18 |
19 |
23 |
24 | 25 | {/* Center Content */} 26 |
27 | 28 |
Prism 0.5.0 (Adelante)
29 |
30 |
31 | ); 32 | } -------------------------------------------------------------------------------- /app/src/components/PageTransition.jsx: -------------------------------------------------------------------------------- 1 | import { motion, AnimatePresence } from 'framer-motion'; 2 | import { useState, useEffect } from 'react'; 3 | import { Loader2 } from "lucide-react"; 4 | 5 | export default function PageTransition({ children }) { 6 | const [isLoading, setIsLoading] = useState(true); 7 | const [progress, setProgress] = useState(0); 8 | 9 | useEffect(() => { 10 | const progressTimer = setInterval(() => { 11 | setProgress((prevProgress) => 12 | prevProgress < 100 ? prevProgress + 10 : 100 13 | ); 14 | }, 60); 15 | 16 | const timer = setTimeout(() => { 17 | setIsLoading(false); 18 | clearInterval(progressTimer); 19 | }, 600); 20 | 21 | return () => { 22 | clearTimeout(timer); 23 | clearInterval(progressTimer); 24 | }; 25 | }, []); 26 | 27 | const pageVariants = { 28 | initial: { 29 | opacity: 0, 30 | y: 40, 31 | scale: 0.98, 32 | filter: 'blur(12px)' 33 | }, 34 | animate: { 35 | opacity: 1, 36 | y: 0, 37 | scale: 1, 38 | filter: 'blur(0px)', 39 | transition: { 40 | type: "spring", 41 | stiffness: 120, 42 | damping: 18, 43 | mass: 1.1, 44 | duration: 0.3 45 | } 46 | }, 47 | exit: { 48 | opacity: 0, 49 | y: -40, 50 | scale: 0.98, 51 | filter: 'blur(12px)', 52 | transition: { 53 | duration: 0.15 54 | } 55 | } 56 | }; 57 | 58 | return ( 59 |
60 | 61 | {isLoading ? ( 62 |
63 | {/* Top Progress Bar */} 64 |
65 |
69 |
70 | 71 | 72 |
73 | ) : ( 74 | 86 | {children} 87 | 88 | )} 89 | 90 |
91 | ); 92 | } -------------------------------------------------------------------------------- /app/src/components/ui/accordion.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as AccordionPrimitive from "@radix-ui/react-accordion" 3 | import { ChevronDown } from "lucide-react" 4 | 5 | import { cn } from "~/lib/utils" 6 | 7 | const Accordion = AccordionPrimitive.Root 8 | 9 | const AccordionItem = React.forwardRef(({ className, ...props }, ref) => ( 10 | 11 | )) 12 | AccordionItem.displayName = "AccordionItem" 13 | 14 | const AccordionTrigger = React.forwardRef(({ className, children, ...props }, ref) => ( 15 | 16 | svg]:rotate-180", 20 | className 21 | )} 22 | {...props}> 23 | {children} 24 | 26 | 27 | 28 | )) 29 | AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName 30 | 31 | const AccordionContent = React.forwardRef(({ className, children, ...props }, ref) => ( 32 | 36 |
{children}
37 |
38 | )) 39 | AccordionContent.displayName = AccordionPrimitive.Content.displayName 40 | 41 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } 42 | -------------------------------------------------------------------------------- /app/src/components/ui/alert-dialog.jsx: -------------------------------------------------------------------------------- 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(({ className, ...props }, ref) => ( 14 | 21 | )) 22 | AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName 23 | 24 | const AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => ( 25 | 26 | 27 | 34 | 35 | )) 36 | AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName 37 | 38 | const AlertDialogHeader = ({ 39 | className, 40 | ...props 41 | }) => ( 42 |
45 | ) 46 | AlertDialogHeader.displayName = "AlertDialogHeader" 47 | 48 | const AlertDialogFooter = ({ 49 | className, 50 | ...props 51 | }) => ( 52 |
55 | ) 56 | AlertDialogFooter.displayName = "AlertDialogFooter" 57 | 58 | const AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => ( 59 | 60 | )) 61 | AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName 62 | 63 | const AlertDialogDescription = React.forwardRef(({ className, ...props }, ref) => ( 64 | 68 | )) 69 | AlertDialogDescription.displayName = 70 | AlertDialogPrimitive.Description.displayName 71 | 72 | const AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => ( 73 | 74 | )) 75 | AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName 76 | 77 | const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => ( 78 | 82 | )) 83 | AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName 84 | 85 | export { 86 | AlertDialog, 87 | AlertDialogPortal, 88 | AlertDialogOverlay, 89 | AlertDialogTrigger, 90 | AlertDialogContent, 91 | AlertDialogHeader, 92 | AlertDialogFooter, 93 | AlertDialogTitle, 94 | AlertDialogDescription, 95 | AlertDialogAction, 96 | AlertDialogCancel, 97 | } 98 | -------------------------------------------------------------------------------- /app/src/components/ui/alert.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva } 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(({ className, variant, ...props }, ref) => ( 23 |
28 | )) 29 | Alert.displayName = "Alert" 30 | 31 | const AlertTitle = React.forwardRef(({ className, ...props }, ref) => ( 32 |
36 | )) 37 | AlertTitle.displayName = "AlertTitle" 38 | 39 | const AlertDescription = React.forwardRef(({ className, ...props }, ref) => ( 40 |
44 | )) 45 | AlertDescription.displayName = "AlertDescription" 46 | 47 | export { Alert, AlertTitle, AlertDescription } 48 | -------------------------------------------------------------------------------- /app/src/components/ui/avatar.jsx: -------------------------------------------------------------------------------- 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(({ className, ...props }, ref) => ( 7 | 11 | )) 12 | Avatar.displayName = AvatarPrimitive.Root.displayName 13 | 14 | const AvatarImage = React.forwardRef(({ className, ...props }, ref) => ( 15 | 19 | )) 20 | AvatarImage.displayName = AvatarPrimitive.Image.displayName 21 | 22 | const AvatarFallback = React.forwardRef(({ className, ...props }, ref) => ( 23 | 30 | )) 31 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName 32 | 33 | export { Avatar, AvatarImage, AvatarFallback } 34 | -------------------------------------------------------------------------------- /app/src/components/ui/badge.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva } 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 | function Badge({ 27 | className, 28 | variant, 29 | ...props 30 | }) { 31 | return (
); 32 | } 33 | 34 | export { Badge, badgeVariants } 35 | -------------------------------------------------------------------------------- /app/src/components/ui/breadcrumb.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { ChevronRight, MoreHorizontal } from "lucide-react" 4 | 5 | import { cn } from "~/lib/utils" 6 | 7 | const Breadcrumb = React.forwardRef( 8 | ({ ...props }, ref) =>