mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 23:49:51 +00:00
Core & UI: support collapsible in meta data
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
'fumadocs-core': patch
|
||||||
|
'fumadocs-ui': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
support `collapsible` in meta data
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
interface INode {
|
interface ID {
|
||||||
/**
|
/**
|
||||||
* ID for the node, unique in all page trees (even across different locales)
|
* ID for the node, unique in all page trees (even across different locales)
|
||||||
*/
|
*/
|
||||||
$id?: string;
|
$id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Root extends INode {
|
export interface Root extends ID {
|
||||||
name: ReactNode;
|
name: ReactNode;
|
||||||
children: Node[];
|
children: Node[];
|
||||||
/**
|
/**
|
||||||
@@ -18,7 +18,7 @@ export interface Root extends INode {
|
|||||||
|
|
||||||
export type Node = Item | Separator | Folder;
|
export type Node = Item | Separator | Folder;
|
||||||
|
|
||||||
export interface Item extends INode {
|
export interface Item extends ID {
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@@ -40,13 +40,13 @@ export interface Item extends INode {
|
|||||||
icon?: ReactNode;
|
icon?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Separator extends INode {
|
export interface Separator extends ID {
|
||||||
type: 'separator';
|
type: 'separator';
|
||||||
name?: ReactNode;
|
name?: ReactNode;
|
||||||
icon?: ReactNode;
|
icon?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Folder extends INode {
|
export interface Folder extends ID {
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@@ -59,6 +59,7 @@ export interface Folder extends INode {
|
|||||||
description?: ReactNode;
|
description?: ReactNode;
|
||||||
root?: boolean;
|
root?: boolean;
|
||||||
defaultOpen?: boolean;
|
defaultOpen?: boolean;
|
||||||
|
collapsible?: boolean;
|
||||||
index?: Item;
|
index?: Item;
|
||||||
icon?: ReactNode;
|
icon?: ReactNode;
|
||||||
children: Node[];
|
children: Node[];
|
||||||
|
|||||||
@@ -268,20 +268,19 @@ function createPageTreeBuilderUtils(ctx: PageTreeBuilderContext) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let meta = storage.read(metaPath);
|
let meta = storage.read(metaPath);
|
||||||
if (meta?.format !== 'meta') {
|
if (meta && meta.format !== 'meta') meta = undefined;
|
||||||
meta = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isRoot = meta?.data.root ?? isGlobalRoot;
|
const metadata = meta?.data ?? {};
|
||||||
|
const { root = isGlobalRoot, pages } = metadata;
|
||||||
let index: PageTree.Item | undefined;
|
let index: PageTree.Item | undefined;
|
||||||
let children: PageTree.Node[];
|
let children: PageTree.Node[];
|
||||||
|
|
||||||
if (meta && meta.data.pages) {
|
if (pages) {
|
||||||
const resolved = meta.data.pages.flatMap<
|
const resolved = pages.flatMap<
|
||||||
PageTree.Node | typeof rest | typeof restReversed
|
PageTree.Node | typeof rest | typeof restReversed
|
||||||
>((item) => this.resolveFolderItem(folderPath, item));
|
>((item) => this.resolveFolderItem(folderPath, item));
|
||||||
|
|
||||||
if (!isRoot && !visitedPaths.has(indexPath)) {
|
if (!root && !visitedPaths.has(indexPath)) {
|
||||||
index = this.file(indexPath);
|
index = this.file(indexPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +299,7 @@ function createPageTreeBuilderUtils(ctx: PageTreeBuilderContext) {
|
|||||||
|
|
||||||
children = resolved as PageTree.Node[];
|
children = resolved as PageTree.Node[];
|
||||||
} else {
|
} else {
|
||||||
if (!isRoot && !visitedPaths.has(indexPath)) {
|
if (!root && !visitedPaths.has(indexPath)) {
|
||||||
index = this.file(indexPath);
|
index = this.file(indexPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,19 +308,20 @@ function createPageTreeBuilderUtils(ctx: PageTreeBuilderContext) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = meta?.data.title ?? index?.name;
|
|
||||||
if (!name) {
|
|
||||||
const folderName = basename(folderPath);
|
|
||||||
name = pathToName(group.exec(folderName)?.[1] ?? folderName);
|
|
||||||
}
|
|
||||||
|
|
||||||
let node: PageTree.Folder = {
|
let node: PageTree.Folder = {
|
||||||
type: 'folder',
|
type: 'folder',
|
||||||
name,
|
name:
|
||||||
icon: meta?.data.icon ?? index?.icon,
|
metadata.title ??
|
||||||
root: meta?.data.root,
|
index?.name ??
|
||||||
defaultOpen: meta?.data.defaultOpen,
|
(() => {
|
||||||
description: meta?.data.description,
|
const folderName = basename(folderPath);
|
||||||
|
return pathToName(group.exec(folderName)?.[1] ?? folderName);
|
||||||
|
})(),
|
||||||
|
icon: metadata.icon,
|
||||||
|
root: metadata.root,
|
||||||
|
defaultOpen: metadata.defaultOpen,
|
||||||
|
description: metadata.description,
|
||||||
|
collapsible: metadata.collapsible,
|
||||||
index,
|
index,
|
||||||
children,
|
children,
|
||||||
$id: nextNodeId(folderPath),
|
$id: nextNodeId(folderPath),
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export interface MetaData {
|
|||||||
root?: boolean | undefined;
|
root?: boolean | undefined;
|
||||||
pages?: string[] | undefined;
|
pages?: string[] | undefined;
|
||||||
defaultOpen?: boolean | undefined;
|
defaultOpen?: boolean | undefined;
|
||||||
|
collapsible?: boolean | undefined;
|
||||||
|
|
||||||
description?: string | undefined;
|
description?: string | undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -491,6 +491,7 @@ test('Loader: Serialize data', async () => {
|
|||||||
"url": "/hello",
|
"url": "/hello",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
"collapsible": undefined,
|
||||||
"defaultOpen": undefined,
|
"defaultOpen": undefined,
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
"icon": undefined,
|
"icon": undefined,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
||||||
import type { MDXPresetOptions } from '@/config/preset';
|
import type { MDXPresetOptions } from '@/config/preset';
|
||||||
import type { ProcessorOptions } from '@mdx-js/mdx';
|
import type { ProcessorOptions } from '@mdx-js/mdx';
|
||||||
import { frontmatterSchema, metaSchema } from '@/config/zod-4';
|
import { metaSchema, pageSchema } from 'fumadocs-core/source/schema';
|
||||||
import type { PostprocessOptions } from '@/loaders/mdx/remark-postprocess';
|
import type { PostprocessOptions } from '@/loaders/mdx/remark-postprocess';
|
||||||
import type { PluginOption } from '@/core';
|
import type { PluginOption } from '@/core';
|
||||||
import type { BuildEnvironment } from './build';
|
import type { BuildEnvironment } from './build';
|
||||||
@@ -106,7 +106,7 @@ export function defineCollections(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function defineDocs<
|
export function defineDocs<
|
||||||
DocSchema extends StandardSchemaV1 = typeof frontmatterSchema,
|
DocSchema extends StandardSchemaV1 = typeof pageSchema,
|
||||||
MetaSchema extends StandardSchemaV1 = typeof metaSchema,
|
MetaSchema extends StandardSchemaV1 = typeof metaSchema,
|
||||||
>(options: {
|
>(options: {
|
||||||
/**
|
/**
|
||||||
@@ -127,7 +127,7 @@ export function defineDocs<
|
|||||||
docs: defineCollections({
|
docs: defineCollections({
|
||||||
type: 'doc',
|
type: 'doc',
|
||||||
dir,
|
dir,
|
||||||
schema: frontmatterSchema as any,
|
schema: pageSchema as any,
|
||||||
...options?.docs,
|
...options?.docs,
|
||||||
}),
|
}),
|
||||||
meta: defineCollections({
|
meta: defineCollections({
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
export * from './define';
|
export * from './define';
|
||||||
export * from '@/config/preset';
|
export * from '@/config/preset';
|
||||||
export * from './zod-4';
|
|
||||||
export { remarkInclude } from '@/loaders/mdx/remark-include';
|
export { remarkInclude } from '@/loaders/mdx/remark-include';
|
||||||
|
|
||||||
export type { PostprocessOptions } from '@/loaders/mdx/remark-postprocess';
|
export type { PostprocessOptions } from '@/loaders/mdx/remark-postprocess';
|
||||||
|
export {
|
||||||
|
metaSchema,
|
||||||
|
pageSchema as frontmatterSchema,
|
||||||
|
} from 'fumadocs-core/source/schema';
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import { z } from 'zod';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Zod 4 schema
|
|
||||||
*/
|
|
||||||
export const metaSchema = z.object({
|
|
||||||
title: z.string().optional(),
|
|
||||||
pages: z.array(z.string()).optional(),
|
|
||||||
description: z.string().optional(),
|
|
||||||
root: z.boolean().optional(),
|
|
||||||
defaultOpen: z.boolean().optional(),
|
|
||||||
icon: z.string().optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Zod 4 schema
|
|
||||||
*/
|
|
||||||
export const frontmatterSchema = z.object({
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string().optional(),
|
|
||||||
icon: z.string().optional(),
|
|
||||||
full: z.boolean().optional(),
|
|
||||||
|
|
||||||
// Fumadocs OpenAPI generated
|
|
||||||
_openapi: z.looseObject({}).optional(),
|
|
||||||
});
|
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
import { defineConfig } from 'tsup';
|
import { defineConfig } from 'tsup';
|
||||||
|
|
||||||
|
const external = ['next', 'typescript', 'bun'];
|
||||||
|
|
||||||
|
const noExternal = [
|
||||||
|
// TODO: remove this when the min `fumadocs-core` version is above 16.2.3
|
||||||
|
'fumadocs-core/source/schema',
|
||||||
|
];
|
||||||
|
|
||||||
export default defineConfig([
|
export default defineConfig([
|
||||||
{
|
{
|
||||||
entry: [
|
entry: [
|
||||||
@@ -11,7 +18,8 @@ export default defineConfig([
|
|||||||
'./src/plugins/*.ts',
|
'./src/plugins/*.ts',
|
||||||
],
|
],
|
||||||
format: 'esm',
|
format: 'esm',
|
||||||
external: ['next', 'typescript', 'bun'],
|
noExternal,
|
||||||
|
external,
|
||||||
dts: true,
|
dts: true,
|
||||||
target: 'node22',
|
target: 'node22',
|
||||||
},
|
},
|
||||||
@@ -22,7 +30,8 @@ export default defineConfig([
|
|||||||
'./next/index': './src/next/index.ts',
|
'./next/index': './src/next/index.ts',
|
||||||
},
|
},
|
||||||
format: 'cjs',
|
format: 'cjs',
|
||||||
external: ['next', 'typescript', 'bun'],
|
noExternal,
|
||||||
|
external,
|
||||||
dts: false,
|
dts: false,
|
||||||
target: 'node22',
|
target: 'node22',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ const FolderContext = createContext<{
|
|||||||
open: boolean;
|
open: boolean;
|
||||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
depth: number;
|
depth: number;
|
||||||
|
collapsible: boolean;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
export function SidebarProvider({
|
export function SidebarProvider({
|
||||||
@@ -125,6 +126,10 @@ export function useSidebar(): SidebarContext {
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useFolder() {
|
||||||
|
return use(FolderContext);
|
||||||
|
}
|
||||||
|
|
||||||
export function useFolderDepth() {
|
export function useFolderDepth() {
|
||||||
return use(FolderContext)?.depth ?? 0;
|
return use(FolderContext)?.depth ?? 0;
|
||||||
}
|
}
|
||||||
@@ -284,17 +289,22 @@ export function SidebarItem({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function SidebarFolder({
|
export function SidebarFolder({
|
||||||
defaultOpen: defaultOpenOption = false,
|
defaultOpen: defaultOpenProp,
|
||||||
|
collapsible = true,
|
||||||
|
active = false,
|
||||||
|
children,
|
||||||
...props
|
...props
|
||||||
}: ComponentProps<'div'> & {
|
}: ComponentProps<'div'> & {
|
||||||
defaultOpen?: boolean | ((currentDefault: boolean) => boolean);
|
active?: boolean;
|
||||||
|
defaultOpen?: boolean;
|
||||||
|
collapsible?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { defaultOpenLevel } = useSidebar();
|
const { defaultOpenLevel } = useSidebar();
|
||||||
const depth = useFolderDepth() + 1;
|
const depth = useFolderDepth() + 1;
|
||||||
const defaultOpen =
|
const defaultOpen =
|
||||||
typeof defaultOpenOption === 'function'
|
collapsible === false ||
|
||||||
? defaultOpenOption(defaultOpenLevel >= depth)
|
active ||
|
||||||
: defaultOpenLevel >= depth || defaultOpenOption;
|
(defaultOpenProp ?? defaultOpenLevel >= depth);
|
||||||
const [open, setOpen] = useState(defaultOpen);
|
const [open, setOpen] = useState(defaultOpen);
|
||||||
|
|
||||||
useOnChange(defaultOpen, (v) => {
|
useOnChange(defaultOpen, (v) => {
|
||||||
@@ -302,33 +312,48 @@ export function SidebarFolder({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapsible open={open} onOpenChange={setOpen} {...props}>
|
<Collapsible
|
||||||
|
open={open}
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
disabled={!collapsible}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
<FolderContext
|
<FolderContext
|
||||||
value={useMemo(() => ({ open, setOpen, depth }), [depth, open])}
|
value={useMemo(
|
||||||
|
() => ({ open, setOpen, depth, collapsible }),
|
||||||
|
[collapsible, depth, open],
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{props.children}
|
{children}
|
||||||
</FolderContext>
|
</FolderContext>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SidebarFolderTrigger(props: CollapsibleTriggerProps) {
|
export function SidebarFolderTrigger({
|
||||||
const { open } = use(FolderContext)!;
|
children,
|
||||||
|
...props
|
||||||
|
}: CollapsibleTriggerProps) {
|
||||||
|
const { open, collapsible } = use(FolderContext)!;
|
||||||
|
|
||||||
return (
|
if (collapsible) {
|
||||||
<CollapsibleTrigger {...props}>
|
return (
|
||||||
{props.children}
|
<CollapsibleTrigger {...props}>
|
||||||
<ChevronDown
|
{children}
|
||||||
data-icon
|
<ChevronDown
|
||||||
className={cn('ms-auto transition-transform', !open && '-rotate-90')}
|
data-icon
|
||||||
/>
|
className={cn('ms-auto transition-transform', !open && '-rotate-90')}
|
||||||
</CollapsibleTrigger>
|
/>
|
||||||
);
|
</CollapsibleTrigger>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div {...(props as ComponentProps<'div'>)}>{children}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SidebarFolderLink(props: LinkProps) {
|
export function SidebarFolderLink({ children, ...props }: LinkProps) {
|
||||||
const ref = useRef<HTMLAnchorElement>(null);
|
const ref = useRef<HTMLAnchorElement>(null);
|
||||||
const { open, setOpen } = use(FolderContext)!;
|
const { open, setOpen, collapsible } = use(FolderContext)!;
|
||||||
const { prefetch } = useSidebar();
|
const { prefetch } = useSidebar();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const active =
|
const active =
|
||||||
@@ -341,6 +366,8 @@ export function SidebarFolderLink(props: LinkProps) {
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
data-active={active}
|
data-active={active}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
if (!collapsible) return;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
e.target instanceof Element &&
|
e.target instanceof Element &&
|
||||||
e.target.matches('[data-icon], [data-icon] *')
|
e.target.matches('[data-icon], [data-icon] *')
|
||||||
@@ -354,11 +381,13 @@ export function SidebarFolderLink(props: LinkProps) {
|
|||||||
prefetch={prefetch}
|
prefetch={prefetch}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{props.children}
|
{children}
|
||||||
<ChevronDown
|
{collapsible && (
|
||||||
data-icon
|
<ChevronDown
|
||||||
className={cn('ms-auto transition-transform', !open && '-rotate-90')}
|
data-icon
|
||||||
/>
|
className={cn('ms-auto transition-transform', !open && '-rotate-90')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ export function createPageTreeRenderer({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarFolder
|
<SidebarFolder
|
||||||
defaultOpen={(value) =>
|
collapsible={item.collapsible}
|
||||||
(item.defaultOpen ?? value) || path.includes(item)
|
active={path.includes(item)}
|
||||||
}
|
defaultOpen={item.defaultOpen}
|
||||||
>
|
>
|
||||||
{item.index ? (
|
{item.index ? (
|
||||||
<SidebarFolderLink
|
<SidebarFolderLink
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ import { Sidebar as SidebarIcon } from 'lucide-react';
|
|||||||
import { mergeRefs } from '@/utils/merge-refs';
|
import { mergeRefs } from '@/utils/merge-refs';
|
||||||
|
|
||||||
const itemVariants = cva(
|
const itemVariants = cva(
|
||||||
'relative flex flex-row items-center gap-2 rounded-lg p-2 text-start text-fd-muted-foreground wrap-anywhere transition-colors hover:bg-fd-accent/50 hover:text-fd-accent-foreground/80 hover:transition-none [&_svg]:size-4 [&_svg]:shrink-0',
|
'relative flex flex-row items-center gap-2 rounded-lg p-2 text-start text-fd-muted-foreground wrap-anywhere [&_svg]:size-4 [&_svg]:shrink-0',
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
link: 'data-[active=true]:bg-fd-primary/10 data-[active=true]:text-fd-primary data-[active=true]:hover:transition-colors',
|
link: 'transition-colors hover:bg-fd-accent/50 hover:text-fd-accent-foreground/80 hover:transition-none data-[active=true]:bg-fd-primary/10 data-[active=true]:text-fd-primary data-[active=true]:hover:transition-colors',
|
||||||
|
button:
|
||||||
|
'transition-colors hover:bg-fd-accent/50 hover:text-fd-accent-foreground/80 hover:transition-none',
|
||||||
},
|
},
|
||||||
highlight: {
|
highlight: {
|
||||||
true: "data-[active=true]:before:content-[''] data-[active=true]:before:bg-fd-primary data-[active=true]:before:absolute data-[active=true]:before:w-px data-[active=true]:before:inset-y-2.5 data-[active=true]:before:start-2.5",
|
true: "data-[active=true]:before:content-[''] data-[active=true]:before:bg-fd-primary data-[active=true]:before:absolute data-[active=true]:before:w-px data-[active=true]:before:inset-y-2.5 data-[active=true]:before:start-2.5",
|
||||||
@@ -179,11 +181,15 @@ export function SidebarFolderTrigger({
|
|||||||
style,
|
style,
|
||||||
...props
|
...props
|
||||||
}: ComponentProps<typeof Base.SidebarFolderTrigger>) {
|
}: ComponentProps<typeof Base.SidebarFolderTrigger>) {
|
||||||
const depth = Base.useFolderDepth();
|
const { depth, collapsible } = Base.useFolder()!;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Base.SidebarFolderTrigger
|
<Base.SidebarFolderTrigger
|
||||||
className={cn(itemVariants(), 'w-full', className)}
|
className={cn(
|
||||||
|
itemVariants({ variant: collapsible ? 'button' : null }),
|
||||||
|
'w-full',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
style={{
|
style={{
|
||||||
paddingInlineStart: getItemOffset(depth - 1),
|
paddingInlineStart: getItemOffset(depth - 1),
|
||||||
...style,
|
...style,
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ import { createLinkItemRenderer } from '@/components/sidebar/link-item';
|
|||||||
import { mergeRefs } from '@/utils/merge-refs';
|
import { mergeRefs } from '@/utils/merge-refs';
|
||||||
|
|
||||||
const itemVariants = cva(
|
const itemVariants = cva(
|
||||||
'relative flex flex-row items-center gap-2 rounded-lg p-2 text-start text-fd-muted-foreground wrap-anywhere transition-colors hover:bg-fd-accent/50 hover:text-fd-accent-foreground/80 hover:transition-none [&_svg]:size-4 [&_svg]:shrink-0',
|
'relative flex flex-row items-center gap-2 rounded-lg p-2 text-start text-fd-muted-foreground wrap-anywhere [&_svg]:size-4 [&_svg]:shrink-0',
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
link: 'data-[active=true]:bg-fd-primary/10 data-[active=true]:text-fd-primary data-[active=true]:hover:transition-colors',
|
link: 'transition-colors hover:bg-fd-accent/50 hover:text-fd-accent-foreground/80 hover:transition-none data-[active=true]:bg-fd-primary/10 data-[active=true]:text-fd-primary data-[active=true]:hover:transition-colors',
|
||||||
|
button:
|
||||||
|
'transition-colors hover:bg-fd-accent/50 hover:text-fd-accent-foreground/80 hover:transition-none',
|
||||||
},
|
},
|
||||||
highlight: {
|
highlight: {
|
||||||
true: "data-[active=true]:before:content-[''] data-[active=true]:before:bg-fd-primary data-[active=true]:before:absolute data-[active=true]:before:w-px data-[active=true]:before:inset-y-2.5 data-[active=true]:before:start-2.5",
|
true: "data-[active=true]:before:content-[''] data-[active=true]:before:bg-fd-primary data-[active=true]:before:absolute data-[active=true]:before:w-px data-[active=true]:before:inset-y-2.5 data-[active=true]:before:start-2.5",
|
||||||
@@ -162,11 +164,15 @@ export function SidebarFolderTrigger({
|
|||||||
style,
|
style,
|
||||||
...props
|
...props
|
||||||
}: ComponentProps<typeof Base.SidebarFolderTrigger>) {
|
}: ComponentProps<typeof Base.SidebarFolderTrigger>) {
|
||||||
const depth = Base.useFolderDepth();
|
const { depth, collapsible } = Base.useFolder()!;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Base.SidebarFolderTrigger
|
<Base.SidebarFolderTrigger
|
||||||
className={cn(itemVariants(), 'w-full', className)}
|
className={cn(
|
||||||
|
itemVariants({ variant: collapsible ? 'button' : null }),
|
||||||
|
'w-full',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
style={{
|
style={{
|
||||||
paddingInlineStart: getItemOffset(depth - 1),
|
paddingInlineStart: getItemOffset(depth - 1),
|
||||||
...style,
|
...style,
|
||||||
|
|||||||
Reference in New Issue
Block a user