blodemd 0.0.15 → 0.2.0
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/README.md +26 -1
- package/dist/cli.mjs +217 -217
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -36
- package/dev-server/app/[[...slug]]/page.tsx +0 -140
- package/dev-server/app/blodemd-dev/invalidate/route.ts +0 -12
- package/dev-server/app/blodemd-dev/static/[...path]/route.ts +0 -32
- package/dev-server/app/blodemd-dev/version/route.ts +0 -14
- package/dev-server/app/blodemd-internal/proxy/route.ts +0 -86
- package/dev-server/app/error.tsx +0 -24
- package/dev-server/app/favicon.ico +0 -0
- package/dev-server/app/globals.css +0 -4
- package/dev-server/app/layout.tsx +0 -38
- package/dev-server/app/not-found.tsx +0 -18
- package/dev-server/app/search/route.ts +0 -17
- package/dev-server/components/dev-reload-script.tsx +0 -86
- package/dev-server/components/providers.tsx +0 -15
- package/dev-server/lib/dev-state.ts +0 -8
- package/dev-server/lib/local-content-source.ts +0 -103
- package/dev-server/lib/local-runtime.tsx +0 -555
- package/dev-server/next-env.d.ts +0 -5
- package/dev-server/next.config.js +0 -54
- package/dev-server/package.json +0 -61
- package/dev-server/postcss.config.mjs +0 -7
- package/dev-server/public/glide-variable.woff2 +0 -0
- package/dev-server/tsconfig.json +0 -50
- package/docs/app/globals.css +0 -471
- package/docs/components/animate-ui/primitives/buttons/button.tsx +0 -14
- package/docs/components/api/api-playground.tsx +0 -467
- package/docs/components/api/api-reference.tsx +0 -157
- package/docs/components/content/collection-index.tsx +0 -114
- package/docs/components/docs/contextual-menu.tsx +0 -495
- package/docs/components/docs/copy-page-menu.tsx +0 -364
- package/docs/components/docs/doc-header.tsx +0 -223
- package/docs/components/docs/doc-shell.tsx +0 -355
- package/docs/components/docs/doc-sidebar.tsx +0 -256
- package/docs/components/docs/doc-toc.tsx +0 -46
- package/docs/components/docs/mobile-nav.tsx +0 -195
- package/docs/components/docs/sidebar-active-highlight.tsx +0 -34
- package/docs/components/docs/sidebar-scroll-area.tsx +0 -63
- package/docs/components/git/repo-picker.tsx +0 -529
- package/docs/components/icons/doc-icon.tsx +0 -96
- package/docs/components/mdx/accordion.tsx +0 -83
- package/docs/components/mdx/agent-instructions.tsx +0 -17
- package/docs/components/mdx/badge.tsx +0 -79
- package/docs/components/mdx/callout.tsx +0 -88
- package/docs/components/mdx/card.tsx +0 -110
- package/docs/components/mdx/code-block.tsx +0 -80
- package/docs/components/mdx/code-group.tsx +0 -203
- package/docs/components/mdx/color.tsx +0 -87
- package/docs/components/mdx/columns.tsx +0 -25
- package/docs/components/mdx/expandable.tsx +0 -45
- package/docs/components/mdx/field-layout.tsx +0 -77
- package/docs/components/mdx/frame.tsx +0 -23
- package/docs/components/mdx/get-text-content.ts +0 -18
- package/docs/components/mdx/icon.tsx +0 -12
- package/docs/components/mdx/iframe.tsx +0 -62
- package/docs/components/mdx/index.tsx +0 -121
- package/docs/components/mdx/installer.tsx +0 -20
- package/docs/components/mdx/panel.tsx +0 -11
- package/docs/components/mdx/param-field.tsx +0 -56
- package/docs/components/mdx/preview.tsx +0 -36
- package/docs/components/mdx/prompt.tsx +0 -63
- package/docs/components/mdx/request-example.tsx +0 -27
- package/docs/components/mdx/response-field.tsx +0 -42
- package/docs/components/mdx/steps.tsx +0 -92
- package/docs/components/mdx/tabs.tsx +0 -193
- package/docs/components/mdx/tile.tsx +0 -43
- package/docs/components/mdx/tooltip.tsx +0 -71
- package/docs/components/mdx/tree.tsx +0 -120
- package/docs/components/mdx/type-table.tsx +0 -71
- package/docs/components/mdx/update.tsx +0 -44
- package/docs/components/mdx/video.tsx +0 -45
- package/docs/components/mdx/view.tsx +0 -66
- package/docs/components/posthog-provider.tsx +0 -42
- package/docs/components/providers.tsx +0 -15
- package/docs/components/tenant-analytics.tsx +0 -49
- package/docs/components/third-parties.tsx +0 -32
- package/docs/components/ui/badge.tsx +0 -61
- package/docs/components/ui/breadcrumb.tsx +0 -112
- package/docs/components/ui/button-group.tsx +0 -83
- package/docs/components/ui/button.tsx +0 -65
- package/docs/components/ui/card.tsx +0 -92
- package/docs/components/ui/command.tsx +0 -167
- package/docs/components/ui/copy-button.tsx +0 -129
- package/docs/components/ui/dialog.tsx +0 -146
- package/docs/components/ui/field.tsx +0 -237
- package/docs/components/ui/input.tsx +0 -23
- package/docs/components/ui/kbd.tsx +0 -98
- package/docs/components/ui/label.tsx +0 -22
- package/docs/components/ui/morph-icon.tsx +0 -79
- package/docs/components/ui/popover.tsx +0 -267
- package/docs/components/ui/search-dialog.tsx +0 -431
- package/docs/components/ui/search.tsx +0 -101
- package/docs/components/ui/separator.tsx +0 -26
- package/docs/components/ui/sheet.tsx +0 -133
- package/docs/components/ui/sidebar.tsx +0 -758
- package/docs/components/ui/skeleton.tsx +0 -11
- package/docs/components/ui/switch.tsx +0 -32
- package/docs/components/ui/tabs.tsx +0 -138
- package/docs/components/ui/theme-toggle.tsx +0 -62
- package/docs/components/ui/tooltip.tsx +0 -53
- package/docs/components/web-mcp.tsx +0 -115
- package/docs/lib/agent-skills.ts +0 -48
- package/docs/lib/api-client.ts +0 -72
- package/docs/lib/config.ts +0 -6
- package/docs/lib/content-root.ts +0 -33
- package/docs/lib/content-source.ts +0 -70
- package/docs/lib/contextual-options.ts +0 -222
- package/docs/lib/dashboard-session.ts +0 -167
- package/docs/lib/db.ts +0 -13
- package/docs/lib/docs-collection.ts +0 -7
- package/docs/lib/docs-runtime.tsx +0 -745
- package/docs/lib/edge-config.ts +0 -95
- package/docs/lib/env.ts +0 -23
- package/docs/lib/etag.ts +0 -22
- package/docs/lib/github-install.ts +0 -33
- package/docs/lib/llms-full.ts +0 -82
- package/docs/lib/marketing-markdown.ts +0 -79
- package/docs/lib/marketing-site.ts +0 -31
- package/docs/lib/mdx.ts +0 -98
- package/docs/lib/navigation.ts +0 -288
- package/docs/lib/openapi-proxy.ts +0 -88
- package/docs/lib/openapi.ts +0 -158
- package/docs/lib/platform-config.ts +0 -6
- package/docs/lib/project-authz.ts +0 -46
- package/docs/lib/routes.ts +0 -103
- package/docs/lib/server-cache.ts +0 -83
- package/docs/lib/shiki.ts +0 -44
- package/docs/lib/supabase.ts +0 -37
- package/docs/lib/tenancy.ts +0 -364
- package/docs/lib/tenant-headers.ts +0 -43
- package/docs/lib/tenant-static.ts +0 -705
- package/docs/lib/tenant-utility-context.ts +0 -62
- package/docs/lib/tenants.ts +0 -72
- package/docs/lib/theme.ts +0 -29
- package/docs/lib/time-ago.ts +0 -24
- package/docs/lib/toc.ts +0 -2
- package/docs/lib/use-mobile.ts +0 -19
- package/docs/lib/use-tab-observer.ts +0 -71
- package/docs/lib/utils.ts +0 -5
- package/packages/@repo/common/dist/index.d.ts +0 -16
- package/packages/@repo/common/dist/index.d.ts.map +0 -1
- package/packages/@repo/common/dist/index.js +0 -84
- package/packages/@repo/common/package.json +0 -34
- package/packages/@repo/common/src/index.ts +0 -101
- package/packages/@repo/contracts/dist/analytics.d.ts +0 -21
- package/packages/@repo/contracts/dist/analytics.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/analytics.js +0 -18
- package/packages/@repo/contracts/dist/dates.d.ts +0 -4
- package/packages/@repo/contracts/dist/dates.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/dates.js +0 -2
- package/packages/@repo/contracts/dist/deployment.d.ts +0 -71
- package/packages/@repo/contracts/dist/deployment.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/deployment.js +0 -46
- package/packages/@repo/contracts/dist/domain.d.ts +0 -94
- package/packages/@repo/contracts/dist/domain.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/domain.js +0 -36
- package/packages/@repo/contracts/dist/git.d.ts +0 -28
- package/packages/@repo/contracts/dist/git.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/git.js +0 -24
- package/packages/@repo/contracts/dist/ids.d.ts +0 -14
- package/packages/@repo/contracts/dist/ids.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/ids.js +0 -11
- package/packages/@repo/contracts/dist/index.d.ts +0 -11
- package/packages/@repo/contracts/dist/index.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/index.js +0 -12
- package/packages/@repo/contracts/dist/pagination.d.ts +0 -23
- package/packages/@repo/contracts/dist/pagination.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/pagination.js +0 -15
- package/packages/@repo/contracts/dist/project.d.ts +0 -42
- package/packages/@repo/contracts/dist/project.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/project.js +0 -25
- package/packages/@repo/contracts/dist/tenant.d.ts +0 -147
- package/packages/@repo/contracts/dist/tenant.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/tenant.js +0 -58
- package/packages/@repo/contracts/dist/user.d.ts +0 -9
- package/packages/@repo/contracts/dist/user.d.ts.map +0 -1
- package/packages/@repo/contracts/dist/user.js +0 -9
- package/packages/@repo/contracts/package.json +0 -37
- package/packages/@repo/contracts/src/analytics.ts +0 -33
- package/packages/@repo/contracts/src/dates.ts +0 -4
- package/packages/@repo/contracts/src/deployment.ts +0 -73
- package/packages/@repo/contracts/src/domain.ts +0 -51
- package/packages/@repo/contracts/src/git.ts +0 -31
- package/packages/@repo/contracts/src/ids.ts +0 -23
- package/packages/@repo/contracts/src/index.ts +0 -12
- package/packages/@repo/contracts/src/pagination.ts +0 -21
- package/packages/@repo/contracts/src/project.ts +0 -32
- package/packages/@repo/contracts/src/tenant.ts +0 -94
- package/packages/@repo/contracts/src/user.ts +0 -12
- package/packages/@repo/models/dist/docs-config.d.ts +0 -961
- package/packages/@repo/models/dist/docs-config.d.ts.map +0 -1
- package/packages/@repo/models/dist/docs-config.js +0 -531
- package/packages/@repo/models/dist/index.d.ts +0 -3
- package/packages/@repo/models/dist/index.d.ts.map +0 -1
- package/packages/@repo/models/dist/index.js +0 -3
- package/packages/@repo/models/dist/tenant.d.ts +0 -37
- package/packages/@repo/models/dist/tenant.d.ts.map +0 -1
- package/packages/@repo/models/dist/tenant.js +0 -1
- package/packages/@repo/models/package.json +0 -37
- package/packages/@repo/models/src/docs-config.ts +0 -629
- package/packages/@repo/models/src/index.ts +0 -3
- package/packages/@repo/models/src/tenant.ts +0 -44
- package/packages/@repo/prebuild/dist/index.d.ts +0 -2
- package/packages/@repo/prebuild/dist/index.d.ts.map +0 -1
- package/packages/@repo/prebuild/dist/index.js +0 -2
- package/packages/@repo/prebuild/dist/openapi.d.ts +0 -43
- package/packages/@repo/prebuild/dist/openapi.d.ts.map +0 -1
- package/packages/@repo/prebuild/dist/openapi.js +0 -86
- package/packages/@repo/prebuild/package.json +0 -39
- package/packages/@repo/prebuild/src/index.ts +0 -2
- package/packages/@repo/prebuild/src/openapi.ts +0 -154
- package/packages/@repo/previewing/dist/blob-source.d.ts +0 -16
- package/packages/@repo/previewing/dist/blob-source.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/blob-source.js +0 -128
- package/packages/@repo/previewing/dist/config-loader.d.ts +0 -134
- package/packages/@repo/previewing/dist/config-loader.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/config-loader.js +0 -231
- package/packages/@repo/previewing/dist/constants.d.ts +0 -15
- package/packages/@repo/previewing/dist/constants.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/constants.js +0 -14
- package/packages/@repo/previewing/dist/content-index.d.ts +0 -7
- package/packages/@repo/previewing/dist/content-index.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/content-index.js +0 -291
- package/packages/@repo/previewing/dist/content-source.d.ts +0 -12
- package/packages/@repo/previewing/dist/content-source.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/content-source.js +0 -1
- package/packages/@repo/previewing/dist/fs-source.d.ts +0 -11
- package/packages/@repo/previewing/dist/fs-source.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/fs-source.js +0 -71
- package/packages/@repo/previewing/dist/index.d.ts +0 -16
- package/packages/@repo/previewing/dist/index.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/index.js +0 -13
- package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts +0 -3
- package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/markdown/agent-markdown.js +0 -176
- package/packages/@repo/previewing/dist/markdown/format.d.ts +0 -8
- package/packages/@repo/previewing/dist/markdown/format.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/markdown/format.js +0 -43
- package/packages/@repo/previewing/dist/markdown/links.d.ts +0 -3
- package/packages/@repo/previewing/dist/markdown/links.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/markdown/links.js +0 -31
- package/packages/@repo/previewing/dist/openapi-pages.d.ts +0 -7
- package/packages/@repo/previewing/dist/openapi-pages.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/openapi-pages.js +0 -200
- package/packages/@repo/previewing/dist/search-index.d.ts +0 -4
- package/packages/@repo/previewing/dist/search-index.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/search-index.js +0 -23
- package/packages/@repo/previewing/dist/serialization.d.ts +0 -13
- package/packages/@repo/previewing/dist/serialization.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/serialization.js +0 -108
- package/packages/@repo/previewing/dist/toc-index.d.ts +0 -5
- package/packages/@repo/previewing/dist/toc-index.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/toc-index.js +0 -53
- package/packages/@repo/previewing/dist/types.d.ts +0 -92
- package/packages/@repo/previewing/dist/types.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/types.js +0 -1
- package/packages/@repo/previewing/dist/utility-index.d.ts +0 -7
- package/packages/@repo/previewing/dist/utility-index.d.ts.map +0 -1
- package/packages/@repo/previewing/dist/utility-index.js +0 -201
- package/packages/@repo/previewing/package.json +0 -41
- package/packages/@repo/previewing/src/blob-source.ts +0 -185
- package/packages/@repo/previewing/src/config-loader.ts +0 -316
- package/packages/@repo/previewing/src/constants.ts +0 -16
- package/packages/@repo/previewing/src/content-index.ts +0 -384
- package/packages/@repo/previewing/src/content-source.ts +0 -12
- package/packages/@repo/previewing/src/fs-source.ts +0 -103
- package/packages/@repo/previewing/src/index.ts +0 -71
- package/packages/@repo/previewing/src/markdown/agent-markdown.ts +0 -254
- package/packages/@repo/previewing/src/markdown/format.ts +0 -63
- package/packages/@repo/previewing/src/markdown/links.ts +0 -46
- package/packages/@repo/previewing/src/openapi-pages.ts +0 -319
- package/packages/@repo/previewing/src/search-index.ts +0 -38
- package/packages/@repo/previewing/src/serialization.ts +0 -191
- package/packages/@repo/previewing/src/toc-index.ts +0 -72
- package/packages/@repo/previewing/src/types.ts +0 -105
- package/packages/@repo/previewing/src/utility-index.ts +0 -304
- package/packages/@repo/validation/dist/index.d.ts +0 -12
- package/packages/@repo/validation/dist/index.d.ts.map +0 -1
- package/packages/@repo/validation/dist/index.js +0 -30
- package/packages/@repo/validation/package.json +0 -38
- package/packages/@repo/validation/src/blodemd-docs-schema.json +0 -3575
- package/packages/@repo/validation/src/index.ts +0 -59
- package/scripts/prepare-package.mjs +0 -53
- package/scripts/repo-packages.mjs +0 -8
|
@@ -1,431 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { SearchIcon } from "blode-icons-react";
|
|
4
|
-
import { useRouter } from "next/navigation";
|
|
5
|
-
import {
|
|
6
|
-
startTransition,
|
|
7
|
-
useCallback,
|
|
8
|
-
useDeferredValue,
|
|
9
|
-
useEffect,
|
|
10
|
-
useMemo,
|
|
11
|
-
useReducer,
|
|
12
|
-
useRef,
|
|
13
|
-
} from "react";
|
|
14
|
-
import type {
|
|
15
|
-
ChangeEvent,
|
|
16
|
-
KeyboardEvent as ReactKeyboardEvent,
|
|
17
|
-
MouseEvent as ReactMouseEvent,
|
|
18
|
-
} from "react";
|
|
19
|
-
|
|
20
|
-
import {
|
|
21
|
-
Dialog,
|
|
22
|
-
DialogContent,
|
|
23
|
-
DialogDescription,
|
|
24
|
-
DialogTitle,
|
|
25
|
-
} from "@/components/ui/dialog";
|
|
26
|
-
import { isExternalHref, resolveHref, toDocHref } from "@/lib/routes";
|
|
27
|
-
|
|
28
|
-
export interface SearchItem {
|
|
29
|
-
href?: string;
|
|
30
|
-
title: string;
|
|
31
|
-
path: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface SearchResponse {
|
|
35
|
-
items: SearchItem[];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
type SearchStatus = "idle" | "loading" | "ready" | "error";
|
|
39
|
-
|
|
40
|
-
interface SearchState {
|
|
41
|
-
activeIndex: number;
|
|
42
|
-
items: SearchItem[];
|
|
43
|
-
query: string;
|
|
44
|
-
status: SearchStatus;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
type SearchAction =
|
|
48
|
-
| { type: "load-error" }
|
|
49
|
-
| { type: "load-start" }
|
|
50
|
-
| { items: SearchItem[]; type: "load-success" }
|
|
51
|
-
| { type: "reset-query" }
|
|
52
|
-
| { index: number; type: "set-active-index" }
|
|
53
|
-
| { query: string; type: "set-query" };
|
|
54
|
-
|
|
55
|
-
const MAX_RESULTS = 12;
|
|
56
|
-
const INITIAL_SEARCH_STATE: SearchState = {
|
|
57
|
-
activeIndex: 0,
|
|
58
|
-
items: [],
|
|
59
|
-
query: "",
|
|
60
|
-
status: "idle",
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const searchMatches = (item: SearchItem, query: string) => {
|
|
64
|
-
if (!query) {
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const haystack =
|
|
69
|
-
`${item.title} ${item.path} ${item.href ?? ""}`.toLowerCase();
|
|
70
|
-
return haystack.includes(query);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const getWrappedNextIndex = (current: number, length: number) => {
|
|
74
|
-
if (length === 0 || current >= length - 1) {
|
|
75
|
-
return 0;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return current + 1;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const getWrappedPrevIndex = (current: number, length: number) => {
|
|
82
|
-
if (length === 0 || current <= 0) {
|
|
83
|
-
return length - 1;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return current - 1;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const searchReducer = (
|
|
90
|
-
state: SearchState,
|
|
91
|
-
action: SearchAction
|
|
92
|
-
): SearchState => {
|
|
93
|
-
switch (action.type) {
|
|
94
|
-
case "load-error": {
|
|
95
|
-
return {
|
|
96
|
-
...state,
|
|
97
|
-
status: "error",
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
case "load-start": {
|
|
101
|
-
return {
|
|
102
|
-
...state,
|
|
103
|
-
status: "loading",
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
case "load-success": {
|
|
107
|
-
return {
|
|
108
|
-
...state,
|
|
109
|
-
items: action.items,
|
|
110
|
-
status: "ready",
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
case "reset-query": {
|
|
114
|
-
return {
|
|
115
|
-
...state,
|
|
116
|
-
activeIndex: 0,
|
|
117
|
-
query: "",
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
case "set-active-index": {
|
|
121
|
-
return {
|
|
122
|
-
...state,
|
|
123
|
-
activeIndex: action.index,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
case "set-query": {
|
|
127
|
-
return {
|
|
128
|
-
...state,
|
|
129
|
-
activeIndex: 0,
|
|
130
|
-
query: action.query,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
default: {
|
|
134
|
-
return state;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const SearchResults = ({
|
|
140
|
-
activeIndex,
|
|
141
|
-
basePath,
|
|
142
|
-
filteredItems,
|
|
143
|
-
onResultClick,
|
|
144
|
-
onResultMouseEnter,
|
|
145
|
-
status,
|
|
146
|
-
}: {
|
|
147
|
-
activeIndex: number;
|
|
148
|
-
basePath: string;
|
|
149
|
-
filteredItems: SearchItem[];
|
|
150
|
-
onResultClick: (event: ReactMouseEvent<HTMLButtonElement>) => void;
|
|
151
|
-
onResultMouseEnter: (event: ReactMouseEvent<HTMLButtonElement>) => void;
|
|
152
|
-
status: SearchStatus;
|
|
153
|
-
}) => {
|
|
154
|
-
if (status === "loading") {
|
|
155
|
-
return (
|
|
156
|
-
<div className="px-3 py-10 text-center text-sm text-muted-foreground">
|
|
157
|
-
Loading search index...
|
|
158
|
-
</div>
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (status === "error") {
|
|
163
|
-
return (
|
|
164
|
-
<div className="px-3 py-10 text-center text-sm text-muted-foreground">
|
|
165
|
-
Search is temporarily unavailable.
|
|
166
|
-
</div>
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (status === "ready" && filteredItems.length === 0) {
|
|
171
|
-
return (
|
|
172
|
-
<div className="px-3 py-10 text-center text-sm text-muted-foreground">
|
|
173
|
-
No results found.
|
|
174
|
-
</div>
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (status !== "ready") {
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return (
|
|
183
|
-
<div className="grid gap-1">
|
|
184
|
-
{filteredItems.map((item, index) => {
|
|
185
|
-
const href = item.href
|
|
186
|
-
? resolveHref(item.href, basePath)
|
|
187
|
-
: toDocHref(item.path, basePath);
|
|
188
|
-
const isActive = index === activeIndex;
|
|
189
|
-
|
|
190
|
-
return (
|
|
191
|
-
<button
|
|
192
|
-
className={
|
|
193
|
-
isActive
|
|
194
|
-
? "grid gap-1 rounded-xl bg-accent px-3 py-2 text-left text-foreground transition-colors"
|
|
195
|
-
: "grid gap-1 rounded-xl px-3 py-2 text-left text-muted-foreground transition-colors hover:bg-accent/70 hover:text-foreground"
|
|
196
|
-
}
|
|
197
|
-
data-index={index}
|
|
198
|
-
key={`${item.path}-${item.href ?? "internal"}`}
|
|
199
|
-
onClick={onResultClick}
|
|
200
|
-
onMouseEnter={onResultMouseEnter}
|
|
201
|
-
type="button"
|
|
202
|
-
>
|
|
203
|
-
<span className="text-sm font-medium text-foreground">
|
|
204
|
-
{item.title}
|
|
205
|
-
</span>
|
|
206
|
-
<span className="text-xs">{href}</span>
|
|
207
|
-
</button>
|
|
208
|
-
);
|
|
209
|
-
})}
|
|
210
|
-
</div>
|
|
211
|
-
);
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
export const SearchDialog = ({
|
|
215
|
-
basePath,
|
|
216
|
-
open,
|
|
217
|
-
onOpenChange,
|
|
218
|
-
}: {
|
|
219
|
-
basePath: string;
|
|
220
|
-
open: boolean;
|
|
221
|
-
onOpenChange: (open: boolean) => void;
|
|
222
|
-
}) => {
|
|
223
|
-
const router = useRouter();
|
|
224
|
-
const inputRef = useRef<HTMLInputElement>(null);
|
|
225
|
-
const requestRef = useRef<Promise<void> | null>(null);
|
|
226
|
-
const loadedRef = useRef(false);
|
|
227
|
-
const [state, dispatch] = useReducer(searchReducer, INITIAL_SEARCH_STATE);
|
|
228
|
-
const { activeIndex, items, query, status } = state;
|
|
229
|
-
|
|
230
|
-
const deferredQuery = useDeferredValue(query.trim().toLowerCase());
|
|
231
|
-
|
|
232
|
-
const loadSearchItems = useCallback(() => {
|
|
233
|
-
if (loadedRef.current) {
|
|
234
|
-
return Promise.resolve();
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (requestRef.current) {
|
|
238
|
-
return requestRef.current;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
dispatch({ type: "load-start" });
|
|
242
|
-
const request = (async () => {
|
|
243
|
-
try {
|
|
244
|
-
const response = await fetch(toDocHref("search", basePath), {
|
|
245
|
-
headers: {
|
|
246
|
-
accept: "application/json",
|
|
247
|
-
},
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
if (!response.ok) {
|
|
251
|
-
throw new Error(`Failed to load search index: ${response.status}`);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const payload = (await response.json()) as SearchResponse;
|
|
255
|
-
const nextItems = Array.isArray(payload.items) ? payload.items : [];
|
|
256
|
-
loadedRef.current = true;
|
|
257
|
-
startTransition(() => {
|
|
258
|
-
dispatch({ items: nextItems, type: "load-success" });
|
|
259
|
-
});
|
|
260
|
-
} catch {
|
|
261
|
-
dispatch({ type: "load-error" });
|
|
262
|
-
} finally {
|
|
263
|
-
requestRef.current = null;
|
|
264
|
-
}
|
|
265
|
-
})();
|
|
266
|
-
|
|
267
|
-
requestRef.current = request;
|
|
268
|
-
return request;
|
|
269
|
-
}, [basePath]);
|
|
270
|
-
|
|
271
|
-
// Load the search index as soon as the dialog mounts.
|
|
272
|
-
useEffect(() => {
|
|
273
|
-
const run = async () => {
|
|
274
|
-
try {
|
|
275
|
-
await loadSearchItems();
|
|
276
|
-
} catch {
|
|
277
|
-
// Errors are surfaced via the reducer's "load-error" action.
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
run();
|
|
282
|
-
}, [loadSearchItems]);
|
|
283
|
-
|
|
284
|
-
const filteredItems = useMemo(
|
|
285
|
-
() =>
|
|
286
|
-
items
|
|
287
|
-
.filter((item) => searchMatches(item, deferredQuery))
|
|
288
|
-
.slice(0, MAX_RESULTS),
|
|
289
|
-
[deferredQuery, items]
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
const closeSearch = useCallback(() => {
|
|
293
|
-
dispatch({ type: "reset-query" });
|
|
294
|
-
onOpenChange(false);
|
|
295
|
-
}, [onOpenChange]);
|
|
296
|
-
|
|
297
|
-
const runSelection = useCallback(
|
|
298
|
-
(item: SearchItem) => {
|
|
299
|
-
closeSearch();
|
|
300
|
-
const href = item.href
|
|
301
|
-
? resolveHref(item.href, basePath)
|
|
302
|
-
: toDocHref(item.path, basePath);
|
|
303
|
-
|
|
304
|
-
if (item.href && isExternalHref(item.href)) {
|
|
305
|
-
window.open(href, "_blank", "noopener,noreferrer");
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
router.push(href);
|
|
310
|
-
},
|
|
311
|
-
[basePath, closeSearch, router]
|
|
312
|
-
);
|
|
313
|
-
|
|
314
|
-
const handleOpenChange = useCallback(
|
|
315
|
-
(nextOpen: boolean) => {
|
|
316
|
-
if (!nextOpen) {
|
|
317
|
-
closeSearch();
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
|
-
[closeSearch]
|
|
321
|
-
);
|
|
322
|
-
|
|
323
|
-
const handleQueryChange = useCallback(
|
|
324
|
-
(event: ChangeEvent<HTMLInputElement>) => {
|
|
325
|
-
dispatch({ query: event.target.value, type: "set-query" });
|
|
326
|
-
},
|
|
327
|
-
[]
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
const handleResultClick = useCallback(
|
|
331
|
-
(event: ReactMouseEvent<HTMLButtonElement>) => {
|
|
332
|
-
const index = Number(event.currentTarget.dataset.index);
|
|
333
|
-
const item = filteredItems[index];
|
|
334
|
-
if (!item) {
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
runSelection(item);
|
|
339
|
-
},
|
|
340
|
-
[filteredItems, runSelection]
|
|
341
|
-
);
|
|
342
|
-
|
|
343
|
-
const handleResultMouseEnter = useCallback(
|
|
344
|
-
(event: ReactMouseEvent<HTMLButtonElement>) => {
|
|
345
|
-
const index = Number(event.currentTarget.dataset.index);
|
|
346
|
-
if (Number.isNaN(index)) {
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
dispatch({ index, type: "set-active-index" });
|
|
351
|
-
},
|
|
352
|
-
[]
|
|
353
|
-
);
|
|
354
|
-
|
|
355
|
-
const handleDialogKeyDown = useCallback(
|
|
356
|
-
(event: ReactKeyboardEvent<HTMLDivElement>) => {
|
|
357
|
-
if (event.key === "ArrowDown") {
|
|
358
|
-
event.preventDefault();
|
|
359
|
-
dispatch({
|
|
360
|
-
index: getWrappedNextIndex(activeIndex, filteredItems.length),
|
|
361
|
-
type: "set-active-index",
|
|
362
|
-
});
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (event.key === "ArrowUp") {
|
|
367
|
-
event.preventDefault();
|
|
368
|
-
dispatch({
|
|
369
|
-
index: getWrappedPrevIndex(activeIndex, filteredItems.length),
|
|
370
|
-
type: "set-active-index",
|
|
371
|
-
});
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (event.key === "Enter") {
|
|
376
|
-
const activeItem = filteredItems[activeIndex];
|
|
377
|
-
if (!activeItem) {
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
event.preventDefault();
|
|
382
|
-
runSelection(activeItem);
|
|
383
|
-
}
|
|
384
|
-
},
|
|
385
|
-
[activeIndex, filteredItems, runSelection]
|
|
386
|
-
);
|
|
387
|
-
|
|
388
|
-
return (
|
|
389
|
-
<Dialog onOpenChange={handleOpenChange} open={open}>
|
|
390
|
-
<DialogContent
|
|
391
|
-
className="max-w-2xl gap-0 overflow-hidden p-0"
|
|
392
|
-
onKeyDown={handleDialogKeyDown}
|
|
393
|
-
showCloseButton={false}
|
|
394
|
-
>
|
|
395
|
-
<DialogTitle className="sr-only">Search documentation</DialogTitle>
|
|
396
|
-
<DialogDescription className="sr-only">
|
|
397
|
-
Search documentation pages and jump directly to a result.
|
|
398
|
-
</DialogDescription>
|
|
399
|
-
<div className="flex items-center gap-3 border-b border-border px-4 py-3">
|
|
400
|
-
<SearchIcon className="size-4 text-muted-foreground" />
|
|
401
|
-
<input
|
|
402
|
-
aria-label="Search documentation"
|
|
403
|
-
className="w-full bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground"
|
|
404
|
-
onChange={handleQueryChange}
|
|
405
|
-
placeholder="Search docs..."
|
|
406
|
-
ref={inputRef}
|
|
407
|
-
type="text"
|
|
408
|
-
value={query}
|
|
409
|
-
/>
|
|
410
|
-
<button
|
|
411
|
-
className="rounded-md border border-border px-2 py-1 text-[11px] text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
412
|
-
onClick={closeSearch}
|
|
413
|
-
type="button"
|
|
414
|
-
>
|
|
415
|
-
Esc
|
|
416
|
-
</button>
|
|
417
|
-
</div>
|
|
418
|
-
<div className="max-h-[min(70vh,32rem)] overflow-y-auto p-2">
|
|
419
|
-
<SearchResults
|
|
420
|
-
activeIndex={activeIndex}
|
|
421
|
-
basePath={basePath}
|
|
422
|
-
filteredItems={filteredItems}
|
|
423
|
-
onResultClick={handleResultClick}
|
|
424
|
-
onResultMouseEnter={handleResultMouseEnter}
|
|
425
|
-
status={status}
|
|
426
|
-
/>
|
|
427
|
-
</div>
|
|
428
|
-
</DialogContent>
|
|
429
|
-
</Dialog>
|
|
430
|
-
);
|
|
431
|
-
};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { SearchIcon } from "blode-icons-react";
|
|
4
|
-
import dynamic from "next/dynamic";
|
|
5
|
-
import { useCallback, useEffect, useState } from "react";
|
|
6
|
-
|
|
7
|
-
const SearchDialog = dynamic(
|
|
8
|
-
async () => {
|
|
9
|
-
const mod = await import("@/components/ui/search-dialog");
|
|
10
|
-
return mod.SearchDialog;
|
|
11
|
-
},
|
|
12
|
-
{ loading: () => null, ssr: false }
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
const preloadDialog = async () => {
|
|
16
|
-
// Eagerly fetch the dialog chunk so it's warm by the time the user opens it.
|
|
17
|
-
try {
|
|
18
|
-
await import("@/components/ui/search-dialog");
|
|
19
|
-
} catch {
|
|
20
|
-
// Ignore preload failures; the dialog will retry on open.
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const isEditableTarget = (target: EventTarget | null) =>
|
|
25
|
-
(target instanceof HTMLElement && target.isContentEditable) ||
|
|
26
|
-
target instanceof HTMLInputElement ||
|
|
27
|
-
target instanceof HTMLTextAreaElement ||
|
|
28
|
-
target instanceof HTMLSelectElement;
|
|
29
|
-
|
|
30
|
-
export const Search = ({ basePath }: { basePath: string }) => {
|
|
31
|
-
const [open, setOpen] = useState(false);
|
|
32
|
-
const [hasMounted, setHasMounted] = useState(false);
|
|
33
|
-
|
|
34
|
-
const openSearch = useCallback(() => {
|
|
35
|
-
preloadDialog();
|
|
36
|
-
setHasMounted(true);
|
|
37
|
-
setOpen(true);
|
|
38
|
-
}, []);
|
|
39
|
-
|
|
40
|
-
const handleOpenChange = useCallback((next: boolean) => {
|
|
41
|
-
setOpen(next);
|
|
42
|
-
}, []);
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
const handleKeydown = (event: KeyboardEvent) => {
|
|
46
|
-
if (
|
|
47
|
-
(event.key === "k" && (event.metaKey || event.ctrlKey)) ||
|
|
48
|
-
event.key === "/"
|
|
49
|
-
) {
|
|
50
|
-
if (isEditableTarget(event.target)) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
event.preventDefault();
|
|
55
|
-
if (open) {
|
|
56
|
-
setOpen(false);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
preloadDialog();
|
|
61
|
-
setHasMounted(true);
|
|
62
|
-
setOpen(true);
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
document.addEventListener("keydown", handleKeydown);
|
|
67
|
-
return () => document.removeEventListener("keydown", handleKeydown);
|
|
68
|
-
}, [open]);
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<>
|
|
72
|
-
<button
|
|
73
|
-
aria-label="Search documentation"
|
|
74
|
-
className="inline-flex size-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground md:hidden"
|
|
75
|
-
onClick={openSearch}
|
|
76
|
-
onFocus={preloadDialog}
|
|
77
|
-
onMouseEnter={preloadDialog}
|
|
78
|
-
type="button"
|
|
79
|
-
>
|
|
80
|
-
<SearchIcon className="size-4.5" />
|
|
81
|
-
</button>
|
|
82
|
-
<button
|
|
83
|
-
className="relative hidden h-8 w-full items-center justify-start rounded-lg border border-border bg-muted/50 pl-3 text-sm font-normal text-foreground shadow-none transition-colors hover:bg-muted/80 md:flex md:w-48 lg:w-56 xl:w-64 dark:bg-card"
|
|
84
|
-
onClick={openSearch}
|
|
85
|
-
onFocus={preloadDialog}
|
|
86
|
-
onMouseEnter={preloadDialog}
|
|
87
|
-
type="button"
|
|
88
|
-
>
|
|
89
|
-
<span className="hidden lg:inline-flex">Search documentation...</span>
|
|
90
|
-
<span className="inline-flex lg:hidden">Search...</span>
|
|
91
|
-
</button>
|
|
92
|
-
{hasMounted ? (
|
|
93
|
-
<SearchDialog
|
|
94
|
-
basePath={basePath}
|
|
95
|
-
onOpenChange={handleOpenChange}
|
|
96
|
-
open={open}
|
|
97
|
-
/>
|
|
98
|
-
) : null}
|
|
99
|
-
</>
|
|
100
|
-
);
|
|
101
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Separator as SeparatorPrimitive } from "radix-ui";
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
|
|
6
|
-
import { cn } from "@/lib/utils";
|
|
7
|
-
|
|
8
|
-
const Separator = ({
|
|
9
|
-
className,
|
|
10
|
-
orientation = "horizontal",
|
|
11
|
-
decorative = true,
|
|
12
|
-
...props
|
|
13
|
-
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) => (
|
|
14
|
-
<SeparatorPrimitive.Root
|
|
15
|
-
data-slot="separator"
|
|
16
|
-
decorative={decorative}
|
|
17
|
-
orientation={orientation}
|
|
18
|
-
className={cn(
|
|
19
|
-
"shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
|
20
|
-
className
|
|
21
|
-
)}
|
|
22
|
-
{...props}
|
|
23
|
-
/>
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
export { Separator };
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { XIcon } from "blode-icons-react";
|
|
4
|
-
import { Dialog as SheetPrimitive } from "radix-ui";
|
|
5
|
-
import * as React from "react";
|
|
6
|
-
|
|
7
|
-
import { cn } from "@/lib/utils";
|
|
8
|
-
|
|
9
|
-
const Sheet = ({
|
|
10
|
-
...props
|
|
11
|
-
}: React.ComponentProps<typeof SheetPrimitive.Root>) => (
|
|
12
|
-
<SheetPrimitive.Root data-slot="sheet" {...props} />
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
const SheetTrigger = ({
|
|
16
|
-
...props
|
|
17
|
-
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) => (
|
|
18
|
-
<SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
const SheetClose = ({
|
|
22
|
-
...props
|
|
23
|
-
}: React.ComponentProps<typeof SheetPrimitive.Close>) => (
|
|
24
|
-
<SheetPrimitive.Close data-slot="sheet-close" {...props} />
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const SheetPortal = ({
|
|
28
|
-
...props
|
|
29
|
-
}: React.ComponentProps<typeof SheetPrimitive.Portal>) => (
|
|
30
|
-
<SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
const SheetOverlay = ({
|
|
34
|
-
className,
|
|
35
|
-
...props
|
|
36
|
-
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) => (
|
|
37
|
-
<SheetPrimitive.Overlay
|
|
38
|
-
data-slot="sheet-overlay"
|
|
39
|
-
className={cn(
|
|
40
|
-
"fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
41
|
-
className
|
|
42
|
-
)}
|
|
43
|
-
{...props}
|
|
44
|
-
/>
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
const SheetContent = ({
|
|
48
|
-
className,
|
|
49
|
-
children,
|
|
50
|
-
side = "right",
|
|
51
|
-
showCloseButton = true,
|
|
52
|
-
...props
|
|
53
|
-
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
|
54
|
-
side?: "top" | "right" | "bottom" | "left";
|
|
55
|
-
showCloseButton?: boolean;
|
|
56
|
-
}) => (
|
|
57
|
-
<SheetPortal>
|
|
58
|
-
<SheetOverlay />
|
|
59
|
-
<SheetPrimitive.Content
|
|
60
|
-
data-slot="sheet-content"
|
|
61
|
-
className={cn(
|
|
62
|
-
"fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
|
|
63
|
-
side === "right" &&
|
|
64
|
-
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
|
|
65
|
-
side === "left" &&
|
|
66
|
-
"inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
|
67
|
-
side === "top" &&
|
|
68
|
-
"inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
|
69
|
-
side === "bottom" &&
|
|
70
|
-
"inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
|
71
|
-
className
|
|
72
|
-
)}
|
|
73
|
-
{...props}
|
|
74
|
-
>
|
|
75
|
-
{children}
|
|
76
|
-
{showCloseButton && (
|
|
77
|
-
<SheetPrimitive.Close className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-secondary">
|
|
78
|
-
<XIcon className="size-4" />
|
|
79
|
-
<span className="sr-only">Close</span>
|
|
80
|
-
</SheetPrimitive.Close>
|
|
81
|
-
)}
|
|
82
|
-
</SheetPrimitive.Content>
|
|
83
|
-
</SheetPortal>
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
const SheetHeader = ({ className, ...props }: React.ComponentProps<"div">) => (
|
|
87
|
-
<div
|
|
88
|
-
data-slot="sheet-header"
|
|
89
|
-
className={cn("flex flex-col gap-1.5 p-4", className)}
|
|
90
|
-
{...props}
|
|
91
|
-
/>
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
const SheetFooter = ({ className, ...props }: React.ComponentProps<"div">) => (
|
|
95
|
-
<div
|
|
96
|
-
data-slot="sheet-footer"
|
|
97
|
-
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
|
98
|
-
{...props}
|
|
99
|
-
/>
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
const SheetTitle = ({
|
|
103
|
-
className,
|
|
104
|
-
...props
|
|
105
|
-
}: React.ComponentProps<typeof SheetPrimitive.Title>) => (
|
|
106
|
-
<SheetPrimitive.Title
|
|
107
|
-
data-slot="sheet-title"
|
|
108
|
-
className={cn("font-semibold text-foreground", className)}
|
|
109
|
-
{...props}
|
|
110
|
-
/>
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
const SheetDescription = ({
|
|
114
|
-
className,
|
|
115
|
-
...props
|
|
116
|
-
}: React.ComponentProps<typeof SheetPrimitive.Description>) => (
|
|
117
|
-
<SheetPrimitive.Description
|
|
118
|
-
data-slot="sheet-description"
|
|
119
|
-
className={cn("text-sm text-muted-foreground", className)}
|
|
120
|
-
{...props}
|
|
121
|
-
/>
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
export {
|
|
125
|
-
Sheet,
|
|
126
|
-
SheetTrigger,
|
|
127
|
-
SheetClose,
|
|
128
|
-
SheetContent,
|
|
129
|
-
SheetHeader,
|
|
130
|
-
SheetFooter,
|
|
131
|
-
SheetTitle,
|
|
132
|
-
SheetDescription,
|
|
133
|
-
};
|