zudoku 0.0.0-e5b3c9b → 0.0.0-e614aaa
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/cli.js +3 -0
- package/dist/app/entry.client.d.ts +5 -0
- package/dist/app/entry.client.js +1 -0
- package/dist/app/entry.client.js.map +1 -1
- package/dist/app/main.js +1 -1
- package/dist/app/main.js.map +1 -1
- package/dist/cli/build/handler.d.ts +1 -3
- package/dist/cli/build/handler.js +7 -0
- package/dist/cli/build/handler.js.map +1 -1
- package/dist/cli/cli.js +5 -0
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/cmds/build.d.ts +11 -3
- package/dist/cli/cmds/build.js +20 -13
- package/dist/cli/cmds/build.js.map +1 -1
- package/dist/cli/cmds/preview.d.ts +16 -0
- package/dist/cli/cmds/preview.js +25 -0
- package/dist/cli/cmds/preview.js.map +1 -0
- package/dist/cli/preview/handler.d.ts +3 -0
- package/dist/cli/preview/handler.js +37 -0
- package/dist/cli/preview/handler.js.map +1 -0
- package/dist/config/common.d.ts +5 -2
- package/dist/config/config.d.ts +2 -7
- package/dist/config/loader.d.ts +4 -4
- package/dist/config/loader.js +7 -4
- package/dist/config/loader.js.map +1 -1
- package/dist/config/validators/common.d.ts +226 -8
- package/dist/config/validators/common.js +26 -8
- package/dist/config/validators/common.js.map +1 -1
- package/dist/config/validators/validate.d.ts +90 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/authentication/providers/auth0.d.ts +2 -2
- package/dist/lib/authentication/providers/auth0.js +1 -0
- package/dist/lib/authentication/providers/auth0.js.map +1 -1
- package/dist/lib/authentication/providers/clerk.js +6 -6
- package/dist/lib/authentication/providers/clerk.js.map +1 -1
- package/dist/lib/authentication/providers/openid.d.ts +4 -3
- package/dist/lib/authentication/providers/openid.js +4 -2
- package/dist/lib/authentication/providers/openid.js.map +1 -1
- package/dist/lib/authentication/state.js +8 -2
- package/dist/lib/authentication/state.js.map +1 -1
- package/dist/lib/components/Banner.js +1 -1
- package/dist/lib/components/Banner.js.map +1 -1
- package/dist/lib/components/Heading.d.ts +1 -1
- package/dist/lib/components/Layout.js +1 -1
- package/dist/lib/components/Layout.js.map +1 -1
- package/dist/lib/components/ThemeSwitch.js +1 -1
- package/dist/lib/components/ThemeSwitch.js.map +1 -1
- package/dist/lib/components/Zudoku.d.ts +1 -1
- package/dist/lib/components/Zudoku.js +7 -6
- package/dist/lib/components/Zudoku.js.map +1 -1
- package/dist/lib/components/context/RouterEventsEmitter.d.ts +1 -0
- package/dist/lib/components/context/RouterEventsEmitter.js +17 -0
- package/dist/lib/components/context/RouterEventsEmitter.js.map +1 -0
- package/dist/lib/components/index.d.ts +1 -1
- package/dist/lib/core/RouteGuard.d.ts +1 -1
- package/dist/lib/core/RouteGuard.js +22 -9
- package/dist/lib/core/RouteGuard.js.map +1 -1
- package/dist/lib/core/ZudokuContext.d.ts +10 -0
- package/dist/lib/core/ZudokuContext.js +17 -1
- package/dist/lib/core/ZudokuContext.js.map +1 -1
- package/dist/lib/core/plugins.d.ts +8 -2
- package/dist/lib/core/plugins.js +1 -0
- package/dist/lib/core/plugins.js.map +1 -1
- package/dist/lib/hooks/index.d.ts +3 -0
- package/dist/lib/hooks/index.js +5 -0
- package/dist/lib/hooks/index.js.map +1 -0
- package/dist/lib/hooks/useEvent.d.ts +11 -0
- package/dist/lib/hooks/useEvent.js +19 -0
- package/dist/lib/hooks/useEvent.js.map +1 -0
- package/dist/lib/hooks/useEvent.test.d.ts +1 -0
- package/dist/lib/hooks/useEvent.test.js +100 -0
- package/dist/lib/hooks/useEvent.test.js.map +1 -0
- package/dist/lib/plugins/api-catalog/Catalog.d.ts +3 -1
- package/dist/lib/plugins/api-catalog/Catalog.js +7 -4
- package/dist/lib/plugins/api-catalog/Catalog.js.map +1 -1
- package/dist/lib/plugins/api-catalog/index.js +1 -1
- package/dist/lib/plugins/api-catalog/index.js.map +1 -1
- package/dist/lib/plugins/markdown/MdxPage.js +1 -1
- package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.d.ts +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +2 -1
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +2 -1
- package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/ParameterList.d.ts +2 -1
- package/dist/lib/plugins/openapi/ParameterList.js +3 -2
- package/dist/lib/plugins/openapi/ParameterList.js.map +1 -1
- package/dist/lib/plugins/openapi/Sidecar.js +1 -1
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PathParams.d.ts +3 -2
- package/dist/lib/plugins/openapi/playground/PathParams.js +3 -2
- package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.js +3 -3
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/search-pagefind/PagefindSearch.d.ts +6 -0
- package/dist/lib/plugins/search-pagefind/PagefindSearch.js +67 -0
- package/dist/lib/plugins/search-pagefind/PagefindSearch.js.map +1 -0
- package/dist/lib/plugins/search-pagefind/ResultList.d.ts +7 -0
- package/dist/lib/plugins/search-pagefind/ResultList.js +30 -0
- package/dist/lib/plugins/search-pagefind/ResultList.js.map +1 -0
- package/dist/lib/plugins/search-pagefind/get-results.d.ts +3 -0
- package/dist/lib/plugins/search-pagefind/get-results.js +37 -0
- package/dist/lib/plugins/search-pagefind/get-results.js.map +1 -0
- package/dist/lib/plugins/search-pagefind/index.d.ts +6 -0
- package/dist/lib/plugins/search-pagefind/index.js +9 -0
- package/dist/lib/plugins/search-pagefind/index.js.map +1 -0
- package/dist/lib/plugins/search-pagefind/types.d.ts +85 -0
- package/dist/lib/plugins/search-pagefind/types.js +2 -0
- package/dist/lib/plugins/search-pagefind/types.js.map +1 -0
- package/dist/lib/ui/Command.d.ts +7 -1
- package/dist/lib/ui/Command.js +2 -2
- package/dist/lib/ui/Command.js.map +1 -1
- package/dist/lib/ui/Stepper.d.ts +4 -0
- package/dist/lib/ui/Stepper.js +7 -0
- package/dist/lib/ui/Stepper.js.map +1 -0
- package/dist/lib/util/MdxComponents.d.ts +3 -1
- package/dist/lib/util/MdxComponents.js +3 -0
- package/dist/lib/util/MdxComponents.js.map +1 -1
- package/dist/lib/util/useScrollToAnchor.js +6 -8
- package/dist/lib/util/useScrollToAnchor.js.map +1 -1
- package/dist/vite/build.js +5 -0
- package/dist/vite/build.js.map +1 -1
- package/dist/vite/config.d.ts +2 -5
- package/dist/vite/config.js +30 -35
- package/dist/vite/config.js.map +1 -1
- package/dist/vite/config.test.js +1 -1
- package/dist/vite/config.test.js.map +1 -1
- package/dist/vite/css/plugin.d.ts +2 -2
- package/dist/vite/css/plugin.js.map +1 -1
- package/dist/vite/dev-server.js +8 -0
- package/dist/vite/dev-server.js.map +1 -1
- package/dist/vite/pagefind.d.ts +4 -0
- package/dist/vite/pagefind.js +15 -0
- package/dist/vite/pagefind.js.map +1 -0
- package/dist/vite/plugin-api-keys.d.ts +2 -2
- package/dist/vite/plugin-api-keys.js +3 -3
- package/dist/vite/plugin-api-keys.js.map +1 -1
- package/dist/vite/plugin-api.d.ts +2 -2
- package/dist/vite/plugin-api.js +5 -5
- package/dist/vite/plugin-api.js.map +1 -1
- package/dist/vite/plugin-auth.d.ts +2 -2
- package/dist/vite/plugin-auth.js +3 -3
- package/dist/vite/plugin-auth.js.map +1 -1
- package/dist/vite/plugin-component.d.ts +2 -2
- package/dist/vite/plugin-component.js +7 -2
- package/dist/vite/plugin-component.js.map +1 -1
- package/dist/vite/plugin-config-reload.d.ts +4 -3
- package/dist/vite/plugin-config-reload.js +11 -6
- package/dist/vite/plugin-config-reload.js.map +1 -1
- package/dist/vite/plugin-config.d.ts +2 -2
- package/dist/vite/plugin-config.js +2 -2
- package/dist/vite/plugin-config.js.map +1 -1
- package/dist/vite/plugin-custom-pages.d.ts +2 -2
- package/dist/vite/plugin-custom-pages.js +3 -3
- package/dist/vite/plugin-custom-pages.js.map +1 -1
- package/dist/vite/plugin-docs.d.ts +2 -2
- package/dist/vite/plugin-docs.js +5 -5
- package/dist/vite/plugin-docs.js.map +1 -1
- package/dist/vite/plugin-frontmatter.d.ts +2 -2
- package/dist/vite/plugin-frontmatter.js +5 -4
- package/dist/vite/plugin-frontmatter.js.map +1 -1
- package/dist/vite/plugin-mdx.d.ts +2 -2
- package/dist/vite/plugin-mdx.js +1 -1
- package/dist/vite/plugin-mdx.js.map +1 -1
- package/dist/vite/plugin-redirect.d.ts +2 -2
- package/dist/vite/plugin-redirect.js +3 -3
- package/dist/vite/plugin-redirect.js.map +1 -1
- package/dist/vite/plugin-search.d.ts +2 -2
- package/dist/vite/plugin-search.js +5 -1
- package/dist/vite/plugin-search.js.map +1 -1
- package/dist/vite/plugin-sidebar.d.ts +2 -2
- package/dist/vite/plugin-sidebar.js +2 -2
- package/dist/vite/plugin-sidebar.js.map +1 -1
- package/dist/vite/plugin-theme-css.d.ts +2 -2
- package/dist/vite/plugin-theme-css.js.map +1 -1
- package/dist/vite/plugin.d.ts +2 -2
- package/dist/vite/plugin.js.map +1 -1
- package/dist/vite/prerender/FileWritingResponse.d.ts +2 -1
- package/dist/vite/prerender/FileWritingResponse.js +4 -1
- package/dist/vite/prerender/FileWritingResponse.js.map +1 -1
- package/dist/vite/prerender/prerender.js +3 -21
- package/dist/vite/prerender/prerender.js.map +1 -1
- package/dist/vite/prerender/worker.d.ts +1 -1
- package/dist/vite/prerender/worker.js +3 -0
- package/dist/vite/prerender/worker.js.map +1 -1
- package/dist/vite/sitemap.js +2 -1
- package/dist/vite/sitemap.js.map +1 -1
- package/lib/{AuthenticationPlugin-BlxA4Mbn.js → AuthenticationPlugin-CiO1FM6Q.js} +2 -2
- package/lib/{AuthenticationPlugin-BlxA4Mbn.js.map → AuthenticationPlugin-CiO1FM6Q.js.map} +1 -1
- package/lib/Dialog-DIKGQxQc.js +83 -0
- package/lib/Dialog-DIKGQxQc.js.map +1 -0
- package/lib/{Markdown-Cr9sYpR_.js → Markdown-DePfm7oQ.js} +1384 -1381
- package/lib/{Markdown-Cr9sYpR_.js.map → Markdown-DePfm7oQ.js.map} +1 -1
- package/lib/MdxPage-BN6l6zXL.js +201 -0
- package/lib/MdxPage-BN6l6zXL.js.map +1 -0
- package/lib/{OasProvider-WVtvHP5H.js → OasProvider-BSuptFK-.js} +3 -3
- package/lib/{OasProvider-WVtvHP5H.js.map → OasProvider-BSuptFK-.js.map} +1 -1
- package/lib/{OperationList-DhOwupvv.js → OperationList-DOcfDmJP.js} +1569 -1530
- package/lib/OperationList-DOcfDmJP.js.map +1 -0
- package/lib/{Select-D9hI1G-y.js → Select-Dqtcn53H.js} +36 -36
- package/lib/{Select-D9hI1G-y.js.map → Select-Dqtcn53H.js.map} +1 -1
- package/lib/{SlotletProvider-CEfNOA8i.js → SlotletProvider-DdtIOUi6.js} +2 -2
- package/lib/{SlotletProvider-CEfNOA8i.js.map → SlotletProvider-DdtIOUi6.js.map} +1 -1
- package/lib/{createServer-DMf6O2Rz.js → createServer-DmusVVsi.js} +987 -967
- package/lib/createServer-DmusVVsi.js.map +1 -0
- package/lib/{hook-CWwSAAlH.js → hook-CN__aZIt.js} +67 -63
- package/lib/{hook-CWwSAAlH.js.map → hook-CN__aZIt.js.map} +1 -1
- package/lib/{index-Do_30Hpk.js → index-BTbP6Lgf.js} +194 -189
- package/lib/index-BTbP6Lgf.js.map +1 -0
- package/lib/index-DwT-v3zK.js +86 -0
- package/lib/index-DwT-v3zK.js.map +1 -0
- package/lib/index-gQD2h1wX.js +447 -0
- package/lib/index-gQD2h1wX.js.map +1 -0
- package/lib/{mutation-B0wxqzSN.js → mutation-EclmI0is.js} +2 -2
- package/lib/{mutation-B0wxqzSN.js.map → mutation-EclmI0is.js.map} +1 -1
- package/lib/objectEntries-yMIkr2mI.js +5 -0
- package/lib/objectEntries-yMIkr2mI.js.map +1 -0
- package/lib/ui/Command.js +105 -78
- package/lib/ui/Command.js.map +1 -1
- package/lib/ui/Stepper.js +6 -0
- package/lib/ui/Stepper.js.map +1 -0
- package/lib/ui/SyntaxHighlight.js +2902 -7
- package/lib/ui/SyntaxHighlight.js.map +1 -1
- package/lib/{useScrollToAnchor-C-sRxs9o.js → useScrollToAnchor-RyqO3lj4.js} +20 -20
- package/lib/{useScrollToAnchor-C-sRxs9o.js.map → useScrollToAnchor-RyqO3lj4.js.map} +1 -1
- package/lib/zudoku.auth-auth0.js +15 -14
- package/lib/zudoku.auth-auth0.js.map +1 -1
- package/lib/zudoku.auth-clerk.js +29 -29
- package/lib/zudoku.auth-clerk.js.map +1 -1
- package/lib/zudoku.auth-openid.js +126 -124
- package/lib/zudoku.auth-openid.js.map +1 -1
- package/lib/zudoku.components.js +443 -389
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.css +1 -0
- package/lib/zudoku.hooks.js +19 -0
- package/lib/zudoku.hooks.js.map +1 -0
- package/lib/zudoku.plugin-api-catalog.js +86 -70
- package/lib/zudoku.plugin-api-catalog.js.map +1 -1
- package/lib/zudoku.plugin-api-keys.js +5 -5
- package/lib/zudoku.plugin-custom-pages.js +1 -1
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +2 -2
- package/lib/zudoku.plugins.js +9 -8
- package/lib/zudoku.plugins.js.map +1 -1
- package/package.json +17 -4
- package/src/app/entry.client.tsx +8 -0
- package/src/app/main.tsx +1 -1
- package/src/lib/authentication/providers/auth0.tsx +3 -2
- package/src/lib/authentication/providers/clerk.tsx +10 -6
- package/src/lib/authentication/providers/openid.tsx +8 -5
- package/src/lib/authentication/state.ts +8 -2
- package/src/lib/components/Banner.tsx +1 -0
- package/src/lib/components/Heading.tsx +1 -1
- package/src/lib/components/Layout.tsx +1 -0
- package/src/lib/components/ThemeSwitch.tsx +1 -1
- package/src/lib/components/Zudoku.tsx +9 -5
- package/src/lib/components/context/RouterEventsEmitter.tsx +19 -0
- package/src/lib/core/RouteGuard.tsx +42 -8
- package/src/lib/core/ZudokuContext.ts +31 -0
- package/src/lib/core/plugins.ts +16 -2
- package/src/lib/hooks/index.ts +5 -0
- package/src/lib/hooks/useEvent.test.tsx +149 -0
- package/src/lib/hooks/useEvent.ts +41 -0
- package/src/lib/plugins/api-catalog/Catalog.tsx +23 -7
- package/src/lib/plugins/api-catalog/index.tsx +1 -0
- package/src/lib/plugins/markdown/MdxPage.tsx +5 -1
- package/src/lib/plugins/openapi/OperationList.tsx +15 -3
- package/src/lib/plugins/openapi/OperationListItem.tsx +8 -0
- package/src/lib/plugins/openapi/ParameterList.tsx +4 -0
- package/src/lib/plugins/openapi/Sidecar.tsx +2 -1
- package/src/lib/plugins/openapi/playground/PathParams.tsx +8 -2
- package/src/lib/plugins/openapi/playground/Playground.tsx +3 -3
- package/src/lib/plugins/search-pagefind/PagefindSearch.tsx +139 -0
- package/src/lib/plugins/search-pagefind/ResultList.tsx +98 -0
- package/src/lib/plugins/search-pagefind/get-results.tsx +54 -0
- package/src/lib/plugins/search-pagefind/index.tsx +21 -0
- package/src/lib/plugins/search-pagefind/types.ts +118 -0
- package/src/lib/ui/Command.tsx +25 -3
- package/src/lib/ui/Stepper.css +43 -0
- package/src/lib/ui/Stepper.tsx +8 -0
- package/src/lib/util/MdxComponents.tsx +4 -1
- package/src/lib/util/useScrollToAnchor.ts +8 -8
- package/lib/MdxPage-Dt-UEQl8.js +0 -193
- package/lib/MdxPage-Dt-UEQl8.js.map +0 -1
- package/lib/OperationList-DhOwupvv.js.map +0 -1
- package/lib/SyntaxHighlight-CcnUjERD.js +0 -2986
- package/lib/SyntaxHighlight-CcnUjERD.js.map +0 -1
- package/lib/createServer-DMf6O2Rz.js.map +0 -1
- package/lib/index-Do_30Hpk.js.map +0 -1
- package/lib/index-Du5aNddU.js +0 -509
- package/lib/index-Du5aNddU.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Control, Controller, useFieldArray } from "react-hook-form";
|
|
1
|
+
import { type Control, Controller, useFieldArray } from "react-hook-form";
|
|
2
2
|
import { Card } from "zudoku/ui/Card.js";
|
|
3
3
|
import { Input } from "../../../ui/Input.js";
|
|
4
4
|
import { ColorizedParam } from "../ColorizedParam.js";
|
|
@@ -7,18 +7,24 @@ import type { PlaygroundForm } from "./Playground.js";
|
|
|
7
7
|
|
|
8
8
|
export const PathParams = ({
|
|
9
9
|
control,
|
|
10
|
+
url,
|
|
10
11
|
}: {
|
|
11
12
|
control: Control<PlaygroundForm>;
|
|
13
|
+
url: string;
|
|
12
14
|
}) => {
|
|
13
15
|
const { fields } = useFieldArray<PlaygroundForm, "pathParams">({
|
|
14
16
|
control,
|
|
15
17
|
name: "pathParams",
|
|
16
18
|
});
|
|
17
19
|
|
|
20
|
+
const sortedFields = [...fields].sort(
|
|
21
|
+
(a, b) => url.indexOf(`{${a.name}}`) - url.indexOf(`{${b.name}}`),
|
|
22
|
+
);
|
|
23
|
+
|
|
18
24
|
return (
|
|
19
25
|
<Card className="rounded-lg">
|
|
20
26
|
<ParamsGrid>
|
|
21
|
-
{
|
|
27
|
+
{sortedFields.map((field, i) => (
|
|
22
28
|
<ParamsGridItem key={field.id}>
|
|
23
29
|
<Controller
|
|
24
30
|
control={control}
|
|
@@ -262,7 +262,7 @@ export const Playground = ({
|
|
|
262
262
|
));
|
|
263
263
|
|
|
264
264
|
const serverSelect = (
|
|
265
|
-
<div className="inline-block opacity-50 hover:opacity-100 transition">
|
|
265
|
+
<div className="inline-block opacity-50 hover:opacity-100 transition translate-y-[4px]">
|
|
266
266
|
{server ? (
|
|
267
267
|
<span>{server.replace(/^https?:\/\//, "")}</span>
|
|
268
268
|
) : (
|
|
@@ -305,7 +305,7 @@ export const Playground = ({
|
|
|
305
305
|
<div className="border-r p-2 bg-muted rounded-l-md self-stretch font-semibold font-mono flex items-center">
|
|
306
306
|
{method.toUpperCase()}
|
|
307
307
|
</div>
|
|
308
|
-
<div className="items-center
|
|
308
|
+
<div className="items-center px-2 py-0.5 font-mono text-xs break-all leading-6">
|
|
309
309
|
{serverSelect}
|
|
310
310
|
{path}
|
|
311
311
|
{urlQueryParams.length > 0 ? "?" : ""}
|
|
@@ -351,7 +351,7 @@ export const Playground = ({
|
|
|
351
351
|
{pathParams.length > 0 && (
|
|
352
352
|
<div className="flex flex-col gap-4 my-4">
|
|
353
353
|
<span className="font-semibold">Path Parameters</span>
|
|
354
|
-
<PathParams control={control} />
|
|
354
|
+
<PathParams url={url} control={control} />
|
|
355
355
|
</div>
|
|
356
356
|
)}
|
|
357
357
|
<div className="flex flex-col gap-4 my-4">
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
|
|
2
|
+
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Callout } from "zudoku/ui/Callout.js";
|
|
5
|
+
import {
|
|
6
|
+
CommandDialog,
|
|
7
|
+
CommandEmpty,
|
|
8
|
+
CommandInput,
|
|
9
|
+
} from "zudoku/ui/Command.js";
|
|
10
|
+
import { DialogTitle } from "zudoku/ui/Dialog.js";
|
|
11
|
+
import { joinUrl } from "../../util/joinUrl.js";
|
|
12
|
+
import { getResults } from "./get-results.js";
|
|
13
|
+
import type { PagefindOptions } from "./index.js";
|
|
14
|
+
import { ResultList } from "./ResultList.js";
|
|
15
|
+
import type { Pagefind } from "./types.js";
|
|
16
|
+
|
|
17
|
+
const DEFAULT_RANKING = {
|
|
18
|
+
// Slightly lower than default because API docs tend to have repetitive terms (parameter names, HTTP methods, etc.)
|
|
19
|
+
termFrequency: 0.8,
|
|
20
|
+
// Lower than default because API documentation pages tend to be longer due to comprehensive endpoint documentation
|
|
21
|
+
pageLength: 0.6,
|
|
22
|
+
// Slightly higher than default because in technical documentation, exact matches should be prioritized
|
|
23
|
+
termSimilarity: 1.2,
|
|
24
|
+
// Slightly lower than default because API docs might have legitimate repetition of terms
|
|
25
|
+
termSaturation: 1.2,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const importPagefind = (): Promise<Pagefind> =>
|
|
29
|
+
import.meta.env.DEV
|
|
30
|
+
? // @ts-expect-error TypeScript can't resolve the import
|
|
31
|
+
import(/* @vite-ignore */ "/pagefind/pagefind.js")
|
|
32
|
+
: import(
|
|
33
|
+
/* @vite-ignore */ joinUrl(
|
|
34
|
+
import.meta.env.BASE_URL,
|
|
35
|
+
"/pagefind/pagefind.js",
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const usePagefind = (options: PagefindOptions) => {
|
|
40
|
+
const { data: pagefind, ...result } = useQuery<Pagefind>({
|
|
41
|
+
queryKey: ["pagefind", options.ranking],
|
|
42
|
+
retry: false,
|
|
43
|
+
queryFn: async () => {
|
|
44
|
+
const pagefind = await importPagefind();
|
|
45
|
+
await pagefind.init();
|
|
46
|
+
await pagefind.options({
|
|
47
|
+
ranking: {
|
|
48
|
+
termFrequency:
|
|
49
|
+
options.ranking?.termFrequency ?? DEFAULT_RANKING.termFrequency,
|
|
50
|
+
pageLength: options.ranking?.pageLength ?? DEFAULT_RANKING.pageLength,
|
|
51
|
+
termSimilarity:
|
|
52
|
+
options.ranking?.termSimilarity ?? DEFAULT_RANKING.termSimilarity,
|
|
53
|
+
termSaturation:
|
|
54
|
+
options.ranking?.termSaturation ?? DEFAULT_RANKING.termSaturation,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return pagefind;
|
|
59
|
+
},
|
|
60
|
+
enabled: typeof window !== "undefined",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (result.isError) {
|
|
64
|
+
// eslint-disable-next-line no-console
|
|
65
|
+
console.error(result.error);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return { ...result, pagefind };
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const PagefindSearch = ({
|
|
72
|
+
isOpen,
|
|
73
|
+
onClose,
|
|
74
|
+
options,
|
|
75
|
+
}: {
|
|
76
|
+
isOpen: boolean;
|
|
77
|
+
onClose: () => void;
|
|
78
|
+
options: PagefindOptions;
|
|
79
|
+
}) => {
|
|
80
|
+
const { pagefind, error, isError } = usePagefind(options);
|
|
81
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
82
|
+
|
|
83
|
+
const { data: searchResults } = useQuery({
|
|
84
|
+
queryKey: ["pagefind-search", searchTerm],
|
|
85
|
+
queryFn: async () => {
|
|
86
|
+
const search = await pagefind?.search(searchTerm);
|
|
87
|
+
if (!search) return [];
|
|
88
|
+
return getResults(search, options);
|
|
89
|
+
},
|
|
90
|
+
placeholderData: keepPreviousData,
|
|
91
|
+
enabled: !!pagefind && !!searchTerm,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<CommandDialog
|
|
96
|
+
command={{ shouldFilter: false }}
|
|
97
|
+
content={{ className: "max-w-[750px]" }}
|
|
98
|
+
open={isOpen}
|
|
99
|
+
onOpenChange={onClose}
|
|
100
|
+
>
|
|
101
|
+
<VisuallyHidden>
|
|
102
|
+
<DialogTitle>Search</DialogTitle>
|
|
103
|
+
</VisuallyHidden>
|
|
104
|
+
<CommandInput
|
|
105
|
+
placeholder="Search..."
|
|
106
|
+
value={searchTerm}
|
|
107
|
+
onValueChange={setSearchTerm}
|
|
108
|
+
disabled={isError}
|
|
109
|
+
/>
|
|
110
|
+
<CommandEmpty>
|
|
111
|
+
{searchTerm ? "No results found." : "Start typing to search"}
|
|
112
|
+
</CommandEmpty>
|
|
113
|
+
{isError ? (
|
|
114
|
+
<div className="p-4 text-sm">
|
|
115
|
+
{error.message === "NOT_BUILT_YET" ? (
|
|
116
|
+
<Callout type="info">
|
|
117
|
+
Search is currently not available in development mode by default.
|
|
118
|
+
<br />
|
|
119
|
+
To still use search in development, run <code>
|
|
120
|
+
zudoku build
|
|
121
|
+
</code>{" "}
|
|
122
|
+
and copy the <code>dist/pagefind</code> directory to your{" "}
|
|
123
|
+
<code>public</code> directory.
|
|
124
|
+
</Callout>
|
|
125
|
+
) : (
|
|
126
|
+
"An error occurred while loading search."
|
|
127
|
+
)}
|
|
128
|
+
</div>
|
|
129
|
+
) : (
|
|
130
|
+
<ResultList
|
|
131
|
+
searchResults={searchResults ?? []}
|
|
132
|
+
searchTerm={searchTerm}
|
|
133
|
+
onClose={onClose}
|
|
134
|
+
maxSubResults={options.maxSubResults}
|
|
135
|
+
/>
|
|
136
|
+
)}
|
|
137
|
+
</CommandDialog>
|
|
138
|
+
);
|
|
139
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { FileTextIcon } from "lucide-react";
|
|
2
|
+
import { Link, useNavigate } from "react-router";
|
|
3
|
+
import { CommandGroup, CommandItem, CommandList } from "zudoku/ui/Command.js";
|
|
4
|
+
import {
|
|
5
|
+
type PagefindSearchFragment,
|
|
6
|
+
type PagefindSubResult,
|
|
7
|
+
} from "./types.js";
|
|
8
|
+
|
|
9
|
+
const sortSubResults = (a: PagefindSubResult, b: PagefindSubResult) => {
|
|
10
|
+
const aScore = a.weighted_locations.reduce(
|
|
11
|
+
(sum, loc) => sum + loc.balanced_score,
|
|
12
|
+
0,
|
|
13
|
+
);
|
|
14
|
+
const bScore = b.weighted_locations.reduce(
|
|
15
|
+
(sum, loc) => sum + loc.balanced_score,
|
|
16
|
+
0,
|
|
17
|
+
);
|
|
18
|
+
return bScore - aScore;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const hoverClassname = `cursor-pointer border border-transparent data-[selected=true]:border-border`;
|
|
22
|
+
|
|
23
|
+
const cleanResultUrl = (url: string) => {
|
|
24
|
+
const clean = url.replace(".html", "");
|
|
25
|
+
return clean.startsWith(import.meta.env.BASE_URL)
|
|
26
|
+
? clean.slice(import.meta.env.BASE_URL.length)
|
|
27
|
+
: clean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const ResultList = ({
|
|
31
|
+
searchResults,
|
|
32
|
+
searchTerm,
|
|
33
|
+
onClose,
|
|
34
|
+
maxSubResults = 4,
|
|
35
|
+
}: {
|
|
36
|
+
searchResults: PagefindSearchFragment[];
|
|
37
|
+
searchTerm: string;
|
|
38
|
+
onClose: () => void;
|
|
39
|
+
maxSubResults?: number;
|
|
40
|
+
}) => {
|
|
41
|
+
const navigate = useNavigate();
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<CommandList className="max-h-[450px]">
|
|
45
|
+
{searchTerm && searchResults.length > 0 && (
|
|
46
|
+
<CommandGroup
|
|
47
|
+
className="text-sm text-muted-foreground"
|
|
48
|
+
heading={`${searchResults.length} results for "${searchTerm}"`}
|
|
49
|
+
/>
|
|
50
|
+
)}
|
|
51
|
+
{searchResults.map((result) => (
|
|
52
|
+
<CommandGroup
|
|
53
|
+
key={[result.meta.title ?? result.excerpt, result.url].join("-")}
|
|
54
|
+
>
|
|
55
|
+
<CommandItem
|
|
56
|
+
asChild
|
|
57
|
+
value={`${result.meta.title}-${result.url}`}
|
|
58
|
+
className={hoverClassname}
|
|
59
|
+
onSelect={() => {
|
|
60
|
+
void navigate(cleanResultUrl(result.url));
|
|
61
|
+
onClose();
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
<Link to={cleanResultUrl(result.url)}>
|
|
65
|
+
<FileTextIcon size={20} className="text-muted-foreground" />
|
|
66
|
+
{result.meta.title}
|
|
67
|
+
</Link>
|
|
68
|
+
</CommandItem>
|
|
69
|
+
{result.sub_results
|
|
70
|
+
.sort(sortSubResults)
|
|
71
|
+
.slice(0, maxSubResults)
|
|
72
|
+
.map((subResult) => (
|
|
73
|
+
<CommandItem
|
|
74
|
+
asChild
|
|
75
|
+
key={`${result.meta.title}-${subResult.url}`}
|
|
76
|
+
value={`${result.meta.title}-${subResult.url}`}
|
|
77
|
+
className={hoverClassname}
|
|
78
|
+
onSelect={() => {
|
|
79
|
+
void navigate(cleanResultUrl(subResult.url));
|
|
80
|
+
onClose();
|
|
81
|
+
}}
|
|
82
|
+
>
|
|
83
|
+
<Link to={cleanResultUrl(subResult.url)} onClick={onClose}>
|
|
84
|
+
<div className="flex flex-col items-start gap-2 ms-2.5 ps-5 border-l border-muted-foreground/50">
|
|
85
|
+
<span className="font-bold">{subResult.title}</span>
|
|
86
|
+
<span
|
|
87
|
+
className="text-[13px] [&_mark]:bg-primary [&_mark]:text-primary-foreground"
|
|
88
|
+
dangerouslySetInnerHTML={{ __html: subResult.excerpt }}
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
</Link>
|
|
92
|
+
</CommandItem>
|
|
93
|
+
))}
|
|
94
|
+
</CommandGroup>
|
|
95
|
+
))}
|
|
96
|
+
</CommandList>
|
|
97
|
+
);
|
|
98
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { PagefindOptions } from "./index.js";
|
|
2
|
+
import type { PagefindSearchFragment, PagefindSearchResults } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export const getResults = async (
|
|
5
|
+
search: PagefindSearchResults,
|
|
6
|
+
options: PagefindOptions,
|
|
7
|
+
) => {
|
|
8
|
+
const maxResults = options.maxResults ?? 10;
|
|
9
|
+
const transformFn = options.transformResults ?? (() => true);
|
|
10
|
+
|
|
11
|
+
const transformedResults: PagefindSearchFragment[] = [];
|
|
12
|
+
|
|
13
|
+
const generator = searchResultGenerator(search, transformFn);
|
|
14
|
+
|
|
15
|
+
for await (const result of generator) {
|
|
16
|
+
transformedResults.push(result);
|
|
17
|
+
if (transformedResults.length >= maxResults) break;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return transformedResults;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
async function* searchResultGenerator(
|
|
24
|
+
search: PagefindSearchResults,
|
|
25
|
+
transformFn: NonNullable<PagefindOptions["transformResults"]>,
|
|
26
|
+
) {
|
|
27
|
+
const batchSize = 5;
|
|
28
|
+
let processedCount = 0;
|
|
29
|
+
|
|
30
|
+
while (processedCount < search.results.length) {
|
|
31
|
+
const batch = search.results.slice(
|
|
32
|
+
processedCount,
|
|
33
|
+
processedCount + batchSize,
|
|
34
|
+
);
|
|
35
|
+
processedCount += batch.length;
|
|
36
|
+
|
|
37
|
+
const batchData = await Promise.all(batch.map((result) => result.data()));
|
|
38
|
+
|
|
39
|
+
for (const result of batchData) {
|
|
40
|
+
const transformed = transformFn(result);
|
|
41
|
+
|
|
42
|
+
if (transformed === false) {
|
|
43
|
+
// Skip this result
|
|
44
|
+
continue;
|
|
45
|
+
} else if (transformed === true || transformed == null) {
|
|
46
|
+
// Keep the original result
|
|
47
|
+
yield result;
|
|
48
|
+
} else {
|
|
49
|
+
// Return the transformed result
|
|
50
|
+
yield transformed;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ZudokuConfig } from "../../../config/validators/validate.js";
|
|
2
|
+
import { ClientOnly } from "../../components/ClientOnly.js";
|
|
3
|
+
import type { ZudokuPlugin } from "../../core/plugins.js";
|
|
4
|
+
import { PagefindSearch } from "./PagefindSearch.js";
|
|
5
|
+
|
|
6
|
+
export type PagefindOptions = Extract<
|
|
7
|
+
ZudokuConfig["search"],
|
|
8
|
+
{ type: "pagefind" }
|
|
9
|
+
>;
|
|
10
|
+
|
|
11
|
+
export const pagefindSearchPlugin = (
|
|
12
|
+
options: PagefindOptions,
|
|
13
|
+
): ZudokuPlugin => {
|
|
14
|
+
return {
|
|
15
|
+
renderSearch: ({ isOpen, onClose }) => (
|
|
16
|
+
<ClientOnly>
|
|
17
|
+
<PagefindSearch isOpen={isOpen} onClose={onClose} options={options} />
|
|
18
|
+
</ClientOnly>
|
|
19
|
+
),
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
interface PagefindIndexOptions {
|
|
2
|
+
basePath?: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
excerptLength?: number;
|
|
5
|
+
indexWeight?: number;
|
|
6
|
+
mergeFilter?: Record<string, unknown>;
|
|
7
|
+
highlightParam?: string;
|
|
8
|
+
language?: string;
|
|
9
|
+
primary?: boolean;
|
|
10
|
+
ranking?: PagefindRankingWeights;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface PagefindRankingWeights {
|
|
14
|
+
termSimilarity?: number;
|
|
15
|
+
pageLength?: number;
|
|
16
|
+
termSaturation?: number;
|
|
17
|
+
termFrequency?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface PagefindSearchOptions {
|
|
21
|
+
preload?: boolean;
|
|
22
|
+
verbose?: boolean;
|
|
23
|
+
filters?: Record<string, unknown>;
|
|
24
|
+
sort?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type PagefindFilterCounts = Record<string, Record<string, number>> & {};
|
|
28
|
+
|
|
29
|
+
interface PagefindSearchResults {
|
|
30
|
+
results: PagefindSearchResult[];
|
|
31
|
+
unfilteredResultCount: number;
|
|
32
|
+
filters: PagefindFilterCounts;
|
|
33
|
+
totalFilters: PagefindFilterCounts;
|
|
34
|
+
timings: {
|
|
35
|
+
preload: number;
|
|
36
|
+
search: number;
|
|
37
|
+
total: number;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface PagefindSearchResult {
|
|
42
|
+
id: string;
|
|
43
|
+
score: number;
|
|
44
|
+
words: number[];
|
|
45
|
+
data: () => Promise<PagefindSearchFragment>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface PagefindSearchFragment {
|
|
49
|
+
url: string;
|
|
50
|
+
raw_url?: string;
|
|
51
|
+
content: string;
|
|
52
|
+
raw_content?: string;
|
|
53
|
+
excerpt: string;
|
|
54
|
+
sub_results: PagefindSubResult[];
|
|
55
|
+
word_count: number;
|
|
56
|
+
locations: number[];
|
|
57
|
+
weighted_locations: PagefindWordLocation[];
|
|
58
|
+
filters: Record<string, string[]>;
|
|
59
|
+
meta: Record<string, string>;
|
|
60
|
+
anchors: PagefindSearchAnchor[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface PagefindSubResult {
|
|
64
|
+
title: string;
|
|
65
|
+
url: string;
|
|
66
|
+
locations: number[];
|
|
67
|
+
weighted_locations: PagefindWordLocation[];
|
|
68
|
+
excerpt: string;
|
|
69
|
+
anchor?: PagefindSearchAnchor;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface PagefindWordLocation {
|
|
73
|
+
weight: number;
|
|
74
|
+
balanced_score: number;
|
|
75
|
+
location: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface PagefindSearchAnchor {
|
|
79
|
+
element: string;
|
|
80
|
+
id: string;
|
|
81
|
+
text?: string;
|
|
82
|
+
location: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface Pagefind {
|
|
86
|
+
debouncedSearch: (
|
|
87
|
+
query: string,
|
|
88
|
+
options?: PagefindSearchOptions,
|
|
89
|
+
duration?: number,
|
|
90
|
+
) => Promise<PagefindSearchResults>;
|
|
91
|
+
destroy: () => Promise<void>;
|
|
92
|
+
filters: () => Promise<PagefindFilterCounts>;
|
|
93
|
+
init: () => Promise<void>;
|
|
94
|
+
mergeIndex: (
|
|
95
|
+
indexPath: string,
|
|
96
|
+
options?: Record<string, unknown>,
|
|
97
|
+
) => Promise<void>;
|
|
98
|
+
options: (options: PagefindIndexOptions) => Promise<void>;
|
|
99
|
+
preload: (term: string, options?: PagefindIndexOptions) => Promise<void>;
|
|
100
|
+
search: (
|
|
101
|
+
term: string,
|
|
102
|
+
options?: PagefindSearchOptions,
|
|
103
|
+
) => Promise<PagefindSearchResults>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type {
|
|
107
|
+
Pagefind,
|
|
108
|
+
PagefindFilterCounts,
|
|
109
|
+
PagefindIndexOptions,
|
|
110
|
+
PagefindRankingWeights,
|
|
111
|
+
PagefindSearchAnchor,
|
|
112
|
+
PagefindSearchFragment,
|
|
113
|
+
PagefindSearchOptions,
|
|
114
|
+
PagefindSearchResult,
|
|
115
|
+
PagefindSearchResults,
|
|
116
|
+
PagefindSubResult,
|
|
117
|
+
PagefindWordLocation,
|
|
118
|
+
};
|
package/src/lib/ui/Command.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import { type DialogProps } from "@radix-ui/react-dialog";
|
|
|
2
2
|
import { Command as CommandPrimitive } from "cmdk";
|
|
3
3
|
import { Search } from "lucide-react";
|
|
4
4
|
import * as React from "react";
|
|
5
|
+
import { ComponentPropsWithoutRef } from "react";
|
|
5
6
|
import { Dialog, DialogContent } from "zudoku/ui/Dialog.js";
|
|
6
7
|
import { cn } from "../util/cn.js";
|
|
7
8
|
|
|
@@ -20,11 +21,32 @@ const Command = React.forwardRef<
|
|
|
20
21
|
));
|
|
21
22
|
Command.displayName = CommandPrimitive.displayName;
|
|
22
23
|
|
|
23
|
-
const CommandDialog = ({
|
|
24
|
+
const CommandDialog = ({
|
|
25
|
+
children,
|
|
26
|
+
command,
|
|
27
|
+
content,
|
|
28
|
+
...props
|
|
29
|
+
}: DialogProps & {
|
|
30
|
+
command?: ComponentPropsWithoutRef<typeof CommandPrimitive>;
|
|
31
|
+
content?: ComponentPropsWithoutRef<typeof DialogContent>;
|
|
32
|
+
}) => {
|
|
24
33
|
return (
|
|
25
34
|
<Dialog {...props}>
|
|
26
|
-
<DialogContent
|
|
27
|
-
|
|
35
|
+
<DialogContent
|
|
36
|
+
{...content}
|
|
37
|
+
className={cn(
|
|
38
|
+
"overflow-hidden p-0 shadow-lg top-[15vh] translate-y-[0%]",
|
|
39
|
+
content?.className,
|
|
40
|
+
)}
|
|
41
|
+
aria-describedby={undefined}
|
|
42
|
+
>
|
|
43
|
+
<Command
|
|
44
|
+
{...command}
|
|
45
|
+
className={cn(
|
|
46
|
+
"[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5",
|
|
47
|
+
command?.className,
|
|
48
|
+
)}
|
|
49
|
+
>
|
|
28
50
|
{children}
|
|
29
51
|
</Command>
|
|
30
52
|
</DialogContent>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
@tailwind components;
|
|
2
|
+
|
|
3
|
+
@layer components {
|
|
4
|
+
.stepper {
|
|
5
|
+
/* @apply mb-6; */
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.stepper > ol {
|
|
9
|
+
--bullet-size: 1.75rem;
|
|
10
|
+
--line-spacing: 0.25rem;
|
|
11
|
+
@apply flex flex-col list-none p-0 m-0;
|
|
12
|
+
counter-reset: step-counter;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.stepper > ol > li {
|
|
16
|
+
@apply relative ps-12 pb-6 my-0;
|
|
17
|
+
counter-increment: step-counter;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.stepper > ol > li:last-child {
|
|
21
|
+
@apply pb-0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Bullet with number */
|
|
25
|
+
.stepper > ol > li::before {
|
|
26
|
+
@apply absolute left-0 flex items-center justify-center size-[--bullet-size];
|
|
27
|
+
@apply bg-muted/80 border border-border text-muted-foreground text-[calc(var(--bullet-size)/2)] font-semibold rounded-full;
|
|
28
|
+
content: counter(step-counter);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Vertical line */
|
|
32
|
+
.stepper > ol > li::after {
|
|
33
|
+
@apply absolute content-[''] w-[2px] bg-border -translate-x-1/2;
|
|
34
|
+
left: calc(var(--bullet-size) / 2);
|
|
35
|
+
top: calc(var(--bullet-size) + var(--line-spacing));
|
|
36
|
+
height: calc(100% - var(--bullet-size) - (2 * var(--line-spacing)));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.stepper > ol > li > :first-child {
|
|
40
|
+
@apply mt-0 pt-0;
|
|
41
|
+
transform: translateY(calc((var(--bullet-size) - 1lh) / 2));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { MDXComponents } from "mdx/types.js";
|
|
1
|
+
import { type MDXComponents } from "mdx/types.js";
|
|
2
2
|
import { Link } from "react-router";
|
|
3
3
|
import { Heading } from "../components/Heading.js";
|
|
4
4
|
import { InlineCode } from "../components/InlineCode.js";
|
|
5
5
|
import { Callout } from "../ui/Callout.js";
|
|
6
|
+
import { Stepper } from "../ui/Stepper.js";
|
|
6
7
|
import { SyntaxHighlight } from "../ui/SyntaxHighlight.js";
|
|
7
8
|
|
|
8
9
|
export type MdxComponentsType = Readonly<MDXComponents> | null | undefined;
|
|
@@ -51,6 +52,8 @@ export const MdxComponents = {
|
|
|
51
52
|
<a href={href} target="_blank" {...props} rel="noreferrer" />
|
|
52
53
|
),
|
|
53
54
|
Callout,
|
|
55
|
+
Stepper,
|
|
56
|
+
SyntaxHighlight,
|
|
54
57
|
tip: (props) => <Callout type="tip" {...props} />,
|
|
55
58
|
info: (props) => <Callout type="info" {...props} />,
|
|
56
59
|
note: (props) => <Callout type="note" {...props} />,
|
|
@@ -9,21 +9,21 @@ export const useScrollToHash = () => {
|
|
|
9
9
|
|
|
10
10
|
const scrollToHash = useCallback(
|
|
11
11
|
(hash: string) => {
|
|
12
|
-
const cleanHash = hash
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.at(0)!;
|
|
12
|
+
const cleanHash = hash.replace(/^#/, "");
|
|
13
|
+
|
|
14
|
+
// Operation list items might have subdivisions that the sidebar doesn't show.
|
|
15
|
+
// The subdivisions are separated by a slash so we need to remove everything before the slash to get the sidebar correct item.
|
|
16
|
+
const linkHash = cleanHash.split("/").at(0)!;
|
|
18
17
|
const element = document.getElementById(decodeURIComponent(cleanHash));
|
|
18
|
+
|
|
19
19
|
const link = document.querySelector(
|
|
20
|
-
`[${DATA_ANCHOR_ATTR}="${
|
|
20
|
+
`[${DATA_ANCHOR_ATTR}="${linkHash}"]`,
|
|
21
21
|
);
|
|
22
22
|
|
|
23
23
|
if (element) {
|
|
24
24
|
element.scrollIntoView();
|
|
25
25
|
scrollIntoViewIfNeeded(link);
|
|
26
|
-
requestIdleCallback(() => setActiveAnchor(
|
|
26
|
+
requestIdleCallback(() => setActiveAnchor(linkHash));
|
|
27
27
|
return true;
|
|
28
28
|
}
|
|
29
29
|
|