From c386a1acfab0db99af57a9a18a49c72b89184f15 Mon Sep 17 00:00:00 2001 From: Clawd Date: Sat, 28 Feb 2026 13:48:34 -0800 Subject: Replace custom markdown renderer with react-markdown - Add react-markdown and remark-gfm dependencies - Remove hacky regex-based renderMarkdown function - Full GFM support: tables, task lists, strikethrough, autolinks - Update CSS for react-markdown output (task lists, blockquotes, hr) - Cleaner, more maintainable code --- renderer/src/components/DocumentPane.tsx | 183 ++++++++++--------------------- 1 file changed, 59 insertions(+), 124 deletions(-) (limited to 'renderer/src/components') diff --git a/renderer/src/components/DocumentPane.tsx b/renderer/src/components/DocumentPane.tsx index c2e1b2c..95d7d03 100644 --- a/renderer/src/components/DocumentPane.tsx +++ b/renderer/src/components/DocumentPane.tsx @@ -1,4 +1,6 @@ -import React, { useState, useMemo } from "react"; +import React, { useState } from "react"; +import ReactMarkdown from "react-markdown"; +import remarkGfm from "remark-gfm"; import type { Phase } from "../types"; interface DocumentPaneProps { @@ -9,108 +11,6 @@ interface DocumentPaneProps { showOnboarding?: boolean; } -function renderTable(tableLines: string[]): string { - if (tableLines.length < 2) return tableLines.join("\n"); - - const parseRow = (line: string): string[] => { - return line - .split("|") - .slice(1, -1) // Remove empty first/last from |col|col| - .map((cell) => cell.trim()); - }; - - const headerCells = parseRow(tableLines[0]); - // Skip separator row (index 1) - const bodyRows = tableLines.slice(2); - - let html = ''; - headerCells.forEach((cell) => { - html += ``; - }); - html += ''; - - bodyRows.forEach((row) => { - if (row.trim()) { - html += ''; - parseRow(row).forEach((cell) => { - html += ``; - }); - html += ''; - } - }); - - html += '
${cell}
${cell}
'; - return html; -} - -function renderMarkdown(md: string): string { - // First, handle tables (before other transformations) - const lines = md.split("\n"); - const processedLines: string[] = []; - let tableBuffer: string[] = []; - let inTable = false; - - for (const line of lines) { - const isTableLine = /^\|.*\|$/.test(line.trim()); - - if (isTableLine) { - inTable = true; - tableBuffer.push(line); - } else { - if (inTable && tableBuffer.length > 0) { - processedLines.push(renderTable(tableBuffer)); - tableBuffer = []; - inTable = false; - } - processedLines.push(line); - } - } - - // Handle table at end of content - if (tableBuffer.length > 0) { - processedLines.push(renderTable(tableBuffer)); - } - - let result = processedLines.join("\n"); - - return ( - result - // Headers - .replace(/^### (.*$)/gm, "

$1

") - .replace(/^## (.*$)/gm, "

$1

") - .replace(/^# (.*$)/gm, "

$1

") - // Bold/italic - .replace(/\*\*([^*]+)\*\*/g, "$1") - .replace(/\*([^*]+)\*/g, "$1") - // Code blocks - .replace( - /```(\w*)\n([\s\S]*?)```/g, - '
$2
' - ) - .replace(/`([^`]+)`/g, "$1") - // Lists - .replace(/^- \[x\] (.*$)/gm, '
  • ☑ $1
  • ') - .replace(/^- \[ \] (.*$)/gm, '
  • ☐ $1
  • ') - .replace(/^- (.*$)/gm, "
  • $1
  • ") - // Review comments (highlight them) - .replace(/(\/\/ REVIEW:.*$)/gm, '$1') - .replace(/(\/\/ NOTE:.*$)/gm, '$1') - // Paragraphs - .replace(/\n\n/g, "

    ") - .replace(/^(.+)$/gm, "

    $1

    ") - // Clean up - .replace(/

    <\/p>/g, "") - .replace(/

    ()/g, "$1") - .replace(/(<\/h[1-3]>)<\/p>/g, "$1") - .replace(/

    (

    )/g, "$1")
    -      .replace(/(<\/pre>)<\/p>/g, "$1")
    -      .replace(/

    ()<\/p>/g, "$1") - .replace(/

    ()/g, "$1") - .replace(/(<\/table>)<\/p>/g, "$1") - ); -} - export function DocumentPane({ content, onChange, @@ -119,7 +19,6 @@ export function DocumentPane({ showOnboarding, }: DocumentPaneProps) { const [isEditing, setIsEditing] = useState(false); - const renderedHtml = useMemo(() => renderMarkdown(content), [content]); if (showOnboarding) { return ( @@ -130,27 +29,61 @@ export function DocumentPane({

    Claude Flow

    - A structured workflow for AI-assisted coding: Research → Plan → Implement. + A structured workflow for AI-assisted coding:{" "} + Research → Plan → Implement.

    Setup

    Export your Anthropic API key:

    -
    export ANTHROPIC_API_KEY=your-key-here
    -

    Get one at platform.claude.com

    +
    +            export ANTHROPIC_API_KEY=your-key-here
    +          
    +

    + Get one at{" "} + + platform.claude.com + +

    Getting Started

      -
    1. Add a project — Select a codebase folder
    2. -
    3. Create a session — Start a new task
    4. -
    5. Describe your work — Tell Claude what you want to build
    6. +
    7. + Add a project — Select a codebase folder +
    8. +
    9. + Create a session — Start a new task +
    10. +
    11. + Describe your work — Tell Claude what you want to + build +

    Workflow

    -

    Research: Claude analyzes your codebase and writes findings to research.md. Add notes like // REVIEW: check this — click Review when done.

    -

    Plan: Claude drafts an implementation plan in plan.md with code snippets and a TODO list. Iterate the same way.

    -

    Implement: Claude executes the plan, marking tasks complete as it goes.

    +

    + Research: Claude analyzes your codebase and writes + findings to research.md. Add notes like{" "} + // REVIEW: check this — click Review{" "} + when done. +

    +

    + Plan: Claude drafts an implementation plan in{" "} + plan.md with code snippets and a TODO list. Iterate the + same way. +

    +

    + Implement: Claude executes the plan, marking tasks + complete as it goes. +

    -

    Iterate on research and plan docs as long as you want. Click Submit when happy to move to the next phase.

    +

    + Iterate on research and plan docs as long as you want. Click{" "} + Submit when happy to move to the next phase. +

    ); @@ -163,10 +96,9 @@ export function DocumentPane({ plan.mdImplementing... -
    +
    + {content} +
    ); } @@ -193,13 +125,16 @@ export function DocumentPane({ ) : (
    Document will appear here after Claude generates it...

    ', - }} onClick={() => !disabled && setIsEditing(true)} - /> + > + {content ? ( + {content} + ) : ( +

    + Document will appear here after Claude generates it... +

    + )} +
    )} ); -- cgit v1.2.3