toolbox: adds devtoolbox to easily manage debug components

This commit is contained in:
2024-03-16 09:18:16 -06:00
parent 9cbd0a62ca
commit df20a47253
11 changed files with 181 additions and 32 deletions

View File

@@ -0,0 +1,52 @@
import { Portal } from "@/lib/portal/components";
import { FC, PropsWithChildren, use, useEffect, useState } from "react";
import { DevToolboxContext } from "./context";
import { WrenchScrewdriverIcon } from "@heroicons/react/24/solid";
import { XMarkIcon } from "@heroicons/react/16/solid";
export const DevToolbox: FC = () => {
const { tools, shouldShowDevTools } = use(DevToolboxContext);
const [open, setOpen] = useState(false);
return shouldShowDevTools
? (
<Portal>
<div className="dev-portal flex flex-col gap-2 fixed bottom-2 right-2 border rounded-lg bg-black/50">
{open
? (
<div className="relative p-2">
<button
className="p-1 absolute top-2 right-2"
onClick={() => setOpen(!open)}
>
<XMarkIcon className="w-3 h-3">
</XMarkIcon>
</button>
<p className="mb-4 mr-8">Dev Toolbox</p>
{Object.values(tools)}
</div>
)
: (
<div>
<button className="p-4" onClick={() => setOpen(!open)}>
<WrenchScrewdriverIcon className="w-4 h-4">
</WrenchScrewdriverIcon>
</button>
</div>
)}
</div>
</Portal>
)
: <></>;
};
export const DevTool: FC<PropsWithChildren<{ id: string }>> = (
{ children, id },
) => {
const { addTool, removeTool } = use(DevToolboxContext);
useEffect(() => {
addTool(id, children);
(() => removeTool(id));
}, [addTool, children, id, removeTool]);
return <></>;
};

View File

@@ -0,0 +1,66 @@
"use client";
import {
createContext,
Dispatch,
FC,
PropsWithChildren,
ReactNode,
SetStateAction,
useCallback,
useEffect,
useState,
} from "react";
import { DevToolbox } from "./Toolbox";
interface ContextProps {
tools: Record<string, ReactNode>;
addTool: (key: string, r: ReactNode) => void;
removeTool: (key: string) => void;
shouldShowDevTools: boolean;
setShouldShowDevTools: Dispatch<SetStateAction<boolean>>;
}
export const DevToolboxContext = createContext<ContextProps>({
tools: {},
addTool: () => {},
removeTool: () => {},
shouldShowDevTools: false,
setShouldShowDevTools: () => {},
});
export const DevToolboxContextProvider: FC<
PropsWithChildren<{ isDev: boolean }>
> = (
{ children, isDev },
) => {
console.log(isDev);
const [tools, setTools] = useState<Record<string, ReactNode>>({});
const [shouldShowDevTools, setShouldShowDevTools] = useState(isDev);
const addTool = useCallback((key: string, r: ReactNode) => {
setTools((t) => ({ ...t, [key]: r }));
}, []);
const removeTool = useCallback((key: string) => {
setTools((t) => ({ ...t, [key]: undefined }));
}, []);
useEffect(() => {
if (localStorage.getItem("dev")) setShouldShowDevTools(true);
}, []);
return (
<DevToolboxContext.Provider
value={{
tools,
addTool,
removeTool,
shouldShowDevTools,
setShouldShowDevTools,
}}
>
{children}
<DevToolbox></DevToolbox>
</DevToolboxContext.Provider>
);
};

View File

@@ -72,7 +72,7 @@ export const MDSkeletonLoader: FC = () => {
i,
) => (
<li
key={t}
key={t + i}
className={"my-2 leading-8 text-black/20 " + indentation[
i === 0 ? 0 : Math.floor(Math.random() * indentation.length)
]}

View File

@@ -1,13 +1,19 @@
"use client";
import { createElements } from "@/lib/tcmd";
import React, { FC, Suspense, useEffect, useMemo, useState } from "react";
import { MDSkeletonLoader } from "../loader";
import { DevTool } from "../devtools/Toolbox";
export const TTCMD: FC<
{ body: string; escapeTOC?: (tokens: Token[]) => boolean }
> = ({ body, escapeTOC = () => false }) => {
interface Props {
body: string;
escapeTOC?: (tokens: Token[]) => boolean;
parserId: string;
title: string;
}
export const TTCMD: FC<Props> = (
{ body, parserId, escapeTOC = () => false, title },
) => {
const elements = useMemo(() => createElements(body), [body]);
const [toc, start, end] = useMemo(() => {
@@ -31,15 +37,19 @@ export const TTCMD: FC<
setHasEscapedTOC(escapeTOC(toc));
}, [escapeTOC, toc]);
console.log("mdId", parserId);
return (
<Suspense fallback={<MDSkeletonLoader />}>
<button
className="btn-primary"
onClick={() =>
navigator.clipboard.writeText(JSON.stringify(elements, null, 2))}
>
copy ast
</button>
<DevTool id={parserId}>
<button
className="btn-primary"
onClick={() =>
navigator.clipboard.writeText(JSON.stringify(elements, null, 2))}
>
Copy AST for {title}
</button>
</DevTool>
{hasEscapedTOC !== undefined &&
(
<TTCMDRenderer