forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsubdocs-menu.tsx
More file actions
96 lines (88 loc) · 2.42 KB
/
Copy pathsubdocs-menu.tsx
File metadata and controls
96 lines (88 loc) · 2.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
"use client";
import { ChevronDown } from "lucide-react";
import {
type HTMLAttributes,
type ReactNode,
useCallback,
useMemo,
useState,
} from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { cn } from "@/lib/utils";
import { useSidebar } from "fumadocs-ui/provider";
export function isActive(
url: string,
pathname: string,
nested = true,
root = false
): boolean {
const isActive =
url === pathname || (nested && pathname.startsWith(root ? url : `${url}/`));
return isActive;
}
export interface Option {
/**
* Redirect URL of the folder, usually the index page
*/
url: string;
icon?: ReactNode;
title: ReactNode;
description?: ReactNode;
bgGradient: string;
selectedBorder: string;
props?: HTMLAttributes<HTMLElement>;
}
export function SubdocsMenu({
options,
...props
}: {
options: Option[];
} & HTMLAttributes<HTMLButtonElement>): React.ReactElement {
const { closeOnRedirect } = useSidebar();
const pathname = usePathname();
const selected = useMemo(() => {
// First, try all non-root options
const nonRootOptions = options.filter((item) => item.url !== "/");
const activeNonRootOption = nonRootOptions.find((item) =>
isActive(item.url, pathname, true)
);
if (activeNonRootOption) {
return activeNonRootOption;
}
// If no non-root options are active, try the root options ("/*")
return options.find((item) => isActive(item.url, pathname, true, true));
}, [options, pathname]);
const onClick = useCallback(() => {
closeOnRedirect.current = false;
}, [closeOnRedirect]);
return (
<div className="flex flex-col gap-2 border-b pb-4 pt-2 px-1">
{options.map((item) => (
<Link
key={item.url}
href={item.url}
onClick={onClick}
{...item.props}
className={cn(
"p-1 flex flex-row gap-3 items-center cursor-pointer group opacity-70 hover:opacity-100",
selected === item && "opacity-100",
item.props?.className
)}
>
<div
className={cn(
"rounded-sm p-1.5",
item.bgGradient,
selected !== item && "",
selected === item && `${item.selectedBorder} ring-2`
)}
>
{item.icon}
</div>
<div className="font-medium">{item.title}</div>
</Link>
))}
</div>
);
}