From d61e9208ec4c05a5c84d2a6ee18cbae36f15364b Mon Sep 17 00:00:00 2001 From: Pranay Kothapalli Date: Sat, 13 Sep 2025 14:21:13 +0530 Subject: [PATCH 1/4] fix: improvements --- .../components/accordion/docs/codeUsage.js | 6 ++- .../accordion/docs/component_api/content.tsx | 38 +++++++++++++++++++ .../accordion/docs/component_api/header.tsx | 38 +++++++++++++++++++ .../accordion/docs/component_api/item.tsx | 2 +- .../accordion/docs/component_api/root.tsx | 2 +- .../accordion/docs/component_api/trigger.tsx | 2 +- .../components/accordion/docs/example_1.tsx | 27 +++++++------ docs/app/docs/components/accordion/page.mdx | 2 + .../docs/components/avatar/docs/codeUsage.js | 6 +-- .../avatar/docs/component_api/fallback.tsx | 4 +- .../avatar/docs/component_api/image.tsx | 4 +- .../avatar/docs/component_api/root.tsx | 12 +++--- .../docs/components/badge/docs/codeUsage.js | 14 +++---- .../button/docs/component_api/button.tsx | 2 +- .../card/docs/component_api/card.tsx | 6 +-- 15 files changed, 122 insertions(+), 43 deletions(-) create mode 100644 docs/app/docs/components/accordion/docs/component_api/content.tsx create mode 100644 docs/app/docs/components/accordion/docs/component_api/header.tsx diff --git a/docs/app/docs/components/accordion/docs/codeUsage.js b/docs/app/docs/components/accordion/docs/codeUsage.js index 272ec9f60..bb1f629cb 100644 --- a/docs/app/docs/components/accordion/docs/codeUsage.js +++ b/docs/app/docs/components/accordion/docs/codeUsage.js @@ -12,6 +12,8 @@ const anatomy_SourceCode = await getSourceCodeFromPath('docs/app/docs/components import root_api_SourceCode from './component_api/root.tsx'; import item_api_SourceCode from './component_api/item.tsx'; import trigger_api_SourceCode from './component_api/trigger.tsx'; +import header_api_SourceCode from './component_api/header.tsx'; +import content_api_SourceCode from './component_api/content.tsx'; export const code = { javascript: { @@ -29,7 +31,9 @@ export const anatomy = { export const api_documentation = { root: root_api_SourceCode, item: item_api_SourceCode, - trigger: trigger_api_SourceCode + trigger: trigger_api_SourceCode, + header: header_api_SourceCode, + content: content_api_SourceCode } export const keyboardShortcuts = { diff --git a/docs/app/docs/components/accordion/docs/component_api/content.tsx b/docs/app/docs/components/accordion/docs/component_api/content.tsx new file mode 100644 index 000000000..e4294ba02 --- /dev/null +++ b/docs/app/docs/components/accordion/docs/component_api/content.tsx @@ -0,0 +1,38 @@ +const data = { + name: "Content", + description: "The content component for the Accordion. This component contains the collapsible content that is shown/hidden when the trigger is activated.", + columns: [ + { + name: "Prop", + id: "prop", + }, + { + name: "Type", + id: "type", + }, + { + name: "Default", + id: "default", + } + ], + data: [ + { + prop: { + name: "className", + info_tooltips: "The class name for the AccordionContent." + }, + type: "string", + default: "--", + }, + { + prop: { + name: "asChild", + info_tooltips: "Whether to use the child component as the AccordionContent." + }, + type: "boolean", + default: "false", + } + ] +} + +export default data; diff --git a/docs/app/docs/components/accordion/docs/component_api/header.tsx b/docs/app/docs/components/accordion/docs/component_api/header.tsx new file mode 100644 index 000000000..acb65c203 --- /dev/null +++ b/docs/app/docs/components/accordion/docs/component_api/header.tsx @@ -0,0 +1,38 @@ +const data = { + name: "Header", + description: "The header component for the Accordion. This component wraps the trigger and provides the header structure for each accordion item.", + columns: [ + { + name: "Prop", + id: "prop", + }, + { + name: "Type", + id: "type", + }, + { + name: "Default", + id: "default", + } + ], + data: [ + { + prop: { + name: "className", + info_tooltips: "The class name for the AccordionHeader." + }, + type: "string", + default: "--", + }, + { + prop: { + name: "asChild", + info_tooltips: "Whether to use the child component as the AccordionHeader." + }, + type: "boolean", + default: "false", + } + ] +} + +export default data; diff --git a/docs/app/docs/components/accordion/docs/component_api/item.tsx b/docs/app/docs/components/accordion/docs/component_api/item.tsx index 819124c09..2b69ba4b6 100644 --- a/docs/app/docs/components/accordion/docs/component_api/item.tsx +++ b/docs/app/docs/components/accordion/docs/component_api/item.tsx @@ -22,7 +22,7 @@ const data = { info_tooltips : "The class name for the AccordionItem." }, type : "string", - default : "--", + default : "''", }, { prop: { diff --git a/docs/app/docs/components/accordion/docs/component_api/root.tsx b/docs/app/docs/components/accordion/docs/component_api/root.tsx index 638d52f43..ef0c0d7f8 100644 --- a/docs/app/docs/components/accordion/docs/component_api/root.tsx +++ b/docs/app/docs/components/accordion/docs/component_api/root.tsx @@ -22,7 +22,7 @@ const data = { info_tooltips : "The class name for the AccordionRoot." }, type : "string", - default : "--", + default : "''", }, { prop : { diff --git a/docs/app/docs/components/accordion/docs/component_api/trigger.tsx b/docs/app/docs/components/accordion/docs/component_api/trigger.tsx index bc75c93a3..ff54b46cb 100644 --- a/docs/app/docs/components/accordion/docs/component_api/trigger.tsx +++ b/docs/app/docs/components/accordion/docs/component_api/trigger.tsx @@ -22,7 +22,7 @@ const data = { info_tooltips : "The class name for the AccordionTrigger." }, type : "string", - default : "--", + default : "''", }, { prop: { diff --git a/docs/app/docs/components/accordion/docs/example_1.tsx b/docs/app/docs/components/accordion/docs/example_1.tsx index 645a04969..4b2a582f1 100644 --- a/docs/app/docs/components/accordion/docs/example_1.tsx +++ b/docs/app/docs/components/accordion/docs/example_1.tsx @@ -20,21 +20,20 @@ const items = [ ] const AccordionExample = () => { - - return ( -
- - {items.map((item) => ( - - - {item.title} - - {item.content} - - ))} - -
) +
+ + {items.map((item, index) => ( + + + {item.title} + + {item.content} + + ))} + +
+ ) } export default AccordionExample; \ No newline at end of file diff --git a/docs/app/docs/components/accordion/page.mdx b/docs/app/docs/components/accordion/page.mdx index db747f49c..ae9de0a9c 100644 --- a/docs/app/docs/components/accordion/page.mdx +++ b/docs/app/docs/components/accordion/page.mdx @@ -30,7 +30,9 @@ import {code, anatomy, keyboardShortcuts, api_documentation} from "./docs/codeUs {/* API Documentation */} + + {/* Keyboard Shortcuts */} diff --git a/docs/app/docs/components/avatar/docs/codeUsage.js b/docs/app/docs/components/avatar/docs/codeUsage.js index d8b9fa9bc..7245aee39 100644 --- a/docs/app/docs/components/avatar/docs/codeUsage.js +++ b/docs/app/docs/components/avatar/docs/codeUsage.js @@ -33,9 +33,9 @@ export const avatarBasicUsageExample = { {name: 'Description', id: 'description'}, ], data: [ - {prop: 'src', type: 'string', default: 'null', description: 'URL of the image to be displayed as the avatar.', id: 'src'}, - {prop: 'fallback', type: 'string', default: 'null', description: 'Text initials or placeholder displayed when the image fails to load or if no src is provided.', id: 'fallback'}, - {prop: 'color', type: 'string', default: 'null', description: 'Accent Color of the text initials or placeholder displayed when the image fails to load or if no src is provided.', id: 'color'}, + {prop: 'src', type: 'string', default: "''", description: 'URL of the image to be displayed as the avatar.', id: 'src'}, + {prop: 'fallback', type: 'string', default: "''", description: 'Text initials or placeholder displayed when the image fails to load or if no src is provided.', id: 'fallback'}, + {prop: 'color', type: 'string', default: "''", description: 'Accent Color of the text initials or placeholder displayed when the image fails to load or if no src is provided.', id: 'color'}, ] } diff --git a/docs/app/docs/components/avatar/docs/component_api/fallback.tsx b/docs/app/docs/components/avatar/docs/component_api/fallback.tsx index b68c836db..8de599098 100644 --- a/docs/app/docs/components/avatar/docs/component_api/fallback.tsx +++ b/docs/app/docs/components/avatar/docs/component_api/fallback.tsx @@ -22,7 +22,7 @@ const data = { info_tooltips : "The children of the AvatarFallback." }, type : "React.ReactNode", - default : "--", + default : "''", }, { prop : { @@ -30,7 +30,7 @@ const data = { info_tooltips : "The class name for the AvatarFallback." }, type : "string", - default : "--", + default : "''", } ] } diff --git a/docs/app/docs/components/avatar/docs/component_api/image.tsx b/docs/app/docs/components/avatar/docs/component_api/image.tsx index e0b6cc777..41cedd167 100644 --- a/docs/app/docs/components/avatar/docs/component_api/image.tsx +++ b/docs/app/docs/components/avatar/docs/component_api/image.tsx @@ -22,7 +22,7 @@ const data = { info_tooltips : "The source of the image." }, type : "string", - default : "--", + default : "''", }, { prop : { @@ -30,7 +30,7 @@ const data = { info_tooltips : "The alternative text for the image." }, type : "string", - default : "--", + default : "''", } ] } diff --git a/docs/app/docs/components/avatar/docs/component_api/root.tsx b/docs/app/docs/components/avatar/docs/component_api/root.tsx index ddb35fc0c..07fc92b9f 100644 --- a/docs/app/docs/components/avatar/docs/component_api/root.tsx +++ b/docs/app/docs/components/avatar/docs/component_api/root.tsx @@ -22,7 +22,7 @@ const data = { info_tooltips : "The class name for the AvatarRoot." }, type : "string", - default : "--", + default : "''", }, { prop : { @@ -30,7 +30,7 @@ const data = { info_tooltips : "The class name for the AvatarRoot." }, type : "string", - default : "--", + default : "''", }, { prop: { @@ -46,7 +46,7 @@ const data = { info_tooltips: 'The children of the AvatarRoot.' }, type: 'React.ReactNode', - default: 'null', + default: "''", }, { prop: { @@ -54,7 +54,7 @@ const data = { info_tooltips: 'The size of the AvatarRoot.' }, type: 'string', - default: '``', + default: "''", }, { prop: { @@ -62,7 +62,7 @@ const data = { info_tooltips: 'The variant of the AvatarRoot.' }, type: 'string', - default: '``', + default: "''", }, { prop: { @@ -70,7 +70,7 @@ const data = { info_tooltips: 'The color of the AvatarRoot.' }, type: 'string', - default: '``', + default: "''", } ] } diff --git a/docs/app/docs/components/badge/docs/codeUsage.js b/docs/app/docs/components/badge/docs/codeUsage.js index 61365e5c4..a9f77be6a 100644 --- a/docs/app/docs/components/badge/docs/codeUsage.js +++ b/docs/app/docs/components/badge/docs/codeUsage.js @@ -23,19 +23,17 @@ const BadgeExample = () => ( }, } -export const BadgeTable ={ - columns: [ +export const BadgeTable = { + columns: [ {name: 'Prop', id: 'prop'}, {name: 'Type', id: 'type'}, {name: 'Default', id: 'default'}, {name: 'Description', id: 'description'}, ], - - data : [ - {prop: 'color', type: 'string', default: 'null', description: 'Accent color of the component', id: 'color'}, - {prop: 'size', type: 'string', default: 'null', description: 'Size of the component', id: 'size'}, - {prop: 'variant', type: 'string', default: 'null', description: 'Variant of the component', id: 'variant'}, - + data: [ + {prop: 'color', type: 'string', default: "''", description: 'Accent color of the component', id: 'color'}, + {prop: 'size', type: 'string', default: "''", description: 'Size of the component', id: 'size'}, + {prop: 'variant', type: 'string', default: "''", description: 'Variant of the component', id: 'variant'}, ] } export default code; \ No newline at end of file diff --git a/docs/app/docs/components/button/docs/component_api/button.tsx b/docs/app/docs/components/button/docs/component_api/button.tsx index 76a77595a..8eab98e4a 100644 --- a/docs/app/docs/components/button/docs/component_api/button.tsx +++ b/docs/app/docs/components/button/docs/component_api/button.tsx @@ -22,7 +22,7 @@ const data = { info_tooltips: "The content to be displayed inside the button." }, type: "ReactNode", - default: "--", + default: "''", }, { prop: { diff --git a/docs/app/docs/components/card/docs/component_api/card.tsx b/docs/app/docs/components/card/docs/component_api/card.tsx index 94adfc512..db57cb782 100644 --- a/docs/app/docs/components/card/docs/component_api/card.tsx +++ b/docs/app/docs/components/card/docs/component_api/card.tsx @@ -22,7 +22,7 @@ const data = { info_tooltips: "The content to be displayed inside the card." }, type: "ReactNode", - default: "--", + default: "''", }, { prop: { @@ -38,7 +38,7 @@ const data = { info_tooltips: "Custom root class name to override default styling." }, type: "string", - default: "--", + default: "''", }, { prop: { @@ -46,7 +46,7 @@ const data = { info_tooltips: "Accent color to apply to the card. Used as a data attribute." }, type: "string", - default: "--", + default: "''", } ] }; From 678fb7727e5f2c1293d7133564b622b0a9dca98d Mon Sep 17 00:00:00 2001 From: Pranay Kothapalli Date: Sat, 13 Sep 2025 14:44:06 +0530 Subject: [PATCH 2/4] fix: improve docs --- .../badge/examples/BadgeVariants.tsx | 2 +- .../button/examples/ButtonVariants.tsx | 2 +- .../callout/examples/CalloutVariants.tsx | 2 +- docs/app/docs/components/card/page.mdx | 2 +- .../app/docs/components/em/docs/EmExample.tsx | 2 +- docs/app/globals.scss | 45 ++++-- docs/app/landingComponents/AddToCartDemo.js | 4 +- docs/app/landingComponents/HeroSection.js | 8 +- .../landingComponents/MusicAppPlayerDemo.js | 4 +- docs/app/landingComponents/SponsorsSection.js | 86 +++++++++++ docs/app/landingComponents/ToolbarDemo.js | 2 +- docs/app/page.tsx | 81 ++++++++-- .../app/playground/components/EmPlayground.js | 2 +- .../components/HeadingPlayground.js | 8 +- .../components/SeparatorPlayground.js | 2 +- docs/app/playground/page.tsx | 2 +- .../music-app/helpers/MusicSidebar.js | 4 +- .../helpers/sections/PlaylistHero.tsx | 2 +- .../music-app/helpers/sections/TopArtists.tsx | 2 +- docs/components/Main/NavBar/index.js | 5 +- docs/components/Performance/LazyComponent.tsx | 34 +++++ .../layout/Documentation/Documentation.js | 2 +- .../Documentation/ModernDocumentation.js | 138 ++++++++++++++++++ .../layout/Documentation/helpers/CodeBlock.js | 1 - .../navigation/ModernNavigation.tsx | 100 +++++++++++++ 25 files changed, 484 insertions(+), 58 deletions(-) create mode 100644 docs/app/landingComponents/SponsorsSection.js create mode 100644 docs/components/Performance/LazyComponent.tsx create mode 100644 docs/components/layout/Documentation/ModernDocumentation.js create mode 100644 docs/components/navigation/ModernNavigation.tsx diff --git a/docs/app/docs/components/badge/examples/BadgeVariants.tsx b/docs/app/docs/components/badge/examples/BadgeVariants.tsx index 79afda5ed..b2522a702 100644 --- a/docs/app/docs/components/badge/examples/BadgeVariants.tsx +++ b/docs/app/docs/components/badge/examples/BadgeVariants.tsx @@ -39,7 +39,7 @@ const BadgeVariants = () => { - + {variant} diff --git a/docs/app/docs/components/button/examples/ButtonVariants.tsx b/docs/app/docs/components/button/examples/ButtonVariants.tsx index ce51ec672..b7a9b3c21 100644 --- a/docs/app/docs/components/button/examples/ButtonVariants.tsx +++ b/docs/app/docs/components/button/examples/ButtonVariants.tsx @@ -42,7 +42,7 @@ const ButtonVariants = () => { - + {variant} diff --git a/docs/app/docs/components/callout/examples/CalloutVariants.tsx b/docs/app/docs/components/callout/examples/CalloutVariants.tsx index d1c0ed24f..dfb258368 100644 --- a/docs/app/docs/components/callout/examples/CalloutVariants.tsx +++ b/docs/app/docs/components/callout/examples/CalloutVariants.tsx @@ -29,7 +29,7 @@ const CalloutVariants = () => { - + {variant} diff --git a/docs/app/docs/components/card/page.mdx b/docs/app/docs/components/card/page.mdx index 6f2d7266a..4fbda1ebd 100644 --- a/docs/app/docs/components/card/page.mdx +++ b/docs/app/docs/components/card/page.mdx @@ -17,7 +17,7 @@ export const metadata = cardMetadata;
Peter Parker - Biochemist + Biochemist
diff --git a/docs/app/docs/components/em/docs/EmExample.tsx b/docs/app/docs/components/em/docs/EmExample.tsx index c6ee7660c..db88e741e 100644 --- a/docs/app/docs/components/em/docs/EmExample.tsx +++ b/docs/app/docs/components/em/docs/EmExample.tsx @@ -4,7 +4,7 @@ import Card from "@radui/ui/Card" const EmExample = () => { return ( - + I have a dream of a scene between the green hills. Clouds pull away and the sunlight's revealed. People don't talk about keeping it real. diff --git a/docs/app/globals.scss b/docs/app/globals.scss index d1c9a696f..ed8f8ea8b 100644 --- a/docs/app/globals.scss +++ b/docs/app/globals.scss @@ -5,6 +5,37 @@ body { font-family: Inter, sans-serif; + font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11'; + font-variation-settings: normal; + text-rendering: optimizelegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* Modern scrollbar */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--rad-ui-color-gray-100); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: var(--rad-ui-color-gray-300); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--rad-ui-color-gray-400); +} + +/* Focus styles */ +*:focus-visible { + outline: 2px solid var(--rad-ui-color-green-500); + outline-offset: 2px; } @@ -70,20 +101,6 @@ code .selector { } -.background-animate { - background-size: 400%; - animation: AnimationName 10s ease infinite; -} - -@keyframes AnimationName { - 0%,100% { - background-position: 0% 50%; - } - - 50% { - background-position: 100% 50%; - } -} diff --git a/docs/app/landingComponents/AddToCartDemo.js b/docs/app/landingComponents/AddToCartDemo.js index b7f2f0d63..a3a5cbf88 100644 --- a/docs/app/landingComponents/AddToCartDemo.js +++ b/docs/app/landingComponents/AddToCartDemo.js @@ -27,9 +27,9 @@ const AddToCartDemo = () => {
- Join the Ultimate Fan Experience + Join the Ultimate Fan Experience
- Limited Edition Band Tee - A Must-Have for Music Lovers! + Limited Edition Band Tee - A Must-Have for Music Lovers!
diff --git a/docs/app/landingComponents/HeroSection.js b/docs/app/landingComponents/HeroSection.js index 0c60da69a..86182f867 100644 --- a/docs/app/landingComponents/HeroSection.js +++ b/docs/app/landingComponents/HeroSection.js @@ -122,7 +122,7 @@ const IntegrationCard = ({ title, description, icon, cta="", ctaLink }) => { {icon} {title} {description} -
@@ -139,7 +139,7 @@ const HeroSection = () => { Accelerate Your UI Development with Prebuilt Components - + Empowering developers with the tools to design and build modern UI effortlessly. Dive in and bring your ideas to life. @@ -189,13 +189,13 @@ color="blue" variant="ghost" onClick={() => { {/* Features Section */}
- + About Rad UI Core Features - + Our features allow you to create modern, efficient UIs with ease. Focus on your projects while we provide the tools to streamline your development process.
diff --git a/docs/app/landingComponents/MusicAppPlayerDemo.js b/docs/app/landingComponents/MusicAppPlayerDemo.js index e27564db8..6c4875eaa 100644 --- a/docs/app/landingComponents/MusicAppPlayerDemo.js +++ b/docs/app/landingComponents/MusicAppPlayerDemo.js @@ -45,7 +45,7 @@ const MusicAppPlayerDemo = () => {
-
+
@@ -61,7 +61,7 @@ const MusicAppPlayerDemo = () => {
Won't Bite - Doja Cat + Doja Cat
02:22 diff --git a/docs/app/landingComponents/SponsorsSection.js b/docs/app/landingComponents/SponsorsSection.js new file mode 100644 index 000000000..766949153 --- /dev/null +++ b/docs/app/landingComponents/SponsorsSection.js @@ -0,0 +1,86 @@ +'use client' +import { useState } from 'react' +import Heading from "@radui/ui/Heading" +import Text from "@radui/ui/Text" +import Button from "@radui/ui/Button" +import Badge from "@radui/ui/Badge" +import Image from 'next/image' +import Card from "@radui/ui/Card" + +const SponsorsSection = () => { + const [hoveredSponsor, setHoveredSponsor] = useState(null) + + const sponsors = [ + { + name: "CodeRabbit", + logoSrc: "/sponsorship/code_rabbit_light.png", + alt: "CodeRabbit", + description: "AI-powered code review assistant", + website: "https://coderabbit.ai/" + }, + { + name: "BrowserStack", + logoSrc: "/sponsorship/browserstack_light.png", + alt: "BrowserStack", + description: "Cross-browser testing platform", + website: "https://www.browserstack.com/" + } + ] + + const handleSponsorClick = (website) => { + window.open(website, '_blank', 'noopener,noreferrer') + } + + return ( +
+
+ Community + Our Sponsors + + We're grateful to our sponsors who help make Rad UI possible. Their support enables us to continue building and maintaining this open-source UI library. + +
+ +
+ {sponsors.map((sponsor) => ( + setHoveredSponsor(sponsor.name)} + onMouseLeave={() => setHoveredSponsor(null)} + onClick={() => handleSponsorClick(sponsor.website)} + > +
+
+ {sponsor.alt} +
+
+ {sponsor.name} + {sponsor.description} +
+
+
+ ))} +
+ +
+ +
+
+ ) +} + +export default SponsorsSection diff --git a/docs/app/landingComponents/ToolbarDemo.js b/docs/app/landingComponents/ToolbarDemo.js index 2479014c1..88898722d 100644 --- a/docs/app/landingComponents/ToolbarDemo.js +++ b/docs/app/landingComponents/ToolbarDemo.js @@ -96,7 +96,7 @@ const ToolbarDemo = () => (
- { }} className='flex flex-1 items-center bg-gray-100 px-2 rounded-md border border-gray-400 text-gray-700'> + { }} className='flex flex-1 items-center bg-gray-100 px-2 rounded-md border border-gray-400 text-gray-950'> diff --git a/docs/app/page.tsx b/docs/app/page.tsx index fb835ebbd..8469e4781 100644 --- a/docs/app/page.tsx +++ b/docs/app/page.tsx @@ -1,11 +1,13 @@ -// 'use client' import HeroSection from './landingComponents/HeroSection' - - import FullHeightScroll from '@/components/layout/ScrollContainers/FullHeightScroll' import Heading from "@radui/ui/Heading" import Text from "@radui/ui/Text" import Link from "@radui/ui/Link" +import Card from "@radui/ui/Card" +import Button from "@radui/ui/Button" +import Badge from "@radui/ui/Badge" +import Image from 'next/image' +import SponsorsSection from './landingComponents/SponsorsSection.js' import baseSeoMetadata from './baseSeo' @@ -55,17 +57,62 @@ const IconWrapper = ({children, href}) => { } +const StatsSection = () => { + const stats = [ + { number: "25+", label: "Components" }, + { number: "100%", label: "Accessible" }, + { number: "TypeScript", label: "First" }, + { number: "0kb", label: "Bundle Size" } + ] + + return ( +
+
+ {stats.map((stat, index) => ( +
+
{stat.number}
+
{stat.label}
+
+ ))} +
+
+ ) +} + + const JoinCommunity = () => { - return
- Join the Community - Join the community to get the latest news and updates. -
- - - - - - + return
+
+ Community + Join the Community + + Join our growing community of developers building accessible, modern web applications with Rad UI. + Get help, share ideas, and contribute to the future of web development. + +
+
+ +
+ + + +
+ Discord + Chat & Support +
+
+
+ +
+ + + +
+ GitHub + Code & Issues +
+
+
} @@ -73,7 +120,7 @@ const JoinCommunity = () => { const DesignedBy = () => { return
- Website designed by Carmen and Maryan. + Website designed by Carmen and Maryan.
} @@ -84,7 +131,11 @@ export default function Home() {
- +
+ + + +
) diff --git a/docs/app/playground/components/EmPlayground.js b/docs/app/playground/components/EmPlayground.js index 32aa09a8f..7ff4c8d22 100644 --- a/docs/app/playground/components/EmPlayground.js +++ b/docs/app/playground/components/EmPlayground.js @@ -10,7 +10,7 @@ const Playground = () => (
- And the time's come to realize there will be Promises I can't Keep + And the time's come to realize there will be Promises I can't Keep
diff --git a/docs/app/playground/components/HeadingPlayground.js b/docs/app/playground/components/HeadingPlayground.js index 89acd4508..b639591b5 100644 --- a/docs/app/playground/components/HeadingPlayground.js +++ b/docs/app/playground/components/HeadingPlayground.js @@ -11,10 +11,10 @@ const Playground = () => (
Excuse me while I kiss the sky Sing a song of sixpence, pocket full of lies - Thinking I'm okay, but they're saying otherwise - Tell me how I look but can't look me in the eyes - Watching as I say this and then I do that - Telling them the old words but in a new rap + Thinking I'm okay, but they're saying otherwise + Tell me how I look but can't look me in the eyes + Watching as I say this and then I do that + Telling them the old words but in a new rap
diff --git a/docs/app/playground/components/SeparatorPlayground.js b/docs/app/playground/components/SeparatorPlayground.js index fa12e9b1c..8e104bc10 100644 --- a/docs/app/playground/components/SeparatorPlayground.js +++ b/docs/app/playground/components/SeparatorPlayground.js @@ -12,7 +12,7 @@ const Playground = () => (
- Linkin Park Meteora + Linkin Park Meteora Linkin Park diff --git a/docs/app/playground/page.tsx b/docs/app/playground/page.tsx index f01aa8a9f..92177a364 100644 --- a/docs/app/playground/page.tsx +++ b/docs/app/playground/page.tsx @@ -15,7 +15,7 @@ import FullHeightScroll from '@/components/layout/ScrollContainers/FullHeightScr const Playground = () => { return ( -
+
diff --git a/docs/app/showcase/music-app/helpers/MusicSidebar.js b/docs/app/showcase/music-app/helpers/MusicSidebar.js index 84f27642e..5d2ad5091 100644 --- a/docs/app/showcase/music-app/helpers/MusicSidebar.js +++ b/docs/app/showcase/music-app/helpers/MusicSidebar.js @@ -11,7 +11,7 @@ const MenuItem = ({children, label="", active=false}) => { return
{children}
- {label} + {label}
} @@ -28,7 +28,7 @@ const MusicSidebar = () => {
- Your Playlists + Your Playlists
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) => { Album Cover
{artist.name} - {artist.album} + {artist.album}
) 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/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..31a79c141 --- /dev/null +++ b/docs/components/layout/Documentation/ModernDocumentation.js @@ -0,0 +1,138 @@ +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 { BookMarkLink } from '@/components/layout/Documentation/utils'; + +const LeftArrow = () => { + return ; +}; + +const RightArrow = () => { + return ; +}; + +const ModernDocumentation = ({ title = '', description = '', currentPage = undefined, children }) => { + return ( +
+ {/* Header */} +
+
+ + + {title} + + +
+ {description && ( + + {description} + + )} +
+ + {/* Content */} +
+ {children} +
+ + +
+ ); +}; + +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 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 ( + + +
+
+ {/* Quick Links */} + + + {/* Navigation Sections */} + {sections.map((section, i) => { + const isCategory = section.type === "CATEGORY"; + if (isCategory) { + return ( +
+ +
+ ) + } else { + return ( +
+ Coming Soon +
+ ) + } + })} +
+
+
+ + + +
+ ) +} + +export default ModernNavigation; From 48bb027e871bb7386f0eef0630c16424472ddd6b Mon Sep 17 00:00:00 2001 From: Pranay Kothapalli Date: Sat, 13 Sep 2025 15:09:25 +0530 Subject: [PATCH 3/4] chore: improvements --- docs/app/docs/layout.tsx | 2 - docs/app/globals.scss | 50 ++++--- docs/app/page.tsx | 2 +- docs/components/AccessibilityFeatures.tsx | 134 ++++++++++++++++++ docs/components/KeyboardShortcuts.tsx | 83 +++++++++++ docs/components/PostHogProvider.tsx | 44 ++++-- docs/components/QuickActions.tsx | 91 ++++++++++++ docs/components/ReadingProgress.tsx | 31 ++++ docs/components/SearchBar.tsx | 114 +++++++++++++++ docs/components/TableOfContents.tsx | 89 ++++++++++++ .../Documentation/ModernDocumentation.js | 57 +++++--- docs/components/navigation/Breadcrumbs.tsx | 86 +++++++++++ .../navigation/ModernNavigation.tsx | 24 ++++ docs/package.json | 1 + docs/pnpm-lock.yaml | 30 ++-- 15 files changed, 774 insertions(+), 64 deletions(-) create mode 100644 docs/components/AccessibilityFeatures.tsx create mode 100644 docs/components/KeyboardShortcuts.tsx create mode 100644 docs/components/QuickActions.tsx create mode 100644 docs/components/ReadingProgress.tsx create mode 100644 docs/components/SearchBar.tsx create mode 100644 docs/components/TableOfContents.tsx create mode 100644 docs/components/navigation/Breadcrumbs.tsx diff --git a/docs/app/docs/layout.tsx b/docs/app/docs/layout.tsx index 075d4a5f5..5d3e33768 100644 --- a/docs/app/docs/layout.tsx +++ b/docs/app/docs/layout.tsx @@ -59,8 +59,6 @@ const DocsLayoutChunks = ({ children }: { children: React.ReactNode }) => { const DocsLayoutGridRoot = ({ children }: { children: React.ReactNode }) => { return
-
-
diff --git a/docs/app/globals.scss b/docs/app/globals.scss index ed8f8ea8b..6e7a122a4 100644 --- a/docs/app/globals.scss +++ b/docs/app/globals.scss @@ -38,6 +38,34 @@ body { outline-offset: 2px; } +/* Accessibility Features */ +.high-contrast { + filter: contrast(150%) brightness(120%); +} + +.reduced-motion * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; +} + +/* Skip to content link */ +.skip-link { + position: absolute; + top: -40px; + left: 6px; + background: var(--rad-ui-color-green-600); + color: white; + padding: 8px; + text-decoration: none; + border-radius: 4px; + z-index: 1000; +} + +.skip-link:focus { + top: 6px; +} + @@ -151,25 +179,3 @@ code .selector { background-color: color-mix(in oklab, var(--rad-ui-color-gray-1000) 5%, transparent); } - -.layout-image { - inset: -11 0 0 0; - width: 100%; - height: 100%; - pointer-events: none; - position: fixed; - - --color: var(--rad-ui-color-gray-200); - - background-color: var(--rad-ui-color-gray-50); - - [data-rad-ui-theme=dark] & { - // Only show the pattern on dark mode - background-image: linear-gradient(0deg, transparent 24%, var(--color) 25%, var(--color) 26%, transparent 27%,transparent 74%, var(--color) 75%, var(--color) 76%, transparent 77%,transparent), - linear-gradient(90deg, transparent 24%, var(--color) 25%, var(--color) 26%, transparent 27%,transparent 74%, var(--color) 75%, var(--color) 76%, transparent 77%,transparent); - background-size: 55px 55px; - } - - - -} \ No newline at end of file diff --git a/docs/app/page.tsx b/docs/app/page.tsx index 8469e4781..a9b4ededc 100644 --- a/docs/app/page.tsx +++ b/docs/app/page.tsx @@ -52,7 +52,7 @@ const GithubLogo = () => { }; const IconWrapper = ({children, href}) => { - return + return {children} } 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 +
+
+ + {fontSize}px + +
+
+ + {/* High Contrast */} +
+
+ {highContrast ? : } + High Contrast +
+ +
+ + {/* Reduced Motion */} +
+
+ Reduced Motion +
+ +
+ + {/* Screen Reader */} +
+
+ {screenReader ? : } + Screen Reader +
+ +
+
+
+ ) +} + +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/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) => ( + + ))} +
+ +
+ 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 && ( + + )} +
+ + {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 +
+ + +
+ ) +} + +export default TableOfContents diff --git a/docs/components/layout/Documentation/ModernDocumentation.js b/docs/components/layout/Documentation/ModernDocumentation.js index 31a79c141..d54f50151 100644 --- a/docs/components/layout/Documentation/ModernDocumentation.js +++ b/docs/components/layout/Documentation/ModernDocumentation.js @@ -8,6 +8,8 @@ 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 = () => { @@ -20,29 +22,42 @@ const RightArrow = () => { const ModernDocumentation = ({ title = '', description = '', currentPage = undefined, children }) => { return ( -
- {/* Header */} -
-
- - - {title} - - -
- {description && ( - - {description} - - )} -
+
+
+ {/* Main Content */} +
+ {/* Breadcrumbs */} + + + {/* Header */} +
+
+ + + {title} + + +
+ {description && ( + + {description} + + )} +
- {/* Content */} -
- {children} + {/* Content */} +
+ {children} +
+ + +
+ + {/* Sidebar */} +
+ +
- -
); }; diff --git a/docs/components/navigation/Breadcrumbs.tsx b/docs/components/navigation/Breadcrumbs.tsx new file mode 100644 index 000000000..663ee19bb --- /dev/null +++ b/docs/components/navigation/Breadcrumbs.tsx @@ -0,0 +1,86 @@ +'use client' +import { usePathname } from 'next/navigation' +import Link from '@radui/ui/Link' +import Text from '@radui/ui/Text' +import { ChevronRight } from 'lucide-react' + +interface BreadcrumbItem { + label: string + href: string + isActive?: boolean +} + +const Breadcrumbs = () => { + 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 ( + + ) +} + +export default Breadcrumbs diff --git a/docs/components/navigation/ModernNavigation.tsx b/docs/components/navigation/ModernNavigation.tsx index b2b6d5a43..db79c3c0c 100644 --- a/docs/components/navigation/ModernNavigation.tsx +++ b/docs/components/navigation/ModernNavigation.tsx @@ -7,6 +7,10 @@ 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 = [ @@ -41,6 +45,26 @@ const ModernNavigation = ({ customSections }: { customSections?: any }) => {
+ {/* Search Bar */} +
+ +
+ + {/* Quick Actions */} +
+ +
+ + {/* Accessibility Features */} +
+ +
+ + {/* Keyboard Shortcuts */} +
+ +
+ {/* Quick Links */}
Quick Links 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: {} From 14d9e914c60953d3dcf4b2878d3421018fabfd5a Mon Sep 17 00:00:00 2001 From: Pranay Kothapalli Date: Sat, 13 Sep 2025 15:18:18 +0530 Subject: [PATCH 4/4] fix: paddings --- docs/app/landingComponents/HeroSection.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/app/landingComponents/HeroSection.js b/docs/app/landingComponents/HeroSection.js index 86182f867..28d9bee38 100644 --- a/docs/app/landingComponents/HeroSection.js +++ b/docs/app/landingComponents/HeroSection.js @@ -134,7 +134,7 @@ const IntegrationCard = ({ title, description, icon, cta="", ctaLink }) => { const HeroSection = () => { - return
+ return
Accelerate Your UI Development with Prebuilt Components @@ -212,9 +212,9 @@ color="blue" variant="ghost" onClick={() => {
-
+
-
+