-
-
Notifications
You must be signed in to change notification settings - Fork 52
docs: add link docs and navigation search #1547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,34 @@ | ||||||||||||||||||||||||||||
// Import API documentation | ||||||||||||||||||||||||||||
import link_api_SourceCode from './component_api/link.tsx'; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const code = { | ||||||||||||||||||||||||||||
javascript: { | ||||||||||||||||||||||||||||
code: `import Link from "@radui/ui/Link" | ||||||||||||||||||||||||||||
const LinkExample = () => ( | ||||||||||||||||||||||||||||
<Link href="https://rad-ui.com" target="_blank">Rad UI</Link> | ||||||||||||||||||||||||||||
)` | ||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||
Comment on lines
+6
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Align code and SCSS; add rel for target="_blank". Sample uses .rad-ui-link styles but the element lacked that class. Also add rel for security. - code: `import Link from "@radui/ui/Link"
-
-const LinkExample = () => (
- <Link href="https://rad-ui.com" target="_blank">Rad UI</Link>
-)
+ code: `import Link from "@radui/ui/Link"
+
+const LinkExample = () => (
+ <Link className="rad-ui-link" href="https://rad-ui.com" target="_blank" rel="noopener noreferrer">
+ Rad UI
+ </Link>
+)
` 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||
scss: { | ||||||||||||||||||||||||||||
code: `.rad-ui-link{ | ||||||||||||||||||||||||||||
color: var(--rad-ui-color-indigo-900); | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
.rad-ui-link:hover{ | ||||||||||||||||||||||||||||
text-decoration: underline; | ||||||||||||||||||||||||||||
}` | ||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// API documentation | ||||||||||||||||||||||||||||
export const api_documentation = { | ||||||||||||||||||||||||||||
link: link_api_SourceCode, | ||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
// Component features | ||||||||||||||||||||||||||||
export const features = [ | ||||||||||||||||||||||||||||
"Supports external and internal navigation", | ||||||||||||||||||||||||||||
"Adjustable sizes", | ||||||||||||||||||||||||||||
"Accessible keyboard navigation", | ||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
export default code; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
const data = { | ||
name: "Link", | ||
description: "Hyperlink component for navigation between pages or external resources.", | ||
columns: [ | ||
{ | ||
name: "Prop", | ||
id: "prop", | ||
}, | ||
{ | ||
name: "Type", | ||
id: "type", | ||
}, | ||
{ | ||
name: "Default", | ||
id: "default", | ||
} | ||
], | ||
data: [ | ||
{ | ||
prop: { | ||
name: "href", | ||
info_tooltips: "Destination URL for the link.", | ||
}, | ||
type: "string", | ||
default: "--", | ||
}, | ||
{ | ||
prop: { | ||
name: "children", | ||
info_tooltips: "Link text or element.", | ||
}, | ||
type: "ReactNode", | ||
default: "--", | ||
}, | ||
{ | ||
prop: { | ||
name: "target", | ||
info_tooltips: "Where to open the linked document.", | ||
}, | ||
type: "string", | ||
default: "'_self'", | ||
}, | ||
{ | ||
prop: { | ||
name: "size", | ||
info_tooltips: "Visual size of the link.", | ||
}, | ||
type: "string", | ||
default: "'medium'", | ||
}, | ||
{ | ||
prop: { | ||
name: "className", | ||
info_tooltips: "Additional CSS class names.", | ||
}, | ||
type: "string", | ||
default: "''", | ||
} | ||
] | ||
}; | ||
|
||
export default data; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import Link from "@radui/ui/Link"; | ||
|
||
const LinkExample = () => { | ||
return ( | ||
<div className="text-gray-1000"> | ||
<Link href="https://rad-ui.com" target="_blank"> | ||
Visit Rad UI | ||
</Link> | ||
</div> | ||
); | ||
}; | ||
|
||
export default LinkExample; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,44 @@ | ||||||||||||||||||||||||||||||||||||
import Documentation from '@/components/layout/Documentation/Documentation'; | ||||||||||||||||||||||||||||||||||||
import Link from '@radui/ui/Link'; | ||||||||||||||||||||||||||||||||||||
import codeUsage, { api_documentation, features } from './docs/codeUsage'; | ||||||||||||||||||||||||||||||||||||
import LinkExample from './examples/LinkExample'; | ||||||||||||||||||||||||||||||||||||
import linkMetadata from './seo'; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
export const metadata = linkMetadata; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
<Documentation | ||||||||||||||||||||||||||||||||||||
title="Link" | ||||||||||||||||||||||||||||||||||||
description="Link navigates users to different pages or external resources." | ||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||
{/* Component Hero */} | ||||||||||||||||||||||||||||||||||||
<Documentation.ComponentHero codeUsage={codeUsage}> | ||||||||||||||||||||||||||||||||||||
<LinkExample /> | ||||||||||||||||||||||||||||||||||||
</Documentation.ComponentHero> | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
{/* Component Features */} | ||||||||||||||||||||||||||||||||||||
<Documentation.ComponentFeatures | ||||||||||||||||||||||||||||||||||||
features={features} | ||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
{/* Embedded Storybook */} | ||||||||||||||||||||||||||||||||||||
<Documentation.Section title="Storybook" as="h2"> | ||||||||||||||||||||||||||||||||||||
<iframe | ||||||||||||||||||||||||||||||||||||
src="/storybook/iframe.html?id=components-link--all" | ||||||||||||||||||||||||||||||||||||
className="w-full h-96 border rounded" | ||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||
</Documentation.Section> | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
{/* Accessibility */} | ||||||||||||||||||||||||||||||||||||
<Documentation.Section title="Accessibility" as="h2"> | ||||||||||||||||||||||||||||||||||||
<p>Links are focusable and support keyboard navigation. Ensure link text clearly describes the destination.</p> | ||||||||||||||||||||||||||||||||||||
</Documentation.Section> | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
{/* API Documentation */} | ||||||||||||||||||||||||||||||||||||
<Documentation.Section title="API Documentation" as="h2" /> | ||||||||||||||||||||||||||||||||||||
<Documentation.Table | ||||||||||||||||||||||||||||||||||||
title="Link" | ||||||||||||||||||||||||||||||||||||
description={api_documentation.link.description} | ||||||||||||||||||||||||||||||||||||
columns={api_documentation.link.columns} | ||||||||||||||||||||||||||||||||||||
data={api_documentation.link.data} | ||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||
</Documentation> | ||||||||||||||||||||||||||||||||||||
Comment on lines
+37
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Wrap the API table inside the Section (layout/spacing & anchor semantics). - {/* API Documentation */}
- <Documentation.Section title="API Documentation" as="h2" />
- <Documentation.Table
- title="Link"
- description={api_documentation.link.description}
- columns={api_documentation.link.columns}
- data={api_documentation.link.data}
- />
+ {/* API Documentation */}
+ <Documentation.Section title="API Documentation" as="h2">
+ <Documentation.Table
+ title="Link"
+ description={api_documentation.link.description}
+ columns={api_documentation.link.columns}
+ data={api_documentation.link.data}
+ />
+ </Documentation.Section> 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import generateSeoMetadata from "@/utils/seo/generateSeoMetadata"; | ||
|
||
const linkMetadata = generateSeoMetadata({ | ||
title: "Link - Rad UI", | ||
description: "Accessible hyperlink component for navigation and external resources.", | ||
}); | ||
|
||
export default linkMetadata; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import Documentation from '@/components/layout/Documentation/Documentation'; | ||
import migrationMetadata from './seo'; | ||
|
||
export const metadata = migrationMetadata; | ||
|
||
<Documentation | ||
title="Migration Guide" | ||
description="Compare Rad UI with other libraries and learn best practices for adopting it." | ||
> | ||
<Documentation.Section title="Migrating from Other Libraries" as="h2"> | ||
<h3>Radix UI</h3> | ||
<p>Rad UI ships with pre-styled components while Radix UI offers unstyled primitives. When migrating, replace Radix primitives with their Rad UI counterparts and remove custom styling where possible.</p> | ||
<h3>Base UI</h3> | ||
<p>Base UI centers around Material Design. Rad UI is design‑system agnostic, so migrate by mapping Base UI components to Rad UI and adjusting theme tokens.</p> | ||
<h3>Ark UI</h3> | ||
<p>Ark UI emphasizes composability. Rad UI provides similar accessibility guarantees with a more opinionated API, making migrations largely drop‑in.</p> | ||
</Documentation.Section> | ||
|
||
<Documentation.Section title="Best Practices" as="h2"> | ||
<ul> | ||
<li>Leverage Rad UI's accessible defaults before customizing.</li> | ||
<li>Prefer composable components for flexibility.</li> | ||
<li>Keep markup semantic and keyboard friendly.</li> | ||
</ul> | ||
</Documentation.Section> | ||
</Documentation> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import generateSeoMetadata from "@/utils/seo/generateSeoMetadata"; | ||
|
||
const migrationMetadata = generateSeoMetadata({ | ||
title: "Migration Guide - Rad UI", | ||
description: "Guidance for migrating to Rad UI and best practices compared with Radix, Base UI, and Ark UI.", | ||
}); | ||
|
||
export default migrationMetadata; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,9 +3,9 @@ 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 docsSections from "@/app/docs/docsNavigationSections"; | ||||||||||||||||||||||||||
import ScrollArea from "@radui/ui/ScrollArea"; | ||||||||||||||||||||||||||
import Category from './Category'; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
@@ -26,42 +26,72 @@ const Navigation = ({ customSections }: { customSections?: any }) => { | |||||||||||||||||||||||||
const pathname = usePathname(); | ||||||||||||||||||||||||||
const { setIsDocsNavOpen } = useContext(NavBarContext) as { isDocsNavOpen: boolean, setIsDocsNavOpen: (isDocsNavOpen: boolean) => void }; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
const [sections, setSections] = useState(docsSections) | ||||||||||||||||||||||||||
const [sections, setSections] = useState(docsSections); | ||||||||||||||||||||||||||
const [query, setQuery] = useState(""); | ||||||||||||||||||||||||||
const versions = ["0.0.47", "0.0.46"]; | ||||||||||||||||||||||||||
const [version, setVersion] = useState(versions[0]); | ||||||||||||||||||||||||||
// customSections || sections; | ||||||||||||||||||||||||||
Comment on lines
+29
to
33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Initialize sections based on pathname to avoid UI flash; respect customSections On non-docs routes, sections initially show docsSections until useEffect runs. Also, customSections is ignored. Initialize from pathname and prefer customSections when provided. - const [sections, setSections] = useState(docsSections);
+ const [sections, setSections] = useState(
+ (customSections ?? (pathname.includes("/docs/") ? docsSections : defaultSections))
+ ); 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||||||
if (pathname.includes("/docs/")) { | ||||||||||||||||||||||||||
setSections(docsSections) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
else { | ||||||||||||||||||||||||||
setSections(defaultSections) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
}, [pathname]) | ||||||||||||||||||||||||||
setSections(defaultSections) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
}, [pathname]) | ||||||||||||||||||||||||||
const filteredSections = sections | ||||||||||||||||||||||||||
Comment on lines
+40
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Effect should handle customSections and unify selection logic Prefer customSections when present; otherwise pick based on pathname. Add customSections to deps. - }, [pathname])
+ }, [pathname, customSections]) And replace the effect body with: useEffect(() => {
if (customSections) {
setSections(customSections);
return;
}
setSections(pathname.includes("/docs/") ? docsSections : defaultSections);
}, [pathname, customSections]); 🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||
.map(section => ({ | ||||||||||||||||||||||||||
...section, | ||||||||||||||||||||||||||
items: section.items.filter((item: any) => | ||||||||||||||||||||||||||
item.title.toLowerCase().includes(query.toLowerCase()) | ||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||
})) | ||||||||||||||||||||||||||
.filter(section => section.items.length > 0); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
return <ScrollArea.Root> | ||||||||||||||||||||||||||
<ScrollArea.Viewport style={{ height: "100%" }}> | ||||||||||||||||||||||||||
<div className="min-w-[240px]"> | ||||||||||||||||||||||||||
<div className="p-4 flex flex-col gap-2"> | ||||||||||||||||||||||||||
<input | ||||||||||||||||||||||||||
aria-label="Search documentation" | ||||||||||||||||||||||||||
type="text" | ||||||||||||||||||||||||||
value={query} | ||||||||||||||||||||||||||
onChange={(e) => setQuery(e.target.value)} | ||||||||||||||||||||||||||
placeholder="Search..." | ||||||||||||||||||||||||||
className="px-2 py-1 text-sm rounded border" | ||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||
<select | ||||||||||||||||||||||||||
aria-label="Select docs version" | ||||||||||||||||||||||||||
value={version} | ||||||||||||||||||||||||||
onChange={(e) => setVersion(e.target.value)} | ||||||||||||||||||||||||||
className="px-2 py-1 text-sm rounded border" | ||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||
{versions.map(v => ( | ||||||||||||||||||||||||||
<option key={v} value={v}>{v}</option> | ||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||
</select> | ||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||
<div className='flex-none pb-20 w-full lg:w-[240px] lg:bg-transparent'> | ||||||||||||||||||||||||||
{filteredSections.map((section, i) => { | ||||||||||||||||||||||||||
const isCategory = section.type === "CATEGORY"; | ||||||||||||||||||||||||||
if (isCategory) { | ||||||||||||||||||||||||||
return <Category key={i} categoryItem={section} pathname={pathname} setIsDocsNavOpen={setIsDocsNavOpen} /> | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
else{ | ||||||||||||||||||||||||||
return <div key={i} className='h-10 w-full bg-gray-100'> | ||||||||||||||||||||||||||
Hello | ||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
})} | ||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
return <ScrollArea.Root> | ||||||||||||||||||||||||||
<ScrollArea.Viewport style={{ height: "100%" }}> | ||||||||||||||||||||||||||
<div className="min-w-[240px]"> | ||||||||||||||||||||||||||
<div className='flex-none pb-20 w-full lg:w-[240px] lg:bg-transparent'> | ||||||||||||||||||||||||||
{sections.map((section, i) => { | ||||||||||||||||||||||||||
const isCategory = section.type === "CATEGORY"; | ||||||||||||||||||||||||||
if (isCategory) { | ||||||||||||||||||||||||||
return <Category key={i} categoryItem={section} pathname={pathname} setIsDocsNavOpen={setIsDocsNavOpen} /> | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
else{ | ||||||||||||||||||||||||||
return <div key={i} className='h-10 w-full bg-gray-100'> | ||||||||||||||||||||||||||
Hello | ||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
})} | ||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
</ScrollArea.Viewport> | ||||||||||||||||||||||||||
<ScrollArea.Scrollbar orientation='vertical' > | ||||||||||||||||||||||||||
<ScrollArea.Thumb /> | ||||||||||||||||||||||||||
</ScrollArea.Scrollbar> | ||||||||||||||||||||||||||
</ScrollArea.Root> | ||||||||||||||||||||||||||
</ScrollArea.Viewport> | ||||||||||||||||||||||||||
<ScrollArea.Scrollbar orientation='vertical' > | ||||||||||||||||||||||||||
<ScrollArea.Thumb /> | ||||||||||||||||||||||||||
</ScrollArea.Scrollbar> | ||||||||||||||||||||||||||
</ScrollArea.Root> | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid importing a .tsx file with an explicit extension from JS.
This can trip bundlers/linters; resolve by omitting the extension (or convert this file to TS).
Also update the reference below:
📝 Committable suggestion
🤖 Prompt for AI Agents