feat: render chat messages as markdown with code blocks

- Add react-markdown and remark-gfm for markdown rendering
- Create MarkdownContent component with custom code block renderer
  featuring language labels and copy-to-clipboard buttons
- Add full markdown prose styles (headings, lists, tables, links,
  blockquotes, inline code) matching the dark zinc theme
- Replace plain-text message rendering in ChatPane with MarkdownContent
- Handle fenced code blocks with and without language specifiers

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-21 19:04:24 +01:00
co-authored by Copilot
parent 9138aa8819
commit 879c6c145c
5 changed files with 436 additions and 4 deletions
+5 -3
View File
@@ -1,6 +1,8 @@
import { type KeyboardEvent, useEffect, useRef, useState } from 'react';
import { AlertCircle, ArrowUp, Bot, Loader2, User } from 'lucide-react';
import { MarkdownContent } from '@renderer/components/MarkdownContent';
import type { PatternDefinition } from '@shared/domain/pattern';
import type { ProjectRecord } from '@shared/domain/project';
import type { SessionRecord } from '@shared/domain/session';
@@ -112,10 +114,10 @@ export function ChatPane({ project, pattern, session, onSend }: ChatPaneProps) {
<div className="mb-1 text-[12px] font-medium text-zinc-400">
{message.authorName}
</div>
<div className="whitespace-pre-wrap text-[14px] leading-relaxed text-zinc-200">
{message.content}
<div className="text-[14px] leading-relaxed text-zinc-200">
<MarkdownContent content={message.content} />
{message.pending && message.content && (
<span className="ml-0.5 inline-block h-[18px] w-[2px] animate-pulse rounded-sm bg-zinc-400 align-text-bottom" />
<span className="mt-1 inline-block h-4 w-[2px] animate-pulse rounded-sm bg-zinc-400" />
)}
</div>
{message.pending && !message.content && <ThinkingDots />}