Skip to content

Commit c84fbce

Browse files
committed
feat: navigation menu
1 parent bca4516 commit c84fbce

File tree

8 files changed

+599
-0
lines changed

8 files changed

+599
-0
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import Link from "next/link"
5+
6+
import {
7+
NavigationMenu,
8+
NavigationMenuContent,
9+
NavigationMenuIndicator,
10+
NavigationMenuItem,
11+
NavigationMenuLink,
12+
NavigationMenuList,
13+
NavigationMenuTrigger,
14+
navigationMenuTriggerStyle,
15+
} from "@/components/ui/8bit/navigation-menu"
16+
17+
const components: { title: string; href: string; description: string }[] = [
18+
{
19+
title: "Alert Dialog",
20+
href: "/docs/primitives/alert-dialog",
21+
description:
22+
"A modal dialog that interrupts the user with important content and expects a response.",
23+
},
24+
{
25+
title: "Hover Card",
26+
href: "/docs/primitives/hover-card",
27+
description:
28+
"For sighted users to preview content available behind a link.",
29+
},
30+
{
31+
title: "Progress",
32+
href: "/docs/primitives/progress",
33+
description:
34+
"Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.",
35+
},
36+
{
37+
title: "Scroll-area",
38+
href: "/docs/primitives/scroll-area",
39+
description: "Visually or semantically separates content.",
40+
},
41+
{
42+
title: "Tabs",
43+
href: "/docs/primitives/tabs",
44+
description:
45+
"A set of layered sections of content—known as tab panels—that are displayed one at a time.",
46+
},
47+
{
48+
title: "Tooltip",
49+
href: "/docs/primitives/tooltip",
50+
description:
51+
"A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.",
52+
},
53+
]
54+
55+
export default function NavigationMenuDemo() {
56+
return (
57+
<NavigationMenu>
58+
<NavigationMenuList>
59+
<NavigationMenuItem>
60+
<NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
61+
<NavigationMenuContent>
62+
<ul className="grid gap-2 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
63+
<li className="row-span-3">
64+
<NavigationMenuLink asChild>
65+
<Link
66+
className="from-muted/50 to-muted flex h-full w-full flex-col justify-end rounded-md bg-linear-to-b p-6 no-underline outline-hidden select-none focus:shadow-md"
67+
href="/"
68+
>
69+
<div className="mt-4 mb-2 text-lg font-medium">
70+
shadcn/ui
71+
</div>
72+
<p className="text-muted-foreground text-sm leading-tight">
73+
Beautifully designed components built with Tailwind CSS.
74+
</p>
75+
</Link>
76+
</NavigationMenuLink>
77+
</li>
78+
<ListItem href="/docs" title="Introduction">
79+
Re-usable components built using Radix UI and Tailwind CSS.
80+
</ListItem>
81+
<ListItem href="/docs/installation" title="Installation">
82+
How to install dependencies and structure your app.
83+
</ListItem>
84+
<ListItem href="/docs/primitives/typography" title="Typography">
85+
Styles for headings, paragraphs, lists...etc
86+
</ListItem>
87+
</ul>
88+
</NavigationMenuContent>
89+
</NavigationMenuItem>
90+
91+
<NavigationMenuItem>
92+
<NavigationMenuTrigger>Components</NavigationMenuTrigger>
93+
<NavigationMenuContent>
94+
<ul className="grid w-[400px] gap-2 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
95+
{components.map((component) => (
96+
<ListItem
97+
key={component.title}
98+
title={component.title}
99+
href={component.href}
100+
>
101+
{component.description}
102+
</ListItem>
103+
))}
104+
</ul>
105+
</NavigationMenuContent>
106+
</NavigationMenuItem>
107+
108+
<NavigationMenuItem>
109+
<NavigationMenuLink asChild className={navigationMenuTriggerStyle()}>
110+
<Link href="/docs">Documentation</Link>
111+
</NavigationMenuLink>
112+
</NavigationMenuItem>
113+
114+
<NavigationMenuIndicator />
115+
</NavigationMenuList>
116+
</NavigationMenu>
117+
)
118+
}
119+
120+
function ListItem({
121+
title,
122+
children,
123+
href,
124+
...props
125+
}: React.ComponentPropsWithoutRef<"li"> & { href: string }) {
126+
return (
127+
<li {...props}>
128+
<NavigationMenuLink asChild>
129+
<Link href={href}>
130+
<div className="text-sm leading-none font-medium">{title}</div>
131+
<p className="text-muted-foreground line-clamp-2 text-sm leading-snug">
132+
{children}
133+
</p>
134+
</Link>
135+
</NavigationMenuLink>
136+
</li>
137+
)
138+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { Metadata } from "next"
2+
3+
import { labelMetaData } from "@/lib/metadata"
4+
import { Separator } from "@/components/ui/separator"
5+
6+
import CodeSnippet from "../code-snippet"
7+
import CopyCommandButton from "../copy-command-button"
8+
import InstallationCommands from "../installation-commands"
9+
import { OpenInV0Button } from "../open-in-v0-button"
10+
import NavigationMenuDemo from "./demo"
11+
12+
export const metadata: Metadata = {
13+
title: "8-bit Label",
14+
description: "Displays an 8-bit label component.",
15+
openGraph: {
16+
images: labelMetaData,
17+
},
18+
}
19+
20+
export default function NavigationMenuPage() {
21+
return (
22+
<div className="flex flex-col gap-4">
23+
<div className="flex flex-col md:flex-row items-center justify-between gap-2">
24+
<h1 className="text-3xl font-bold">Navigation Menu</h1>
25+
<CopyCommandButton
26+
copyCommand={`pnpm dlx shadcn@canary add ${process.env.NEXT_PUBLIC_BASE_URL}/r/8bit-navigation-menu.json`}
27+
command={"pnpm dlx shadcn@canary add 8bit-navigation-menu"}
28+
/>
29+
</div>
30+
31+
<p className="text-muted-foreground">
32+
Displays an 8-bit navigation menu component.
33+
</p>
34+
35+
<div className="flex flex-col gap-4 border rounded-lg p-4 min-h-[450px] relative">
36+
<div className="flex items-center justify-between">
37+
<h2 className="text-sm text-muted-foreground sm:pl-3">
38+
8-bit navigation menu component
39+
</h2>
40+
41+
<div className="flex items-center gap-2">
42+
<OpenInV0Button name="8bit-navigation-menu" className="w-fit" />
43+
</div>
44+
</div>
45+
<div className="flex items-center justify-center min-h-[400px] relative space-x-2">
46+
<NavigationMenuDemo />
47+
</div>
48+
</div>
49+
50+
<h3 className="text-lg font-bold">Installation</h3>
51+
52+
<Separator />
53+
54+
<InstallationCommands
55+
packageUrl={`${process.env.NEXT_PUBLIC_BASE_URL}/r/8bit-navigation-menu.json`}
56+
/>
57+
58+
<h3 className="text-lg font-bold mt-10">Usage</h3>
59+
60+
<Separator />
61+
62+
<CodeSnippet>{`import {
63+
NavigationMenu,
64+
NavigationMenuContent,
65+
NavigationMenuIndicator,
66+
NavigationMenuItem,
67+
NavigationMenuLink,
68+
NavigationMenuList,
69+
NavigationMenuTrigger,
70+
NavigationMenuViewport,
71+
} from "@/components/ui/navigation-menu"
72+
`}</CodeSnippet>
73+
74+
<CodeSnippet>{`<NavigationMenu>
75+
<NavigationMenuList>
76+
<NavigationMenuItem>
77+
<NavigationMenuTrigger>Item One</NavigationMenuTrigger>
78+
<NavigationMenuContent>
79+
<NavigationMenuLink>Link</NavigationMenuLink>
80+
</NavigationMenuContent>
81+
</NavigationMenuItem>
82+
</NavigationMenuList>
83+
</NavigationMenu>
84+
`}</CodeSnippet>
85+
</div>
86+
)
87+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import * as React from "react"
2+
import { Press_Start_2P } from "next/font/google"
3+
import { cva, VariantProps } from "class-variance-authority"
4+
5+
import { cn } from "@/lib/utils"
6+
import {
7+
NavigationMenu as ShadcnNavigationMenu,
8+
NavigationMenuContent as ShadcnNavigationMenuContent,
9+
NavigationMenuIndicator as ShadcnNavigationMenuIndicator,
10+
NavigationMenuItem as ShadcnNavigationMenuItem,
11+
NavigationMenuLink as ShadcnNavigationMenuLink,
12+
NavigationMenuList as ShadcnNavigationMenuList,
13+
NavigationMenuTrigger as ShadcnNavigationMenuTrigger,
14+
NavigationMenuViewport as ShadcnNavigationMenuViewport,
15+
} from "@/components/ui/navigation-menu"
16+
17+
export { navigationMenuTriggerStyle } from "@/components/ui/navigation-menu"
18+
19+
const pressStart = Press_Start_2P({
20+
weight: ["400"],
21+
subsets: ["latin"],
22+
})
23+
24+
export const navigationMenuVariants = cva("", {
25+
variants: {
26+
font: {
27+
normal: "",
28+
retro: pressStart.className,
29+
},
30+
},
31+
defaultVariants: {
32+
font: "retro",
33+
},
34+
})
35+
36+
type FontVariantProps = VariantProps<typeof navigationMenuVariants>
37+
38+
export interface BitNavigationMenuProps
39+
extends React.ComponentProps<typeof ShadcnNavigationMenu>,
40+
VariantProps<typeof navigationMenuVariants> {
41+
asChild?: boolean
42+
}
43+
44+
function NavigationMenu({
45+
className,
46+
font,
47+
...props
48+
}: React.ComponentProps<typeof ShadcnNavigationMenu> & FontVariantProps) {
49+
return (
50+
<ShadcnNavigationMenu
51+
className={cn(font !== "normal" && pressStart.className, className)}
52+
{...props}
53+
/>
54+
)
55+
}
56+
57+
function NavigationMenuList({
58+
className,
59+
font,
60+
...props
61+
}: React.ComponentProps<typeof ShadcnNavigationMenuList> &
62+
VariantProps<typeof navigationMenuVariants>) {
63+
return (
64+
<ShadcnNavigationMenuList
65+
className={cn(font !== "normal" && pressStart.className, className)}
66+
{...props}
67+
/>
68+
)
69+
}
70+
71+
function NavigationMenuItem({
72+
className,
73+
font,
74+
...props
75+
}: React.ComponentProps<typeof ShadcnNavigationMenuItem> & FontVariantProps) {
76+
return (
77+
<ShadcnNavigationMenuItem
78+
className={cn(
79+
"static",
80+
font !== "normal" && pressStart.className,
81+
className
82+
)}
83+
{...props}
84+
/>
85+
)
86+
}
87+
88+
function NavigationMenuTrigger({
89+
className,
90+
font,
91+
...props
92+
}: React.ComponentProps<typeof ShadcnNavigationMenuTrigger> &
93+
FontVariantProps) {
94+
return (
95+
<ShadcnNavigationMenuTrigger
96+
className={cn(font !== "normal" && pressStart.className, className)}
97+
{...props}
98+
/>
99+
)
100+
}
101+
102+
function NavigationMenuContent({
103+
className,
104+
font,
105+
children,
106+
...props
107+
}: React.ComponentProps<typeof ShadcnNavigationMenuContent> &
108+
FontVariantProps) {
109+
return (
110+
<ShadcnNavigationMenuContent
111+
className={cn(font !== "normal" && pressStart.className, className)}
112+
{...props}
113+
>
114+
{children}
115+
</ShadcnNavigationMenuContent>
116+
)
117+
}
118+
119+
function NavigationMenuViewport({
120+
className,
121+
font,
122+
...props
123+
}: React.ComponentProps<typeof ShadcnNavigationMenuViewport> &
124+
FontVariantProps) {
125+
return (
126+
<ShadcnNavigationMenuViewport
127+
className={cn(font !== "normal" && pressStart.className, className)}
128+
{...props}
129+
/>
130+
)
131+
}
132+
133+
function NavigationMenuLink({
134+
className,
135+
font,
136+
...props
137+
}: React.ComponentProps<typeof ShadcnNavigationMenuLink> & FontVariantProps) {
138+
return (
139+
<ShadcnNavigationMenuLink
140+
className={cn(font !== "normal" && pressStart.className, className)}
141+
{...props}
142+
/>
143+
)
144+
}
145+
146+
function NavigationMenuIndicator({
147+
className,
148+
font,
149+
...props
150+
}: React.ComponentProps<typeof ShadcnNavigationMenuIndicator> &
151+
FontVariantProps) {
152+
return (
153+
<ShadcnNavigationMenuIndicator
154+
className={cn(font !== "normal" && pressStart.className, className)}
155+
{...props}
156+
/>
157+
)
158+
}
159+
160+
export {
161+
NavigationMenu,
162+
NavigationMenuContent,
163+
NavigationMenuIndicator,
164+
NavigationMenuItem,
165+
NavigationMenuLink,
166+
NavigationMenuList,
167+
NavigationMenuTrigger,
168+
NavigationMenuViewport,
169+
}

0 commit comments

Comments
 (0)