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:
30
components/loader.tsx
Normal file
30
components/loader.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { FC } from "react";
|
||||
|
||||
export const Loader: FC = () => {
|
||||
const tragedy = [
|
||||
"Did you ever hear the tragedy of Darth Plagueis the Wise?",
|
||||
"No.",
|
||||
"I thought not. It's not a story the Jedi would tell you. It's a Sith legend. Darth Plagueis... was a Dark Lord of the Sith so powerful and so wise, he could use the Force to influence the midi-chlorians... to create... life. He had such a knowledge of the dark side, he could even keep the ones he cared about... from dying.",
|
||||
"He could actually... save people from death?",
|
||||
"The dark side of the Force is a pathway to many abilities... some consider to be unnatural.",
|
||||
"Wh– What happened to him?",
|
||||
"He became so powerful, the only thing he was afraid of was... losing his power. Which eventually, of course, he did. Unfortunately, he taught his apprentice everything he knew. Then his apprentice killed him in his sleep. It's ironic. He could save others from death, but not himself.",
|
||||
"Is it possible to learn this power?",
|
||||
"Not from a Jedi.",
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="heading">
|
||||
<h2 className="strapline skeleton">Do It</h2>
|
||||
<h1 className="skeleton">Kill him. Kill him now.</h1>
|
||||
</section>
|
||||
<section>
|
||||
{tragedy.map((t) => <p key={t} className=".skeleton">{t}</p>)}
|
||||
</section>
|
||||
</>
|
||||
// <div className="mx-auto text-9xl flex justify-center py-24">
|
||||
// Wrangling Cats...
|
||||
// </div>
|
||||
);
|
||||
};
|
@@ -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