Files
pansy/web/package.json
T
steveandClaude Opus 4.8 ae3d52db31
Build image / build-and-push (push) Successful in 12s
Gadfly review (reusable) / review (pull_request) Successful in 12m49s
Adversarial Review (Gadfly) / review (pull_request) Successful in 12m49s
Render the assistant's replies as Markdown
The assistant answers in Markdown — tables, lists, bold, links — but the
chat bubble showed the raw source (whitespace-pre-wrap), so a table came
through as a wall of pipes.

- New MarkdownMessage: react-markdown + remark-gfm (for GFM tables). It does
  NOT enable raw HTML (no rehype-raw), so a model reply can't inject markup;
  every element the assistant actually uses is Tailwind-styled for a chat
  bubble, and wide content (tables, code) scrolls in its own box so the
  bubble can't blow out.
- Only ASSISTANT bubbles render as Markdown; the user's own text stays
  literal (their `*` shouldn't become a bullet) and the assistant bubble goes
  full-width so a table has room.
- Lazy-loaded: the renderer + its ecosystem (~150 KB) is its own async chunk,
  loaded only when an assistant message renders — not for everyone who opens
  the editor. To keep it out of the eager first paint, manualChunks now
  vendors only the app-wide core (react/react-dom/scheduler kept together —
  splitting react-dom breaks React 19 at load) and lets everything else ride
  with its importer.

Tested via renderToStaticMarkup (node, no DOM): a GFM table renders with
styled cells + horizontal scroll; **bold**/lists render; raw <script>/<b> are
escaped not emitted; links get rel="noopener noreferrer". App re-verified to
mount cleanly with the re-chunk (no React-19 init-order break). tsc + vitest
(99) + build green, no >500 KB warning.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ
2026-07-22 12:17:34 -04:00

43 lines
1.0 KiB
JSON

{
"name": "pansy-web",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "Pansy garden planner — web frontend.",
"engines": {
"node": ">=20"
},
"scripts": {
"dev": "vite",
"build": "tsc --noEmit && vite build",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest",
"preview": "vite preview"
},
"dependencies": {
"@tanstack/react-query": "^5.62.0",
"@tanstack/react-router": "^1.95.0",
"@use-gesture/react": "^10.3.1",
"clsx": "^2.1.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-markdown": "^9.1.0",
"remark-gfm": "^4.0.1",
"tailwind-merge": "^2.6.0",
"zod": "^3.24.1",
"zustand": "^5.0.14"
},
"devDependencies": {
"@tailwindcss/vite": "^4.0.0",
"@types/node": "^22.10.5",
"@types/react": "^19.0.2",
"@types/react-dom": "^19.0.2",
"@vitejs/plugin-react": "^4.3.4",
"tailwindcss": "^4.0.0",
"typescript": "^5.7.2",
"vite": "^6.0.7",
"vitest": "^4.1.10"
}
}