Skip to content

Commit

Permalink
Replace old dev portal stuff with Zudoku (#345)
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-lee authored Nov 21, 2024
1 parent 09ed7df commit 3aab44f
Show file tree
Hide file tree
Showing 19 changed files with 179 additions and 193 deletions.
8 changes: 4 additions & 4 deletions packages/zudoku/src/app/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { configuredRedirectPlugin } from "virtual:zudoku-redirect-plugin";
import { configuredSearchPlugin } from "virtual:zudoku-search-plugin";
import { configuredSidebar } from "virtual:zudoku-sidebar";
import "virtual:zudoku-theme.css";
import { DevPortal, Layout, RouterError } from "zudoku/components";
import { Layout, RouterError, Zudoku } from "zudoku/components";
import type { ZudokuConfig } from "../config/config.js";
import type { ZudokuContextOptions } from "../lib/core/DevPortalContext.js";
import type { ZudokuContextOptions } from "../lib/core/ZudokuContext.js";
import { isNavigationPlugin } from "../lib/core/plugins.js";

export const convertZudokuConfigToOptions = (
Expand Down Expand Up @@ -92,9 +92,9 @@ export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
return [
{
element: (
<DevPortal {...options}>
<Zudoku {...options}>
<Layout />
</DevPortal>
</Zudoku>
),
children: [
{
Expand Down
16 changes: 8 additions & 8 deletions packages/zudoku/src/config/validators/validate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Options } from "@mdx-js/rollup";
import type { ComponentType, ReactNode } from "react";
import type { DevPortalPlugin } from "src/lib/core/plugins.js";
import type { ZudokuPlugin } from "src/lib/core/plugins.js";
import z, {
type ZodEnumDef,
ZodOptional,
Expand All @@ -10,7 +10,7 @@ import z, {
} from "zod";
import { fromError } from "zod-validation-error";
import type { ExposedComponentProps } from "../../lib/components/SlotletProvider.js";
import { DevPortalContext } from "../../lib/core/DevPortalContext.js";
import { ZudokuContext } from "../../lib/core/ZudokuContext.js";
import type { ApiKey } from "../../lib/plugins/api-keys/index.js";
import type { MdxComponentsType } from "../../lib/util/MdxComponents.js";
import { InputSidebarSchema } from "./InputSidebarSchema.js";
Expand Down Expand Up @@ -64,32 +64,32 @@ const ApiKeysSchema = z.union([
}),
z.object({
enabled: z.boolean(),
getKeys: z.custom<(context: DevPortalContext) => Promise<ApiKey[]>>(
getKeys: z.custom<(context: ZudokuContext) => Promise<ApiKey[]>>(
(val) => typeof val === "function",
),
rollKey: z
.custom<
(id: string, context: DevPortalContext) => Promise<void>
(id: string, context: ZudokuContext) => Promise<void>
>((val) => typeof val === "function")
.optional(),
deleteKey: z
.custom<
(id: string, context: DevPortalContext) => Promise<void>
(id: string, context: ZudokuContext) => Promise<void>
>((val) => typeof val === "function")
.optional(),
updateKeyDescription: z
.custom<
(
apiKey: { id: string; description: string },
context: DevPortalContext,
context: ZudokuContext,
) => Promise<void>
>((val) => typeof val === "function")
.optional(),
createKey: z
.custom<
(
apiKey: { description: string; expiresOn?: string },
context: DevPortalContext,
context: ZudokuContext,
) => Promise<void>
>((val) => typeof val === "function")
.optional(),
Expand Down Expand Up @@ -286,7 +286,7 @@ const ConfigSchema = z
prose: z.boolean().optional(),
}),
),
plugins: z.array(z.custom<DevPortalPlugin>()),
plugins: z.array(z.custom<ZudokuPlugin>()),
sitemap: SiteMapSchema,
build: z.custom<{
remarkPlugins?: Options["remarkPlugins"];
Expand Down
7 changes: 2 additions & 5 deletions packages/zudoku/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@ export type {
export type { ExposedComponentProps } from "./lib/components/SlotletProvider.js";
export type { MDXImport } from "./lib/plugins/markdown/index.js";

export {
DevPortalContext,
type ApiIdentity,
} from "./lib/core/DevPortalContext.js";
export type {
ApiIdentityPlugin,
CommonPlugin,
DevPortalPlugin,
NavigationPlugin,
ProfileMenuPlugin,
ProfileNavigationItem,
RouteObject,
SearchProviderPlugin,
ZudokuPlugin,
} from "./lib/core/plugins.js";
export { ZudokuContext, type ApiIdentity } from "./lib/core/ZudokuContext.js";
export type { MdxComponentsType } from "./lib/util/MdxComponents.js";
4 changes: 2 additions & 2 deletions packages/zudoku/src/lib/authentication/authentication.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { DevPortalPlugin } from "../core/plugins.js";
import { ZudokuPlugin } from "../core/plugins.js";

export interface AuthenticationProvider {
signUp(options?: { redirectTo?: string }): Promise<void>;
signIn(options?: { redirectTo?: string }): Promise<void>;
signOut(): Promise<void>;
getAccessToken(): Promise<string>;
pageLoad?(): void;
getAuthenticationPlugin?(): DevPortalPlugin;
getAuthenticationPlugin?(): ZudokuPlugin;
}

export interface AuthenticationProviderInitializer<TConfig> {
Expand Down
111 changes: 0 additions & 111 deletions packages/zudoku/src/lib/components/DevPortal.tsx

This file was deleted.

113 changes: 113 additions & 0 deletions packages/zudoku/src/lib/components/Zudoku.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { MDXProvider } from "@mdx-js/react";
import { QueryClientProvider } from "@tanstack/react-query";
import { Helmet } from "@zudoku/react-helmet-async";
import {
Fragment,
memo,
type PropsWithChildren,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import { ErrorBoundary } from "react-error-boundary";
import { Outlet, useNavigation } from "react-router-dom";
import { hasHead, isMdxProviderPlugin } from "../core/plugins.js";
import {
queryClient,
ZudokuContext,
ZudokuContextOptions,
} from "../core/ZudokuContext.js";
import { TopLevelError } from "../errors/TopLevelError.js";
import { StaggeredRenderContext } from "../plugins/openapi/StaggeredRender.js";
import { MdxComponents } from "../util/MdxComponents.js";
import "../util/requestIdleCallbackPolyfill.js";
import {
ComponentsProvider,
DEFAULT_COMPONENTS,
} from "./context/ComponentsContext.js";
import { ThemeProvider } from "./context/ThemeProvider.js";
import { ViewportAnchorProvider } from "./context/ViewportAnchorContext.js";
import { ZudokuProvider } from "./context/ZudokuProvider.js";
import { SlotletProvider } from "./SlotletProvider.js";

const ZudokoInner = memo(
({ children, ...props }: PropsWithChildren<ZudokuContextOptions>) => {
const components = useMemo(
() => ({ ...DEFAULT_COMPONENTS, ...props.overrides }),
[props.overrides],
);

const mdxComponents = useMemo(() => {
const componentsFromPlugins = (props.plugins ?? [])
.filter(isMdxProviderPlugin)
.flatMap((plugin) =>
plugin.getMdxComponents ? [plugin.getMdxComponents()] : [],
);

return {
...componentsFromPlugins.reduce(
(acc, curr) => ({ ...acc, ...curr }),
{},
),
...MdxComponents,
...props.mdx?.components,
};
}, [props.mdx?.components, props.plugins]);
const { stagger } = useContext(StaggeredRenderContext);
const [didNavigate, setDidNavigate] = useState(false);
const staggeredValue = useMemo(
() => (didNavigate ? { stagger: true } : { stagger }),
[stagger, didNavigate],
);
const navigation = useNavigation();

useEffect(() => {
if (didNavigate) {
return;
}
setDidNavigate(true);
}, [didNavigate, navigation.location]);

const [zudokuContext] = useState(() => new ZudokuContext(props));

const heads = props.plugins
?.filter(hasHead)
// eslint-disable-next-line react/no-array-index-key
.map((plugin, i) => <Fragment key={i}>{plugin.getHead?.()}</Fragment>);

return (
<QueryClientProvider client={queryClient}>
<Helmet>{heads}</Helmet>
<StaggeredRenderContext.Provider value={staggeredValue}>
<ZudokuProvider context={zudokuContext}>
<MDXProvider components={mdxComponents}>
<ThemeProvider>
<ComponentsProvider value={components}>
<SlotletProvider slotlets={props.slotlets}>
<ViewportAnchorProvider>
{children ?? <Outlet />}
</ViewportAnchorProvider>
</SlotletProvider>
</ComponentsProvider>
</ThemeProvider>
</MDXProvider>
</ZudokuProvider>
</StaggeredRenderContext.Provider>
</QueryClientProvider>
);
},
);

ZudokoInner.displayName = "ZudokoInner";

const Zudoku = (props: ZudokuContextOptions) => {
return (
<ErrorBoundary FallbackComponent={TopLevelError}>
<ZudokoInner {...props} />
</ErrorBoundary>
);
};
Zudoku.displayName = "Zudoku";

export { Zudoku };
6 changes: 3 additions & 3 deletions packages/zudoku/src/lib/components/context/ZudokuContext.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
import { createContext, useContext } from "react";
import { matchPath, useLocation } from "react-router-dom";
import { DevPortalContext } from "../../core/DevPortalContext.js";
import { ZudokuContext } from "../../core/ZudokuContext.js";
import { joinPath } from "../../util/joinPath.js";
import { traverseSidebar } from "../navigation/utils.js";

export const ZudokuReactContext = createContext<DevPortalContext | undefined>(
export const ZudokuReactContext = createContext<ZudokuContext | undefined>(
undefined,
);

export const useZudoku = () => {
const context = useContext(ZudokuReactContext);

if (!context) {
throw new Error("useDevPortal must be used within a DevPortalProvider.");
throw new Error("useZudoku must be used within a ZudokuProvider.");
}

return context;
Expand Down
4 changes: 2 additions & 2 deletions packages/zudoku/src/lib/components/context/ZudokuProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useSuspenseQuery } from "@tanstack/react-query";
import type { PropsWithChildren } from "react";
import { DevPortalContext } from "../../core/DevPortalContext.js";
import { ZudokuContext } from "../../core/ZudokuContext.js";
import { ZudokuReactContext } from "./ZudokuContext.js";

export const ZudokuProvider = ({
children,
context,
}: PropsWithChildren<{ context: DevPortalContext }>) => {
}: PropsWithChildren<{ context: ZudokuContext }>) => {
useSuspenseQuery({
queryFn: async () => {
await context.initialize();
Expand Down
Loading

0 comments on commit 3aab44f

Please sign in to comment.