ttcmd: adds hr element
help pages: adds a way to extract the table of contents to the parent, smoothes out the rough loading on help pages
This commit is contained in:
@@ -4,36 +4,89 @@ import { Accordion, AccordionContent } from "@/lib/accordion";
|
||||
import { Poppable } from "@/lib/poppables/components/poppable";
|
||||
import { createElements } from "@/lib/tcmd";
|
||||
import Link from "next/link";
|
||||
import React, { FC, Fragment, ReactNode, use, useMemo } from "react";
|
||||
import React, {
|
||||
FC,
|
||||
Fragment,
|
||||
Suspense,
|
||||
use,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
import { sanitize } from "isomorphic-dompurify";
|
||||
import StaticGenerationSearchParamsBailoutProvider from "next/dist/client/components/static-generation-searchparams-bailout-provider";
|
||||
import { Loader } from "../loader";
|
||||
|
||||
export const TTCMD: FC<
|
||||
{ body: string; escapeTOC?: (tokens: Token[]) => boolean }
|
||||
> = ({ body, escapeTOC = () => false }) => {
|
||||
const elements = useMemo(() => createElements(body), [body]);
|
||||
|
||||
const [toc, start, end] = useMemo(() => {
|
||||
const tocHead = elements.findIndex((t) =>
|
||||
t.content.includes("Table of Contents")
|
||||
);
|
||||
if (tocHead > -1) {
|
||||
const hr = elements.slice(tocHead).findIndex((t) => t.type === "hr");
|
||||
if (hr > -1) {
|
||||
const end = hr + 1;
|
||||
return [elements.slice(tocHead, end), tocHead, end - tocHead];
|
||||
}
|
||||
}
|
||||
return [[], 0, 0];
|
||||
}, [elements]);
|
||||
|
||||
// const hasEscapedTOC = useMemo(() => toc && escapeTOC(toc), [escapeTOC, toc])
|
||||
const [hasEscapedTOC, setHasEscapedTOC] = useState<boolean>();
|
||||
|
||||
useEffect(() => {
|
||||
setHasEscapedTOC(escapeTOC(toc));
|
||||
}, [escapeTOC, toc]);
|
||||
|
||||
export const TTCMD: FC<{ body: Promise<string> }> = ({ body }) => {
|
||||
"use client";
|
||||
const text = use(body);
|
||||
const [elements, tabSpacing] = useMemo(() => createElements(text), [text]);
|
||||
const tada = useMemo(
|
||||
() => <>{renderer(elements.map((e) => e.token))}</>,
|
||||
[elements],
|
||||
);
|
||||
return (
|
||||
<div className="text-lg col-span-2">
|
||||
<div>
|
||||
<button
|
||||
className="btn-primary"
|
||||
onClick={() =>
|
||||
navigator.clipboard.writeText(JSON.stringify(elements, null, 2))}
|
||||
>
|
||||
copy ast
|
||||
</button>
|
||||
</div>
|
||||
{/* {elements.map((e, i) => <Fragment key={e.uuid}>{render(e)}</Fragment>)} */}
|
||||
<Suspense fallback={<Loader />}>
|
||||
{
|
||||
/* <button
|
||||
className="btn-primary"
|
||||
onClick={() =>
|
||||
navigator.clipboard.writeText(JSON.stringify(elements, null, 2))}
|
||||
>
|
||||
copy ast
|
||||
</button> */
|
||||
}
|
||||
{hasEscapedTOC !== undefined &&
|
||||
(
|
||||
<TTCMDRenderer
|
||||
tokens={hasEscapedTOC
|
||||
? [...elements].toSpliced(start, end)
|
||||
: elements}
|
||||
/>
|
||||
)}
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
||||
export const TTCMDRenderer: FC<{ tokens: Token[] }> = ({ tokens }) => {
|
||||
const tada = useMemo(
|
||||
() => (
|
||||
<>
|
||||
{renderer(tokens)}
|
||||
</>
|
||||
),
|
||||
[tokens],
|
||||
);
|
||||
if (!tokens.length) {
|
||||
const audio = new Audio(
|
||||
"https://assets.mixkit.co/active_storage/sfx/221/221-preview.mp3",
|
||||
);
|
||||
audio.onload = () => {
|
||||
audio.play();
|
||||
};
|
||||
}
|
||||
return (
|
||||
<div className="text-lg">
|
||||
{tada}
|
||||
</div>
|
||||
// <div className="grid grid-cols-3">
|
||||
// {/* <pre suppressHydrationWarning>{JSON.stringify(elements,null,2)}</pre> */}
|
||||
// </div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -214,6 +267,8 @@ function render(token: Token, usedIds: string[]) {
|
||||
{token.children?.map((c) => render(c, usedIds))}
|
||||
</li>
|
||||
);
|
||||
case "hr":
|
||||
return <div className="w-full border-b border-mixed-500 my-3"></div>;
|
||||
default:
|
||||
return (
|
||||
<div className="p bg-red-600 text-white">
|
||||
|
Reference in New Issue
Block a user