├── .env.example ├── .gitignore ├── LICENSE ├── README.md ├── app ├── dashboard │ ├── chat │ │ └── page.tsx │ ├── editor │ │ ├── page.tsx │ │ └── snippet │ │ │ └── [id] │ │ │ └── page.tsx │ ├── layout.tsx │ ├── page.tsx │ ├── quizzes │ │ ├── page.tsx │ │ └── play │ │ │ └── [id] │ │ │ └── page.tsx │ ├── roadmaps │ │ ├── [id] │ │ │ └── page.tsx │ │ ├── create │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ └── page.tsx │ ├── settings │ │ └── page.tsx │ └── snippets │ │ └── page.tsx ├── globals.css ├── layout.tsx ├── page.tsx ├── providers.tsx ├── sign-in │ └── page.tsx └── unauthorized │ └── page.tsx ├── bun.lock ├── components.json ├── components ├── FeatureGuard.tsx ├── dashboard │ ├── chat-interface.tsx │ ├── code-editor.tsx │ ├── dashboard-stats.tsx │ ├── quick-actions.tsx │ ├── quiz-manager.tsx │ ├── recent-activity.tsx │ ├── roadmap-manager.tsx │ ├── sidebar.tsx │ └── snippets-manager.tsx ├── landing │ ├── cta.tsx │ ├── faq.tsx │ ├── features.tsx │ ├── footer.tsx │ ├── hero.tsx │ ├── navbar.tsx │ └── team.tsx ├── protected-route.tsx ├── snippet-card.tsx ├── theme-provider.tsx ├── theme-switch.tsx └── 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 │ ├── fancy-cta.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 │ ├── sidebar-keyboard-shortcut.tsx │ ├── sidebar.tsx │ ├── skeleton.tsx │ ├── slider.tsx │ ├── sonner.tsx │ ├── sparkles-text.tsx │ ├── switch.tsx │ ├── table.tsx │ ├── tabs.tsx │ ├── textarea.tsx │ ├── toast.tsx │ ├── toaster.tsx │ ├── toggle-group.tsx │ ├── toggle.tsx │ ├── tooltip.tsx │ ├── use-mobile.tsx │ └── use-toast.ts ├── contexts └── auth-context.tsx ├── hooks ├── use-mobile.tsx └── use-toast.ts ├── lib ├── ai │ ├── chat-ai.ts │ └── roadmap-ai.ts ├── code-execution.ts ├── getTraits.ts ├── quiz-generation.ts ├── supported-languages.ts └── utils.ts ├── middleware.ts ├── next.config.mjs ├── package.json ├── postcss.config.mjs ├── providers └── FeatureFlagProvider.tsx ├── store ├── chatStore.ts ├── quizStore.ts ├── roadmapStore.ts └── snippetStore.ts ├── tailwind.config.ts └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_RAPIDAPI_KEY=your_rapidapi_key 2 | NEXT_PUBLIC_GEMINI_API_KEY=your_gemini_api_key 3 | FLAGSMITH_ENVIRONMENT_ID=your_flagsmith_environment_id -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # next.js 7 | /.next/ 8 | /out/ 9 | 10 | # production 11 | /build 12 | 13 | # debug 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | .pnpm-debug.log* 18 | 19 | # env files 20 | .env 21 | 22 | # vercel 23 | .vercel 24 | 25 | # typescript 26 | *.tsbuildinfo 27 | next-env.d.ts -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

🧠 CodeMonkey 🧠

2 |

Supercharge Your Coding Journey with AI-Powered Tools

3 | 4 |

5 | 6 |

7 | 8 | > [!NOTE] 9 | > 10 | > CodeMonkey is an AI-powered platform designed to help developers learn, practice, and improve their coding skills. It combines AI chat assistance, interactive quizzes, personalized learning roadmaps, and coding tools in one integrated environment. 11 | 12 | ## 🌟 Features 13 | 14 | > **CodeMonkey** offers a comprehensive suite of tools for modern developers: 15 | 16 | - **AI Chat Assistant** – Get instant help with coding problems, explanations of complex concepts, and personalized guidance from our AI assistant 17 | - **Interactive Quizzes** – Test your knowledge with AI-generated quizzes tailored to your learning goals and skill level 18 | - **Learning Roadmaps** – Follow structured learning paths designed to take you from beginner to expert in any programming domain 19 | - **Code Editor** – Write, run, and debug code directly in your browser with our powerful integrated development environment 20 | - **Snippet Manager** – Save and organize your code snippets for easy access and reuse across your projects 21 | - **Personalized Learning** – Our AI analyzes your progress and adapts content to focus on areas where you need the most improvement 22 | 23 | ## 💫 Why Choose CodeMonkey? 24 | 25 | - **AI-Powered Learning** – Our advanced AI understands your learning style and adapts content to help you learn faster 26 | - **All-in-One Platform** – No need to switch between different tools – everything you need is integrated in one place 27 | - **Privacy Focused** – Your code and learning data stay private and secure with end-to-end encryption 28 | 29 | ## 💻 Installation 30 | 31 | > Get started with CodeMonkey in just a few steps: 32 | 33 | ```bash 34 | # Clone the repository 35 | git clone https://github.com/kom-senapati/code-monkey.git 36 | 37 | # Navigate to the project directory 38 | cd code-monkey 39 | 40 | # Install dependencies 41 | bun install 42 | 43 | # Start the development server 44 | bun dev 45 | ``` 46 | 47 | 54 | 55 | --- 56 | 57 | ## 👤 Authors 58 | 59 | 60 | 61 | 62 | 71 | 80 | 81 | 82 |
63 | 64 | Rohith Singh 65 |
66 | Rohith Singh 67 |
68 | Founder 69 |
70 |
72 | 73 | K Om Senapati 74 |
75 | K Om Senapati 76 |
77 | Developer 78 |
79 |
83 | 84 | --- 85 | 86 |

📄 License

87 | 88 |

89 | CodeMonkey is licensed under the Unlicense License. See the LICENSE file for more details. 90 |

91 | 92 | --- 93 | 94 |

95 | 🌟 If you find CodeMonkey helpful, please give it a star on GitHub! 🌟 96 |

97 | -------------------------------------------------------------------------------- /app/dashboard/chat/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { ChatInterface } from "@/components/dashboard/chat-interface" 4 | 5 | export default function ChatPage() { 6 | return ( 7 |
8 |

AI Chat Assistant

9 |

10 | Chat with your AI assistant about code, get explanations, or ask for help with problems. 11 |

12 | 13 |
14 | ) 15 | } 16 | 17 | -------------------------------------------------------------------------------- /app/dashboard/layout.tsx: -------------------------------------------------------------------------------- 1 | import type React from "react" 2 | import { SidebarProvider } from "@/components/ui/sidebar" 3 | import { DashboardSidebar } from "@/components/dashboard/sidebar" 4 | import { SidebarToggleButton, SidebarKeyboardShortcut } from "@/components/ui/sidebar-keyboard-shortcut" 5 | import { cookies } from "next/headers" 6 | 7 | export default async function DashboardLayout({ 8 | children, 9 | }: { 10 | children: React.ReactNode 11 | }) { 12 | const cookieStore = await cookies() 13 | const defaultOpen = cookieStore.get("sidebar:state")?.value !== "false" 14 | 15 | return ( 16 | 17 |
18 | 19 | 20 | 21 |
{children}
22 |
23 |
24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /app/dashboard/quizzes/page.tsx: -------------------------------------------------------------------------------- 1 | import { QuizManager } from "@/components/dashboard/quiz-manager" 2 | 3 | export default function QuizzesPage() { 4 | return ( 5 |
6 |

Quiz Bot

7 |

8 | Create, edit, and take coding quizzes. Generate new quizzes from any topic or code snippet. 9 |

10 | 11 | 12 |
13 | ) 14 | } 15 | 16 | -------------------------------------------------------------------------------- /app/dashboard/roadmaps/create/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState } from "react" 4 | import { useRouter } from "next/navigation" 5 | import { ArrowLeft } from "lucide-react" 6 | import { Button } from "@/components/ui/button" 7 | import { Input } from "@/components/ui/input" 8 | import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" 9 | import { Label } from "@/components/ui/label" 10 | import Link from "next/link" 11 | import { generateRoadmap } from "@/lib/ai/roadmap-ai" 12 | import { useRoadmapStore } from "@/store/roadmapStore" 13 | 14 | export default function CreateRoadmapPage() { 15 | const router = useRouter() 16 | const [topic, setTopic] = useState("") 17 | const [isGenerating, setIsGenerating] = useState(false) 18 | const [error, setError] = useState(null) 19 | const { addRoadmap } = useRoadmapStore() 20 | 21 | const handleGenerate = async () => { 22 | if (!topic.trim()) return 23 | 24 | setIsGenerating(true) 25 | setError(null) 26 | 27 | try { 28 | const roadmap = await generateRoadmap(topic) 29 | addRoadmap(roadmap) 30 | router.push(`/dashboard/roadmaps/${roadmap.id}`) 31 | } catch (err) { 32 | console.error("Error generating roadmap:", err) 33 | setError("Failed to generate roadmap. Please try again with a different topic.") 34 | } finally { 35 | setIsGenerating(false) 36 | } 37 | } 38 | 39 | return ( 40 |
41 | 47 | 48 |
49 |

Create New Learning Roadmap

50 | 51 | 52 | 53 | Generate with AI 54 | 55 | Enter a topic to generate a personalized learning roadmap using AI 56 | 57 | 58 | 59 |
60 |
61 | 62 | setTopic(e.target.value)} 67 | className="w-full" 68 | /> 69 |

70 | Be specific to get better results. Include skill level if relevant. 71 |

72 |
73 | 74 | {error &&

{error}

} 75 | 76 | 90 |
91 |
92 |
93 | 94 |
95 |

Tips for better roadmaps:

96 |
    97 |
  • Specify the technology or skill area (e.g., "Flutter app development")
  • 98 |
  • Include your experience level (e.g., "beginner Python machine learning")
  • 99 |
  • Mention specific goals (e.g., "building a fullstack web application")
  • 100 |
101 |
102 |
103 |
104 | ) 105 | } -------------------------------------------------------------------------------- /app/dashboard/roadmaps/layout.tsx: -------------------------------------------------------------------------------- 1 | import { FeatureGuard } from '@/components/FeatureGuard'; 2 | 3 | export default function RoadmapsLayout({ 4 | children, 5 | }: { 6 | children: React.ReactNode; 7 | }) { 8 | return ( 9 | 10 | {children} 11 | 12 | ); 13 | } -------------------------------------------------------------------------------- /app/dashboard/roadmaps/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useEffect } from "react" 4 | import Link from "next/link" 5 | import { useRouter } from "next/navigation" 6 | import { PlusCircle, BookOpen, ArrowRight, Menu } from "lucide-react" 7 | import { Button } from "@/components/ui/button" 8 | import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" 9 | import { Badge } from "@/components/ui/badge" 10 | import { Progress } from "@/components/ui/progress" 11 | import { useRoadmapStore } from "@/store/roadmapStore" 12 | 13 | export default function RoadmapsPage() { 14 | const { roadmaps, setActiveRoadmap } = useRoadmapStore() 15 | const router = useRouter() 16 | 17 | useEffect(() => { 18 | setActiveRoadmap(null) 19 | }, [setActiveRoadmap]) 20 | 21 | const formatDate = (date: Date) => { 22 | return new Date(date).toLocaleDateString('en-US', { 23 | month: 'short', 24 | day: 'numeric', 25 | year: 'numeric' 26 | }) 27 | } 28 | 29 | return ( 30 |
31 |
32 |

Learning Roadmaps

33 | 39 |
40 | 41 | {roadmaps.length === 0 ? ( 42 | 43 | 44 | 45 |

No roadmaps yet

46 |

47 | Create your first learning roadmap to organize your educational journey 48 |

49 | 55 |
56 |
57 | ) : ( 58 |
59 | {roadmaps.map((roadmap) => ( 60 | 61 | 62 |
63 | {roadmap.category} 64 | 65 | Created: {formatDate(roadmap.created)} 66 | 67 |
68 | {roadmap.title} 69 | 70 | {roadmap.description} 71 | 72 |
73 | 74 |
75 |
76 | Progress 77 | {roadmap.progress}% 78 |
79 | 80 |
81 |
82 |
Learning Path
83 |
    84 | {roadmap.steps.slice(0, 3).map((step, i) => ( 85 |
  • 86 |
    87 | {step.title} 88 |
  • 89 | ))} 90 | {roadmap.steps.length > 3 && ( 91 |
  • 92 | +{roadmap.steps.length - 3} more steps 93 |
  • 94 | )} 95 |
96 |
97 |
98 | 99 | 105 | 106 |
107 | ))} 108 |
109 | )} 110 |
111 | ) 112 | } 113 | 114 | -------------------------------------------------------------------------------- /app/dashboard/snippets/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { SnippetsManager } from "@/components/dashboard/snippets-manager" 4 | 5 | export default function SnippetsPage() { 6 | return ( 7 |
8 |

Snippets Manager

9 |

10 | Store, organize, and reuse your code snippets. Send them to AI chat for analysis or generate quizzes. 11 |

12 | 13 | 14 |
15 | ) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 240 10% 3.9%; 9 | --card: 0 0% 100%; 10 | --card-foreground: 240 10% 3.9%; 11 | --popover: 0 0% 100%; 12 | --popover-foreground: 240 10% 3.9%; 13 | --primary: 240 5.9% 10%; 14 | --primary-foreground: 0 0% 98%; 15 | --secondary: 240 4.8% 95.9%; 16 | --secondary-foreground: 240 5.9% 10%; 17 | --muted: 240 4.8% 95.9%; 18 | --muted-foreground: 240 3.8% 46.1%; 19 | --accent: 240 4.8% 95.9%; 20 | --accent-foreground: 240 5.9% 10%; 21 | --destructive: 0 84.2% 60.2%; 22 | --destructive-foreground: 0 0% 98%; 23 | --border: 240 5.9% 90%; 24 | --input: 240 5.9% 90%; 25 | --ring: 240 5.9% 10%; 26 | --radius: 0.5rem; 27 | --sidebar: 0 0% 98%; 28 | --sidebar-foreground: 240 5.3% 26.1%; 29 | --sidebar-primary: 240 5.9% 10%; 30 | --sidebar-primary-foreground: 0 0% 98%; 31 | --sidebar-accent: 240 4.8% 95.9%; 32 | --sidebar-accent-foreground: 240 5.9% 10%; 33 | --sidebar-border: 220 13% 91%; 34 | --sidebar-ring: 217.2 91.2% 59.8%; 35 | } 36 | 37 | .dark { 38 | --background: 240 10% 3.9%; 39 | --foreground: 0 0% 98%; 40 | --card: 240 10% 3.9%; 41 | --card-foreground: 0 0% 98%; 42 | --popover: 240 10% 3.9%; 43 | --popover-foreground: 0 0% 98%; 44 | --primary: 0 0% 98%; 45 | --primary-foreground: 240 5.9% 10%; 46 | --secondary: 240 3.7% 15.9%; 47 | --secondary-foreground: 0 0% 98%; 48 | --muted: 240 3.7% 15.9%; 49 | --muted-foreground: 240 5% 64.9%; 50 | --accent: 240 3.7% 15.9%; 51 | --accent-foreground: 0 0% 98%; 52 | --destructive: 0 62.8% 30.6%; 53 | --destructive-foreground: 0 0% 98%; 54 | --border: 240 3.7% 15.9%; 55 | --input: 240 3.7% 15.9%; 56 | --ring: 240 4.9% 83.9%; 57 | --sidebar: 240 5.9% 10%; 58 | --sidebar-foreground: 240 4.8% 95.9%; 59 | --sidebar-primary: 0 0% 98%; 60 | --sidebar-primary-foreground: 240 5.9% 10%; 61 | --sidebar-accent: 240 3.7% 15.9%; 62 | --sidebar-accent-foreground: 240 4.8% 95.9%; 63 | --sidebar-border: 240 3.7% 15.9%; 64 | --sidebar-ring: 217.2 91.2% 59.8%; 65 | } 66 | } 67 | 68 | @layer base { 69 | * { 70 | @apply border-border; 71 | } 72 | body { 73 | @apply bg-background text-foreground; 74 | } 75 | } 76 | 77 | .bg-grid-pattern { 78 | background-image: linear-gradient(to right, rgba(0, 0, 0, 0.1) 1px, transparent 1px), 79 | linear-gradient(to bottom, rgba(0, 0, 0, 0.1) 1px, transparent 1px); 80 | background-size: 20px 20px; 81 | } 82 | 83 | .dark .bg-grid-pattern { 84 | background-image: linear-gradient(to right, rgba(255, 255, 255, 0.1) 1px, transparent 1px), 85 | linear-gradient(to bottom, rgba(255, 255, 255, 0.1) 1px, transparent 1px); 86 | background-size: 20px 20px; 87 | } 88 | 89 | .toggle { 90 | @apply relative h-6 w-11 cursor-pointer appearance-none rounded-full bg-muted transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50; 91 | } 92 | 93 | .toggle:checked { 94 | @apply bg-primary; 95 | } 96 | 97 | .toggle::before { 98 | content: ""; 99 | @apply block h-5 w-5 translate-x-0.5 rounded-full bg-background shadow-sm transition-transform; 100 | } 101 | 102 | .toggle:checked::before { 103 | @apply translate-x-5; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type React from "react" 2 | import { Inter } from "next/font/google" 3 | import type { Metadata } from "next" 4 | import { ThemeProvider } from "@/components/theme-provider" 5 | import { AuthProvider } from "@/contexts/auth-context" 6 | import "./globals.css" 7 | import { FeatureFlagProvider } from '@/providers/FeatureFlagProvider'; 8 | import { createFlagsmithInstance } from "flagsmith/isomorphic" 9 | import getTraits from "@/lib/getTraits" 10 | 11 | const inter = Inter({ subsets: ["latin"] }) 12 | 13 | export const metadata: Metadata = { 14 | title: "CodeMonkey - Developer Dashboard", 15 | description: "AI-powered developer tools and resources", 16 | } 17 | 18 | export default async function RootLayout({ 19 | children, 20 | }: { 21 | children: React.ReactNode 22 | }) { 23 | const flagsmith = createFlagsmithInstance() 24 | const data = await getTraits(); 25 | await flagsmith.init({ 26 | environmentID: process.env.FLAGSMITH_ENVIRONMENT_ID || '', 27 | identity: data.username, 28 | traits: { 29 | userId: data.userId, 30 | username: data.username, 31 | email: data.email, 32 | isPremium: data.isPremium || false, 33 | }, 34 | }) 35 | const serverState = flagsmith.getState() 36 | 37 | return ( 38 | 39 | 40 | 41 | 42 | 43 | {children} 44 | 45 | 46 | 47 | 48 | 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import { Navbar } from "@/components/landing/navbar" 2 | import { Hero } from "@/components/landing/hero" 3 | import { Features } from "@/components/landing/features" 4 | import { Cta } from "@/components/landing/cta" 5 | import { Faq } from "@/components/landing/faq" 6 | import { Footer } from "@/components/landing/footer" 7 | import { TeamSection } from "@/components/landing/team" 8 | 9 | export default function LandingPage() { 10 | return ( 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 | ) 21 | } 22 | 23 | -------------------------------------------------------------------------------- /app/providers.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import React from "react" 4 | import { AuthProvider } from "@/contexts/auth-context" 5 | 6 | export function Providers({ children }: { children: React.ReactNode }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } -------------------------------------------------------------------------------- /app/sign-in/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import type React from "react" 4 | 5 | import { useState } from "react" 6 | import { useRouter } from "next/navigation" 7 | import Link from "next/link" 8 | import { ArrowLeft, BrainCircuit, Loader2 } from "lucide-react" 9 | import { Button } from "@/components/ui/button" 10 | import { Input } from "@/components/ui/input" 11 | import { Label } from "@/components/ui/label" 12 | import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" 13 | import { useToast } from "@/hooks/use-toast" 14 | import { useAuth } from "@/contexts/auth-context" 15 | 16 | export default function SignInPage() { 17 | const router = useRouter() 18 | const { toast } = useToast() 19 | const { login } = useAuth() 20 | const [isLoading, setIsLoading] = useState(false) 21 | const [formData, setFormData] = useState({ 22 | username: "", 23 | password: "", 24 | }) 25 | 26 | const handleChange = (e: React.ChangeEvent) => { 27 | const { name, value } = e.target 28 | setFormData((prev) => ({ ...prev, [name]: value })) 29 | } 30 | 31 | const handleSubmit = async (e: React.FormEvent) => { 32 | e.preventDefault() 33 | setIsLoading(true) 34 | 35 | try { 36 | const user = await login(formData.username, formData.password) 37 | toast({ 38 | title: "Sign in successful", 39 | description: `Welcome back, ${user.name}!`, 40 | }) 41 | router.push("/dashboard") 42 | } catch (error) { 43 | toast({ 44 | title: "Authentication failed", 45 | description: "Invalid username or password. Try admin/12345", 46 | variant: "destructive", 47 | }) 48 | setIsLoading(false) 49 | } 50 | } 51 | 52 | return ( 53 |
54 | 55 | 59 | 60 | 61 |
62 | 63 |

CodeMonkey

64 |
65 | 66 | 67 | 68 | Sign In 69 | Enter your credentials to access your account 70 | 71 |
72 | 73 |
74 | 75 | 83 |
84 |
85 |
86 | 87 | 88 | Forgot password? 89 | 90 |
91 | 100 |
101 |
102 | Available accounts: 103 |
    104 |
  • admin (Premium)
  • 105 |
  • dev1 (Premium)
  • 106 |
  • user (Free)
  • 107 |
108 |

All passwords: 12345

109 |
110 |
111 | 112 | 122 | 123 |
124 |
125 |
126 | ) 127 | } 128 | 129 | -------------------------------------------------------------------------------- /app/unauthorized/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import Link from "next/link" 4 | import { ArrowLeft, ShieldAlert } from "lucide-react" 5 | import { Button } from "@/components/ui/button" 6 | import { useAuth } from "@/contexts/auth-context" 7 | 8 | export default function UnauthorizedPage() { 9 | const { user } = useAuth() 10 | 11 | return ( 12 |
13 |
14 | 15 |

Access Denied

16 |

17 | {user 18 | ? "Sorry, you don't have permission to access this page." 19 | : "You need to be logged in to access this page."} 20 |

21 |
22 | 23 | 27 | 28 | {!user && ( 29 | 30 | 31 | 32 | )} 33 |
34 |
35 |
36 | ) 37 | } -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.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 | } -------------------------------------------------------------------------------- /components/FeatureGuard.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useFeatureFlags } from '@/providers/FeatureFlagProvider'; 4 | import { useRouter } from 'next/navigation'; 5 | import { useEffect, ReactNode, useState } from 'react'; 6 | 7 | interface FeatureGuardProps { 8 | children: ReactNode; 9 | featureName: keyof ReturnType; 10 | redirectTo?: string; 11 | refreshInterval?: number | null; 12 | } 13 | 14 | export const FeatureGuard = ({ 15 | children, 16 | featureName, 17 | redirectTo = '/dashboard', 18 | refreshInterval = null 19 | }: FeatureGuardProps) => { 20 | const featureFlags = useFeatureFlags(); 21 | const router = useRouter(); 22 | const isEnabled = featureFlags[featureName]; 23 | const [isInitialCheck, setIsInitialCheck] = useState(true); 24 | const [isRefreshing, setIsRefreshing] = useState(false); 25 | 26 | // Initial check for feature flag 27 | useEffect(() => { 28 | if (isInitialCheck) { 29 | // Only refresh flags once during initial check if feature isn't enabled 30 | if (!isEnabled) { 31 | setIsRefreshing(true); 32 | featureFlags.refreshFlags() 33 | .then(() => { 34 | setIsRefreshing(false); 35 | setIsInitialCheck(false); 36 | }) 37 | .catch(error => { 38 | console.error('Error refreshing flags:', error); 39 | setIsRefreshing(false); 40 | setIsInitialCheck(false); 41 | }); 42 | } else { 43 | // If feature is already enabled, no need to refresh 44 | setIsInitialCheck(false); 45 | } 46 | } 47 | }, [isEnabled, featureFlags, isInitialCheck]); 48 | 49 | // Redirect if feature is not enabled after initial check 50 | useEffect(() => { 51 | if (!isEnabled && !isInitialCheck && !isRefreshing) { 52 | router.push(redirectTo); 53 | } 54 | }, [isEnabled, router, redirectTo, isInitialCheck, isRefreshing]); 55 | 56 | // Set up periodic refreshing if requested 57 | useEffect(() => { 58 | if (refreshInterval) { 59 | const interval = setInterval(() => { 60 | // Don't trigger another refresh if already refreshing 61 | if (!isRefreshing) { 62 | setIsRefreshing(true); 63 | featureFlags.refreshFlags() 64 | .then(() => { 65 | setIsRefreshing(false); 66 | }) 67 | .catch(error => { 68 | console.error('Error refreshing flags:', error); 69 | setIsRefreshing(false); 70 | }); 71 | } 72 | }, refreshInterval); 73 | 74 | return () => clearInterval(interval); 75 | } 76 | }, [featureFlags, refreshInterval, isRefreshing]); 77 | 78 | // Show loading state during initial check or refreshing 79 | if (isInitialCheck || isRefreshing) { 80 | // You might want to return a loading indicator here instead of null 81 | return null; 82 | } 83 | 84 | // If feature is disabled after checks, hide content and redirect 85 | if (!isEnabled) { 86 | return null; 87 | } 88 | 89 | // Feature is enabled, show the content 90 | return <>{children}; 91 | }; -------------------------------------------------------------------------------- /components/dashboard/dashboard-stats.tsx: -------------------------------------------------------------------------------- 1 | import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" 2 | import { MessageSquare, BookOpen, Map, Code, FileCode } from "lucide-react" 3 | 4 | export function DashboardStats() { 5 | const stats = [ 6 | { 7 | title: "AI Chat Messages", 8 | value: "128", 9 | icon: MessageSquare, 10 | description: "Past 30 days", 11 | }, 12 | { 13 | title: "Quizzes Created", 14 | value: "14", 15 | icon: BookOpen, 16 | description: "Total quizzes", 17 | }, 18 | { 19 | title: "Learning Roadmaps", 20 | value: "5", 21 | icon: Map, 22 | description: "Active roadmaps", 23 | }, 24 | { 25 | title: "Code Snippets", 26 | value: "42", 27 | icon: FileCode, 28 | description: "Saved snippets", 29 | }, 30 | { 31 | title: "Coding Sessions", 32 | value: "23", 33 | icon: Code, 34 | description: "This month", 35 | }, 36 | ] 37 | 38 | return ( 39 | <> 40 | {stats.map((stat) => ( 41 | 42 | 43 | {stat.title} 44 | 45 | 46 | 47 |
{stat.value}
48 |

{stat.description}

49 |
50 |
51 | ))} 52 | 53 | ) 54 | } 55 | 56 | -------------------------------------------------------------------------------- /components/dashboard/quick-actions.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "@/components/ui/button" 2 | import { MessageSquare, BookOpen, Map, Code, FileCode } from "lucide-react" 3 | import Link from "next/link" 4 | 5 | export function QuickActions() { 6 | const actions = [ 7 | { 8 | title: "Start AI Chat", 9 | icon: MessageSquare, 10 | href: "/chat", 11 | variant: "default" as const, 12 | }, 13 | { 14 | title: "Create New Quiz", 15 | icon: BookOpen, 16 | href: "/quizzes/new", 17 | variant: "outline" as const, 18 | }, 19 | { 20 | title: "Generate Roadmap", 21 | icon: Map, 22 | href: "/roadmaps/new", 23 | variant: "outline" as const, 24 | }, 25 | { 26 | title: "Open Code Editor", 27 | icon: Code, 28 | href: "/editor", 29 | variant: "outline" as const, 30 | }, 31 | { 32 | title: "Add Code Snippet", 33 | icon: FileCode, 34 | href: "/snippets/new", 35 | variant: "outline" as const, 36 | }, 37 | ] 38 | 39 | return ( 40 |
41 | {actions.map((action) => ( 42 | 48 | ))} 49 |
50 | ) 51 | } 52 | 53 | -------------------------------------------------------------------------------- /components/dashboard/recent-activity.tsx: -------------------------------------------------------------------------------- 1 | import { Avatar, AvatarFallback } from "@/components/ui/avatar" 2 | 3 | export function RecentActivity() { 4 | const activities = [ 5 | { 6 | id: 1, 7 | type: "chat", 8 | title: "AI Chat Session", 9 | description: "Asked about React hooks optimization", 10 | time: "2 hours ago", 11 | icon: "AI", 12 | }, 13 | { 14 | id: 2, 15 | type: "quiz", 16 | title: "Completed Quiz", 17 | description: "JavaScript Promises - Score: 8/10", 18 | time: "Yesterday", 19 | icon: "Q", 20 | }, 21 | { 22 | id: 3, 23 | type: "roadmap", 24 | title: "Roadmap Updated", 25 | description: "Added new milestone to Backend Development path", 26 | time: "2 days ago", 27 | icon: "R", 28 | }, 29 | { 30 | id: 4, 31 | type: "snippet", 32 | title: "New Snippet Created", 33 | description: "React custom hook for form validation", 34 | time: "3 days ago", 35 | icon: "S", 36 | }, 37 | { 38 | id: 5, 39 | type: "editor", 40 | title: "Code Execution", 41 | description: "Ran TypeScript algorithm solution", 42 | time: "4 days ago", 43 | icon: "C", 44 | }, 45 | ] 46 | 47 | return ( 48 |
49 | {activities.map((activity) => ( 50 |
51 | 52 | {activity.icon} 53 | 54 |
55 |

{activity.title}

56 |

{activity.description}

57 |
58 |
{activity.time}
59 |
60 | ))} 61 |
62 | ) 63 | } 64 | 65 | -------------------------------------------------------------------------------- /components/landing/cta.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { SimpleCard_V7 } from "../ui/fancy-cta" 4 | 5 | export function Cta() { 6 | return ( 7 |
8 | 12 |
13 | ) 14 | } 15 | 16 | -------------------------------------------------------------------------------- /components/landing/faq.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState } from "react" 4 | import { motion } from "framer-motion" 5 | import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion" 6 | 7 | const faqs = [ 8 | { 9 | question: "What is CodeMonkey?", 10 | answer: 11 | "CodeMonkey is an AI-powered platform designed to help developers learn, practice, and improve their coding skills. It combines AI chat assistance, interactive quizzes, personalized learning roadmaps, and coding tools in one integrated environment.", 12 | }, 13 | { 14 | question: "Do I need to be an experienced programmer to use CodeMonkey?", 15 | answer: 16 | "Not at all! CodeMonkey is designed for developers of all skill levels, from beginners to experts. Our AI adapts to your knowledge level and provides appropriate guidance and challenges.", 17 | }, 18 | { 19 | question: "How does the AI chat assistant work?", 20 | answer: 21 | "Our AI chat assistant uses advanced language models to understand your coding questions and provide helpful, contextual responses. You can ask about specific programming concepts, get help debugging code, or receive guidance on best practices.", 22 | }, 23 | { 24 | question: "How are the learning roadmaps created?", 25 | answer: 26 | "Our learning roadmaps are designed by experienced developers and educators, then personalized by our AI based on your goals and current skill level. Each roadmap provides a structured path to master specific technologies or concepts.", 27 | }, 28 | { 29 | question: "Is my code secure on CodeMonkey?", 30 | answer: 31 | "Absolutely. We take security seriously and use encryption to protect your code and personal data. Your code is private by default and only shared when you explicitly choose to do so.", 32 | }, 33 | ] 34 | 35 | export function Faq() { 36 | const [openItems, setOpenItems] = useState([]) 37 | 38 | const toggleItem = (value: string) => { 39 | setOpenItems((prev) => (prev.includes(value) ? prev.filter((item) => item !== value) : [...prev, value])) 40 | } 41 | 42 | return ( 43 |
44 |
45 |
46 | 52 |

Frequently Asked Questions

53 |

54 | Got questions? We've got answers. If you don't see what you're looking for, feel free to contact us. 55 |

56 |
57 |
58 | 59 | 66 | 67 | {faqs.map((faq, index) => ( 68 | 69 | {faq.question} 70 | {faq.answer} 71 | 72 | ))} 73 | 74 | 75 | 76 | 83 |

84 | Still have questions?{" "} 85 | 86 | Contact our team 87 | 88 |

89 |
90 |
91 |
92 | ) 93 | } 94 | -------------------------------------------------------------------------------- /components/landing/footer.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { motion } from "framer-motion"; 4 | import Link from "next/link"; 5 | import { BrainCircuit, Github, Twitter, Linkedin } from "lucide-react"; 6 | 7 | export function Footer() { 8 | return ( 9 |
10 |
11 | 12 |
13 | 14 | 19 | 20 | 21 | 22 | 28 | Codemonkey - Built for hackers, by hackers. 29 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 54 | © {new Date().getFullYear()} Codemonkey. All rights reserved. 55 | 56 |
57 |
58 | ); 59 | } -------------------------------------------------------------------------------- /components/landing/navbar.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState, useEffect } from "react" 4 | import Link from "next/link" 5 | import { BrainCircuit, Menu, X, User, Github } from "lucide-react" 6 | import { Button } from "@/components/ui/button" 7 | import { cn } from "@/lib/utils" 8 | 9 | export function Navbar() { 10 | const [isScrolled, setIsScrolled] = useState(false) 11 | 12 | useEffect(() => { 13 | const handleScroll = () => { 14 | setIsScrolled(window.scrollY > 10) 15 | } 16 | window.addEventListener("scroll", handleScroll) 17 | return () => window.removeEventListener("scroll", handleScroll) 18 | }, []) 19 | 20 | return ( 21 |
26 |
27 | {!isScrolled && ( 28 | 29 | 30 | CodeMonkey 31 | 32 | )} 33 | 34 | 45 | 46 | {!isScrolled && ( 47 |
48 | 49 | 52 | 53 | 54 | 57 | 58 |
59 | )} 60 |
61 |
62 | ) 63 | } 64 | 65 | -------------------------------------------------------------------------------- /components/landing/team.tsx: -------------------------------------------------------------------------------- 1 | import { Card, CardContent } from "@/components/ui/card"; 2 | import { GithubIcon } from "lucide-react"; 3 | import Link from "next/link"; 4 | import Image from "next/image"; 5 | 6 | interface TeamMemberProps { 7 | name: string; 8 | role: string; 9 | github: string; 10 | image: string; 11 | } 12 | 13 | const teamMembers: TeamMemberProps[] = [ 14 | { 15 | name: "Rohith Singh", 16 | role: "Founder", 17 | github: "https://github.com/rohittcodes", 18 | image: "https://github.com/rohittcodes.png", 19 | }, 20 | { 21 | name: "K Om Senapati", 22 | role: "Developer", 23 | github: "https://github.com/kom-senapati", 24 | image: "https://github.com/kom-senapati.png", 25 | }, 26 | ]; 27 | 28 | export const TeamSection = () => { 29 | return ( 30 |
31 |

32 | Our Team 33 |

34 | 35 |

36 | Meet the Developers 37 |

38 | 39 |

40 | Passionate developers building tools to help you become a better 41 | programmer. 42 |

43 | 44 |
45 | {teamMembers.map((member) => ( 46 | 47 | 48 |
49 |
50 | {member.name} 56 |
57 |

{member.name}

58 |

{member.role}

59 | 64 | 65 | GitHub 66 | 67 |
68 |
69 |
70 | ))} 71 |
72 |
73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /components/protected-route.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useEffect, useState } from "react" 4 | import { useRouter } from "next/navigation" 5 | import { useAuth } from "@/contexts/auth-context" 6 | 7 | interface ProtectedRouteProps { 8 | children: React.ReactNode 9 | } 10 | 11 | export function ProtectedRoute({ children }: ProtectedRouteProps) { 12 | const router = useRouter() 13 | const { user, isLoading } = useAuth() 14 | const [isMounted, setIsMounted] = useState(false) 15 | 16 | useEffect(() => { 17 | setIsMounted(true) 18 | }, []) 19 | 20 | useEffect(() => { 21 | if (isMounted && !isLoading && !user) { 22 | router.push("/sign-in") 23 | } 24 | }, [user, isLoading, router, isMounted]) 25 | 26 | if (!isMounted || isLoading) { 27 | return
Loading...
28 | } 29 | 30 | if (!user) { 31 | return null 32 | } 33 | 34 | return <>{children} 35 | } -------------------------------------------------------------------------------- /components/snippet-card.tsx: -------------------------------------------------------------------------------- 1 | import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card" 2 | import { Badge } from "@/components/ui/badge" 3 | import { CodeSquare } from "lucide-react" 4 | import { Snippet } from "@/store/snippetStore" 5 | import { cn } from "@/lib/utils" 6 | 7 | interface SnippetCardProps { 8 | snippet: Snippet 9 | isActive: boolean 10 | onClick: () => void 11 | } 12 | 13 | export function SnippetCard({ snippet, isActive, onClick }: SnippetCardProps) { 14 | return ( 15 | 22 | 23 | 24 | 25 | {snippet.title} 26 | 27 | 28 | 29 |

30 | {snippet.description} 31 |

32 |
33 | 34 | {snippet.language} 35 | 36 | {snippet.tags.slice(0, 2).map(tag => ( 37 | 38 | {tag} 39 | 40 | ))} 41 | {snippet.tags.length > 2 && ( 42 | 43 | +{snippet.tags.length - 2} 44 | 45 | )} 46 |
47 |
48 |
49 | ) 50 | } -------------------------------------------------------------------------------- /components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { 5 | ThemeProvider as NextThemesProvider, 6 | type ThemeProviderProps, 7 | } from 'next-themes' 8 | import { useFeatureFlags } from '@/providers/FeatureFlagProvider' 9 | 10 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 11 | const toggleTheme = useFeatureFlags().toggleTheme 12 | 13 | const modifiedProps = { 14 | ...props, 15 | forcedTheme: toggleTheme ? undefined : 'light' 16 | } 17 | 18 | return {children} 19 | } 20 | -------------------------------------------------------------------------------- /components/theme-switch.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useTheme } from "next-themes" 4 | import { Moon, Sun } from "lucide-react" 5 | import { Button } from "@/components/ui/button" 6 | import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" 7 | 8 | export function ThemeSwitch() { 9 | const { setTheme, forcedTheme } = useTheme() 10 | const isThemeForced = forcedTheme !== undefined 11 | 12 | return ( 13 | 14 | 15 | 20 | 21 | {!isThemeForced && ( 22 | 23 | setTheme("light")}>Light 24 | setTheme("dark")}>Dark 25 | setTheme("system")}>System 26 | 27 | )} 28 | 29 | ) 30 | } 31 | 32 | -------------------------------------------------------------------------------- /components/ui/accordion.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as AccordionPrimitive from "@radix-ui/react-accordion" 5 | import { ChevronDown } from "lucide-react" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const Accordion = AccordionPrimitive.Root 10 | 11 | const AccordionItem = React.forwardRef< 12 | React.ElementRef, 13 | React.ComponentPropsWithoutRef 14 | >(({ className, ...props }, ref) => ( 15 | 20 | )) 21 | AccordionItem.displayName = "AccordionItem" 22 | 23 | const AccordionTrigger = React.forwardRef< 24 | React.ElementRef, 25 | React.ComponentPropsWithoutRef 26 | >(({ className, children, ...props }, ref) => ( 27 | 28 | svg]:rotate-180", 32 | className 33 | )} 34 | {...props} 35 | > 36 | {children} 37 | 38 | 39 | 40 | )) 41 | AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName 42 | 43 | const AccordionContent = React.forwardRef< 44 | React.ElementRef, 45 | React.ComponentPropsWithoutRef 46 | >(({ className, children, ...props }, ref) => ( 47 | 52 |
{children}
53 |
54 | )) 55 | 56 | AccordionContent.displayName = AccordionPrimitive.Content.displayName 57 | 58 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } 59 | -------------------------------------------------------------------------------- /components/ui/alert-dialog.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" 5 | 6 | import { cn } from "@/lib/utils" 7 | import { buttonVariants } from "@/components/ui/button" 8 | 9 | const AlertDialog = AlertDialogPrimitive.Root 10 | 11 | const AlertDialogTrigger = AlertDialogPrimitive.Trigger 12 | 13 | const AlertDialogPortal = AlertDialogPrimitive.Portal 14 | 15 | const AlertDialogOverlay = React.forwardRef< 16 | React.ElementRef, 17 | React.ComponentPropsWithoutRef 18 | >(({ className, ...props }, ref) => ( 19 | 27 | )) 28 | AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName 29 | 30 | const AlertDialogContent = React.forwardRef< 31 | React.ElementRef, 32 | React.ComponentPropsWithoutRef 33 | >(({ className, ...props }, ref) => ( 34 | 35 | 36 | 44 | 45 | )) 46 | AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName 47 | 48 | const AlertDialogHeader = ({ 49 | className, 50 | ...props 51 | }: React.HTMLAttributes) => ( 52 |
59 | ) 60 | AlertDialogHeader.displayName = "AlertDialogHeader" 61 | 62 | const AlertDialogFooter = ({ 63 | className, 64 | ...props 65 | }: React.HTMLAttributes) => ( 66 |
73 | ) 74 | AlertDialogFooter.displayName = "AlertDialogFooter" 75 | 76 | const AlertDialogTitle = React.forwardRef< 77 | React.ElementRef, 78 | React.ComponentPropsWithoutRef 79 | >(({ className, ...props }, ref) => ( 80 | 85 | )) 86 | AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName 87 | 88 | const AlertDialogDescription = React.forwardRef< 89 | React.ElementRef, 90 | React.ComponentPropsWithoutRef 91 | >(({ className, ...props }, ref) => ( 92 | 97 | )) 98 | AlertDialogDescription.displayName = 99 | AlertDialogPrimitive.Description.displayName 100 | 101 | const AlertDialogAction = React.forwardRef< 102 | React.ElementRef, 103 | React.ComponentPropsWithoutRef 104 | >(({ className, ...props }, ref) => ( 105 | 110 | )) 111 | AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName 112 | 113 | const AlertDialogCancel = React.forwardRef< 114 | React.ElementRef, 115 | React.ComponentPropsWithoutRef 116 | >(({ className, ...props }, ref) => ( 117 | 126 | )) 127 | AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName 128 | 129 | export { 130 | AlertDialog, 131 | AlertDialogPortal, 132 | AlertDialogOverlay, 133 | AlertDialogTrigger, 134 | AlertDialogContent, 135 | AlertDialogHeader, 136 | AlertDialogFooter, 137 | AlertDialogTitle, 138 | AlertDialogDescription, 139 | AlertDialogAction, 140 | AlertDialogCancel, 141 | } 142 | -------------------------------------------------------------------------------- /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 p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", 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 | -------------------------------------------------------------------------------- /components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" 4 | 5 | const AspectRatio = AspectRatioPrimitive.Root 6 | 7 | export { AspectRatio } 8 | -------------------------------------------------------------------------------- /components/ui/avatar.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as AvatarPrimitive from "@radix-ui/react-avatar" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Avatar = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ className, ...props }, ref) => ( 12 | 20 | )) 21 | Avatar.displayName = AvatarPrimitive.Root.displayName 22 | 23 | const AvatarImage = React.forwardRef< 24 | React.ElementRef, 25 | React.ComponentPropsWithoutRef 26 | >(({ className, ...props }, ref) => ( 27 | 32 | )) 33 | AvatarImage.displayName = AvatarPrimitive.Image.displayName 34 | 35 | const AvatarFallback = React.forwardRef< 36 | React.ElementRef, 37 | React.ComponentPropsWithoutRef 38 | >(({ className, ...props }, ref) => ( 39 | 47 | )) 48 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName 49 | 50 | export { Avatar, AvatarImage, AvatarFallback } 51 | -------------------------------------------------------------------------------- /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-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", 8 | { 9 | variants: { 10 | variant: { 11 | default: 12 | "border-transparent bg-primary text-primary-foreground 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 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 | -------------------------------------------------------------------------------- /components/ui/breadcrumb.tsx: -------------------------------------------------------------------------------- 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 | HTMLElement, 9 | React.ComponentPropsWithoutRef<"nav"> & { 10 | separator?: React.ReactNode 11 | } 12 | >(({ ...props }, ref) =>