zudoku 0.0.0-f2a195f → 0.0.0-f417aae
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/dist/app/main.js +2 -4
- package/dist/app/main.js.map +1 -1
- package/dist/config/validators/InputSidebarSchema.d.ts +19 -4
- package/dist/config/validators/InputSidebarSchema.js +7 -28
- package/dist/config/validators/InputSidebarSchema.js.map +1 -1
- package/dist/config/validators/SidebarSchema.js +5 -6
- package/dist/config/validators/SidebarSchema.js.map +1 -1
- package/dist/config/validators/validate.d.ts +103 -19
- package/dist/config/validators/validate.js +17 -1
- package/dist/config/validators/validate.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/lib/authentication/components/CallbackHandler.js +21 -31
- package/dist/lib/authentication/components/CallbackHandler.js.map +1 -1
- package/dist/lib/authentication/hook.d.ts +1 -1
- package/dist/lib/authentication/hook.js +1 -1
- package/dist/lib/authentication/hook.js.map +1 -1
- package/dist/lib/components/MobileTopNavigation.js +4 -1
- package/dist/lib/components/MobileTopNavigation.js.map +1 -1
- package/dist/lib/components/SlotletProvider.d.ts +6 -2
- package/dist/lib/components/SlotletProvider.js +3 -5
- package/dist/lib/components/SlotletProvider.js.map +1 -1
- package/dist/lib/components/TopNavigation.d.ts +3 -0
- package/dist/lib/components/TopNavigation.js +9 -1
- package/dist/lib/components/TopNavigation.js.map +1 -1
- package/dist/lib/components/context/ZudokuContext.d.ts +2 -0
- package/dist/lib/components/index.d.ts +17 -8
- package/dist/lib/components/index.js +10 -3
- package/dist/lib/components/index.js.map +1 -1
- package/dist/lib/components/navigation/Sidebar.js +1 -1
- package/dist/lib/components/navigation/Sidebar.js.map +1 -1
- package/dist/lib/components/navigation/SidebarCategory.js +18 -7
- package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
- package/dist/lib/components/navigation/SidebarItem.js +12 -5
- package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
- package/dist/lib/core/DevPortalContext.d.ts +1 -0
- package/dist/lib/core/DevPortalContext.js.map +1 -1
- package/dist/lib/errors/ErrorAlert.d.ts +1 -1
- package/dist/lib/errors/ErrorAlert.js +8 -3
- package/dist/lib/errors/ErrorAlert.js.map +1 -1
- package/dist/lib/plugins/custom-pages/CustomPage.d.ts +2 -0
- package/dist/lib/plugins/custom-pages/CustomPage.js +11 -0
- package/dist/lib/plugins/custom-pages/CustomPage.js.map +1 -0
- package/dist/lib/plugins/custom-pages/index.d.ts +8 -6
- package/dist/lib/plugins/custom-pages/index.js +3 -4
- package/dist/lib/plugins/custom-pages/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/playground/Playground.js +1 -0
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/util/invariant.d.ts +9 -0
- package/dist/lib/util/invariant.js +7 -3
- package/dist/lib/util/invariant.js.map +1 -1
- package/dist/lib/util/useExposedProps.d.ts +2 -0
- package/dist/lib/util/useExposedProps.js +8 -0
- package/dist/lib/util/useExposedProps.js.map +1 -0
- package/dist/vite/dev-server.js +1 -1
- package/dist/vite/dev-server.js.map +1 -1
- package/dist/vite/plugin-mdx.js +17 -0
- package/dist/vite/plugin-mdx.js.map +1 -1
- package/dist/vite/plugin-search.d.ts +3 -0
- package/dist/vite/plugin-search.js +26 -0
- package/dist/vite/plugin-search.js.map +1 -0
- package/dist/vite/plugin.js +2 -0
- package/dist/vite/plugin.js.map +1 -1
- package/lib/{AuthenticationPlugin-D_5jC4vE.js → AuthenticationPlugin-tBvLKsFg.js} +3 -3
- package/lib/{AuthenticationPlugin-D_5jC4vE.js.map → AuthenticationPlugin-tBvLKsFg.js.map} +1 -1
- package/lib/{CategoryHeading-C7VfgpFZ.js → CategoryHeading-D2WS6sRI.js} +2 -2
- package/lib/{CategoryHeading-C7VfgpFZ.js.map → CategoryHeading-D2WS6sRI.js.map} +1 -1
- package/lib/ClientOnly-CVN6leDu.js +11 -0
- package/lib/ClientOnly-CVN6leDu.js.map +1 -0
- package/lib/{DeveloperHint-CNyuFROc.js → DeveloperHint-CRiZjqd2.js} +2 -2
- package/lib/{DeveloperHint-CNyuFROc.js.map → DeveloperHint-CRiZjqd2.js.map} +1 -1
- package/lib/{Input-CYTkk51A.js → Input-CO-1DOZa.js} +4 -4
- package/lib/{Input-CYTkk51A.js.map → Input-CO-1DOZa.js.map} +1 -1
- package/lib/{Markdown-C-0TaxoY.js → Markdown-DM4zv3MA.js} +9 -8
- package/lib/{Markdown-C-0TaxoY.js.map → Markdown-DM4zv3MA.js.map} +1 -1
- package/lib/{MdxPage-Cbj8ILOL.js → MdxPage-tWI_P8wP.js} +7 -7
- package/lib/MdxPage-tWI_P8wP.js.map +1 -0
- package/lib/{OperationList-Dto8Wvgo.js → OperationList-Cd3lue0b.js} +11 -12
- package/lib/{OperationList-Dto8Wvgo.js.map → OperationList-Cd3lue0b.js.map} +1 -1
- package/lib/{Route-DLH-PALM.js → Route-DI0Y0pIV.js} +3 -3
- package/lib/{Route-DLH-PALM.js.map → Route-DI0Y0pIV.js.map} +1 -1
- package/lib/SlotletProvider-CBqY8mp6.js +241 -0
- package/lib/SlotletProvider-CBqY8mp6.js.map +1 -0
- package/lib/{SidebarBadge-BWvFQTc1.js → Spinner-DFQhPMBl.js} +60 -58
- package/lib/Spinner-DFQhPMBl.js.map +1 -0
- package/lib/{ZudokuContext-uV_XfHPK.js → ZudokuContext-DEoP3GGJ.js} +2 -2
- package/lib/{ZudokuContext-uV_XfHPK.js.map → ZudokuContext-DEoP3GGJ.js.map} +1 -1
- package/lib/_commonjsHelpers-BkfeUUK-.js +29 -0
- package/lib/_commonjsHelpers-BkfeUUK-.js.map +1 -0
- package/lib/index-Bn6Lc9tq.js +9 -0
- package/lib/{index-DJqnphbT.js.map → index-Bn6Lc9tq.js.map} +1 -1
- package/lib/{index-aHWE7ArR.js → index-Bs9roz8y.js} +599 -590
- package/lib/index-Bs9roz8y.js.map +1 -0
- package/lib/{index-SyxHzsgJ.js → index-CBr6BM_4.js} +13 -13
- package/lib/index-CBr6BM_4.js.map +1 -0
- package/lib/{index-SrtqdZ3j.js → index-CRo94sKK.js} +8 -6
- package/lib/{index-SrtqdZ3j.js.map → index-CRo94sKK.js.map} +1 -1
- package/lib/{index-D06ATMgg.js → index-LNp6rxyU.js} +2 -2
- package/lib/{index-D06ATMgg.js.map → index-LNp6rxyU.js.map} +1 -1
- package/lib/{index-LstIRx3V.js → index-UUT9q9f9.js} +3 -3
- package/lib/{index-LstIRx3V.js.map → index-UUT9q9f9.js.map} +1 -1
- package/lib/invariant-Caa8-XvF.js +26 -0
- package/lib/invariant-Caa8-XvF.js.map +1 -0
- package/lib/{router-Oe6YmY6B.js → router-BsfSoK2j.js} +3 -3
- package/lib/{router-Oe6YmY6B.js.map → router-BsfSoK2j.js.map} +1 -1
- package/lib/urql-core-KJnLL26g.js.map +1 -1
- package/lib/useExposedProps-B9K-9GTc.js +9 -0
- package/lib/useExposedProps-B9K-9GTc.js.map +1 -0
- package/lib/{utils-CCcr3AZm.js → utils-G5XSiZc9.js} +4 -4
- package/lib/{utils-CCcr3AZm.js.map → utils-G5XSiZc9.js.map} +1 -1
- package/lib/zudoku.auth-clerk.js +1 -1
- package/lib/zudoku.auth-openid.js +477 -483
- package/lib/zudoku.auth-openid.js.map +1 -1
- package/lib/zudoku.components.js +1014 -1002
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.openapi-worker.js +2 -2
- package/lib/zudoku.plugin-api-keys.js +60 -70
- package/lib/zudoku.plugin-api-keys.js.map +1 -1
- package/lib/zudoku.plugin-custom-pages.js +16 -8
- package/lib/zudoku.plugin-custom-pages.js.map +1 -1
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +7 -8
- package/lib/zudoku.plugin-openapi.js.map +1 -1
- package/lib/zudoku.plugin-redirect.js +1 -1
- package/lib/zudoku.plugin-search-inkeep.js +9 -13
- package/lib/zudoku.plugin-search-inkeep.js.map +1 -1
- package/package.json +1 -1
- package/src/app/main.css +0 -1
- package/src/app/main.tsx +2 -4
- package/src/lib/authentication/components/CallbackHandler.tsx +20 -51
- package/src/lib/authentication/hook.ts +1 -1
- package/src/lib/components/MobileTopNavigation.tsx +6 -2
- package/src/lib/components/SlotletProvider.tsx +14 -7
- package/src/lib/components/TopNavigation.tsx +14 -1
- package/src/lib/components/index.ts +13 -4
- package/src/lib/components/navigation/Sidebar.tsx +1 -1
- package/src/lib/components/navigation/SidebarCategory.tsx +34 -26
- package/src/lib/components/navigation/SidebarItem.tsx +16 -17
- package/src/lib/core/DevPortalContext.ts +6 -1
- package/src/lib/errors/ErrorAlert.tsx +18 -5
- package/src/lib/plugins/custom-pages/CustomPage.tsx +18 -0
- package/src/lib/plugins/custom-pages/index.tsx +11 -9
- package/src/lib/plugins/markdown/MdxPage.tsx +10 -8
- package/src/lib/plugins/openapi/playground/Playground.tsx +1 -0
- package/src/lib/util/invariant.ts +15 -3
- package/src/lib/util/useExposedProps.tsx +10 -0
- package/lib/ErrorPage-CUz-Zzmx.js +0 -16
- package/lib/ErrorPage-CUz-Zzmx.js.map +0 -1
- package/lib/MdxPage-Cbj8ILOL.js.map +0 -1
- package/lib/SidebarBadge-BWvFQTc1.js.map +0 -1
- package/lib/SlotletProvider-BGEs7yyu.js +0 -240
- package/lib/SlotletProvider-BGEs7yyu.js.map +0 -1
- package/lib/Spinner-3cQDBVGr.js +0 -7
- package/lib/Spinner-3cQDBVGr.js.map +0 -1
- package/lib/index-DJqnphbT.js +0 -35
- package/lib/index-SyxHzsgJ.js.map +0 -1
- package/lib/index-aHWE7ArR.js.map +0 -1
package/src/app/main.tsx
CHANGED
|
@@ -5,11 +5,11 @@ import { configuredAuthProvider } from "virtual:zudoku-auth";
|
|
|
5
5
|
import { configuredCustomPagesPlugin } from "virtual:zudoku-custom-pages-plugin";
|
|
6
6
|
import { configuredDocsPlugins } from "virtual:zudoku-docs-plugins";
|
|
7
7
|
import { configuredRedirectPlugin } from "virtual:zudoku-redirect-plugin";
|
|
8
|
+
import { configuredSearchPlugin } from "virtual:zudoku-search-plugin";
|
|
8
9
|
import { configuredSidebar } from "virtual:zudoku-sidebar";
|
|
9
10
|
import "virtual:zudoku-theme.css";
|
|
10
11
|
import { DevPortal, Layout, RouterError } from "zudoku/components";
|
|
11
12
|
import { isNavigationPlugin } from "zudoku/internal";
|
|
12
|
-
import { inkeepSearchPlugin } from "zudoku/plugins/search-inkeep";
|
|
13
13
|
import type { ZudokuConfig } from "../config/config.js";
|
|
14
14
|
import { traverseSidebar } from "../lib/components/navigation/utils.js";
|
|
15
15
|
import type { ZudokuContextOptions } from "../lib/core/DevPortalContext.js";
|
|
@@ -53,11 +53,9 @@ export const convertZudokuConfigToOptions = (
|
|
|
53
53
|
mdx: config.mdx,
|
|
54
54
|
authentication: configuredAuthProvider,
|
|
55
55
|
plugins: [
|
|
56
|
-
...(config.search?.type === "inkeep"
|
|
57
|
-
? [inkeepSearchPlugin(config.search)]
|
|
58
|
-
: []),
|
|
59
56
|
...configuredDocsPlugins,
|
|
60
57
|
...configuredApiPlugins,
|
|
58
|
+
...(configuredSearchPlugin ? [configuredSearchPlugin] : []),
|
|
61
59
|
...(configuredRedirectPlugin ? [configuredRedirectPlugin] : []),
|
|
62
60
|
...(configuredApiKeysPlugin ? [configuredApiKeysPlugin] : []),
|
|
63
61
|
...(configuredCustomPagesPlugin ? [configuredCustomPagesPlugin] : []),
|
|
@@ -1,59 +1,28 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { DeveloperHint } from "../../components/DeveloperHint.js";
|
|
5
|
-
import { ErrorPage } from "../../components/ErrorPage.js";
|
|
6
|
-
import { Spinner } from "../../components/Spinner.js";
|
|
7
|
-
import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
|
|
1
|
+
import { useSuspenseQuery } from "@tanstack/react-query";
|
|
2
|
+
import { Navigate } from "react-router-dom";
|
|
3
|
+
import { ZudokuError } from "../../util/invariant.js";
|
|
8
4
|
|
|
9
5
|
export function CallbackHandler({
|
|
10
6
|
handleCallback,
|
|
11
7
|
}: {
|
|
12
8
|
handleCallback: () => Promise<string>;
|
|
13
9
|
}) {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
const executeCallback = useSuspenseQuery({
|
|
11
|
+
retry: false,
|
|
12
|
+
queryKey: ["oauth-callback"],
|
|
13
|
+
queryFn: async () => {
|
|
14
|
+
try {
|
|
15
|
+
return await handleCallback();
|
|
16
|
+
} catch (error) {
|
|
17
|
+
throw new ZudokuError("Could not validate user", {
|
|
18
|
+
cause: error,
|
|
19
|
+
title: "Authentication Error",
|
|
20
|
+
developerHint:
|
|
21
|
+
"Check the configuration of your authorization provider and ensure all settings such as the callback URL are configured correctly.",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
});
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
if (didInitialize.current) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
didInitialize.current = true;
|
|
25
|
-
handleCallback()
|
|
26
|
-
.then((redirect) => {
|
|
27
|
-
navigate(redirect);
|
|
28
|
-
})
|
|
29
|
-
.catch((err) => {
|
|
30
|
-
logger.error(err);
|
|
31
|
-
setError(err);
|
|
32
|
-
});
|
|
33
|
-
}, [navigate, handleCallback]);
|
|
34
|
-
|
|
35
|
-
if (error) {
|
|
36
|
-
return (
|
|
37
|
-
<ErrorPage
|
|
38
|
-
category="Error"
|
|
39
|
-
title="Authentication Error"
|
|
40
|
-
message={
|
|
41
|
-
<>
|
|
42
|
-
<DeveloperHint className="mb-4">
|
|
43
|
-
Check the configuration of your authorization provider and ensure
|
|
44
|
-
all settings such as the callback URL are configured correctly.
|
|
45
|
-
</DeveloperHint>
|
|
46
|
-
An error occurred while authorizing the user.
|
|
47
|
-
<SyntaxHighlight code={error.toString()} language="plain" />
|
|
48
|
-
</>
|
|
49
|
-
}
|
|
50
|
-
/>
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<div className="grid h-full place-items-center">
|
|
56
|
-
<Spinner />
|
|
57
|
-
</div>
|
|
58
|
-
);
|
|
27
|
+
return <Navigate to={executeCallback.data} />;
|
|
59
28
|
}
|
|
@@ -2,6 +2,7 @@ import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
|
|
|
2
2
|
import { cx } from "class-variance-authority";
|
|
3
3
|
import { MenuIcon } from "lucide-react";
|
|
4
4
|
import { NavLink } from "react-router-dom";
|
|
5
|
+
import { useAuth } from "../authentication/hook.js";
|
|
5
6
|
import {
|
|
6
7
|
Drawer,
|
|
7
8
|
DrawerClose,
|
|
@@ -11,9 +12,12 @@ import {
|
|
|
11
12
|
} from "../ui/Drawer.js";
|
|
12
13
|
import { useZudoku } from "./context/ZudokuContext.js";
|
|
13
14
|
import { Search } from "./Search.js";
|
|
15
|
+
import { isHiddenItem } from "./TopNavigation.js";
|
|
14
16
|
|
|
15
17
|
export const MobileTopNavigation = () => {
|
|
16
18
|
const { topNavigation } = useZudoku();
|
|
19
|
+
const { isAuthenticated } = useAuth();
|
|
20
|
+
|
|
17
21
|
return (
|
|
18
22
|
<Drawer direction="right">
|
|
19
23
|
<div className="flex lg:hidden justify-self-end">
|
|
@@ -22,7 +26,7 @@ export const MobileTopNavigation = () => {
|
|
|
22
26
|
</DrawerTrigger>
|
|
23
27
|
</div>
|
|
24
28
|
<DrawerContent
|
|
25
|
-
className="lg:hidden h-screen right-0 left-auto w-[320px] rounded-none"
|
|
29
|
+
className="lg:hidden h-screen right-0 left-auto w-[320px] rounded-none overflow-auto"
|
|
26
30
|
aria-describedby={undefined}
|
|
27
31
|
>
|
|
28
32
|
<VisuallyHidden>
|
|
@@ -32,7 +36,7 @@ export const MobileTopNavigation = () => {
|
|
|
32
36
|
<Search />
|
|
33
37
|
</div>
|
|
34
38
|
<ul className="flex flex-col items-center gap-4 p-4">
|
|
35
|
-
{topNavigation.map((item) => (
|
|
39
|
+
{topNavigation.filter(isHiddenItem(isAuthenticated)).map((item) => (
|
|
36
40
|
<li key={item.label}>
|
|
37
41
|
<NavLink
|
|
38
42
|
className={({ isActive }) =>
|
|
@@ -5,10 +5,16 @@ import React, {
|
|
|
5
5
|
useContext,
|
|
6
6
|
} from "react";
|
|
7
7
|
import { isValidElementType } from "react-is";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
type Location,
|
|
10
|
+
type NavigateFunction,
|
|
11
|
+
type SetURLSearchParams,
|
|
12
|
+
} from "react-router-dom";
|
|
13
|
+
import { useExposedProps } from "../util/useExposedProps.js";
|
|
14
|
+
|
|
9
15
|
export type Slotlets = Record<
|
|
10
16
|
string,
|
|
11
|
-
ReactNode | ReactElement | ComponentType<
|
|
17
|
+
ReactNode | ReactElement | ComponentType<ExposedComponentProps>
|
|
12
18
|
>;
|
|
13
19
|
|
|
14
20
|
const SlotletContext = React.createContext<Slotlets | undefined>({});
|
|
@@ -27,19 +33,20 @@ export const SlotletProvider = ({
|
|
|
27
33
|
);
|
|
28
34
|
};
|
|
29
35
|
|
|
30
|
-
export type
|
|
36
|
+
export type ExposedComponentProps = {
|
|
31
37
|
location: Location;
|
|
38
|
+
navigate: NavigateFunction;
|
|
39
|
+
searchParams: URLSearchParams;
|
|
40
|
+
setSearchParams: SetURLSearchParams;
|
|
32
41
|
};
|
|
33
42
|
|
|
34
43
|
export const Slotlet = ({ name }: { name: string }) => {
|
|
35
44
|
const context = useContext(SlotletContext);
|
|
36
45
|
const componentOrElement = context?.[name];
|
|
37
|
-
const
|
|
46
|
+
const slotletProps = useExposedProps();
|
|
38
47
|
|
|
39
48
|
if (isValidElementType(componentOrElement)) {
|
|
40
|
-
return React.createElement(componentOrElement,
|
|
41
|
-
location,
|
|
42
|
-
});
|
|
49
|
+
return React.createElement(componentOrElement, slotletProps);
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
return componentOrElement as ReactNode;
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { cx } from "class-variance-authority";
|
|
2
2
|
import { NavLink } from "react-router-dom";
|
|
3
3
|
|
|
4
|
+
import { useAuth } from "../authentication/hook.js";
|
|
4
5
|
import { useZudoku } from "./context/ZudokuContext.js";
|
|
5
6
|
|
|
7
|
+
export const isHiddenItem =
|
|
8
|
+
(isAuthenticated?: boolean) =>
|
|
9
|
+
(item: { display?: "auth" | "anon" | "always" }) => {
|
|
10
|
+
return (
|
|
11
|
+
(item.display === "auth" && isAuthenticated) ||
|
|
12
|
+
(item.display === "anon" && !isAuthenticated) ||
|
|
13
|
+
!item.display ||
|
|
14
|
+
item.display === "always"
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
6
18
|
export const TopNavigation = () => {
|
|
7
19
|
const { topNavigation } = useZudoku();
|
|
20
|
+
const { isAuthenticated } = useAuth();
|
|
8
21
|
|
|
9
22
|
// Hide top nav if there is only one item
|
|
10
23
|
if (topNavigation.length <= 1) {
|
|
@@ -14,7 +27,7 @@ export const TopNavigation = () => {
|
|
|
14
27
|
return (
|
|
15
28
|
<nav className="hidden lg:block border-b text-sm px-12 h-[--top-nav-height]">
|
|
16
29
|
<ul className="flex flex-row items-center gap-8">
|
|
17
|
-
{topNavigation.map((item) => (
|
|
30
|
+
{topNavigation.filter(isHiddenItem(isAuthenticated)).map((item) => (
|
|
18
31
|
<li key={item.label}>
|
|
19
32
|
<NavLink
|
|
20
33
|
className={({ isActive }) =>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useMDXComponents as useMDXComponentsImport } from "@mdx-js/react";
|
|
2
2
|
import { Helmet } from "@zudoku/react-helmet-async";
|
|
3
3
|
import { Link as LinkImport } from "react-router-dom";
|
|
4
|
+
import { useAuthState } from "../authentication/state.js";
|
|
4
5
|
import { RouterError as RouterErrorImport } from "../errors/RouterError.js";
|
|
5
6
|
import { ServerError as ServerErrorImport } from "../errors/ServerError.js";
|
|
6
7
|
import { Button as ButtonImport } from "../ui/Button.js";
|
|
@@ -9,17 +10,25 @@ import {
|
|
|
9
10
|
Bootstrap as BootstrapImport,
|
|
10
11
|
BootstrapStatic as BootstrapStaticImport,
|
|
11
12
|
} from "./Bootstrap.js";
|
|
13
|
+
import { ClientOnly as ClientOnlyImport } from "./ClientOnly.js";
|
|
12
14
|
import { DevPortal as DevPortalImport } from "./DevPortal.js";
|
|
13
15
|
import { Layout as LayoutImport } from "./Layout.js";
|
|
14
|
-
|
|
16
|
+
import { useZudoku as useZudokuImport } from "./context/ZudokuContext.js";
|
|
15
17
|
export const useMDXComponents = /*@__PURE__*/ useMDXComponentsImport;
|
|
16
|
-
export const Callout = /*@__PURE__*/ CalloutImport;
|
|
17
18
|
export const DevPortal = /*@__PURE__*/ DevPortalImport;
|
|
18
19
|
export const Layout = /*@__PURE__*/ LayoutImport;
|
|
19
|
-
export const Link: typeof LinkImport = /*@__PURE__*/ LinkImport;
|
|
20
20
|
export const RouterError = /*@__PURE__*/ RouterErrorImport;
|
|
21
21
|
export const ServerError = /*@__PURE__*/ ServerErrorImport;
|
|
22
22
|
export const Bootstrap = /*@__PURE__*/ BootstrapImport;
|
|
23
23
|
export const BootstrapStatic = /*@__PURE__*/ BootstrapStaticImport;
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
export const Head = /*@__PURE__*/ Helmet;
|
|
26
|
+
|
|
27
|
+
export const useZudoku = /*@__PURE__*/ useZudokuImport;
|
|
28
|
+
export const useAuth = /*@__PURE__*/ useAuthState;
|
|
29
|
+
export const Zudoku = /*@__PURE__*/ DevPortalImport;
|
|
30
|
+
|
|
31
|
+
export const Callout = /*@__PURE__*/ CalloutImport;
|
|
32
|
+
export const ClientOnly = /*@__PURE__*/ ClientOnlyImport;
|
|
33
|
+
export const Button = /*@__PURE__*/ ButtonImport;
|
|
34
|
+
export const Link: typeof LinkImport = /*@__PURE__*/ LinkImport;
|
|
@@ -24,7 +24,7 @@ export const Sidebar = () => {
|
|
|
24
24
|
<Slotlet name="zudoku-after-navigation" />
|
|
25
25
|
</SidebarWrapper>
|
|
26
26
|
<DrawerContent
|
|
27
|
-
className="lg:hidden h-screen left-0 p-6 w-[320px] rounded-none"
|
|
27
|
+
className="lg:hidden h-screen left-0 p-6 w-[320px] rounded-none overflow-auto"
|
|
28
28
|
aria-describedby={undefined}
|
|
29
29
|
>
|
|
30
30
|
<VisuallyHidden>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
2
2
|
import { ChevronRightIcon } from "lucide-react";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
|
-
import { NavLink } from "react-router-dom";
|
|
4
|
+
import { NavLink, useMatch } from "react-router-dom";
|
|
5
5
|
import type { SidebarItemCategory } from "../../../config/validators/SidebarSchema.js";
|
|
6
6
|
import { cn } from "../../util/cn.js";
|
|
7
7
|
import { joinPath } from "../../util/joinPath.js";
|
|
@@ -26,6 +26,7 @@ export const SidebarCategory = ({
|
|
|
26
26
|
!isCollapsible || !isCollapsed || isCategoryOpen,
|
|
27
27
|
);
|
|
28
28
|
const [open, setOpen] = useState(isDefaultOpen);
|
|
29
|
+
const isActive = useMatch(joinPath(topNavItem?.id, category.link?.id));
|
|
29
30
|
|
|
30
31
|
useEffect(() => {
|
|
31
32
|
// this is triggered when an item from the sidebar is clicked
|
|
@@ -56,46 +57,54 @@ export const SidebarCategory = ({
|
|
|
56
57
|
|
|
57
58
|
return (
|
|
58
59
|
<Collapsible.Root
|
|
59
|
-
className=
|
|
60
|
+
className="flex flex-col"
|
|
60
61
|
defaultOpen={isDefaultOpen}
|
|
61
62
|
open={open}
|
|
62
63
|
onOpenChange={() => setOpen(true)}
|
|
63
64
|
>
|
|
64
65
|
<Collapsible.Trigger className="group" asChild disabled={!isCollapsible}>
|
|
65
66
|
<div
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
onClick={() => setHasInteracted(true)}
|
|
68
|
+
className={navigationListItem({
|
|
69
|
+
isActive: false,
|
|
70
|
+
isTopLevel: level === 0,
|
|
71
|
+
className: [
|
|
72
|
+
"text-start",
|
|
73
|
+
isCollapsible
|
|
74
|
+
? "cursor-pointer"
|
|
75
|
+
: "cursor-default hover:bg-transparent",
|
|
76
|
+
],
|
|
77
|
+
})}
|
|
73
78
|
>
|
|
74
79
|
{category.icon && (
|
|
75
80
|
<category.icon
|
|
76
81
|
size={16}
|
|
77
|
-
className=
|
|
82
|
+
className={cn(
|
|
83
|
+
"align-[-0.125em] -translate-x-1",
|
|
84
|
+
isActive && "text-primary",
|
|
85
|
+
)}
|
|
78
86
|
/>
|
|
79
87
|
)}
|
|
80
88
|
{category.link?.type === "doc" ? (
|
|
81
89
|
<NavLink
|
|
82
90
|
to={joinPath(topNavItem?.id, category.link.id)}
|
|
83
91
|
className="flex-1"
|
|
84
|
-
onClick={() =>
|
|
92
|
+
onClick={() => {
|
|
93
|
+
// if it is the current path and closed then open it because there's no path change to trigger the open
|
|
94
|
+
if (isActive && !open) {
|
|
95
|
+
setOpen(true);
|
|
96
|
+
}
|
|
97
|
+
}}
|
|
85
98
|
>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
<div className="truncate">{category.label}</div>
|
|
96
|
-
{ToggleButton}
|
|
97
|
-
</div>
|
|
98
|
-
)}
|
|
99
|
+
<div
|
|
100
|
+
className={cn(
|
|
101
|
+
"flex items-center gap-2 justify-between w-full",
|
|
102
|
+
isActive ? "text-primary" : "text-foreground/80",
|
|
103
|
+
)}
|
|
104
|
+
>
|
|
105
|
+
<div className="truncate">{category.label}</div>
|
|
106
|
+
{ToggleButton}
|
|
107
|
+
</div>
|
|
99
108
|
</NavLink>
|
|
100
109
|
) : (
|
|
101
110
|
<div className="flex items-center justify-between w-full">
|
|
@@ -109,10 +118,9 @@ export const SidebarCategory = ({
|
|
|
109
118
|
className={cn(
|
|
110
119
|
// CollapsibleContent class is used to animate and it should only be applied when the user has triggered the toggle
|
|
111
120
|
hasInteracted && "CollapsibleContent",
|
|
112
|
-
"ms-[calc(var(--padding-nav-item)*1.125)]",
|
|
113
121
|
)}
|
|
114
122
|
>
|
|
115
|
-
<ul className="mt-1 border-l
|
|
123
|
+
<ul className="mt-1 border-l ms-0.5">
|
|
116
124
|
{category.items.map((item) => (
|
|
117
125
|
<SidebarItem
|
|
118
126
|
key={
|
|
@@ -3,7 +3,6 @@ import { ExternalLinkIcon } from "lucide-react";
|
|
|
3
3
|
import { NavLink, useSearchParams } from "react-router-dom";
|
|
4
4
|
|
|
5
5
|
import type { SidebarItem as SidebarItemType } from "../../../config/validators/SidebarSchema.js";
|
|
6
|
-
import { cn } from "../../util/cn.js";
|
|
7
6
|
import { joinPath } from "../../util/joinPath.js";
|
|
8
7
|
import { AnchorLink } from "../AnchorLink.js";
|
|
9
8
|
import { useViewportAnchor } from "../context/ViewportAnchorContext.js";
|
|
@@ -16,7 +15,8 @@ export const navigationListItem = cva(
|
|
|
16
15
|
{
|
|
17
16
|
variants: {
|
|
18
17
|
isTopLevel: {
|
|
19
|
-
true: "font-
|
|
18
|
+
true: "font-medium -mx-[--padding-nav-item]",
|
|
19
|
+
false: "-mr-[--padding-nav-item] ml-[--padding-nav-item]",
|
|
20
20
|
},
|
|
21
21
|
isActive: {
|
|
22
22
|
true: "text-primary font-medium",
|
|
@@ -27,6 +27,9 @@ export const navigationListItem = cva(
|
|
|
27
27
|
false: "",
|
|
28
28
|
},
|
|
29
29
|
},
|
|
30
|
+
defaultVariants: {
|
|
31
|
+
isActive: false,
|
|
32
|
+
},
|
|
30
33
|
},
|
|
31
34
|
);
|
|
32
35
|
|
|
@@ -58,7 +61,7 @@ export const SidebarItem = ({
|
|
|
58
61
|
{item.icon && <item.icon size={16} className="align-[-0.125em]" />}
|
|
59
62
|
{item.badge ? (
|
|
60
63
|
<>
|
|
61
|
-
<span className="truncate" title={item.label}>
|
|
64
|
+
<span className="truncate flex-1" title={item.label}>
|
|
62
65
|
{item.label}
|
|
63
66
|
</span>
|
|
64
67
|
<SidebarBadge {...item.badge} />
|
|
@@ -73,13 +76,11 @@ export const SidebarItem = ({
|
|
|
73
76
|
<AnchorLink
|
|
74
77
|
to={{ hash: item.href, search: searchParams.toString() }}
|
|
75
78
|
{...{ [DATA_ANCHOR_ATTR]: item.href.slice(1) }}
|
|
76
|
-
className={
|
|
77
|
-
|
|
78
|
-
level === 0
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}),
|
|
82
|
-
)}
|
|
79
|
+
className={navigationListItem({
|
|
80
|
+
isActive: item.href.slice(1) === activeAnchor,
|
|
81
|
+
isTopLevel: level === 0,
|
|
82
|
+
className: item.badge?.placement !== "start" && "justify-between",
|
|
83
|
+
})}
|
|
83
84
|
>
|
|
84
85
|
{item.badge ? (
|
|
85
86
|
<>
|
|
@@ -94,7 +95,9 @@ export const SidebarItem = ({
|
|
|
94
95
|
</AnchorLink>
|
|
95
96
|
) : !item.href.startsWith("http") ? (
|
|
96
97
|
<NavLink
|
|
97
|
-
className={
|
|
98
|
+
className={navigationListItem({
|
|
99
|
+
className: item.badge?.placement !== "start" && "justify-between",
|
|
100
|
+
})}
|
|
98
101
|
to={item.href}
|
|
99
102
|
>
|
|
100
103
|
{item.badge ? (
|
|
@@ -110,10 +113,7 @@ export const SidebarItem = ({
|
|
|
110
113
|
</NavLink>
|
|
111
114
|
) : (
|
|
112
115
|
<a
|
|
113
|
-
className={
|
|
114
|
-
navigationListItem({ isTopLevel: level === 0 }),
|
|
115
|
-
"block",
|
|
116
|
-
)}
|
|
116
|
+
className={navigationListItem({ isTopLevel: level === 0 })}
|
|
117
117
|
href={item.href}
|
|
118
118
|
target="_blank"
|
|
119
119
|
rel="noopener noreferrer"
|
|
@@ -121,8 +121,7 @@ export const SidebarItem = ({
|
|
|
121
121
|
<span className="whitespace-normal">{item.label}</span>
|
|
122
122
|
{/* This prevents that the icon would be positioned in its own line if the text fills a line entirely */}
|
|
123
123
|
<span className="whitespace-nowrap">
|
|
124
|
-
|
|
125
|
-
<ExternalLinkIcon className="inline ml-1" size={12} />
|
|
124
|
+
<ExternalLinkIcon className="inline -translate-y-0.5" size={12} />
|
|
126
125
|
</span>
|
|
127
126
|
</a>
|
|
128
127
|
);
|
|
@@ -60,7 +60,12 @@ export type ZudokuContextOptions = {
|
|
|
60
60
|
metadata?: Metadata;
|
|
61
61
|
page?: Page;
|
|
62
62
|
authentication?: AuthenticationProvider;
|
|
63
|
-
topNavigation?: Array<{
|
|
63
|
+
topNavigation?: Array<{
|
|
64
|
+
id: string;
|
|
65
|
+
label: string;
|
|
66
|
+
default?: string;
|
|
67
|
+
display?: "auth" | "anon" | "always";
|
|
68
|
+
}>;
|
|
64
69
|
sidebars?: SidebarConfig;
|
|
65
70
|
plugins?: DevPortalPlugin[];
|
|
66
71
|
slotlets?: Slotlets;
|
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { DeveloperHint } from "../components/DeveloperHint.js";
|
|
3
|
+
import { ZudokuError } from "../util/invariant.js";
|
|
4
|
+
|
|
5
|
+
export function ErrorAlert({ error }: { error: unknown }) {
|
|
6
|
+
const message =
|
|
7
|
+
error instanceof Error ? error.message : "Something went wrong";
|
|
8
|
+
const hint = error instanceof ZudokuError ? error.developerHint : undefined;
|
|
9
|
+
const title =
|
|
10
|
+
error instanceof ZudokuError ? error.title : "Something went wrong";
|
|
11
|
+
const stack = error instanceof Error ? error.stack : undefined;
|
|
12
|
+
const cause = error instanceof Error ? error.cause : undefined;
|
|
5
13
|
|
|
6
14
|
return (
|
|
7
15
|
<div className="flex h-screen max-h-screen min-h-full items-center justify-center bg-primary-background px-4 py-16 lg:px-8">
|
|
8
16
|
<div className="mx-auto max-w-[85%] sm:max-w-[50%]">
|
|
9
17
|
<h1 className="text-4xl font-bold tracking-tight text-h1-text sm:text-5xl">
|
|
10
|
-
|
|
18
|
+
{title}
|
|
11
19
|
</h1>
|
|
12
20
|
<p className="mt-5 text-h1-text">{message}</p>
|
|
13
|
-
{
|
|
21
|
+
{hint && <DeveloperHint className="mb-4">{hint}</DeveloperHint>}
|
|
22
|
+
{cause instanceof Error ? (
|
|
23
|
+
<pre className="mt-5 max-h-[400px] w-full overflow-scroll rounded-md border border-input-border bg-input-background p-3 text-property-name-text text-red-700">
|
|
24
|
+
{cause.stack}
|
|
25
|
+
</pre>
|
|
26
|
+
) : stack ? (
|
|
14
27
|
<pre className="mt-5 max-h-[400px] w-full overflow-scroll rounded-md border border-input-border bg-input-background p-3 text-property-name-text text-red-700">
|
|
15
28
|
{stack}
|
|
16
29
|
</pre>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ProseClasses } from "../../components/Markdown.js";
|
|
3
|
+
import { cn } from "../../util/cn.js";
|
|
4
|
+
import { useExposedProps } from "../../util/useExposedProps.js";
|
|
5
|
+
import type { CustomPageConfig } from "./index.js";
|
|
6
|
+
|
|
7
|
+
export const CustomPage = ({
|
|
8
|
+
element,
|
|
9
|
+
render,
|
|
10
|
+
prose = true,
|
|
11
|
+
}: Omit<CustomPageConfig, "path">) => {
|
|
12
|
+
const slotletProps = useExposedProps();
|
|
13
|
+
const content = render ? React.createElement(render, slotletProps) : element;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className={cn(prose && ProseClasses, "max-w-full")}>{content}</div>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -1,22 +1,24 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ComponentType, type ReactNode } from "react";
|
|
2
2
|
import type { RouteObject } from "react-router-dom";
|
|
3
|
-
import {
|
|
3
|
+
import { type ExposedComponentProps } from "../../components/SlotletProvider.js";
|
|
4
4
|
import type { DevPortalPlugin, NavigationPlugin } from "../../core/plugins.js";
|
|
5
|
+
import { CustomPage } from "./CustomPage.js";
|
|
5
6
|
|
|
6
|
-
type
|
|
7
|
+
export type CustomPageConfig = {
|
|
7
8
|
path: string;
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
prose?: boolean;
|
|
10
|
+
element?: ReactNode;
|
|
11
|
+
render?: ComponentType<ExposedComponentProps>;
|
|
12
|
+
};
|
|
10
13
|
|
|
11
14
|
export const customPagesPlugin = (
|
|
12
|
-
config:
|
|
15
|
+
config: CustomPageConfig[],
|
|
13
16
|
): DevPortalPlugin & NavigationPlugin => {
|
|
14
17
|
return {
|
|
15
18
|
getRoutes: (): RouteObject[] =>
|
|
16
|
-
config.map(({ path,
|
|
19
|
+
config.map(({ path, ...props }) => ({
|
|
17
20
|
path,
|
|
18
|
-
|
|
19
|
-
element: <div className={ProseClasses + " max-w-full"}>{element}</div>,
|
|
21
|
+
element: <CustomPage {...props} />,
|
|
20
22
|
})),
|
|
21
23
|
};
|
|
22
24
|
};
|
|
@@ -68,14 +68,16 @@ export const MdxPage = ({
|
|
|
68
68
|
"max-w-full xl:w-full xl:max-w-prose flex-1 flex-shrink pt-[--padding-content-top] pb-[--padding-content-bottom]",
|
|
69
69
|
)}
|
|
70
70
|
>
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{title}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
{(category || title) && (
|
|
72
|
+
<header>
|
|
73
|
+
{category && <CategoryHeading>{category}</CategoryHeading>}
|
|
74
|
+
{title && (
|
|
75
|
+
<Heading level={1} id={slugify(title)}>
|
|
76
|
+
{title}
|
|
77
|
+
</Heading>
|
|
78
|
+
)}
|
|
79
|
+
</header>
|
|
80
|
+
)}
|
|
79
81
|
<MdxComponent
|
|
80
82
|
components={{ ...useMDXComponents(), ...MarkdownHeadings }}
|
|
81
83
|
/>
|
|
@@ -18,9 +18,21 @@ export default function invariant(
|
|
|
18
18
|
throw new ZudokuError(provided ?? "Invariant failed");
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
class ZudokuError extends Error {
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
export class ZudokuError extends Error {
|
|
22
|
+
public developerHint: string | undefined;
|
|
23
|
+
public title: string | undefined;
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
message: string,
|
|
27
|
+
{
|
|
28
|
+
developerHint,
|
|
29
|
+
title,
|
|
30
|
+
cause,
|
|
31
|
+
}: { developerHint?: string; title?: string; cause?: Error } = {},
|
|
32
|
+
) {
|
|
33
|
+
super(message, { cause });
|
|
24
34
|
this.name = "ZudokuError";
|
|
35
|
+
this.title = title;
|
|
36
|
+
this.developerHint = developerHint;
|
|
25
37
|
}
|
|
26
38
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
|
|
2
|
+
import type { ExposedComponentProps } from "../components/SlotletProvider.js";
|
|
3
|
+
|
|
4
|
+
export const useExposedProps = (): ExposedComponentProps => {
|
|
5
|
+
const location = useLocation();
|
|
6
|
+
const navigate = useNavigate();
|
|
7
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
8
|
+
|
|
9
|
+
return { location, navigate, searchParams, setSearchParams };
|
|
10
|
+
};
|