diff --git a/docs/app/showcase/music-app/helpers/sections/PlaylistHero.tsx b/docs/app/showcase/music-app/helpers/sections/PlaylistHero.tsx
index 00f687271..2b4df7351 100644
--- a/docs/app/showcase/music-app/helpers/sections/PlaylistHero.tsx
+++ b/docs/app/showcase/music-app/helpers/sections/PlaylistHero.tsx
@@ -59,7 +59,7 @@ const PlaylistHero: any = () => {
diff --git a/docs/app/showcase/music-app/helpers/sections/TopArtists.tsx b/docs/app/showcase/music-app/helpers/sections/TopArtists.tsx
index 952f1a985..94b3d2167 100644
--- a/docs/app/showcase/music-app/helpers/sections/TopArtists.tsx
+++ b/docs/app/showcase/music-app/helpers/sections/TopArtists.tsx
@@ -63,7 +63,7 @@ const Artist: any = ({ artist }: any) => {
{artist.name}
- {artist.album}
+ {artist.album}
)
diff --git a/docs/components/AccessibilityFeatures.tsx b/docs/components/AccessibilityFeatures.tsx
new file mode 100644
index 000000000..0b15cec4a
--- /dev/null
+++ b/docs/components/AccessibilityFeatures.tsx
@@ -0,0 +1,134 @@
+'use client'
+import { useState, useEffect } from 'react'
+import Button from '@radui/ui/Button'
+import Card from '@radui/ui/Card'
+import Text from '@radui/ui/Text'
+import { Eye, EyeOff, Type, Volume2, VolumeX } from 'lucide-react'
+
+const AccessibilityFeatures = () => {
+ const [fontSize, setFontSize] = useState(16)
+ const [highContrast, setHighContrast] = useState(false)
+ const [reducedMotion, setReducedMotion] = useState(false)
+ const [screenReader, setScreenReader] = useState(false)
+
+ useEffect(() => {
+ // Apply font size
+ document.documentElement.style.fontSize = `${fontSize}px`
+
+ return () => {
+ document.documentElement.style.fontSize = ''
+ }
+ }, [fontSize])
+
+ useEffect(() => {
+ // Apply high contrast
+ if (highContrast) {
+ document.body.classList.add('high-contrast')
+ } else {
+ document.body.classList.remove('high-contrast')
+ }
+
+ return () => {
+ document.body.classList.remove('high-contrast')
+ }
+ }, [highContrast])
+
+ useEffect(() => {
+ // Apply reduced motion
+ if (reducedMotion) {
+ document.body.classList.add('reduced-motion')
+ } else {
+ document.body.classList.remove('reduced-motion')
+ }
+
+ return () => {
+ document.body.classList.remove('reduced-motion')
+ }
+ }, [reducedMotion])
+
+ const toggleScreenReader = () => {
+ setScreenReader(!screenReader)
+ // In a real implementation, this would integrate with screen reader APIs
+ }
+
+ return (
+
+ Accessibility
+
+
+ {/* Font Size */}
+
+
+
+ Font Size
+
+
+ setFontSize(Math.max(12, fontSize - 2))}
+ disabled={fontSize <= 12}
+ >
+ A-
+
+ {fontSize}px
+ setFontSize(Math.min(24, fontSize + 2))}
+ disabled={fontSize >= 24}
+ >
+ A+
+
+
+
+
+ {/* High Contrast */}
+
+
+ {highContrast ? : }
+ High Contrast
+
+
setHighContrast(!highContrast)}
+ >
+ {highContrast ? 'On' : 'Off'}
+
+
+
+ {/* Reduced Motion */}
+
+
+ Reduced Motion
+
+
setReducedMotion(!reducedMotion)}
+ >
+ {reducedMotion ? 'On' : 'Off'}
+
+
+
+ {/* Screen Reader */}
+
+
+ {screenReader ? : }
+ Screen Reader
+
+
+ {screenReader ? 'On' : 'Off'}
+
+
+
+
+ )
+}
+
+export default AccessibilityFeatures
diff --git a/docs/components/KeyboardShortcuts.tsx b/docs/components/KeyboardShortcuts.tsx
new file mode 100644
index 000000000..aea1a5ddc
--- /dev/null
+++ b/docs/components/KeyboardShortcuts.tsx
@@ -0,0 +1,83 @@
+'use client'
+import { useEffect } from 'react'
+import Card from '@radui/ui/Card'
+import Text from '@radui/ui/Text'
+import Badge from '@radui/ui/Badge'
+
+const KeyboardShortcuts = () => {
+ useEffect(() => {
+ const handleKeyDown = (e: KeyboardEvent) => {
+ // Ctrl/Cmd + K for search
+ if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
+ e.preventDefault()
+ const searchInput = document.querySelector('input[placeholder*="Search"]') as HTMLInputElement
+ if (searchInput) {
+ searchInput.focus()
+ }
+ }
+
+ // Ctrl/Cmd + / for help
+ if ((e.ctrlKey || e.metaKey) && e.key === '/') {
+ e.preventDefault()
+ // Toggle keyboard shortcuts help
+ const helpElement = document.getElementById('keyboard-shortcuts-help')
+ if (helpElement) {
+ helpElement.style.display = helpElement.style.display === 'none' ? 'block' : 'none'
+ }
+ }
+
+ // Escape to close modals/dropdowns
+ if (e.key === 'Escape') {
+ const activeElement = document.activeElement as HTMLElement
+ if (activeElement && activeElement.blur) {
+ activeElement.blur()
+ }
+ }
+ }
+
+ document.addEventListener('keydown', handleKeyDown)
+ return () => document.removeEventListener('keydown', handleKeyDown)
+ }, [])
+
+ const shortcuts = [
+ { keys: ['Ctrl', 'K'], description: 'Focus search' },
+ { keys: ['Ctrl', '/'], description: 'Show shortcuts' },
+ { keys: ['Esc'], description: 'Close dialogs' },
+ { keys: ['Tab'], description: 'Navigate focus' },
+ { keys: ['Enter'], description: 'Activate focused' },
+ { keys: ['Space'], description: 'Toggle elements' },
+ ]
+
+ return (
+
+
+ Shortcuts
+ Keyboard Shortcuts
+
+
+
+ {shortcuts.map((shortcut, index) => (
+
+
+ {shortcut.keys.map((key, keyIndex) => (
+
+ {keyIndex > 0 && + }
+
+ {key}
+
+
+ ))}
+
+
{shortcut.description}
+
+ ))}
+
+
+
+ Press Ctrl + / to toggle this help
+
+
+ )
+}
+
+export default KeyboardShortcuts
diff --git a/docs/components/Main/NavBar/index.js b/docs/components/Main/NavBar/index.js
index ebd145ae3..1611d20dc 100644
--- a/docs/components/Main/NavBar/index.js
+++ b/docs/components/Main/NavBar/index.js
@@ -2,6 +2,7 @@
import NavRoot from "./helpers/NavRoot"
import Navigation from "@/components/navigation/Navigation"
+import ModernNavigation from "@/components/navigation/ModernNavigation"
import { NavBarContext } from "./NavBarContext"
import { useContext, useEffect, useState } from "react"
@@ -12,8 +13,8 @@ const NavBar = ({ darkMode, setDarkMode, cookies, setCookie }) => {
return
-
}
diff --git a/docs/components/Performance/LazyComponent.tsx b/docs/components/Performance/LazyComponent.tsx
new file mode 100644
index 000000000..9d3b06ddd
--- /dev/null
+++ b/docs/components/Performance/LazyComponent.tsx
@@ -0,0 +1,34 @@
+'use client'
+import { Suspense, lazy } from 'react'
+import Card from '@radui/ui/Card'
+import Text from '@radui/ui/Text'
+
+interface LazyComponentProps {
+ component: () => Promise
+ fallback?: React.ReactNode
+ className?: string
+}
+
+const DefaultFallback = () => (
+
+
+
+)
+
+const LazyComponent = ({ component, fallback, className }: LazyComponentProps) => {
+ const LazyLoadedComponent = lazy(component)
+
+ return (
+ }>
+
+
+
+
+ )
+}
+
+export default LazyComponent
diff --git a/docs/components/PostHogProvider.tsx b/docs/components/PostHogProvider.tsx
index 3541f0955..9a1a2255e 100644
--- a/docs/components/PostHogProvider.tsx
+++ b/docs/components/PostHogProvider.tsx
@@ -2,9 +2,11 @@
import posthog from "posthog-js"
import { PostHogProvider as PHProvider } from "posthog-js/react"
-import { useEffect } from "react"
+import { useEffect, useState } from "react"
export function PostHogProvider({ children }: { children: React.ReactNode }) {
+ const [postHogEnabled, setPostHogEnabled] = useState(true)
+
// Early return if no API key - prevents any PostHog code from running
const hasPostHogKey = process.env.NEXT_PUBLIC_POSTHOG_KEY &&
process.env.NEXT_PUBLIC_POSTHOG_KEY.trim() !== '' &&
@@ -16,32 +18,56 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
return
}
+ // Check if we're in a browser environment
+ if (typeof window === 'undefined') {
+ return
+ }
+
+ let requestCount = 0
+ const maxFailedRequests = 3
+
try {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || "https://us.posthog.com",
ui_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || "https://us.posthog.com",
defaults: '2025-05-24',
- capture_exceptions: true,
- debug: process.env.NODE_ENV === "development",
+ capture_exceptions: false, // Disable to prevent error loops
+ debug: false, // Disable debug mode to reduce noise
loaded: (posthog) => {
if (process.env.NODE_ENV === "development") {
console.log('PostHog loaded successfully')
- posthog.capture('my event', { property: 'value' })
}
},
- on_xhr_error: (failedRequest) => {
+ on_request_error: (failedRequest) => {
+ requestCount++
+
+ // If too many failed requests, disable PostHog completely
+ if (requestCount >= maxFailedRequests) {
+ setPostHogEnabled(false)
+ if (process.env.NODE_ENV === "development") {
+ console.warn('PostHog disabled due to repeated network failures')
+ }
+ return
+ }
+
+ // Silently handle network errors to prevent console spam
if (process.env.NODE_ENV === "development") {
- console.warn('PostHog request failed:', failedRequest)
+ console.warn('PostHog request failed (this is normal if API key is invalid):', 'Network error')
}
- }
+ },
+ // Disable automatic pageview capture to prevent errors
+ capture_pageview: false,
+ // Disable automatic session recording
+ disable_session_recording: true
})
} catch (error) {
console.error('PostHog initialization failed:', error)
+ setPostHogEnabled(false)
}
}, [hasPostHogKey])
- // If no valid API key, return children without PostHog provider
- if (!hasPostHogKey) {
+ // If no valid API key or PostHog is disabled, return children without PostHog provider
+ if (!hasPostHogKey || !postHogEnabled) {
return <>{children}>
}
diff --git a/docs/components/QuickActions.tsx b/docs/components/QuickActions.tsx
new file mode 100644
index 000000000..818de7f1a
--- /dev/null
+++ b/docs/components/QuickActions.tsx
@@ -0,0 +1,91 @@
+'use client'
+import { useState } from 'react'
+import Button from '@radui/ui/Button'
+import Card from '@radui/ui/Card'
+import Text from '@radui/ui/Text'
+import { Copy, ExternalLink, Github, MessageCircle, Star } from 'lucide-react'
+
+const QuickActions = () => {
+ const [copied, setCopied] = useState(false)
+
+ const copyInstallCommand = () => {
+ navigator.clipboard.writeText('npm install @radui/ui')
+ setCopied(true)
+ setTimeout(() => setCopied(false), 2000)
+ }
+
+ const actions = [
+ {
+ icon: ,
+ label: 'Copy Install Command',
+ action: copyInstallCommand,
+ variant: 'outline' as const
+ },
+ {
+ icon: ,
+ label: 'Open Playground',
+ action: () => window.open('/playground', '_blank'),
+ variant: 'outline' as const
+ },
+ {
+ icon: ,
+ label: 'View on GitHub',
+ action: () => window.open('https://github.com/rad-ui/ui', '_blank'),
+ variant: 'outline' as const
+ },
+ {
+ icon: ,
+ label: 'Join Discord',
+ action: () => window.open('https://discord.gg/nMaQfeEPNp', '_blank'),
+ variant: 'outline' as const
+ },
+ {
+ icon: ,
+ label: 'Star on GitHub',
+ action: () => window.open('https://github.com/rad-ui/ui', '_blank'),
+ variant: 'solid' as const,
+ color: 'green' as const
+ }
+ ]
+
+ return (
+
+ Quick Actions
+
+
+ {actions.map((action, index) => (
+
+ {action.icon}
+ {action.label === 'Copy Install Command' && copied ? 'Copied!' : action.label}
+
+ ))}
+
+
+
+
Install Rad UI
+
+
+ npm install @radui/ui
+
+
+
+
+
+
+
+ )
+}
+
+export default QuickActions
diff --git a/docs/components/ReadingProgress.tsx b/docs/components/ReadingProgress.tsx
new file mode 100644
index 000000000..62b6c5b24
--- /dev/null
+++ b/docs/components/ReadingProgress.tsx
@@ -0,0 +1,31 @@
+'use client'
+import { useEffect, useState } from 'react'
+
+const ReadingProgress = () => {
+ const [progress, setProgress] = useState(0)
+
+ useEffect(() => {
+ const updateProgress = () => {
+ const scrollTop = window.scrollY
+ const docHeight = document.documentElement.scrollHeight - window.innerHeight
+ const scrollPercent = (scrollTop / docHeight) * 100
+ setProgress(scrollPercent)
+ }
+
+ window.addEventListener('scroll', updateProgress)
+ updateProgress() // Initial calculation
+
+ return () => window.removeEventListener('scroll', updateProgress)
+ }, [])
+
+ return (
+
+ )
+}
+
+export default ReadingProgress
diff --git a/docs/components/SearchBar.tsx b/docs/components/SearchBar.tsx
new file mode 100644
index 000000000..6faa00647
--- /dev/null
+++ b/docs/components/SearchBar.tsx
@@ -0,0 +1,114 @@
+'use client'
+import { useState, useEffect } from 'react'
+import { Search, X } from 'lucide-react'
+import Card from '@radui/ui/Card'
+import Text from '@radui/ui/Text'
+import Link from '@radui/ui/Link'
+
+interface SearchResult {
+ title: string
+ href: string
+ description?: string
+ category: string
+}
+
+const SearchBar = () => {
+ const [query, setQuery] = useState('')
+ const [results, setResults] = useState([])
+ const [isOpen, setIsOpen] = useState(false)
+
+ // Mock search data - in a real app, this would come from an API or search index
+ const searchData: SearchResult[] = [
+ { title: 'Installation', href: '/docs/first-steps/installation', description: 'Get started with Rad UI', category: 'Getting Started' },
+ { title: 'Introduction', href: '/docs/first-steps/introduction', description: 'Learn about Rad UI', category: 'Getting Started' },
+ { title: 'Button', href: '/docs/components/button', description: 'Interactive button component', category: 'Components' },
+ { title: 'Card', href: '/docs/components/card', description: 'Container component', category: 'Components' },
+ { title: 'Input', href: '/docs/components/input', description: 'Form input component', category: 'Components' },
+ { title: 'Modal', href: '/docs/components/modal', description: 'Overlay dialog component', category: 'Components' },
+ { title: 'Accordion', href: '/docs/components/accordion', description: 'Collapsible content component', category: 'Components' },
+ { title: 'Avatar', href: '/docs/components/avatar', description: 'User profile image component', category: 'Components' },
+ { title: 'Badge', href: '/docs/components/badge', description: 'Status indicator component', category: 'Components' },
+ { title: 'Playground', href: '/playground', description: 'Interactive component playground', category: 'Tools' },
+ { title: 'Sponsors', href: '/sponsors', description: 'Our amazing sponsors', category: 'Community' },
+ ]
+
+ useEffect(() => {
+ if (query.length < 2) {
+ setResults([])
+ return
+ }
+
+ const filtered = searchData.filter(item =>
+ item.title.toLowerCase().includes(query.toLowerCase()) ||
+ item.description?.toLowerCase().includes(query.toLowerCase()) ||
+ item.category.toLowerCase().includes(query.toLowerCase())
+ )
+
+ setResults(filtered.slice(0, 8)) // Limit to 8 results
+ }, [query])
+
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === 'Escape') {
+ setIsOpen(false)
+ setQuery('')
+ }
+ }
+
+ return (
+
+
+
+ setQuery(e.target.value)}
+ onFocus={() => setIsOpen(true)}
+ onKeyDown={handleKeyDown}
+ className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent"
+ />
+ {query && (
+ {
+ setQuery('')
+ setResults([])
+ }}
+ className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
+ >
+
+
+ )}
+
+
+ {isOpen && results.length > 0 && (
+
+
+ {results.map((result, index) => (
+
{
+ setIsOpen(false)
+ setQuery('')
+ }}
+ >
+
+
+ {result.title}
+ {result.description && (
+ {result.description}
+ )}
+
+
{result.category}
+
+
+ ))}
+
+
+ )}
+
+ )
+}
+
+export default SearchBar
diff --git a/docs/components/TableOfContents.tsx b/docs/components/TableOfContents.tsx
new file mode 100644
index 000000000..4e9fa7f55
--- /dev/null
+++ b/docs/components/TableOfContents.tsx
@@ -0,0 +1,89 @@
+'use client'
+import { useEffect, useState } from 'react'
+import Card from '@radui/ui/Card'
+import Text from '@radui/ui/Text'
+import Link from '@radui/ui/Link'
+import Badge from '@radui/ui/Badge'
+
+interface TocItem {
+ id: string
+ title: string
+ level: number
+ element: HTMLElement
+}
+
+const TableOfContents = () => {
+ const [tocItems, setTocItems] = useState([])
+ const [activeId, setActiveId] = useState('')
+
+ useEffect(() => {
+ const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6')
+ const items: TocItem[] = []
+
+ headings.forEach((heading) => {
+ const element = heading as HTMLElement
+ const id = element.id || element.textContent?.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, '') || ''
+
+ if (id) {
+ element.id = id
+ items.push({
+ id,
+ title: element.textContent || '',
+ level: parseInt(element.tagName.charAt(1)),
+ element
+ })
+ }
+ })
+
+ setTocItems(items)
+
+ // Intersection Observer for active section
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ setActiveId(entry.target.id)
+ }
+ })
+ },
+ {
+ rootMargin: '-20% 0% -80% 0%',
+ threshold: 0
+ }
+ )
+
+ items.forEach((item) => observer.observe(item.element))
+
+ return () => observer.disconnect()
+ }, [])
+
+ if (tocItems.length === 0) return null
+
+ return (
+
+
+ Contents
+ Table of Contents
+
+
+
+ {tocItems.map((item) => (
+
+ {item.title}
+
+ ))}
+
+
+ )
+}
+
+export default TableOfContents
diff --git a/docs/components/layout/Documentation/Documentation.js b/docs/components/layout/Documentation/Documentation.js
index c302046a5..4f2ff9f14 100644
--- a/docs/components/layout/Documentation/Documentation.js
+++ b/docs/components/layout/Documentation/Documentation.js
@@ -25,7 +25,7 @@ const Documentation = ({ title = '', description = '', currentPage = undefined,
{title}
- {description && {description} }
+ {description && {description} }
{children}
diff --git a/docs/components/layout/Documentation/ModernDocumentation.js b/docs/components/layout/Documentation/ModernDocumentation.js
new file mode 100644
index 000000000..d54f50151
--- /dev/null
+++ b/docs/components/layout/Documentation/ModernDocumentation.js
@@ -0,0 +1,153 @@
+import Text from '@radui/ui/Text';
+import Heading from '@radui/ui/Heading';
+import Link from '@radui/ui/Link';
+import Separator from '@radui/ui/Separator';
+import Badge from '@radui/ui/Badge';
+import Card from '@radui/ui/Card';
+import DocsTable from './helpers/DocsTable';
+import CodeBlock from '@/components/layout/Documentation/helpers/CodeBlock';
+import ComponentHero from '@/components/layout/Documentation/helpers/ComponentHero/ComponentHero';
+import ComponentFeatures from '@/components/layout/Documentation/helpers/ComponentFeatures/ComponentFeatures';
+import Breadcrumbs from '@/components/navigation/Breadcrumbs';
+import TableOfContents from '@/components/TableOfContents';
+import { BookMarkLink } from '@/components/layout/Documentation/utils';
+
+const LeftArrow = () => {
+ return
;
+};
+
+const RightArrow = () => {
+ return
;
+};
+
+const ModernDocumentation = ({ title = '', description = '', currentPage = undefined, children }) => {
+ return (
+
+
+ {/* Main Content */}
+
+ {/* Breadcrumbs */}
+
+
+ {/* Header */}
+
+
+
+
+ {title}
+
+
+
+ {description && (
+
+ {description}
+
+ )}
+
+
+ {/* Content */}
+
+ {children}
+
+
+
+
+
+ {/* Sidebar */}
+
+
+
+ );
+};
+
+const Anatomy = ({ code, as = "h3", language = 'jsx' }) => {
+ return (
+
+
+
+
+ Anatomy
+ Component Structure
+
+
+
+ Import all parts of the component and piece them together
+
+
+
+ {code}
+
+
+ );
+};
+
+const Section = ({ title = '', as = "h2", children }) => {
+ return (
+
+
+
+ Section
+ {title}
+
+
+
+ {children}
+
+
+ );
+};
+
+const TableOfContents = ({ items = [] }) => {
+ if (items.length === 0) return null;
+
+ return (
+
+
+ Contents
+ Table of Contents
+
+
+ {items.map((item, index) => (
+
+
+ {item.title}
+
+
+ ))}
+
+
+ );
+};
+
+const UnderConstruction = ({ children }) => {
+ return (
+
+
+ Under Construction
+
+
+ Documentation Coming Soon
+
+
+ We're working hard to bring you comprehensive documentation. Check back soon!
+
+
+ );
+};
+
+// Export all components
+ModernDocumentation.UnderConstruction = UnderConstruction;
+ModernDocumentation.Anatomy = Anatomy;
+ModernDocumentation.Section = Section;
+ModernDocumentation.ComponentHero = ComponentHero;
+ModernDocumentation.ComponentFeatures = ComponentFeatures;
+ModernDocumentation.CodeBlock = CodeBlock;
+ModernDocumentation.Table = DocsTable;
+ModernDocumentation.TableOfContents = TableOfContents;
+
+export default ModernDocumentation;
diff --git a/docs/components/layout/Documentation/helpers/CodeBlock.js b/docs/components/layout/Documentation/helpers/CodeBlock.js
index fb1abc2e8..1a78e2ac1 100644
--- a/docs/components/layout/Documentation/helpers/CodeBlock.js
+++ b/docs/components/layout/Documentation/helpers/CodeBlock.js
@@ -74,7 +74,6 @@ className={`language-${language} whitespace-pre-wrap`}
{
+ const pathname = usePathname()
+
+ const generateBreadcrumbs = (): BreadcrumbItem[] => {
+ const segments = pathname.split('/').filter(Boolean)
+ const breadcrumbs: BreadcrumbItem[] = [
+ { label: 'Home', href: '/' }
+ ]
+
+ let currentPath = ''
+
+ segments.forEach((segment, index) => {
+ currentPath += `/${segment}`
+ const isLast = index === segments.length - 1
+
+ // Format segment labels
+ let label = segment
+ .split('-')
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
+ .join(' ')
+
+ // Special cases
+ if (segment === 'docs') {
+ label = 'Documentation'
+ } else if (segment === 'first-steps') {
+ label = 'Getting Started'
+ } else if (segment === 'components') {
+ label = 'Components'
+ } else if (segment === 'showcase') {
+ label = 'Showcase'
+ } else if (segment === 'playground') {
+ label = 'Playground'
+ } else if (segment === 'sponsors') {
+ label = 'Sponsors'
+ }
+
+ breadcrumbs.push({
+ label,
+ href: currentPath,
+ isActive: isLast
+ })
+ })
+
+ return breadcrumbs
+ }
+
+ const breadcrumbs = generateBreadcrumbs()
+
+ if (breadcrumbs.length <= 1) return null
+
+ return (
+
+ {breadcrumbs.map((item, index) => (
+
+ {index > 0 && (
+
+ )}
+ {item.isActive ? (
+ {item.label}
+ ) : (
+
+ {item.label}
+
+ )}
+
+ ))}
+
+ )
+}
+
+export default Breadcrumbs
diff --git a/docs/components/navigation/ModernNavigation.tsx b/docs/components/navigation/ModernNavigation.tsx
new file mode 100644
index 000000000..db79c3c0c
--- /dev/null
+++ b/docs/components/navigation/ModernNavigation.tsx
@@ -0,0 +1,124 @@
+'use client'
+import { usePathname } from 'next/navigation';
+import { useContext, useEffect, useState } from 'react';
+import { NavBarContext } from '@/components/Main/NavBar/NavBarContext';
+import docsSections from "@/app/docs/docsNavigationSections"
+import ScrollArea from "@radui/ui/ScrollArea"
+import Category from './Category'
+import Badge from "@radui/ui/Badge"
+import Text from "@radui/ui/Text"
+import SearchBar from '../SearchBar'
+import QuickActions from '../QuickActions'
+import AccessibilityFeatures from '../AccessibilityFeatures'
+import KeyboardShortcuts from '../KeyboardShortcuts'
+
+const ModernNavigation = ({ customSections }: { customSections?: any }) => {
+ const defaultSections = [
+ {
+ type: "CATEGORY",
+ title: "Main",
+ items: [
+ { title: "Documentation", path: "/docs/first-steps/introduction" },
+ { title: "Showcase", path: "/showcase/music-app" }
+ ]
+ }
+ ]
+
+ const pathname = usePathname();
+ const { setIsDocsNavOpen } = useContext(NavBarContext) as {
+ isDocsNavOpen: boolean,
+ setIsDocsNavOpen: (isDocsNavOpen: boolean) => void
+ };
+
+ const [sections, setSections] = useState(docsSections);
+
+ useEffect(() => {
+ if (pathname.includes("/docs/")) {
+ setSections(docsSections)
+ } else {
+ setSections(defaultSections)
+ }
+ }, [pathname])
+
+ return (
+
+
+
+
+ {/* Search Bar */}
+
+
+
+
+ {/* Quick Actions */}
+
+
+
+
+ {/* Accessibility Features */}
+
+
+ {/* Keyboard Shortcuts */}
+
+
+
+
+ {/* Quick Links */}
+
+
+ {/* Navigation Sections */}
+ {sections.map((section, i) => {
+ const isCategory = section.type === "CATEGORY";
+ if (isCategory) {
+ return (
+
+
+
+ )
+ } else {
+ return (
+
+ Coming Soon
+
+ )
+ }
+ })}
+
+
+
+
+
+
+
+ )
+}
+
+export default ModernNavigation;
diff --git a/docs/package.json b/docs/package.json
index 50a31a28e..a76f31d37 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -28,6 +28,7 @@
"eslint": "8.48.0",
"eslint-config-next": "15.1.2",
"js-cookie": "^3.0.5",
+ "lucide-react": "^0.544.0",
"motion": "^12.9.2",
"next": "^15.2.4",
"next-cookies": "^2.0.3",
diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml
index 63af39b21..437610821 100644
--- a/docs/pnpm-lock.yaml
+++ b/docs/pnpm-lock.yaml
@@ -59,6 +59,9 @@ importers:
js-cookie:
specifier: ^3.0.5
version: 3.0.5
+ lucide-react:
+ specifier: ^0.544.0
+ version: 0.544.0(react@19.0.0)
motion:
specifier: ^12.9.2
version: 12.9.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -1520,6 +1523,11 @@ packages:
resolution: {integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==}
engines: {node: 14 || >=16.14}
+ lucide-react@0.544.0:
+ resolution: {integrity: sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==}
+ peerDependencies:
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
markdown-extensions@2.0.0:
resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==}
engines: {node: '>=16'}
@@ -3340,8 +3348,8 @@ snapshots:
'@typescript-eslint/parser': 8.18.1(eslint@8.48.0)(typescript@5.2.2)
eslint: 8.48.0
eslint-import-resolver-node: 0.3.9
- eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.48.0)
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-typescript@3.6.1)(eslint@8.48.0)
+ eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint@8.48.0))(eslint@8.48.0)
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint@8.48.0))(eslint@8.48.0))(eslint@8.48.0)
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.48.0)
eslint-plugin-react: 7.37.2(eslint@8.48.0)
eslint-plugin-react-hooks: 5.1.0(eslint@8.48.0)
@@ -3359,13 +3367,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.48.0):
+ eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint@8.48.0))(eslint@8.48.0):
dependencies:
debug: 4.3.4
enhanced-resolve: 5.15.0
eslint: 8.48.0
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.48.0)
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-typescript@3.6.1)(eslint@8.48.0)
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint@8.48.0))(eslint@8.48.0))(eslint@8.48.0)
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint@8.48.0))(eslint@8.48.0))(eslint@8.48.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.2
is-core-module: 2.16.0
@@ -3376,18 +3384,18 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
- eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.48.0):
+ eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint@8.48.0))(eslint@8.48.0))(eslint@8.48.0):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.18.1(eslint@8.48.0)(typescript@5.2.2)
eslint: 8.48.0
eslint-import-resolver-node: 0.3.9
- eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.48.0)
+ eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint@8.48.0))(eslint@8.48.0)
transitivePeerDependencies:
- supports-color
- eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-typescript@3.6.1)(eslint@8.48.0):
+ eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint@8.48.0))(eslint@8.48.0))(eslint@8.48.0):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.8
@@ -3398,7 +3406,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.48.0
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.48.0)
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.1(eslint@8.48.0)(typescript@5.2.2))(eslint@8.48.0))(eslint@8.48.0))(eslint@8.48.0)
hasown: 2.0.2
is-core-module: 2.16.0
is-glob: 4.0.3
@@ -4052,6 +4060,10 @@ snapshots:
lru-cache@10.1.0: {}
+ lucide-react@0.544.0(react@19.0.0):
+ dependencies:
+ react: 19.0.0
+
markdown-extensions@2.0.0: {}
math-intrinsics@1.1.0: {}