/// import { type Cell, Default, handler, lift, recipe, str } from "commontools"; interface MarkdownPreviewArgs { initialContent: Default; preview: Default; } type UpdateContentEvent = { text?: unknown; }; const sanitizeContent = (value: unknown): string => { return typeof value === "string" ? value : ""; }; const sanitizePreview = (value: unknown): boolean => { return value === true; }; const formatMarkdown = (raw: string): string => { const lines = raw.split(/\r?\n/); return lines .map((line) => { if (line.startsWith("### ")) { return `

${line.slice(4).trim()}

`; } if (line.startsWith("## ")) { return `

${line.slice(3).trim()}

`; } if (line.startsWith("# ")) { return `

${line.slice(2).trim()}

`; } const formattedBold = line.replaceAll( /\*\*(.+?)\*\*/g, (_match, content: string) => `${content}`, ); const formattedItalic = formattedBold.replaceAll( /_(.+?)_/g, (_match, content: string) => `${content}`, ); return formattedItalic; }) .join("\n"); }; const updateContent = handler( ( event: UpdateContentEvent | undefined, context: { content: Cell }, ) => { const next = sanitizeContent(event?.text); context.content.set(next); }, ); const togglePreview = handler( (_event: unknown, context: { preview: Cell }) => { const current = sanitizePreview(context.preview.get()); context.preview.set(!current); }, ); export const markdownPreviewToggle = recipe( "Markdown Preview Toggle", ({ initialContent, preview }) => { const content = lift(sanitizeContent)(initialContent); const previewEnabled = lift(sanitizePreview)(preview); const previewText = lift((value: string) => formatMarkdown(value))( content, ); const modeLabel = lift((enabled: boolean) => enabled ? "Preview" : "Raw")( previewEnabled, ); const activeView = lift( ({ enabled, raw, formatted }: { enabled: boolean; raw: string; formatted: string; }) => (enabled ? formatted : raw), )({ enabled: previewEnabled, raw: content, formatted: previewText, }); const summary = str`${modeLabel} view — ${activeView}`; return { content, previewEnabled, previewText, activeView, summary, togglePreview: togglePreview({ preview }), updateContent: updateContent({ content: initialContent }), }; }, );