Skip to content

Commit acb231e

Browse files
committed
feat(landing): add shadcn ui components
- accordion: FAQ section support - dialog: modal/waitlist popup - navigation-menu: navbar dropdowns - separator: visual dividers - sheet: mobile menu drawer - switch: theme toggle - tabs: tabbed content - tooltip: hover hints - update landing barrel exports
1 parent dd0a34f commit acb231e

9 files changed

Lines changed: 568 additions & 3 deletions

File tree

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
// Landing page components barrel export
12
export { Navbar } from './Navbar'
23
export { Hero } from './Hero'
3-
export { HeroSearch, type HeroSearchHandle } from './HeroSearch'
4-
export { RepoSwitcher } from './RepoSwitcher'
4+
export { HeroSearch } from './HeroSearch'
5+
export { ResultsView } from './ResultsView'
56
export { ResultCard } from './ResultCard'
67
export { SkeletonCard } from './SkeletonCard'
78
export { CompactSearchBar } from './CompactSearchBar'
8-
export { ResultsView } from './ResultsView'
9+
export { RepoSwitcher } from './RepoSwitcher'
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import * as AccordionPrimitive from "@radix-ui/react-accordion"
5+
import { ChevronDown } from "lucide-react"
6+
7+
import { cn } from "@/lib/utils"
8+
9+
const Accordion = AccordionPrimitive.Root
10+
11+
const AccordionItem = React.forwardRef<
12+
React.ElementRef<typeof AccordionPrimitive.Item>,
13+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
14+
>(({ className, ...props }, ref) => (
15+
<AccordionPrimitive.Item
16+
ref={ref}
17+
className={cn("border-b", className)}
18+
{...props}
19+
/>
20+
))
21+
AccordionItem.displayName = "AccordionItem"
22+
23+
const AccordionTrigger = React.forwardRef<
24+
React.ElementRef<typeof AccordionPrimitive.Trigger>,
25+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
26+
>(({ className, children, ...props }, ref) => (
27+
<AccordionPrimitive.Header className="flex">
28+
<AccordionPrimitive.Trigger
29+
ref={ref}
30+
className={cn(
31+
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline text-left [&[data-state=open]>svg]:rotate-180",
32+
className
33+
)}
34+
{...props}
35+
>
36+
{children}
37+
<ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
38+
</AccordionPrimitive.Trigger>
39+
</AccordionPrimitive.Header>
40+
))
41+
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
42+
43+
const AccordionContent = React.forwardRef<
44+
React.ElementRef<typeof AccordionPrimitive.Content>,
45+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
46+
>(({ className, children, ...props }, ref) => (
47+
<AccordionPrimitive.Content
48+
ref={ref}
49+
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
50+
{...props}
51+
>
52+
<div className={cn("pb-4 pt-0", className)}>{children}</div>
53+
</AccordionPrimitive.Content>
54+
))
55+
AccordionContent.displayName = AccordionPrimitive.Content.displayName
56+
57+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import * as DialogPrimitive from "@radix-ui/react-dialog"
5+
import { X } from "lucide-react"
6+
7+
import { cn } from "@/lib/utils"
8+
9+
const Dialog = DialogPrimitive.Root
10+
const DialogTrigger = DialogPrimitive.Trigger
11+
const DialogPortal = DialogPrimitive.Portal
12+
const DialogClose = DialogPrimitive.Close
13+
14+
const DialogOverlay = React.forwardRef<
15+
React.ElementRef<typeof DialogPrimitive.Overlay>,
16+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
17+
>(({ className, ...props }, ref) => (
18+
<DialogPrimitive.Overlay
19+
ref={ref}
20+
className={cn(
21+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
22+
className
23+
)}
24+
{...props}
25+
/>
26+
))
27+
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
28+
29+
const DialogContent = React.forwardRef<
30+
React.ElementRef<typeof DialogPrimitive.Content>,
31+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
32+
>(({ className, children, ...props }, ref) => (
33+
<DialogPortal>
34+
<DialogOverlay />
35+
<DialogPrimitive.Content
36+
ref={ref}
37+
className={cn(
38+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
39+
className
40+
)}
41+
{...props}
42+
>
43+
{children}
44+
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
45+
<X className="h-4 w-4" />
46+
<span className="sr-only">Close</span>
47+
</DialogPrimitive.Close>
48+
</DialogPrimitive.Content>
49+
</DialogPortal>
50+
))
51+
DialogContent.displayName = DialogPrimitive.Content.displayName
52+
53+
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
54+
<div className={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)} {...props} />
55+
)
56+
DialogHeader.displayName = "DialogHeader"
57+
58+
const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
59+
<div className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)} {...props} />
60+
)
61+
DialogFooter.displayName = "DialogFooter"
62+
63+
const DialogTitle = React.forwardRef<
64+
React.ElementRef<typeof DialogPrimitive.Title>,
65+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
66+
>(({ className, ...props }, ref) => (
67+
<DialogPrimitive.Title ref={ref} className={cn("text-lg font-semibold leading-none tracking-tight", className)} {...props} />
68+
))
69+
DialogTitle.displayName = DialogPrimitive.Title.displayName
70+
71+
const DialogDescription = React.forwardRef<
72+
React.ElementRef<typeof DialogPrimitive.Description>,
73+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
74+
>(({ className, ...props }, ref) => (
75+
<DialogPrimitive.Description ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
76+
))
77+
DialogDescription.displayName = DialogPrimitive.Description.displayName
78+
79+
export {
80+
Dialog,
81+
DialogPortal,
82+
DialogOverlay,
83+
DialogTrigger,
84+
DialogClose,
85+
DialogContent,
86+
DialogHeader,
87+
DialogFooter,
88+
DialogTitle,
89+
DialogDescription,
90+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
5+
import { cva } from "class-variance-authority"
6+
import { ChevronDown } from "lucide-react"
7+
8+
import { cn } from "@/lib/utils"
9+
10+
const NavigationMenu = React.forwardRef<
11+
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
12+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
13+
>(({ className, children, ...props }, ref) => (
14+
<NavigationMenuPrimitive.Root
15+
ref={ref}
16+
className={cn(
17+
"relative z-10 flex max-w-max flex-1 items-center justify-center",
18+
className
19+
)}
20+
{...props}
21+
>
22+
{children}
23+
<NavigationMenuViewport />
24+
</NavigationMenuPrimitive.Root>
25+
))
26+
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
27+
28+
const NavigationMenuList = React.forwardRef<
29+
React.ElementRef<typeof NavigationMenuPrimitive.List>,
30+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
31+
>(({ className, ...props }, ref) => (
32+
<NavigationMenuPrimitive.List
33+
ref={ref}
34+
className={cn(
35+
"group flex flex-1 list-none items-center justify-center space-x-1",
36+
className
37+
)}
38+
{...props}
39+
/>
40+
))
41+
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
42+
43+
const NavigationMenuItem = NavigationMenuPrimitive.Item
44+
45+
const navigationMenuTriggerStyle = cva(
46+
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"
47+
)
48+
49+
const NavigationMenuTrigger = React.forwardRef<
50+
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
51+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
52+
>(({ className, children, ...props }, ref) => (
53+
<NavigationMenuPrimitive.Trigger
54+
ref={ref}
55+
className={cn(navigationMenuTriggerStyle(), "group", className)}
56+
{...props}
57+
>
58+
{children}{" "}
59+
<ChevronDown
60+
className="relative top-[1px] ml-1 h-3 w-3 transition duration-300 group-data-[state=open]:rotate-180"
61+
aria-hidden="true"
62+
/>
63+
</NavigationMenuPrimitive.Trigger>
64+
))
65+
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
66+
67+
const NavigationMenuContent = React.forwardRef<
68+
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
69+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
70+
>(({ className, ...props }, ref) => (
71+
<NavigationMenuPrimitive.Content
72+
ref={ref}
73+
className={cn(
74+
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto",
75+
className
76+
)}
77+
{...props}
78+
/>
79+
))
80+
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName
81+
82+
const NavigationMenuLink = NavigationMenuPrimitive.Link
83+
84+
const NavigationMenuViewport = React.forwardRef<
85+
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
86+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
87+
>(({ className, ...props }, ref) => (
88+
<div className={cn("absolute left-0 top-full flex justify-center")}>
89+
<NavigationMenuPrimitive.Viewport
90+
className={cn(
91+
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
92+
className
93+
)}
94+
ref={ref}
95+
{...props}
96+
/>
97+
</div>
98+
))
99+
NavigationMenuViewport.displayName =
100+
NavigationMenuPrimitive.Viewport.displayName
101+
102+
const NavigationMenuIndicator = React.forwardRef<
103+
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
104+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
105+
>(({ className, ...props }, ref) => (
106+
<NavigationMenuPrimitive.Indicator
107+
ref={ref}
108+
className={cn(
109+
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
110+
className
111+
)}
112+
{...props}
113+
>
114+
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
115+
</NavigationMenuPrimitive.Indicator>
116+
))
117+
NavigationMenuIndicator.displayName =
118+
NavigationMenuPrimitive.Indicator.displayName
119+
120+
export {
121+
navigationMenuTriggerStyle,
122+
NavigationMenu,
123+
NavigationMenuList,
124+
NavigationMenuItem,
125+
NavigationMenuContent,
126+
NavigationMenuTrigger,
127+
NavigationMenuLink,
128+
NavigationMenuIndicator,
129+
NavigationMenuViewport,
130+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import * as SeparatorPrimitive from "@radix-ui/react-separator"
5+
6+
import { cn } from "@/lib/utils"
7+
8+
const Separator = React.forwardRef<
9+
React.ElementRef<typeof SeparatorPrimitive.Root>,
10+
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
11+
>(
12+
(
13+
{ className, orientation = "horizontal", decorative = true, ...props },
14+
ref
15+
) => (
16+
<SeparatorPrimitive.Root
17+
ref={ref}
18+
decorative={decorative}
19+
orientation={orientation}
20+
className={cn(
21+
"shrink-0 bg-border",
22+
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
23+
className
24+
)}
25+
{...props}
26+
/>
27+
)
28+
)
29+
Separator.displayName = SeparatorPrimitive.Root.displayName
30+
31+
export { Separator }

0 commit comments

Comments
 (0)