|
1 | 1 | 'use client'; |
2 | 2 |
|
3 | 3 | import { Sidebar as SidebarIcon } from 'lucide-react'; |
4 | | -import { type ComponentProps } from 'react'; |
| 4 | +import { type ComponentProps, useMemo } from 'react'; |
5 | 5 | import { cn } from '@/utils/cn'; |
6 | 6 | import { buttonVariants } from '@/components/ui/button'; |
7 | 7 | import { useSidebar } from '@/contexts/sidebar'; |
8 | 8 | import { useNav } from '@/contexts/layout'; |
9 | 9 | import { SidebarCollapseTrigger } from '@/components/layout/sidebar'; |
10 | 10 | import { SearchToggle } from '@/components/layout/search-toggle'; |
| 11 | +import type { Option } from '@/components/layout/root-toggle'; |
| 12 | +import { usePathname } from 'fumadocs-core/framework'; |
| 13 | +import { isTabActive } from '@/utils/is-active'; |
| 14 | +import Link from 'fumadocs-core/link'; |
11 | 15 |
|
12 | 16 | export function Navbar(props: ComponentProps<'header'>) { |
13 | 17 | const { isTransparent } = useNav(); |
@@ -79,3 +83,56 @@ export function CollapsibleControl() { |
79 | 83 | </div> |
80 | 84 | ); |
81 | 85 | } |
| 86 | + |
| 87 | +export function LayoutTabs({ |
| 88 | + options, |
| 89 | + ...props |
| 90 | +}: ComponentProps<'div'> & { |
| 91 | + options: Option[]; |
| 92 | +}) { |
| 93 | + const pathname = usePathname(); |
| 94 | + const selected = useMemo(() => { |
| 95 | + return options.findLast((option) => isTabActive(option, pathname)); |
| 96 | + }, [options, pathname]); |
| 97 | + |
| 98 | + return ( |
| 99 | + <div |
| 100 | + {...props} |
| 101 | + className={cn( |
| 102 | + 'flex flex-row items-end gap-6 overflow-auto', |
| 103 | + props.className, |
| 104 | + )} |
| 105 | + > |
| 106 | + {options.map((option) => ( |
| 107 | + <LayoutTab |
| 108 | + key={option.url} |
| 109 | + selected={selected === option} |
| 110 | + option={option} |
| 111 | + /> |
| 112 | + ))} |
| 113 | + </div> |
| 114 | + ); |
| 115 | +} |
| 116 | + |
| 117 | +function LayoutTab({ |
| 118 | + option: { title, url, unlisted, props }, |
| 119 | + selected = false, |
| 120 | +}: { |
| 121 | + option: Option; |
| 122 | + selected?: boolean; |
| 123 | +}) { |
| 124 | + return ( |
| 125 | + <Link |
| 126 | + href={url} |
| 127 | + {...props} |
| 128 | + className={cn( |
| 129 | + 'inline-flex border-b-2 border-transparent transition-colors items-center pb-1.5 font-medium gap-2 text-fd-muted-foreground text-sm text-nowrap hover:text-fd-accent-foreground', |
| 130 | + unlisted && !selected && 'hidden', |
| 131 | + selected && 'border-fd-primary text-fd-primary', |
| 132 | + props?.className, |
| 133 | + )} |
| 134 | + > |
| 135 | + {title} |
| 136 | + </Link> |
| 137 | + ); |
| 138 | +} |
0 commit comments