"use client"; import { Accordion, AccordionContent } from "@/lib/accordion"; import { Poppable } from "@/lib/poppables/components/poppable"; import { buildAbstractSyntaxTree, createElements } from "@/lib/tcmd"; import Link from "next/link"; import React, { FC, Fragment, ReactNode, use, useMemo } from "react"; import { sanitize } from "isomorphic-dompurify"; import StaticGenerationSearchParamsBailoutProvider from "next/dist/client/components/static-generation-searchparams-bailout-provider"; export const TTCMD: FC<{ body: Promise }> = ({ body }) => { const text = use(body); const [elements, tabSpacing] = useMemo(() => createElements(text), [text]); return (
{/* {elements.map((e, i) => {render(e)})} */} {renderer(elements, tabSpacing)}
//
// {/*
{JSON.stringify(elements,null,2)}
*/} //
); }; const renderer = (tokens: Token[], tabSpacing: number) => { const usedIds: string[] = []; return tokens.map((t) => ( {render(t, usedIds, tabSpacing)} )); }; const render = (token: Token, usedIds: string[], tabSpacing: number) => { switch (token.type) { case "heading": return (
{token.content}
); case "grid": return (
{token.children?.map((c, i) => (
{render(c, usedIds, tabSpacing)}
))}
); case "code": return (
          {token.content}
        
); case "card": return (
{token.children?.map((e) => ( {render(e, usedIds, tabSpacing)} ))}
); case "anchor": return ( {token.content} ); case "image": { token.metadata.src = token.metadata.src as string; if (token.metadata.src.startsWith(" ); } // eslint-disable-next-line @next/next/no-img-element return {token.content}; } case "inline-code": return ( {token.content} ); case "popover": return ( render(c, usedIds, tabSpacing)) || token.content} preferredAlign="centered" preferredEdge="bottom" className="cursor-pointer mx-2" > {token.metadata.title} ); case "text": return {token.content}; case "p": return (
{token.children?.map((e, i) => ( {render(e, usedIds, tabSpacing)} ))}
); case "accordion": return (
{token.children?.map((e, i) => ( {render(e, usedIds, tabSpacing)} ))}
); default: return (
Block or paragraph missing implementation: {token.type}
); } }; const renderBlock = ( block: BlockChildren, usedIds: string[] = [], ): ReactNode => { usedIds = usedIds || []; switch (block.type) { case "block": return block.children.map((e, i) => ( {renderBlock(e, usedIds)} )); case "grid": return (
{block.children.map((c, i) => (
{renderBlock(c, usedIds)}
))}
); case "card": return (
{block.children.map((e, i) => ( {renderBlock(e, usedIds)} ))}
); case "accordion": return (
{block.children.map((e, i) => ( {renderBlock(e, usedIds)} ))}
); default: return ( renderParagraph(block as ParagraphToken, usedIds) ); } }; const renderParagraph = (p: ParagraphToken, usedIds: string[]) => { switch (p.type) { case "p": return (
{p.content.map((e, i) => ( {renderToken(e, usedIds)} ))}
); case "code": return (
          {p.content.map((c) => c.line.toString()).join("\n\n")}
        
); default: return (
Block or paragraph missing implementation: {p.type}
); } }; const generateId = (t: string, usedIds: string[]) => { let id = t.toLowerCase().replace(/[^a-z\s]/ig, "").trim().replaceAll( " ", "-", ); let idNum = 1; while (usedIds.includes(id)) { id = id.replace(/-[0-9]+$/g, ""); id += "-" + idNum; idNum++; } return id; }; const renderToken = (t: Token, usedIds: string[]) => { switch (t.type) { case "h1": { return (
{renderInlineToken(t.line)}
); } case "h2": { return (
{renderInlineToken(t.line)}
); } case "h3": { return (
{renderInlineToken(t.line)}
); } case "p": return (
{t.lines.map((e, i) => ( {renderInlineToken(e.line)} ))}
); case "text": return ( <> {renderInlineToken(t.line)}   ); case "list1": return
  • {renderInlineToken(t.line)}
  • ; case "list2": return
  • {renderInlineToken(t.line)}
  • ; default: return (
    Missing implementation for tcMD element `{(t as { type: string }) .type}`
    ); } }; const renderInlineToken = (l: Line) => { if (typeof l === "string") return l; return l.map((token) => ( {(() => { switch (token.type) { case "text": return {token.content}; case "bold": return {token.content}; case "italic": return {token.content}; case "anchor": return ( {token.content} ); case "image": { token.data.src = token.data.src as string; if (token.data.src.startsWith(" ); } // eslint-disable-next-line @next/next/no-img-element return {token.content}; } case "popover": return ( {token.content} ); case "inline-code": return ( {token.content} ); default: return ( Inline element not implemented: {token.type} ); } })()} )); };