├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING ├── LICENSE ├── README.md ├── app ├── binary-tree │ ├── loading.tsx │ └── page.tsx ├── globals.css ├── graph │ └── page.tsx ├── graphs │ └── page.tsx ├── hash-table │ ├── loading.tsx │ └── page.tsx ├── icon.ico ├── layout.tsx ├── linked-list │ └── page.tsx ├── page.tsx ├── preload.js ├── queue │ └── page.tsx ├── queues │ └── page.tsx ├── stack │ └── page.tsx ├── stacks │ └── page.tsx ├── trees │ └── page.tsx └── tutorials │ ├── applications │ └── page.tsx │ ├── binary-tree │ ├── applications │ │ └── page.tsx │ ├── delete-operation │ │ └── page.tsx │ ├── insert-operation │ │ └── page.tsx │ ├── introduction │ │ └── page.tsx │ ├── layout.tsx │ ├── search-operation │ │ └── page.tsx │ └── traversal-operation │ │ └── page.tsx │ ├── creating-nodes │ └── page.tsx │ ├── deletion │ └── page.tsx │ ├── hash-table │ ├── applications │ │ └── page.tsx │ ├── delete-operation │ │ └── page.tsx │ ├── insert-operation │ │ └── page.tsx │ ├── introduction │ │ └── page.tsx │ └── search-operation │ │ └── page.tsx │ ├── insertion │ └── page.tsx │ ├── introduction │ └── page.tsx │ ├── queue │ ├── applications │ │ └── page.tsx │ ├── dequeue-operation │ │ └── page.tsx │ ├── enqueue-operation │ │ └── page.tsx │ ├── introduction │ │ └── page.tsx │ └── peek-operation │ │ └── page.tsx │ ├── searching │ └── page.tsx │ ├── stack │ ├── applications │ │ └── page.tsx │ ├── introduction │ │ └── page.tsx │ ├── operations │ │ └── page.tsx │ ├── peek-operation │ │ └── page.tsx │ ├── pop-operation │ │ └── page.tsx │ └── push-operation │ │ └── page.tsx │ └── traversal │ └── page.tsx ├── components.json ├── components ├── binary-tree-tutorial-layout.tsx ├── binary-tree │ ├── binary-tree-operations.tsx │ ├── binary-tree-properties.tsx │ └── binary-tree-visualizer.tsx ├── code-block.tsx ├── dynamic-tutorial-content.tsx ├── graph │ ├── graph-operations.tsx │ ├── graph-properties.tsx │ └── graph-visualizer.tsx ├── hash-table-tutorial-layout.tsx ├── hash-table │ ├── hash-table-operations.tsx │ ├── hash-table-properties.tsx │ └── hash-table-visualizer.tsx ├── interactive-exercise.tsx ├── linked-list-visualizer.tsx ├── optimized-image.tsx ├── queue-tutorial-layout.tsx ├── queue-visualizer.tsx ├── queue │ ├── queue-operations.tsx │ ├── queue-properties.tsx │ ├── queue-visualizer.tsx │ └── simple-queue-visualizer.tsx ├── stack-tutorial-layout.tsx ├── stack-visualizer.tsx ├── stack │ ├── stack-operations.tsx │ ├── stack-properties.tsx │ └── stack-visualizer.tsx ├── theme-provider.tsx ├── tutorial-layout.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 │ ├── code-block.tsx │ ├── collapsible.tsx │ ├── command.tsx │ ├── context-menu.tsx │ ├── dialog.tsx │ ├── drawer.tsx │ ├── dropdown-menu.tsx │ ├── form.tsx │ ├── hover-card.tsx │ ├── input-otp.tsx │ ├── input.tsx │ ├── label.tsx │ ├── menubar.tsx │ ├── navigation-menu.tsx │ ├── pagination.tsx │ ├── popover.tsx │ ├── progress.tsx │ ├── radio-group.tsx │ ├── resizable.tsx │ ├── scroll-area.tsx │ ├── select.tsx │ ├── separator.tsx │ ├── sheet.tsx │ ├── sidebar.tsx │ ├── skeleton.tsx │ ├── slider.tsx │ ├── sonner.tsx │ ├── switch.tsx │ ├── table.tsx │ ├── tabs.tsx │ ├── textarea.tsx │ ├── toast.tsx │ ├── toaster.tsx │ ├── toggle-group.tsx │ ├── toggle.tsx │ ├── tooltip.tsx │ ├── use-mobile.tsx │ └── use-toast.ts ├── hooks ├── use-mobile.tsx └── use-toast.ts ├── lib ├── data-structures │ ├── binary-tree.ts │ ├── graph.ts │ ├── hash-table.ts │ ├── queue.ts │ └── stack.ts └── utils.ts ├── next-env.d.ts ├── next.config.mjs ├── package.json ├── pnpm-lock.yaml ├── postcss.config.mjs ├── styles └── globals.css ├── tailwind.config.js ├── tasks.txt └── tsconfig.json /.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 -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | pauaranega20@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for your interest in contributing! Here’s how you can help: 4 | 5 | 1. **Fork the repo** and create a new branch. 6 | 2. **Make your changes** and test them. 7 | 3. **Submit a pull request (PR)** with a clear description. 8 | 9 | Issues and feature requests are welcome! 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Pau Aranega Bellido 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📊 Data Structures Visualizer 2 | 3 | An interactive web app to visualize data structures in real-time. Perfect for students, educators, and developers learning how algorithms work under the hood. 4 | 5 | --- 6 | 7 | ## 🚀 Latest Update: Interactive Tutorials & UI Revamp 8 | 9 | We’ve just launched a major update focused on **learning, usability, and design**! 10 | 11 | ### What's New 12 | 13 | - **📚 Interactive Tutorials** 14 | Learn core data structures—arrays, linked lists, stacks, queues, trees, graphs—with step-by-step tutorials, visual walkthroughs, and live coding environments. 15 | 16 | - **🎨 UI Overhaul** 17 | Redesigned all pages with modern aesthetics, smoother navigation, and full responsiveness across devices. 18 | 19 | - **♿ Accessibility & UX Enhancements** 20 | Improved visual consistency, readability, and user interactions for a better, more inclusive experience. 21 | 22 | --- 23 | 24 | ✨ Features 25 | 26 | - Visualize trees, graphs, linked lists, stacks, and queues 27 | - Perform key operations: insert, delete, search, and traverse 28 | - Real-time animations to show how each structure changes 29 | - Basic complexity analysis to understand performance 30 | 31 | --- 32 | ## 🤝 Contributing 33 | Thanks for your interest in contributing! Here's how to get started: 34 | 35 | 36 | 1. Fork the repo and create a new branch. 37 | 38 | 2. Make your changes and test them. 39 | 40 | 3. Submit a pull request with a clear description. 41 | 42 | Got ideas or found a bug? Open an issue or request a feature—contributions are always welcome! 43 | 44 | ## 🛠️ Installation 45 | 46 | Clone the repository and run the app locally: 47 | 48 | ``` 49 | git clone https://github.com/paudefclasspy/data-structures.git 50 | ``` 51 | ``` 52 | cd data-structures 53 | ``` 54 | ``` 55 | npm install 56 | npm run dev 57 | ``` 58 | -------------------------------------------------------------------------------- /app/binary-tree/loading.tsx: -------------------------------------------------------------------------------- 1 | export default function Loading() { 2 | return null 3 | } 4 | -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 260 40% 12%; 8 | --foreground: 0 0% 100%; 9 | --card: 261 40% 16%; 10 | --card-foreground: 0 0% 100%; 11 | --popover: 261 40% 16%; 12 | --popover-foreground: 0 0% 100%; 13 | --primary: 252 100% 69%; 14 | --primary-foreground: 0 0% 100%; 15 | --secondary: 260 40% 20%; 16 | --secondary-foreground: 0 0% 100%; 17 | --muted: 260 40% 16%; 18 | --muted-foreground: 0 0% 80%; 19 | --accent: 252 100% 69%; 20 | --accent-foreground: 0 0% 100%; 21 | --destructive: 0 84% 60%; 22 | --destructive-foreground: 0 0% 100%; 23 | --border: 260 40% 20%; 24 | --input: 260 40% 20%; 25 | --ring: 252 100% 69%; 26 | --radius: 0.75rem; 27 | } 28 | } 29 | 30 | @layer base { 31 | * { 32 | @apply border-border; 33 | } 34 | body { 35 | @apply bg-gradient-purple text-foreground antialiased; 36 | } 37 | } 38 | 39 | @keyframes fade-up { 40 | 0% { 41 | opacity: 1; 42 | transform: translateY(0); 43 | } 44 | 100% { 45 | opacity: 0; 46 | transform: translateY(-20px); 47 | } 48 | } 49 | 50 | @keyframes fade-left { 51 | 0% { 52 | opacity: 1; 53 | transform: translateX(0); 54 | } 55 | 100% { 56 | opacity: 0; 57 | transform: translateX(-20px); 58 | } 59 | } 60 | 61 | .animate-fade-up { 62 | animation: fade-up 1s forwards; 63 | } 64 | 65 | .animate-fade-left { 66 | animation: fade-left 1s forwards; 67 | } 68 | 69 | /* Custom styles for cards and buttons */ 70 | .card-gradient { 71 | background: linear-gradient(145deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%); 72 | backdrop-filter: blur(10px); 73 | border: 1px solid rgba(255, 255, 255, 0.1); 74 | } 75 | 76 | .button-gradient { 77 | background: linear-gradient(90deg, #6d28d9 0%, #7c3aed 100%); 78 | transition: all 0.3s ease; 79 | } 80 | 81 | .button-gradient:hover { 82 | background: linear-gradient(90deg, #5b21b6 0%, #6d28d9 100%); 83 | transform: translateY(-1px); 84 | } 85 | 86 | .button-outline { 87 | background: transparent; 88 | border: 1px solid rgba(255, 255, 255, 0.2); 89 | transition: all 0.3s ease; 90 | } 91 | 92 | .button-outline:hover { 93 | border-color: rgba(255, 255, 255, 0.4); 94 | background: rgba(255, 255, 255, 0.05); 95 | } 96 | 97 | /* Custom node styles */ 98 | .node { 99 | background: linear-gradient(145deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%); 100 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); 101 | transition: all 0.3s ease; 102 | } 103 | 104 | .node:hover { 105 | transform: translateY(-2px); 106 | box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15); 107 | } 108 | 109 | /* Custom animations */ 110 | @keyframes float { 111 | 0% { 112 | transform: translateY(0px); 113 | } 114 | 50% { 115 | transform: translateY(-10px); 116 | } 117 | 100% { 118 | transform: translateY(0px); 119 | } 120 | } 121 | 122 | .animate-float { 123 | animation: float 3s ease-in-out infinite; 124 | } 125 | -------------------------------------------------------------------------------- /app/hash-table/loading.tsx: -------------------------------------------------------------------------------- 1 | export default function Loading() { 2 | return null 3 | } 4 | -------------------------------------------------------------------------------- /app/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paudefclasspy/data-structures/HEAD/app/icon.ico -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type React from "react" 2 | import "./globals.css" 3 | import type { Metadata } from "next" 4 | import { Inter } from "next/font/google" 5 | 6 | const inter = Inter({ subsets: ["latin"] }) 7 | 8 | export const metadata: Metadata = { 9 | title: "Data Structures Visualizer", 10 | description: "Interactive visualizations of common data structures", 11 | } 12 | 13 | export default function RootLayout({ 14 | children, 15 | }: { 16 | children: React.ReactNode 17 | }) { 18 | return ( 19 | 20 | {children} 21 | 22 | ) 23 | } 24 | 25 | 26 | import './globals.css' -------------------------------------------------------------------------------- /app/preload.js: -------------------------------------------------------------------------------- 1 | // This file is used to preload critical resources 2 | export function preload() { 3 | // Preload critical CSS 4 | const linkPreload = document.createElement('link') 5 | linkPreload.rel = 'preload' 6 | linkPreload.as = 'style' 7 | linkPreload.href = '/styles.css' 8 | document.head.appendChild(linkPreload) 9 | 10 | // Preconnect to external domains 11 | const domains = [ 12 | 'fonts.googleapis.com', 13 | 'fonts.gstatic.com' 14 | ] 15 | 16 | domains.forEach(domain => { 17 | const link = document.createElement('link') 18 | link.rel = 'preconnect' 19 | link.href = `https://${domain}` 20 | link.crossOrigin = 'anonymous' 21 | document.head.appendChild(link) 22 | }) 23 | 24 | // Preload critical fonts 25 | const fontPreload = document.createElement('link') 26 | fontPreload.rel = 'preload' 27 | fontPreload.as = 'font' 28 | fontPreload.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap' 29 | fontPreload.crossOrigin = 'anonymous' 30 | document.head.appendChild(fontPreload) 31 | } 32 | -------------------------------------------------------------------------------- /app/queues/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState } from "react" 4 | import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" 5 | import { Button } from "@/components/ui/button" 6 | import { CodeBlock } from "@/components/code-block" 7 | import { QueueVisualizer } from "@/components/queue/simple-queue-visualizer" 8 | 9 | export default function QueuesPage() { 10 | const [queue, setQueue] = useState([1, 2, 3, 4, 5]) 11 | const [value, setValue] = useState(0) 12 | const [selectedOperation, setSelectedOperation] = useState(null) 13 | 14 | // Base code structure for Queue operations 15 | const baseCode = `class Queue { 16 | constructor() { 17 | this.items = []; 18 | this.front = 0; 19 | this.rear = -1; 20 | } 21 | }` 22 | 23 | // Operation-specific code snippets 24 | const operationCodes: Record = { 25 | enqueue: { 26 | code: ` // Add an element to the end of the queue 27 | enqueue(value) { 28 | this.rear++; 29 | this.items[this.rear] = value; 30 | return this.items; // O(1) constant time operation 31 | }`, 32 | description: "Enqueue operation adds an element to the end of the queue with O(1) time complexity.", 33 | }, 34 | dequeue: { 35 | code: ` // Remove the front element from the queue 36 | dequeue() { 37 | if (this.isEmpty()) { 38 | return "Queue underflow"; 39 | } 40 | 41 | const value = this.items[this.front]; 42 | this.front++; 43 | 44 | // Reset the queue when it becomes empty 45 | if (this.front > this.rear) { 46 | this.front = 0; 47 | this.rear = -1; 48 | this.items = []; 49 | } 50 | 51 | return value; // O(1) constant time operation 52 | }`, 53 | description: "Dequeue operation removes the front element from the queue with O(1) time complexity.", 54 | }, 55 | peek: { 56 | code: ` // View the front element without removing it 57 | peek() { 58 | if (this.isEmpty()) { 59 | return "Queue is empty"; 60 | } 61 | 62 | return this.items[this.front]; // O(1) constant time operation 63 | }`, 64 | description: "Peek operation returns the front element without removing it with O(1) time complexity.", 65 | }, 66 | isEmpty: { 67 | code: ` // Check if the queue is empty 68 | isEmpty() { 69 | return this.front > this.rear; // O(1) constant time operation 70 | }`, 71 | description: "isEmpty operation checks if the queue is empty with O(1) time complexity.", 72 | }, 73 | } 74 | 75 | // Combine base code with selected operation code 76 | const getDisplayCode = () => { 77 | if (!selectedOperation) return baseCode 78 | return `${baseCode}\n\n${operationCodes[selectedOperation].code}` 79 | } 80 | 81 | // Get description based on selected operation 82 | const getDescription = () => { 83 | if (!selectedOperation) return "Select an operation to see its implementation and time complexity." 84 | return operationCodes[selectedOperation].description 85 | } 86 | 87 | const handleEnqueue = () => { 88 | setSelectedOperation("enqueue") 89 | const newQueue = [...queue] 90 | newQueue.push(value) 91 | setQueue(newQueue) 92 | } 93 | 94 | const handleDequeue = () => { 95 | setSelectedOperation("dequeue") 96 | if (queue.length > 0) { 97 | const newQueue = [...queue] 98 | newQueue.shift() 99 | setQueue(newQueue) 100 | } 101 | } 102 | 103 | const handlePeek = () => { 104 | setSelectedOperation("peek") 105 | // Just visual indication, not changing the queue 106 | } 107 | 108 | const handleIsEmpty = () => { 109 | setSelectedOperation("isEmpty") 110 | // Just visual indication, not changing the queue 111 | } 112 | 113 | const resetView = () => { 114 | setSelectedOperation(null) 115 | } 116 | 117 | return ( 118 |
119 |

Queues

120 |
121 | 122 | 123 | Queue Operations 124 | {getDescription()} 125 | 126 | 127 |
128 |
129 | 130 | 131 | 132 | 133 | {selectedOperation && ( 134 | 137 | )} 138 |
139 |
140 | 141 | setValue(Number.parseInt(e.target.value) || 0)} 145 | className="w-full p-2 border rounded" 146 | /> 147 |
148 |
149 |
150 |
151 | 152 | 153 | 154 | Queue Visualization 155 | Visual representation of the queue and its operations 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | {selectedOperation 166 | ? `${selectedOperation.charAt(0).toUpperCase() + selectedOperation.slice(1)} Operation Code` 167 | : "Queue Implementation"} 168 | 169 | 170 | {selectedOperation 171 | ? `Highlighting the ${selectedOperation} operation implementation` 172 | : "Select an operation to see its implementation"} 173 | 174 | 175 | 176 | 177 | 178 | 179 |
180 |
181 | ) 182 | } 183 | -------------------------------------------------------------------------------- /app/stacks/page.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState } from "react" 4 | import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" 5 | import { Button } from "@/components/ui/button" 6 | import { CodeBlock } from "@/components/code-block" 7 | import { StackVisualizer } from "@/components/stack-visualizer" 8 | 9 | export default function StacksPage() { 10 | const [stack, setStack] = useState([5, 4, 3, 2, 1]) 11 | const [value, setValue] = useState(0) 12 | const [selectedOperation, setSelectedOperation] = useState(null) 13 | 14 | // Base code structure for Stack operations 15 | const baseCode = `class Stack { 16 | constructor() { 17 | this.items = []; 18 | this.top = -1; 19 | } 20 | }` 21 | 22 | // Operation-specific code snippets 23 | const operationCodes: Record = { 24 | push: { 25 | code: ` // Add an element to the top of the stack 26 | push(value) { 27 | this.top++; 28 | this.items[this.top] = value; 29 | return this.items; // O(1) constant time operation 30 | }`, 31 | description: "Push operation adds an element to the top of the stack with O(1) time complexity.", 32 | }, 33 | pop: { 34 | code: ` // Remove the top element from the stack 35 | pop() { 36 | if (this.isEmpty()) { 37 | return "Stack underflow"; 38 | } 39 | 40 | const value = this.items[this.top]; 41 | this.top--; 42 | this.items.length = this.top + 1; 43 | return value; // O(1) constant time operation 44 | }`, 45 | description: "Pop operation removes the top element from the stack with O(1) time complexity.", 46 | }, 47 | peek: { 48 | code: ` // View the top element without removing it 49 | peek() { 50 | if (this.isEmpty()) { 51 | return "Stack is empty"; 52 | } 53 | 54 | return this.items[this.top]; // O(1) constant time operation 55 | }`, 56 | description: "Peek operation returns the top element without removing it with O(1) time complexity.", 57 | }, 58 | isEmpty: { 59 | code: ` // Check if the stack is empty 60 | isEmpty() { 61 | return this.top === -1; // O(1) constant time operation 62 | }`, 63 | description: "isEmpty operation checks if the stack is empty with O(1) time complexity.", 64 | }, 65 | } 66 | 67 | // Combine base code with selected operation code 68 | const getDisplayCode = () => { 69 | if (!selectedOperation) return baseCode 70 | return `${baseCode}\n\n${operationCodes[selectedOperation].code}` 71 | } 72 | 73 | // Get description based on selected operation 74 | const getDescription = () => { 75 | if (!selectedOperation) return "Select an operation to see its implementation and time complexity." 76 | return operationCodes[selectedOperation].description 77 | } 78 | 79 | const handlePush = () => { 80 | setSelectedOperation("push") 81 | const newStack = [...stack] 82 | newStack.push(value) 83 | setStack(newStack) 84 | } 85 | 86 | const handlePop = () => { 87 | setSelectedOperation("pop") 88 | if (stack.length > 0) { 89 | const newStack = [...stack] 90 | newStack.pop() 91 | setStack(newStack) 92 | } 93 | } 94 | 95 | const handlePeek = () => { 96 | setSelectedOperation("peek") 97 | // Just visual indication, not changing the stack 98 | } 99 | 100 | const handleIsEmpty = () => { 101 | setSelectedOperation("isEmpty") 102 | // Just visual indication, not changing the stack 103 | } 104 | 105 | const resetView = () => { 106 | setSelectedOperation(null) 107 | } 108 | 109 | return ( 110 |
111 |

Stacks

112 |
113 | 114 | 115 | Stack Operations 116 | {getDescription()} 117 | 118 | 119 |
120 |
121 | 122 | 123 | 124 | 125 | {selectedOperation && ( 126 | 129 | )} 130 |
131 |
132 | 133 | setValue(Number.parseInt(e.target.value) || 0)} 137 | className="w-full p-2 border rounded" 138 | /> 139 |
140 |
141 |
142 |
143 | 144 | 145 | 146 | Stack Visualization 147 | Visual representation of the stack and its operations 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | {selectedOperation 158 | ? `${selectedOperation.charAt(0).toUpperCase() + selectedOperation.slice(1)} Operation Code` 159 | : "Stack Implementation"} 160 | 161 | 162 | {selectedOperation 163 | ? `Highlighting the ${selectedOperation} operation implementation` 164 | : "Select an operation to see its implementation"} 165 | 166 | 167 | 168 | 169 | 170 | 171 |
172 |
173 | ) 174 | } 175 | -------------------------------------------------------------------------------- /app/tutorials/binary-tree/introduction/page.tsx: -------------------------------------------------------------------------------- 1 | import BinaryTreeTutorialLayout from "@/components/binary-tree-tutorial-layout" 2 | import { CodeBlock } from "@/components/code-block" 3 | 4 | export default function IntroductionToBinaryTrees() { 5 | return ( 6 | 13 |
14 |
15 |

What is a Binary Tree?

16 |

17 | A binary tree is a hierarchical data structure in which each node has at most two children, referred to as 18 | the left child and the right child. Each node in a binary tree contains: 19 |

20 |
    21 |
  • A data element (or value)
  • 22 |
  • A reference to the left child
  • 23 |
  • A reference to the right child
  • 24 |
25 |
26 | 27 |
28 |

Types of Binary Trees

29 |
30 |
31 |

Full Binary Tree

32 |

A binary tree in which every node has either 0 or 2 children.

33 |
34 |
35 |

Complete Binary Tree

36 |

37 | A binary tree in which all levels are completely filled except possibly the last level, which is filled 38 | from left to right. 39 |

40 |
41 |
42 |

Perfect Binary Tree

43 |

44 | A binary tree in which all internal nodes have exactly two children and all leaf nodes are at the same 45 | level. 46 |

47 |
48 |
49 |

Binary Search Tree (BST)

50 |

51 | A binary tree with the property that for each node, all elements in its left subtree are less than the 52 | node's value, and all elements in its right subtree are greater than the node's value. 53 |

54 |
55 |
56 |
57 | 58 |
59 |

Basic Structure of a Binary Tree Node

60 |

Here's how we define a basic binary tree node in TypeScript:

61 | 75 |
76 | 77 |
78 |

Why Use Binary Trees?

79 |

Binary trees are useful for many reasons:

80 |
    81 |
  • 82 | Efficient Searching: Binary search trees provide O(log n) search 83 | time on average. 84 |
  • 85 |
  • 86 | Hierarchical Structure: They naturally represent hierarchical 87 | relationships between data. 88 |
  • 89 |
  • 90 | Efficient Insertions/Deletions: BSTs allow for efficient insertions 91 | and deletions. 92 |
  • 93 |
  • 94 | Ordered Traversal: In-order traversal of a BST gives elements in 95 | sorted order. 96 |
  • 97 |
  • 98 | Foundation for Advanced Data Structures: They form the basis for 99 | more complex structures like AVL trees, Red-Black trees, and heaps. 100 |
  • 101 |
102 |
103 | 104 |
105 |

Common Operations

106 |

The main operations performed on binary trees include:

107 |
108 |
109 |

Insertion

110 |

Adding a new node to the tree

111 |
112 |
113 |

Deletion

114 |

Removing a node from the tree

115 |
116 |
117 |

Searching

118 |

Finding a specific value in the tree

119 |
120 |
121 |

Traversal

122 |

Visiting all nodes in the tree in a specific order (in-order, pre-order, post-order, level-order)

123 |
124 |
125 |
126 | 127 |
128 |

Next Steps

129 |

130 | In the following sections, we'll explore each of these operations in detail, focusing on binary search trees 131 | (BSTs) as they are one of the most commonly used types of binary trees. 132 |

133 |
134 |
135 |
136 | ) 137 | } 138 | -------------------------------------------------------------------------------- /app/tutorials/binary-tree/layout.tsx: -------------------------------------------------------------------------------- 1 | import type React from "react" 2 | 3 | export default function Layout({ 4 | children, 5 | }: { 6 | children: React.ReactNode 7 | }) { 8 | return <>{children} 9 | } 10 | -------------------------------------------------------------------------------- /app/tutorials/introduction/page.tsx: -------------------------------------------------------------------------------- 1 | import { TutorialLayout } from "@/components/tutorial-layout" 2 | import { LinkedListVisualizer } from "@/components/linked-list-visualizer" 3 | import { CodeBlock } from "@/components/code-block" 4 | import { InteractiveExercise } from "@/components/interactive-exercise" 5 | 6 | export default function IntroductionPage() { 7 | return ( 8 | 15 |
16 |
17 |

What is a Linked List?

18 |

19 | A linked list is a linear data structure where elements are stored in nodes. Unlike arrays, linked list 20 | elements are not stored in contiguous memory locations. Instead, each node contains data and a reference (or 21 | link) to the next node in the sequence. 22 |

23 | 24 |
25 | 26 |
27 | 28 |

29 | In the visualization above, you can see a simple linked list with four nodes. Each node contains a value, 30 | and an arrow pointing to the next node in the sequence. The last node points to null, indicating the end of 31 | the list. 32 |

33 |
34 | 35 |
36 |

Key Characteristics of Linked Lists

37 | 38 |
    39 |
  • 40 | Dynamic Size: Linked lists can grow or shrink during execution as needed. 41 |
  • 42 |
  • 43 | Efficient Insertions/Deletions: Adding or removing elements doesn't require shifting 44 | other elements. 45 |
  • 46 |
  • 47 | Non-Contiguous Memory: Nodes can be stored anywhere in memory, unlike arrays. 48 |
  • 49 |
  • 50 | Sequential Access: To access a specific element, you must traverse from the head node. 51 |
  • 52 |
53 |
54 | 55 |
56 |

Basic Structure in Code

57 | 58 | 77 | 78 |

79 | The code above shows the basic structure of a linked list in JavaScript. Each node contains a value and a 80 | reference to the next node. The linked list itself has a head property that points to the first node in the 81 | list. 82 |

83 |
84 | 85 |
86 |

Advantages and Disadvantages

87 | 88 |
89 |
90 |

Advantages

91 |
    92 |
  • Dynamic size allocation
  • 93 |
  • Efficient insertions and deletions
  • 94 |
  • No need to pre-allocate memory
  • 95 |
  • Can easily grow or shrink during execution
  • 96 |
97 |
98 | 99 |
100 |

Disadvantages

101 |
    102 |
  • No random access (must traverse from head)
  • 103 |
  • Extra memory for storing references
  • 104 |
  • Not cache-friendly due to non-contiguous memory
  • 105 |
  • Reverse traversal is difficult in singly linked lists
  • 106 |
107 |
108 |
109 |
110 | 111 |
112 |

Check Your Understanding

113 | 114 | 125 |
126 | 127 |
128 |

Next Steps

129 |

130 | Now that you understand what linked lists are and their basic structure, let's move on to creating nodes and 131 | building a linked list from scratch in the next tutorial. 132 |

133 |
134 |
135 |
136 | ) 137 | } 138 | -------------------------------------------------------------------------------- /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/binary-tree/binary-tree-properties.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { memo } from "react" 4 | import Link from "next/link" 5 | import { Button } from "@/components/ui/button" 6 | import { Info, BookOpen } from "lucide-react" 7 | import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" 8 | 9 | const BinaryTreeProperties = memo(() => { 10 | return ( 11 | 12 | 13 | 14 | 15 | Binary Search Tree Properties 16 | 17 | 18 | 19 |
20 |
21 |

Ordered Structure

22 |

23 | For each node, all values in the left subtree are less than the node's value, and all values in the right subtree are greater. 24 |

25 |
26 | 27 |
28 |

Time Complexity

29 |
30 | Insert: 31 | O(log n) average 32 |
33 |
34 | Find: 35 | O(log n) average 36 |
37 |
38 | Remove: 39 | O(log n) average 40 |
41 |
42 | 43 |
44 |

Applications

45 |
    46 |
  • Hierarchical data storage
  • 47 |
  • Priority queues
  • 48 |
  • Sorting algorithms
  • 49 |
  • Database indexing
  • 50 |
51 |
52 | 53 |
54 | 55 | 59 | 60 |
61 |
62 |
63 |
64 | ) 65 | }) 66 | 67 | BinaryTreeProperties.displayName = "BinaryTreeProperties" 68 | 69 | export { BinaryTreeProperties } 70 | -------------------------------------------------------------------------------- /components/binary-tree/binary-tree-visualizer.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState, useRef, useEffect, memo } from "react" 4 | import { BinarySearchTree, TreeNode } from "@/lib/data-structures/binary-tree" 5 | import { CodeBlock } from "@/components/code-block" 6 | 7 | interface BinaryTreeVisualizerProps { 8 | initialItems?: number[] 9 | } 10 | 11 | interface TreeNodeProps { 12 | node: TreeNode 13 | isHighlighted?: boolean 14 | level: number 15 | } 16 | 17 | const TreeNodeComponent = memo(({ node, isHighlighted, level }: TreeNodeProps) => { 18 | return ( 19 |
20 |
30 | {node.value} 31 |
32 | 33 | {(node.left || node.right) && ( 34 |
35 | {node.left ? ( 36 |
37 |
38 | 39 |
40 | ) : ( 41 |
42 | )} 43 | 44 | {node.right ? ( 45 |
46 |
47 | 48 |
49 | ) : ( 50 |
51 | )} 52 |
53 | )} 54 |
55 | ) 56 | }) 57 | 58 | TreeNodeComponent.displayName = "TreeNodeComponent" 59 | 60 | const BinaryTreeVisualizer = memo(({ initialItems = [50, 30, 70, 20, 40, 60, 80] }: BinaryTreeVisualizerProps) => { 61 | const [tree] = useState(new BinarySearchTree()) 62 | const [treeRoot, setTreeRoot] = useState(null) 63 | const [animationStep, setAnimationStep] = useState(0) 64 | const [animationValue, setAnimationValue] = useState(null) 65 | const [isAnimating, setIsAnimating] = useState(false) 66 | const [operationDescription, setOperationDescription] = useState("") 67 | const [currentCodeSnippet, setCurrentCodeSnippet] = useState("") 68 | const [currentOperation, setCurrentOperation] = useState("empty") 69 | const [highlightedPath, setHighlightedPath] = useState([]) 70 | const animationTimeoutRef = useRef(null) 71 | 72 | // Update the tree visualization whenever the tree changes 73 | const updateTree = () => { 74 | setTreeRoot(tree.getTree()) 75 | } 76 | 77 | // Initialize the tree with example items 78 | useEffect(() => { 79 | if (!treeRoot && initialItems.length > 0) { 80 | initialItems.forEach(item => tree.insert(item)) 81 | updateTree() 82 | } 83 | }, [tree, treeRoot, initialItems]) 84 | 85 | // Clean up animations on unmount 86 | useEffect(() => { 87 | return () => { 88 | if (animationTimeoutRef.current) { 89 | clearTimeout(animationTimeoutRef.current) 90 | } 91 | } 92 | }, []) 93 | 94 | return ( 95 |
96 |
97 |
98 | {treeRoot ? ( 99 | 100 | ) : ( 101 |
102 |

The tree is empty

103 |

Use the controls to add nodes

104 |
105 | )} 106 |
107 |
108 | 109 | {/* Operation description */} 110 | {isAnimating && ( 111 |
112 |

{operationDescription}

113 |

114 | {animationStep === 1 && "Traversing the tree..."} 115 | {animationStep === 2 && "Performing operation..."} 116 | {animationStep === 3 && "Operation completed successfully"} 117 |

118 |
119 | )} 120 | 121 | {/* Code snippet for current operation */} 122 | {currentCodeSnippet && ( 123 |
124 | 138 |
139 | )} 140 |
141 | ) 142 | }) 143 | 144 | BinaryTreeVisualizer.displayName = "BinaryTreeVisualizer" 145 | 146 | export { BinaryTreeVisualizer } 147 | -------------------------------------------------------------------------------- /components/code-block.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState } from "react" 4 | import { Check, Clipboard, Code } from "lucide-react" 5 | import { cn } from "@/lib/utils" 6 | 7 | interface CodeBlockProps { 8 | code: string 9 | language?: string 10 | title?: string 11 | highlightLines?: number[] 12 | className?: string 13 | } 14 | 15 | export function CodeBlock({ code, language = "javascript", title, highlightLines = [], className }: CodeBlockProps) { 16 | const [copied, setCopied] = useState(false) 17 | 18 | const handleCopy = () => { 19 | navigator.clipboard.writeText(code) 20 | setCopied(true) 21 | setTimeout(() => setCopied(false), 2000) 22 | } 23 | 24 | return ( 25 |
26 | {title && ( 27 |
28 |
29 | 30 | {title} 31 |
32 |
33 | 49 |
50 |
51 | )} 52 |
53 |         {code.split("\n").map((line, i) => (
54 |           
61 | {line || " "} 62 |
63 | ))} 64 |
65 |
66 | ) 67 | } 68 | -------------------------------------------------------------------------------- /components/dynamic-tutorial-content.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import dynamic from 'next/dynamic' 4 | import { useState, useEffect } from 'react' 5 | import { Skeleton } from '@/components/ui/skeleton' 6 | 7 | interface DynamicTutorialContentProps { 8 | tutorialPath: string 9 | fallback?: React.ReactNode 10 | } 11 | 12 | export function DynamicTutorialContent({ 13 | tutorialPath, 14 | fallback =
15 | 16 | 17 | 18 | 19 |
20 | 21 |
22 |
23 | }: DynamicTutorialContentProps) { 24 | const [Component, setComponent] = useState | null>(null) 25 | const [isLoading, setIsLoading] = useState(true) 26 | 27 | useEffect(() => { 28 | setIsLoading(true) 29 | 30 | // Dynamically import the tutorial content 31 | const importComponent = async () => { 32 | try { 33 | const module = await import(`@/app/tutorials/${tutorialPath}/page`) 34 | setComponent(() => module.default) 35 | } catch (error) { 36 | console.error(`Error loading tutorial content: ${tutorialPath}`, error) 37 | } finally { 38 | setIsLoading(false) 39 | } 40 | } 41 | 42 | importComponent() 43 | }, [tutorialPath]) 44 | 45 | if (isLoading || !Component) { 46 | return <>{fallback} 47 | } 48 | 49 | return 50 | } 51 | -------------------------------------------------------------------------------- /components/graph/graph-properties.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { memo } from "react" 4 | import Link from "next/link" 5 | import { Button } from "@/components/ui/button" 6 | import { Info, BookOpen } from "lucide-react" 7 | import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" 8 | 9 | const GraphProperties = memo(() => { 10 | return ( 11 | 12 | 13 | 14 | 15 | Graph Properties 16 | 17 | 18 | 19 |
20 |
21 |

Vertices and Edges

22 |

23 | Graphs consist of vertices (nodes) connected by edges, representing relationships between entities. 24 |

25 |
26 | 27 |
28 |

Time Complexity

29 |
30 | Add Vertex: 31 | O(1) 32 |
33 |
34 | Add Edge: 35 | O(1) 36 |
37 |
38 | Remove Vertex: 39 | O(V + E) 40 |
41 |
42 | BFS/DFS: 43 | O(V + E) 44 |
45 |
46 | 47 |
48 |

Applications

49 |
    50 |
  • Social networks
  • 51 |
  • Route planning
  • 52 |
  • Web page ranking
  • 53 |
  • Network topology
  • 54 |
55 |
56 | 57 |
58 | 59 | 63 | 64 |
65 |
66 |
67 |
68 | ) 69 | }) 70 | 71 | GraphProperties.displayName = "GraphProperties" 72 | 73 | export { GraphProperties } 74 | -------------------------------------------------------------------------------- /components/hash-table/hash-table-properties.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { memo } from "react" 4 | import Link from "next/link" 5 | import { Button } from "@/components/ui/button" 6 | import { Info, BookOpen } from "lucide-react" 7 | import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" 8 | 9 | const HashTableProperties = memo(() => { 10 | return ( 11 | 12 | 13 | 14 | 15 | Hash Table Properties 16 | 17 | 18 | 19 |
20 |
21 |

Key-Value Storage

22 |

23 | Hash tables store data as key-value pairs with fast lookups. 24 |

25 |
26 | 27 |
28 |

Time Complexity

29 |
30 | Set: 31 | O(1) average 32 |
33 |
34 | Get: 35 | O(1) average 36 |
37 |
38 | Delete: 39 | O(1) average 40 |
41 |
42 | 43 |
44 |

Applications

45 |
    46 |
  • Database indexing
  • 47 |
  • Caching
  • 48 |
  • Symbol tables
  • 49 |
  • Associative arrays
  • 50 |
51 |
52 | 53 |
54 | 55 | 59 | 60 |
61 |
62 |
63 |
64 | ) 65 | }) 66 | 67 | HashTableProperties.displayName = "HashTableProperties" 68 | 69 | export { HashTableProperties } 70 | -------------------------------------------------------------------------------- /components/hash-table/hash-table-visualizer.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState, useRef, useEffect, memo } from "react" 4 | import { HashTable } from "@/lib/data-structures/hash-table" 5 | import { CodeBlock } from "@/components/code-block" 6 | 7 | interface HashTableVisualizerProps { 8 | initialItems?: { key: string, value: any }[] 9 | } 10 | 11 | const HashTableVisualizer = memo(({ initialItems = [ 12 | { key: "name", value: "John" }, 13 | { key: "age", value: 30 }, 14 | { key: "city", value: "New York" } 15 | ] }: HashTableVisualizerProps) => { 16 | const [hashTable] = useState(new HashTable(10)) 17 | const [buckets, setBuckets] = useState([]) 18 | const [animationStep, setAnimationStep] = useState(0) 19 | const [animationItem, setAnimationItem] = useState<{ key: string, value: any, index: number } | null>(null) 20 | const [isAnimating, setIsAnimating] = useState(false) 21 | const [operationDescription, setOperationDescription] = useState("") 22 | const [currentCodeSnippet, setCurrentCodeSnippet] = useState("") 23 | const [currentOperation, setCurrentOperation] = useState("empty") 24 | const animationTimeoutRef = useRef(null) 25 | 26 | // Update the buckets whenever the hash table changes 27 | const updateBuckets = () => { 28 | setBuckets(hashTable.getBuckets()) 29 | } 30 | 31 | // Initialize the hash table with example items 32 | useEffect(() => { 33 | if (buckets.length === 0 && initialItems.length > 0) { 34 | initialItems.forEach(item => hashTable.set(item.key, item.value)) 35 | updateBuckets() 36 | } 37 | }, [hashTable, buckets.length, initialItems]) 38 | 39 | // Clean up animations on unmount 40 | useEffect(() => { 41 | return () => { 42 | if (animationTimeoutRef.current) { 43 | clearTimeout(animationTimeoutRef.current) 44 | } 45 | } 46 | }, []) 47 | 48 | return ( 49 |
50 |
51 | {buckets.map((bucket, index) => ( 52 |
53 |
54 | {index} 55 |
56 |
57 | {bucket.length === 0 ? ( 58 |
Empty bucket
59 | ) : ( 60 |
61 | {bucket.map((item, itemIndex) => ( 62 |
75 | {item.key}: {item.value} 76 |
77 | ))} 78 |
79 | )} 80 |
81 |
82 | ))} 83 |
84 | 85 | {/* Operation description */} 86 | {isAnimating && ( 87 |
88 |

{operationDescription}

89 |

90 | {animationStep === 1 && "Calculating hash..."} 91 | {animationStep === 2 && "Placing item in bucket..."} 92 | {animationStep === 3 && "Operation completed successfully"} 93 |

94 |
95 | )} 96 | 97 | {/* Code snippet for current operation */} 98 | {currentCodeSnippet && ( 99 |
100 | 116 |
117 | )} 118 |
119 | ) 120 | }) 121 | 122 | HashTableVisualizer.displayName = "HashTableVisualizer" 123 | 124 | export { HashTableVisualizer } 125 | -------------------------------------------------------------------------------- /components/interactive-exercise.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState } from "react" 4 | import { AlertCircle, CheckCircle2 } from "lucide-react" 5 | import { Button } from "@/components/ui/button" 6 | import { cn } from "@/lib/utils" 7 | 8 | interface Question { 9 | question: string 10 | options: string[] 11 | correctAnswer: number 12 | explanation: string 13 | } 14 | 15 | interface InteractiveExerciseProps { 16 | questions: Question | Question[] 17 | className?: string 18 | } 19 | 20 | export function InteractiveExercise({ questions, className }: InteractiveExerciseProps) { 21 | const questionArray = Array.isArray(questions) ? questions : [questions] 22 | const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0) 23 | const [selectedOptions, setSelectedOptions] = useState<(number | null)[]>(questionArray.map(() => null)) 24 | const [isSubmitted, setIsSubmitted] = useState(false) 25 | 26 | const currentQuestion = questionArray[currentQuestionIndex] 27 | 28 | // If there's no current question, render nothing 29 | if (!currentQuestion) { 30 | return null 31 | } 32 | 33 | const isCorrect = selectedOptions[currentQuestionIndex] === currentQuestion.correctAnswer 34 | 35 | const handleOptionSelect = (index: number) => { 36 | if (!isSubmitted) { 37 | const newSelectedOptions = [...selectedOptions] 38 | newSelectedOptions[currentQuestionIndex] = index 39 | setSelectedOptions(newSelectedOptions) 40 | } 41 | } 42 | 43 | const handleSubmit = () => { 44 | if (selectedOptions[currentQuestionIndex] !== null) { 45 | setIsSubmitted(true) 46 | } 47 | } 48 | 49 | const handleNext = () => { 50 | if (currentQuestionIndex < questionArray.length - 1) { 51 | setCurrentQuestionIndex(currentQuestionIndex + 1) 52 | setIsSubmitted(false) 53 | } 54 | } 55 | 56 | const handleReset = () => { 57 | const newSelectedOptions = [...selectedOptions] 58 | newSelectedOptions[currentQuestionIndex] = null 59 | setSelectedOptions(newSelectedOptions) 60 | setIsSubmitted(false) 61 | } 62 | 63 | return ( 64 |
65 |
{currentQuestion.question}
66 | 67 |
68 | {currentQuestion.options.map((option, index) => ( 69 | 88 | ))} 89 |
90 | 91 | {isSubmitted && ( 92 |
98 | {isCorrect ? ( 99 | 100 | ) : ( 101 | 102 | )} 103 |
104 |

{isCorrect ? "Correct!" : "Incorrect"}

105 |

{currentQuestion.explanation}

106 |
107 |
108 | )} 109 | 110 |
111 | {isSubmitted ? ( 112 | <> 113 | 114 | {currentQuestionIndex < questionArray.length - 1 && } 115 | 116 | ) : ( 117 | 120 | )} 121 |
122 |
123 | ) 124 | } 125 | -------------------------------------------------------------------------------- /components/optimized-image.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState, useEffect } from 'react' 4 | import Image from 'next/image' 5 | import { cn } from '@/lib/utils' 6 | 7 | interface OptimizedImageProps { 8 | src: string 9 | alt: string 10 | width: number 11 | height: number 12 | className?: string 13 | priority?: boolean 14 | } 15 | 16 | export function OptimizedImage({ 17 | src, 18 | alt, 19 | width, 20 | height, 21 | className, 22 | priority = false, 23 | }: OptimizedImageProps) { 24 | const [isLoaded, setIsLoaded] = useState(false) 25 | 26 | return ( 27 |
28 | {alt} setIsLoaded(true)} 38 | priority={priority} 39 | loading={priority ? "eager" : "lazy"} 40 | /> 41 | {!isLoaded && ( 42 |
43 | )} 44 |
45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /components/queue-visualizer.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState, useEffect } from "react" 4 | import { cn } from "@/lib/utils" 5 | 6 | interface QueueVisualizerProps { 7 | initialValues?: number[] 8 | className?: string 9 | } 10 | 11 | export default function QueueVisualizer({ initialValues = [], className }: QueueVisualizerProps) { 12 | const [queue, setQueue] = useState([]) 13 | 14 | useEffect(() => { 15 | setQueue(initialValues) 16 | }, [initialValues]) 17 | 18 | return ( 19 |
20 | {/* Queue visualization */} 21 |
22 | {queue.length === 0 ? ( 23 |
24 |

The queue is empty

25 |
26 | ) : ( 27 |
28 | {queue.map((value, index) => ( 29 |
30 |
31 | {value} 32 |
33 | {index < queue.length - 1 && ( 34 |
35 | > 36 |
37 | )} 38 |
39 | ))} 40 |
41 | )} 42 |
43 |
44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /components/queue/queue-properties.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { memo } from "react" 4 | import Link from "next/link" 5 | import { Button } from "@/components/ui/button" 6 | import { Info, BookOpen } from "lucide-react" 7 | import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" 8 | 9 | const QueueProperties = memo(() => { 10 | return ( 11 | 12 | 13 | 14 | 15 | Queue Properties 16 | 17 | 18 | 19 |
20 |
21 |

First-In-First-Out (FIFO)

22 |

23 | The first item added to the queue is the first one to be removed. 24 |

25 |
26 | 27 |
28 |

Time Complexity

29 |
30 | Enqueue: 31 | O(1) 32 |
33 |
34 | Dequeue: 35 | O(n) 36 |
37 |
38 | Peek: 39 | O(1) 40 |
41 |
42 | 43 |
44 |

Applications

45 |
    46 |
  • Task scheduling
  • 47 |
  • Print job management
  • 48 |
  • Breadth-first search
  • 49 |
  • Message queues
  • 50 |
51 |
52 | 53 |
54 | 55 | 59 | 60 |
61 |
62 |
63 |
64 | ) 65 | }) 66 | 67 | QueueProperties.displayName = "QueueProperties" 68 | 69 | export { QueueProperties } 70 | -------------------------------------------------------------------------------- /components/queue/queue-visualizer.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState, useRef, useEffect, memo } from "react" 4 | import { Queue } from "@/lib/data-structures/queue" 5 | import { CodeBlock } from "@/components/code-block" 6 | 7 | interface QueueVisualizerProps { 8 | initialItems?: number[] 9 | } 10 | 11 | const QueueVisualizer = memo(({ initialItems = [10, 20, 30] }: QueueVisualizerProps) => { 12 | const [queue] = useState(new Queue()) 13 | const [queueItems, setQueueItems] = useState([]) 14 | const [animationStep, setAnimationStep] = useState(0) 15 | const [animationItem, setAnimationItem] = useState(null) 16 | const [isAnimating, setIsAnimating] = useState(false) 17 | const [operationDescription, setOperationDescription] = useState("") 18 | const [dequeuedItem, setDequeuedItem] = useState(null) 19 | const [currentCodeSnippet, setCurrentCodeSnippet] = useState("") 20 | const [currentOperation, setCurrentOperation] = useState("empty") 21 | const animationTimeoutRef = useRef(null) 22 | 23 | // Update the queue items whenever the queue changes 24 | const updateQueueItems = () => { 25 | setQueueItems(queue.getItems()) 26 | } 27 | 28 | // Initialize the queue with example items 29 | useEffect(() => { 30 | if (queueItems.length === 0 && initialItems.length > 0) { 31 | initialItems.forEach(item => queue.enqueue(item)) 32 | updateQueueItems() 33 | } 34 | }, [queue, queueItems.length, initialItems]) 35 | 36 | // Clean up animations on unmount 37 | useEffect(() => { 38 | return () => { 39 | if (animationTimeoutRef.current) { 40 | clearTimeout(animationTimeoutRef.current) 41 | } 42 | } 43 | }, []) 44 | 45 | return ( 46 |
47 | {queueItems.length === 0 ? ( 48 |
49 |

The queue is empty

50 |

Use the controls to add items

51 |
52 | ) : ( 53 |
54 |
55 |
Front
56 |
Back
57 |
58 |
59 | {queueItems.map((value, index) => ( 60 |
74 | {value} 75 |
76 | ))} 77 |
78 |
79 | )} 80 | 81 | {/* Animation for enqueuing */} 82 | {isAnimating && animationStep === 1 && animationItem !== null && ( 83 |
84 | {animationItem} 85 |
86 | )} 87 | 88 | {/* Animation for dequeuing */} 89 | {isAnimating && animationStep === 2 && dequeuedItem !== null && ( 90 |
91 | {dequeuedItem} 92 |
93 | )} 94 | 95 | {/* Operation description */} 96 | {isAnimating && ( 97 |
98 |

{operationDescription}

99 |

100 | {animationStep === 1 && "Preparing operation..."} 101 | {animationStep === 2 && "Operation completed successfully"} 102 | {animationStep === 3 && "Peeking at the front element without removing it"} 103 |

104 |
105 | )} 106 | 107 | {/* Code snippet for current operation */} 108 | {currentCodeSnippet && ( 109 |
110 | 124 |
125 | )} 126 |
127 | ) 128 | }) 129 | 130 | QueueVisualizer.displayName = "QueueVisualizer" 131 | 132 | export { QueueVisualizer } 133 | -------------------------------------------------------------------------------- /components/queue/simple-queue-visualizer.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { memo } from "react" 4 | import { cn } from "@/lib/utils" 5 | 6 | interface QueueVisualizerProps { 7 | queue?: number[] 8 | highlightIndex?: number 9 | highlightedIndices?: number[] 10 | highlightedValues?: number[] 11 | } 12 | 13 | const SimpleQueueVisualizer = memo(({ 14 | queue = [], 15 | highlightIndex = -1, 16 | highlightedIndices = [], 17 | highlightedValues = [] 18 | }: QueueVisualizerProps) => { 19 | return ( 20 |
21 | {queue.length === 0 ? ( 22 |
23 |

The queue is empty

24 |
25 | ) : ( 26 |
27 |
28 |
Front
29 |
Back
30 |
31 |
32 | {queue.map((value, index) => ( 33 |
42 | {value} 43 |
44 | ))} 45 |
46 |
47 | )} 48 |
49 | ) 50 | }) 51 | 52 | SimpleQueueVisualizer.displayName = "SimpleQueueVisualizer" 53 | 54 | export { SimpleQueueVisualizer as QueueVisualizer } 55 | -------------------------------------------------------------------------------- /components/stack/stack-properties.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { memo } from "react" 4 | import Link from "next/link" 5 | import { Button } from "@/components/ui/button" 6 | import { Info, BookOpen } from "lucide-react" 7 | import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" 8 | 9 | const StackProperties = memo(() => { 10 | return ( 11 | 12 | 13 | 14 | 15 | Stack Properties 16 | 17 | 18 | 19 |
20 |
21 |

Last-In-First-Out (LIFO)

22 |

23 | The last item added to the stack is the first one to be removed. 24 |

25 |
26 | 27 |
28 |

Time Complexity

29 |
30 | Push: 31 | O(1) 32 |
33 |
34 | Pop: 35 | O(1) 36 |
37 |
38 | Peek: 39 | O(1) 40 |
41 |
42 | 43 |
44 |

Applications

45 |
    46 |
  • Function call management
  • 47 |
  • Expression evaluation
  • 48 |
  • Undo mechanisms
  • 49 |
  • Backtracking algorithms
  • 50 |
51 |
52 | 53 |
54 | 55 | 59 | 60 |
61 |
62 |
63 |
64 | ) 65 | }) 66 | 67 | StackProperties.displayName = "StackProperties" 68 | 69 | export { StackProperties } 70 | -------------------------------------------------------------------------------- /components/stack/stack-visualizer.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useState, useRef, useEffect, memo } from "react" 4 | import { Stack } from "@/lib/data-structures/stack" 5 | import { CodeBlock } from "@/components/code-block" 6 | 7 | interface StackVisualizerProps { 8 | initialItems?: number[] 9 | } 10 | 11 | const StackVisualizer = memo(({ initialItems = [10, 20, 30] }: StackVisualizerProps) => { 12 | const [stack] = useState(new Stack()) 13 | const [stackItems, setStackItems] = useState([]) 14 | const [animationStep, setAnimationStep] = useState(0) 15 | const [animationItem, setAnimationItem] = useState(null) 16 | const [isAnimating, setIsAnimating] = useState(false) 17 | const [operationDescription, setOperationDescription] = useState("") 18 | const [poppedItem, setPoppedItem] = useState(null) 19 | const [currentCodeSnippet, setCurrentCodeSnippet] = useState("") 20 | const [currentOperation, setCurrentOperation] = useState("empty") 21 | const animationTimeoutRef = useRef(null) 22 | 23 | // Update the stack items whenever the stack changes 24 | const updateStackItems = () => { 25 | setStackItems(stack.getItems()) 26 | } 27 | 28 | // Clear any ongoing animations 29 | const clearAnimation = () => { 30 | if (animationTimeoutRef.current) { 31 | clearTimeout(animationTimeoutRef.current) 32 | animationTimeoutRef.current = null 33 | } 34 | setAnimationStep(0) 35 | setAnimationItem(null) 36 | setIsAnimating(false) 37 | setPoppedItem(null) 38 | } 39 | 40 | // Initialize the stack with example items 41 | useEffect(() => { 42 | if (stackItems.length === 0 && initialItems.length > 0) { 43 | initialItems.forEach(item => stack.push(item)) 44 | updateStackItems() 45 | } 46 | }, [stack, stackItems.length, initialItems]) 47 | 48 | // Clean up animations on unmount 49 | useEffect(() => { 50 | return () => { 51 | if (animationTimeoutRef.current) { 52 | clearTimeout(animationTimeoutRef.current) 53 | } 54 | } 55 | }, []) 56 | 57 | return ( 58 |
59 | {stackItems.length === 0 ? ( 60 |
61 |

The stack is empty

62 |

Use the controls to add items

63 |
64 | ) : ( 65 |
66 |
Bottom
67 | {stackItems.map((value, index) => ( 68 |
82 | {value} 83 |
84 | ))} 85 |
Top
86 |
87 | )} 88 | 89 | {/* Animation for pushing */} 90 | {isAnimating && animationStep === 1 && animationItem !== null && ( 91 |
92 | {animationItem} 93 |
94 | )} 95 | 96 | {/* Animation for popping */} 97 | {isAnimating && animationStep === 2 && poppedItem !== null && ( 98 |
99 | {poppedItem} 100 |
101 | )} 102 | 103 | {/* Operation description */} 104 | {isAnimating && ( 105 |
106 |

{operationDescription}

107 |

108 | {animationStep === 1 && "Preparing operation..."} 109 | {animationStep === 2 && "Operation completed successfully"} 110 | {animationStep === 3 && "Peeking at the top element without removing it"} 111 |

112 |
113 | )} 114 | 115 | {/* Code snippet for current operation */} 116 | {currentCodeSnippet && ( 117 |
118 | 132 |
133 | )} 134 |
135 | ) 136 | }) 137 | 138 | StackVisualizer.displayName = "StackVisualizer" 139 | 140 | export { StackVisualizer } 141 | -------------------------------------------------------------------------------- /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 | 9 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 10 | return {children} 11 | } 12 | -------------------------------------------------------------------------------- /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) =>