@hanzo/ui 5.3.26 → 5.3.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/content/index.ts +26 -0
- package/dist/util/index.js +6 -0
- package/dist/util/index.mjs +6 -1
- package/docs/_registry/index.ts +426 -0
- package/docs/_registry/layout/docs-min.tsx +197 -0
- package/docs/_registry/layout/page-min.tsx +128 -0
- package/docs/components/accordion.tsx +118 -0
- package/docs/components/banner.tsx +144 -0
- package/docs/components/callout.tsx +112 -0
- package/docs/components/card.tsx +52 -0
- package/docs/components/codeblock.tsx +258 -0
- package/docs/components/dialog/search-algolia.tsx +132 -0
- package/docs/components/dialog/search-default.tsx +131 -0
- package/docs/components/dialog/search-orama.tsx +143 -0
- package/docs/components/dialog/search.tsx +529 -0
- package/docs/components/dynamic-codeblock.tsx +129 -0
- package/docs/components/files.tsx +81 -0
- package/docs/components/github-info.tsx +107 -0
- package/docs/components/heading.tsx +33 -0
- package/docs/components/image-zoom.css +77 -0
- package/docs/components/image-zoom.tsx +58 -0
- package/docs/components/index.ts +7 -0
- package/docs/components/inline-toc.tsx +48 -0
- package/docs/components/sidebar/base.tsx +451 -0
- package/docs/components/sidebar/link-item.tsx +65 -0
- package/docs/components/sidebar/page-tree.tsx +113 -0
- package/docs/components/sidebar/tabs/dropdown.tsx +109 -0
- package/docs/components/sidebar/tabs/index.tsx +89 -0
- package/docs/components/steps.tsx +9 -0
- package/docs/components/tabs.tsx +203 -0
- package/docs/components/toc/clerk.tsx +173 -0
- package/docs/components/toc/default.tsx +57 -0
- package/docs/components/toc/index.tsx +136 -0
- package/docs/components/type-table.tsx +174 -0
- package/docs/components/ui/accordion.tsx +88 -0
- package/docs/components/ui/button.tsx +28 -0
- package/docs/components/ui/collapsible.tsx +42 -0
- package/docs/components/ui/navigation-menu.tsx +83 -0
- package/docs/components/ui/popover.tsx +32 -0
- package/docs/components/ui/scroll-area.tsx +59 -0
- package/docs/components/ui/tabs.tsx +145 -0
- package/docs/contexts/i18n.tsx +56 -0
- package/docs/contexts/search.tsx +165 -0
- package/docs/contexts/tree.tsx +65 -0
- package/docs/css/black.css +39 -0
- package/docs/css/catppuccin.css +49 -0
- package/docs/css/colors/index.css +51 -0
- package/docs/css/dusk.css +47 -0
- package/docs/css/layouts/docs.css +1 -0
- package/docs/css/layouts/home.css +1 -0
- package/docs/css/layouts/notebook.css +1 -0
- package/docs/css/neutral.css +7 -0
- package/docs/css/ocean.css +48 -0
- package/docs/css/preset.css +305 -0
- package/docs/css/purple.css +39 -0
- package/docs/css/shadcn.css +36 -0
- package/docs/css/shiki.css +90 -0
- package/docs/css/solar.css +75 -0
- package/docs/css/style.css +9 -0
- package/docs/css/vitepress.css +77 -0
- package/docs/i18n.tsx +30 -0
- package/docs/icons.tsx +354 -0
- package/docs/layouts/docs/client.tsx +129 -0
- package/docs/layouts/docs/index.tsx +321 -0
- package/docs/layouts/docs/page/client.tsx +376 -0
- package/docs/layouts/docs/page/index.tsx +251 -0
- package/docs/layouts/docs/sidebar.tsx +265 -0
- package/docs/layouts/home/client.tsx +375 -0
- package/docs/layouts/home/index.tsx +51 -0
- package/docs/layouts/home/navbar.tsx +55 -0
- package/docs/layouts/notebook/client.tsx +281 -0
- package/docs/layouts/notebook/index.tsx +461 -0
- package/docs/layouts/notebook/page/client.tsx +375 -0
- package/docs/layouts/notebook/page/index.tsx +251 -0
- package/docs/layouts/notebook/sidebar.tsx +248 -0
- package/docs/layouts/shared/index.tsx +89 -0
- package/docs/layouts/shared/language-toggle.tsx +66 -0
- package/docs/layouts/shared/link-item.tsx +119 -0
- package/docs/layouts/shared/search-toggle.tsx +78 -0
- package/docs/layouts/shared/theme-toggle.tsx +86 -0
- package/docs/mdx.server.tsx +37 -0
- package/docs/mdx.tsx +97 -0
- package/docs/og.tsx +101 -0
- package/docs/page.tsx +85 -0
- package/docs/provider/base.tsx +173 -0
- package/docs/provider/next.tsx +23 -0
- package/docs/provider/react-router.tsx +23 -0
- package/docs/provider/tanstack.tsx +23 -0
- package/docs/provider/waku.tsx +23 -0
- package/docs/source.ts +3 -0
- package/docs/theme/typography/LICENSE +21 -0
- package/docs/theme/typography/index.ts +201 -0
- package/docs/theme/typography/styles.ts +449 -0
- package/docs/utils/cn.ts +1 -0
- package/docs/utils/is-active.ts +23 -0
- package/docs/utils/merge-refs.ts +15 -0
- package/docs/utils/use-copy-button.ts +39 -0
- package/docs/utils/use-footer-items.ts +27 -0
- package/docs/utils/use-is-scroll-top.ts +21 -0
- package/package.json +4 -2
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { type ComponentProps, Fragment, useMemo, useState } from 'react';
|
|
3
|
+
import { cva } from 'class-variance-authority';
|
|
4
|
+
import Link from '@hanzo/docs-core/link';
|
|
5
|
+
import { cn } from '@/utils/cn';
|
|
6
|
+
import {
|
|
7
|
+
type LinkItemType,
|
|
8
|
+
type NavOptions,
|
|
9
|
+
resolveLinkItems,
|
|
10
|
+
} from '@/layouts/shared';
|
|
11
|
+
import { LinkItem } from '@/layouts/shared/link-item';
|
|
12
|
+
import {
|
|
13
|
+
NavigationMenu,
|
|
14
|
+
NavigationMenuContent,
|
|
15
|
+
NavigationMenuItem,
|
|
16
|
+
NavigationMenuLink,
|
|
17
|
+
NavigationMenuList,
|
|
18
|
+
NavigationMenuTrigger,
|
|
19
|
+
NavigationMenuViewport,
|
|
20
|
+
} from '@/components/ui/navigation-menu';
|
|
21
|
+
import { buttonVariants } from '@/components/ui/button';
|
|
22
|
+
import type { HomeLayoutProps } from '.';
|
|
23
|
+
import {
|
|
24
|
+
LargeSearchToggle,
|
|
25
|
+
SearchToggle,
|
|
26
|
+
} from '@/layouts/shared/search-toggle';
|
|
27
|
+
import { ThemeToggle } from '@/layouts/shared/theme-toggle';
|
|
28
|
+
import {
|
|
29
|
+
LanguageToggle,
|
|
30
|
+
LanguageToggleText,
|
|
31
|
+
} from '@/layouts/shared/language-toggle';
|
|
32
|
+
import { ChevronDown, Languages } from '@icons';
|
|
33
|
+
import { useIsScrollTop } from '@/utils/use-is-scroll-top';
|
|
34
|
+
|
|
35
|
+
export const navItemVariants = cva('[&_svg]:size-4', {
|
|
36
|
+
variants: {
|
|
37
|
+
variant: {
|
|
38
|
+
main: 'inline-flex items-center gap-1 p-2 text-fd-muted-foreground transition-colors hover:text-fd-accent-foreground data-[active=true]:text-fd-primary',
|
|
39
|
+
button: buttonVariants({
|
|
40
|
+
color: 'secondary',
|
|
41
|
+
className: 'gap-1.5',
|
|
42
|
+
}),
|
|
43
|
+
icon: buttonVariants({
|
|
44
|
+
color: 'ghost',
|
|
45
|
+
size: 'icon',
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
defaultVariants: {
|
|
50
|
+
variant: 'main',
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export function Header({
|
|
55
|
+
nav = {},
|
|
56
|
+
i18n = false,
|
|
57
|
+
links,
|
|
58
|
+
githubUrl,
|
|
59
|
+
themeSwitch = {},
|
|
60
|
+
searchToggle = {},
|
|
61
|
+
}: HomeLayoutProps) {
|
|
62
|
+
const { navItems, menuItems } = useMemo(() => {
|
|
63
|
+
const navItems: LinkItemType[] = [];
|
|
64
|
+
const menuItems: LinkItemType[] = [];
|
|
65
|
+
|
|
66
|
+
for (const item of resolveLinkItems({ links, githubUrl })) {
|
|
67
|
+
switch (item.on ?? 'all') {
|
|
68
|
+
case 'menu':
|
|
69
|
+
menuItems.push(item);
|
|
70
|
+
break;
|
|
71
|
+
case 'nav':
|
|
72
|
+
navItems.push(item);
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
navItems.push(item);
|
|
76
|
+
menuItems.push(item);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return { navItems, menuItems };
|
|
81
|
+
}, [links, githubUrl]);
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<HeaderNavigationMenu transparentMode={nav.transparentMode}>
|
|
85
|
+
<Link
|
|
86
|
+
href={nav.url ?? '/'}
|
|
87
|
+
className="inline-flex items-center gap-2.5 font-semibold"
|
|
88
|
+
>
|
|
89
|
+
{nav.title}
|
|
90
|
+
</Link>
|
|
91
|
+
{nav.children}
|
|
92
|
+
<ul className="flex flex-row items-center gap-2 px-6 max-sm:hidden">
|
|
93
|
+
{navItems
|
|
94
|
+
.filter((item) => !isSecondary(item))
|
|
95
|
+
.map((item, i) => (
|
|
96
|
+
<NavigationMenuLinkItem key={i} item={item} className="text-sm" />
|
|
97
|
+
))}
|
|
98
|
+
</ul>
|
|
99
|
+
<div className="flex flex-row items-center justify-end gap-1.5 flex-1 max-lg:hidden">
|
|
100
|
+
{searchToggle.enabled !== false &&
|
|
101
|
+
(searchToggle.components?.lg ?? (
|
|
102
|
+
<LargeSearchToggle
|
|
103
|
+
className="w-full rounded-full ps-2.5 max-w-[240px]"
|
|
104
|
+
hideIfDisabled
|
|
105
|
+
/>
|
|
106
|
+
))}
|
|
107
|
+
{themeSwitch.enabled !== false &&
|
|
108
|
+
(themeSwitch.component ?? <ThemeToggle mode={themeSwitch?.mode} />)}
|
|
109
|
+
{i18n && (
|
|
110
|
+
<LanguageToggle>
|
|
111
|
+
<Languages className="size-5" />
|
|
112
|
+
</LanguageToggle>
|
|
113
|
+
)}
|
|
114
|
+
<ul className="flex flex-row gap-2 items-center empty:hidden">
|
|
115
|
+
{navItems.filter(isSecondary).map((item, i) => (
|
|
116
|
+
<NavigationMenuLinkItem
|
|
117
|
+
key={i}
|
|
118
|
+
className={cn(
|
|
119
|
+
item.type === 'icon' && '-mx-1 first:ms-0 last:me-0',
|
|
120
|
+
)}
|
|
121
|
+
item={item}
|
|
122
|
+
/>
|
|
123
|
+
))}
|
|
124
|
+
</ul>
|
|
125
|
+
</div>
|
|
126
|
+
<ul className="flex flex-row items-center ms-auto -me-1.5 lg:hidden">
|
|
127
|
+
{searchToggle.enabled !== false &&
|
|
128
|
+
(searchToggle.components?.sm ?? (
|
|
129
|
+
<SearchToggle className="p-2" hideIfDisabled />
|
|
130
|
+
))}
|
|
131
|
+
<NavigationMenuItem>
|
|
132
|
+
<NavigationMenuTrigger
|
|
133
|
+
aria-label="Toggle Menu"
|
|
134
|
+
className={cn(
|
|
135
|
+
buttonVariants({
|
|
136
|
+
size: 'icon',
|
|
137
|
+
color: 'ghost',
|
|
138
|
+
className: 'group [&_svg]:size-5.5',
|
|
139
|
+
}),
|
|
140
|
+
)}
|
|
141
|
+
onPointerMove={
|
|
142
|
+
nav.enableHoverToOpen ? undefined : (e) => e.preventDefault()
|
|
143
|
+
}
|
|
144
|
+
>
|
|
145
|
+
<ChevronDown className="transition-transform duration-300 group-data-[state=open]:rotate-180" />
|
|
146
|
+
</NavigationMenuTrigger>
|
|
147
|
+
<NavigationMenuContent className="flex flex-col p-4 sm:flex-row sm:items-center sm:justify-end">
|
|
148
|
+
{menuItems
|
|
149
|
+
.filter((item) => !isSecondary(item))
|
|
150
|
+
.map((item, i) => (
|
|
151
|
+
<MobileNavigationMenuLinkItem
|
|
152
|
+
key={i}
|
|
153
|
+
item={item}
|
|
154
|
+
className="sm:hidden"
|
|
155
|
+
/>
|
|
156
|
+
))}
|
|
157
|
+
<div className="-ms-1.5 flex flex-row items-center gap-2 max-sm:mt-2">
|
|
158
|
+
{menuItems.filter(isSecondary).map((item, i) => (
|
|
159
|
+
<MobileNavigationMenuLinkItem
|
|
160
|
+
key={i}
|
|
161
|
+
item={item}
|
|
162
|
+
className={cn(item.type === 'icon' && '-mx-1 first:ms-0')}
|
|
163
|
+
/>
|
|
164
|
+
))}
|
|
165
|
+
<div role="separator" className="flex-1" />
|
|
166
|
+
{i18n && (
|
|
167
|
+
<LanguageToggle>
|
|
168
|
+
<Languages className="size-5" />
|
|
169
|
+
<LanguageToggleText />
|
|
170
|
+
<ChevronDown className="size-3 text-fd-muted-foreground" />
|
|
171
|
+
</LanguageToggle>
|
|
172
|
+
)}
|
|
173
|
+
{themeSwitch.enabled !== false &&
|
|
174
|
+
(themeSwitch.component ?? (
|
|
175
|
+
<ThemeToggle mode={themeSwitch?.mode} />
|
|
176
|
+
))}
|
|
177
|
+
</div>
|
|
178
|
+
</NavigationMenuContent>
|
|
179
|
+
</NavigationMenuItem>
|
|
180
|
+
</ul>
|
|
181
|
+
</HeaderNavigationMenu>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function isSecondary(item: LinkItemType): boolean {
|
|
186
|
+
if ('secondary' in item && item.secondary != null) return item.secondary;
|
|
187
|
+
|
|
188
|
+
return item.type === 'icon';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function HeaderNavigationMenu({
|
|
192
|
+
transparentMode = 'none',
|
|
193
|
+
...props
|
|
194
|
+
}: ComponentProps<'div'> & {
|
|
195
|
+
transparentMode?: NavOptions['transparentMode'];
|
|
196
|
+
}) {
|
|
197
|
+
const [value, setValue] = useState('');
|
|
198
|
+
const isTop = useIsScrollTop({ enabled: transparentMode === 'top' }) ?? true;
|
|
199
|
+
const isTransparent =
|
|
200
|
+
transparentMode === 'top' ? isTop : transparentMode === 'always';
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<NavigationMenu value={value} onValueChange={setValue} asChild>
|
|
204
|
+
<header
|
|
205
|
+
id="nd-nav"
|
|
206
|
+
{...props}
|
|
207
|
+
className={cn('sticky h-14 top-0 z-40', props.className)}
|
|
208
|
+
>
|
|
209
|
+
<div
|
|
210
|
+
className={cn(
|
|
211
|
+
'backdrop-blur-lg border-b transition-colors *:mx-auto *:max-w-(--fd-layout-width)',
|
|
212
|
+
value.length > 0 && 'max-lg:shadow-lg max-lg:rounded-b-2xl',
|
|
213
|
+
(!isTransparent || value.length > 0) && 'bg-fd-background/80',
|
|
214
|
+
)}
|
|
215
|
+
>
|
|
216
|
+
<NavigationMenuList
|
|
217
|
+
className="flex h-14 w-full items-center px-4"
|
|
218
|
+
asChild
|
|
219
|
+
>
|
|
220
|
+
<nav>{props.children}</nav>
|
|
221
|
+
</NavigationMenuList>
|
|
222
|
+
|
|
223
|
+
<NavigationMenuViewport />
|
|
224
|
+
</div>
|
|
225
|
+
</header>
|
|
226
|
+
</NavigationMenu>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function NavigationMenuLinkItem({
|
|
231
|
+
item,
|
|
232
|
+
...props
|
|
233
|
+
}: {
|
|
234
|
+
item: LinkItemType;
|
|
235
|
+
className?: string;
|
|
236
|
+
}) {
|
|
237
|
+
if (item.type === 'custom') return <div {...props}>{item.children}</div>;
|
|
238
|
+
|
|
239
|
+
if (item.type === 'menu') {
|
|
240
|
+
const children = item.items.map((child, j) => {
|
|
241
|
+
if (child.type === 'custom') {
|
|
242
|
+
return <Fragment key={j}>{child.children}</Fragment>;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const {
|
|
246
|
+
banner = child.icon ? (
|
|
247
|
+
<div className="w-fit rounded-md border bg-fd-muted p-1 [&_svg]:size-4">
|
|
248
|
+
{child.icon}
|
|
249
|
+
</div>
|
|
250
|
+
) : null,
|
|
251
|
+
...rest
|
|
252
|
+
} = child.menu ?? {};
|
|
253
|
+
|
|
254
|
+
return (
|
|
255
|
+
<NavigationMenuLink key={`${j}-${child.url}`} asChild>
|
|
256
|
+
<Link
|
|
257
|
+
href={child.url}
|
|
258
|
+
external={child.external}
|
|
259
|
+
{...rest}
|
|
260
|
+
className={cn(
|
|
261
|
+
'flex flex-col gap-2 rounded-lg border bg-fd-card p-3 transition-colors hover:bg-fd-accent/80 hover:text-fd-accent-foreground',
|
|
262
|
+
rest.className,
|
|
263
|
+
)}
|
|
264
|
+
>
|
|
265
|
+
{rest.children ?? (
|
|
266
|
+
<>
|
|
267
|
+
{banner}
|
|
268
|
+
<p className="text-base font-medium">{child.text}</p>
|
|
269
|
+
<p className="text-sm text-fd-muted-foreground empty:hidden">
|
|
270
|
+
{child.description}
|
|
271
|
+
</p>
|
|
272
|
+
</>
|
|
273
|
+
)}
|
|
274
|
+
</Link>
|
|
275
|
+
</NavigationMenuLink>
|
|
276
|
+
);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<NavigationMenuItem {...props}>
|
|
281
|
+
<NavigationMenuTrigger className={cn(navItemVariants(), 'rounded-md')}>
|
|
282
|
+
{item.url ? (
|
|
283
|
+
<Link href={item.url} external={item.external}>
|
|
284
|
+
{item.text}
|
|
285
|
+
</Link>
|
|
286
|
+
) : (
|
|
287
|
+
item.text
|
|
288
|
+
)}
|
|
289
|
+
</NavigationMenuTrigger>
|
|
290
|
+
<NavigationMenuContent className="grid grid-cols-1 gap-2 p-4 md:grid-cols-2 lg:grid-cols-3">
|
|
291
|
+
{children}
|
|
292
|
+
</NavigationMenuContent>
|
|
293
|
+
</NavigationMenuItem>
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return (
|
|
298
|
+
<NavigationMenuItem {...props}>
|
|
299
|
+
<NavigationMenuLink asChild>
|
|
300
|
+
<LinkItem
|
|
301
|
+
item={item}
|
|
302
|
+
aria-label={item.type === 'icon' ? item.label : undefined}
|
|
303
|
+
className={cn(navItemVariants({ variant: item.type }))}
|
|
304
|
+
>
|
|
305
|
+
{item.type === 'icon' ? item.icon : item.text}
|
|
306
|
+
</LinkItem>
|
|
307
|
+
</NavigationMenuLink>
|
|
308
|
+
</NavigationMenuItem>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function MobileNavigationMenuLinkItem({
|
|
313
|
+
item,
|
|
314
|
+
...props
|
|
315
|
+
}: {
|
|
316
|
+
item: LinkItemType;
|
|
317
|
+
className?: string;
|
|
318
|
+
}) {
|
|
319
|
+
if (item.type === 'custom')
|
|
320
|
+
return <div className={cn('grid', props.className)}>{item.children}</div>;
|
|
321
|
+
|
|
322
|
+
if (item.type === 'menu') {
|
|
323
|
+
const header = (
|
|
324
|
+
<>
|
|
325
|
+
{item.icon}
|
|
326
|
+
{item.text}
|
|
327
|
+
</>
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
return (
|
|
331
|
+
<div className={cn('mb-4 flex flex-col', props.className)}>
|
|
332
|
+
<p className="mb-1 text-sm text-fd-muted-foreground">
|
|
333
|
+
{item.url ? (
|
|
334
|
+
<NavigationMenuLink asChild>
|
|
335
|
+
<Link href={item.url} external={item.external}>
|
|
336
|
+
{header}
|
|
337
|
+
</Link>
|
|
338
|
+
</NavigationMenuLink>
|
|
339
|
+
) : (
|
|
340
|
+
header
|
|
341
|
+
)}
|
|
342
|
+
</p>
|
|
343
|
+
{item.items.map((child, i) => (
|
|
344
|
+
<MobileNavigationMenuLinkItem key={i} item={child} />
|
|
345
|
+
))}
|
|
346
|
+
</div>
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return (
|
|
351
|
+
<NavigationMenuLink asChild>
|
|
352
|
+
<LinkItem
|
|
353
|
+
item={item}
|
|
354
|
+
className={cn(
|
|
355
|
+
{
|
|
356
|
+
main: 'inline-flex items-center gap-2 py-1.5 transition-colors hover:text-fd-popover-foreground/50 data-[active=true]:font-medium data-[active=true]:text-fd-primary [&_svg]:size-4',
|
|
357
|
+
icon: buttonVariants({
|
|
358
|
+
size: 'icon',
|
|
359
|
+
color: 'ghost',
|
|
360
|
+
}),
|
|
361
|
+
button: buttonVariants({
|
|
362
|
+
color: 'secondary',
|
|
363
|
+
className: 'gap-1.5 [&_svg]:size-4',
|
|
364
|
+
}),
|
|
365
|
+
}[item.type ?? 'main'],
|
|
366
|
+
props.className,
|
|
367
|
+
)}
|
|
368
|
+
aria-label={item.type === 'icon' ? item.label : undefined}
|
|
369
|
+
>
|
|
370
|
+
{item.icon}
|
|
371
|
+
{item.type === 'icon' ? undefined : item.text}
|
|
372
|
+
</LinkItem>
|
|
373
|
+
</NavigationMenuLink>
|
|
374
|
+
);
|
|
375
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
import { cn } from '@/utils/cn';
|
|
3
|
+
import { type BaseLayoutProps, type NavOptions } from '@/layouts/shared';
|
|
4
|
+
import { Header } from '@/layouts/home/client';
|
|
5
|
+
|
|
6
|
+
export interface HomeLayoutProps extends BaseLayoutProps {
|
|
7
|
+
nav?: Partial<
|
|
8
|
+
NavOptions & {
|
|
9
|
+
/**
|
|
10
|
+
* Open mobile menu when hovering the trigger
|
|
11
|
+
*/
|
|
12
|
+
enableHoverToOpen?: boolean;
|
|
13
|
+
}
|
|
14
|
+
>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function HomeLayout(props: HomeLayoutProps & ComponentProps<'main'>) {
|
|
18
|
+
const {
|
|
19
|
+
nav = {},
|
|
20
|
+
links,
|
|
21
|
+
githubUrl,
|
|
22
|
+
i18n,
|
|
23
|
+
themeSwitch = {},
|
|
24
|
+
searchToggle,
|
|
25
|
+
...rest
|
|
26
|
+
} = props;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<main
|
|
30
|
+
id="nd-home-layout"
|
|
31
|
+
{...rest}
|
|
32
|
+
className={cn(
|
|
33
|
+
'flex flex-1 flex-col [--fd-layout-width:1400px]',
|
|
34
|
+
rest.className,
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
{nav.enabled !== false &&
|
|
38
|
+
(nav.component ?? (
|
|
39
|
+
<Header
|
|
40
|
+
links={links}
|
|
41
|
+
nav={nav}
|
|
42
|
+
themeSwitch={themeSwitch}
|
|
43
|
+
searchToggle={searchToggle}
|
|
44
|
+
i18n={i18n}
|
|
45
|
+
githubUrl={githubUrl}
|
|
46
|
+
/>
|
|
47
|
+
))}
|
|
48
|
+
{props.children}
|
|
49
|
+
</main>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import Link, { type LinkProps } from '@hanzo/docs-core/link';
|
|
3
|
+
import { cn } from '@/utils/cn';
|
|
4
|
+
import {
|
|
5
|
+
NavigationMenuContent,
|
|
6
|
+
type NavigationMenuContentProps,
|
|
7
|
+
NavigationMenuItem,
|
|
8
|
+
NavigationMenuLink,
|
|
9
|
+
NavigationMenuTrigger,
|
|
10
|
+
type NavigationMenuTriggerProps,
|
|
11
|
+
} from '@/components/ui/navigation-menu';
|
|
12
|
+
import { navItemVariants } from './client';
|
|
13
|
+
|
|
14
|
+
export const NavbarMenu = NavigationMenuItem;
|
|
15
|
+
|
|
16
|
+
export function NavbarMenuContent(props: NavigationMenuContentProps) {
|
|
17
|
+
return (
|
|
18
|
+
<NavigationMenuContent
|
|
19
|
+
{...props}
|
|
20
|
+
className={cn(
|
|
21
|
+
'grid grid-cols-1 gap-2 p-4 md:grid-cols-2 lg:grid-cols-3',
|
|
22
|
+
props.className,
|
|
23
|
+
)}
|
|
24
|
+
>
|
|
25
|
+
{props.children}
|
|
26
|
+
</NavigationMenuContent>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function NavbarMenuTrigger(props: NavigationMenuTriggerProps) {
|
|
31
|
+
return (
|
|
32
|
+
<NavigationMenuTrigger
|
|
33
|
+
{...props}
|
|
34
|
+
className={cn(navItemVariants(), 'rounded-md', props.className)}
|
|
35
|
+
>
|
|
36
|
+
{props.children}
|
|
37
|
+
</NavigationMenuTrigger>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function NavbarMenuLink(props: LinkProps) {
|
|
42
|
+
return (
|
|
43
|
+
<NavigationMenuLink asChild>
|
|
44
|
+
<Link
|
|
45
|
+
{...props}
|
|
46
|
+
className={cn(
|
|
47
|
+
'flex flex-col gap-2 rounded-lg border bg-fd-card p-3 transition-colors hover:bg-fd-accent/80 hover:text-fd-accent-foreground',
|
|
48
|
+
props.className,
|
|
49
|
+
)}
|
|
50
|
+
>
|
|
51
|
+
{props.children}
|
|
52
|
+
</Link>
|
|
53
|
+
</NavigationMenuLink>
|
|
54
|
+
);
|
|
55
|
+
}
|