92 lines
2.2 KiB
TypeScript

import { createElements } from "@/lib/tcmd";
import React, { FC, Suspense, useEffect, useMemo, useState } from "react";
import { MDSkeletonLoader } from "../loader";
import { DevTool } from "../devtools/DevTool";
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(() => {
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]);
return (
<Suspense fallback={<MDSkeletonLoader />}>
<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
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>
);
};
function renderer(tokens: Token[]) {
return tokens.map((t) => <div className="p" key={t.uuid}>{t.render(t)}</div>);
}