Render GFM tables in chat replies

Enable remark-gfm in AnswerBubble so pipe-table syntax parses instead
of showing as raw text, and add table styling to markdown-content.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-09-09 09:38:54 -04:00
parent cd94f98c63
commit 7aef6484c3
4 changed files with 211 additions and 1 deletions
+1
View File
@@ -20,6 +20,7 @@
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-markdown": "^10.1.0",
"remark-gfm": "^4.0.1",
"tailwind-merge": "^3.5.0",
"watch": "^1.0.2"
},
+23
View File
@@ -117,6 +117,29 @@ body {
.markdown-content strong { font-weight: 700; }
.markdown-content em { font-style: italic; }
.markdown-content table {
width: 100%;
border-collapse: collapse;
margin: 0.75em 0;
font-size: 0.9em;
display: block;
overflow-x: auto;
}
.markdown-content th,
.markdown-content td {
border: 1px solid var(--color-sand-light);
padding: 0.4em 0.6em;
text-align: left;
vertical-align: top;
}
.markdown-content thead th {
background: var(--color-sand-light);
font-weight: 700;
}
.markdown-content tbody tr:nth-child(even) {
background: color-mix(in srgb, var(--color-sand-light) 35%, transparent);
}
/* ── Animations ─────────────────────────────────────── */
@keyframes fadeSlideUp {
from { opacity: 0; transform: translateY(10px); }
@@ -1,5 +1,6 @@
import React from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { cn } from "../lib/utils";
type AnswerBubbleProps = {
@@ -29,7 +30,7 @@ export const AnswerBubble = React.memo(({ text, loading }: AnswerBubbleProps) =>
</div>
) : (
<div className="markdown-content text-sm leading-relaxed text-charcoal">
<ReactMarkdown>{text}</ReactMarkdown>
<ReactMarkdown remarkPlugins={[remarkGfm]}>{text}</ReactMarkdown>
</div>
)}
</div>
+185
View File
@@ -695,6 +695,11 @@ es-set-tostringtag@^2.1.0:
has-tostringtag "^1.0.2"
hasown "^2.0.2"
escape-string-regexp@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
estree-util-is-identifier-name@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz#0b5ef4c4ff13508b34dcd01ecfa945f61fce5dbd"
@@ -1011,6 +1016,11 @@ magic-string@^0.30.21:
dependencies:
"@jridgewell/sourcemap-codec" "^1.5.5"
markdown-table@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.4.tgz#fe44d6d410ff9d6f2ea1797a3f60aa4d2b631c2a"
integrity sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==
marked@^16.3.0:
version "16.4.2"
resolved "https://registry.yarnpkg.com/marked/-/marked-16.4.2.tgz#4959a64be6c486f0db7467ead7ce288de54290a3"
@@ -1021,6 +1031,16 @@ math-intrinsics@^1.1.0:
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
mdast-util-find-and-replace@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz#70a3174c894e14df722abf43bc250cbae44b11df"
integrity sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==
dependencies:
"@types/mdast" "^4.0.0"
escape-string-regexp "^5.0.0"
unist-util-is "^6.0.0"
unist-util-visit-parents "^6.0.0"
mdast-util-from-markdown@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz#c95822b91aab75f18a4cbe8b2f51b873ed2cf0c7"
@@ -1039,6 +1059,71 @@ mdast-util-from-markdown@^2.0.0:
micromark-util-types "^2.0.0"
unist-util-stringify-position "^4.0.0"
mdast-util-gfm-autolink-literal@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz#abd557630337bd30a6d5a4bd8252e1c2dc0875d5"
integrity sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==
dependencies:
"@types/mdast" "^4.0.0"
ccount "^2.0.0"
devlop "^1.0.0"
mdast-util-find-and-replace "^3.0.0"
micromark-util-character "^2.0.0"
mdast-util-gfm-footnote@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz#7778e9d9ca3df7238cc2bd3fa2b1bf6a65b19403"
integrity sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==
dependencies:
"@types/mdast" "^4.0.0"
devlop "^1.1.0"
mdast-util-from-markdown "^2.0.0"
mdast-util-to-markdown "^2.0.0"
micromark-util-normalize-identifier "^2.0.0"
mdast-util-gfm-strikethrough@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz#d44ef9e8ed283ac8c1165ab0d0dfd058c2764c16"
integrity sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==
dependencies:
"@types/mdast" "^4.0.0"
mdast-util-from-markdown "^2.0.0"
mdast-util-to-markdown "^2.0.0"
mdast-util-gfm-table@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz#7a435fb6223a72b0862b33afbd712b6dae878d38"
integrity sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==
dependencies:
"@types/mdast" "^4.0.0"
devlop "^1.0.0"
markdown-table "^3.0.0"
mdast-util-from-markdown "^2.0.0"
mdast-util-to-markdown "^2.0.0"
mdast-util-gfm-task-list-item@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz#e68095d2f8a4303ef24094ab642e1047b991a936"
integrity sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==
dependencies:
"@types/mdast" "^4.0.0"
devlop "^1.0.0"
mdast-util-from-markdown "^2.0.0"
mdast-util-to-markdown "^2.0.0"
mdast-util-gfm@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz#2cdf63b92c2a331406b0fb0db4c077c1b0331751"
integrity sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==
dependencies:
mdast-util-from-markdown "^2.0.0"
mdast-util-gfm-autolink-literal "^2.0.0"
mdast-util-gfm-footnote "^2.0.0"
mdast-util-gfm-strikethrough "^2.0.0"
mdast-util-gfm-table "^2.0.0"
mdast-util-gfm-task-list-item "^2.0.0"
mdast-util-to-markdown "^2.0.0"
mdast-util-mdx-expression@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz#43f0abac9adc756e2086f63822a38c8d3c3a5096"
@@ -1153,6 +1238,85 @@ micromark-core-commonmark@^2.0.0:
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
micromark-extension-gfm-autolink-literal@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz#6286aee9686c4462c1e3552a9d505feddceeb935"
integrity sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==
dependencies:
micromark-util-character "^2.0.0"
micromark-util-sanitize-uri "^2.0.0"
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
micromark-extension-gfm-footnote@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz#4dab56d4e398b9853f6fe4efac4fc9361f3e0750"
integrity sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==
dependencies:
devlop "^1.0.0"
micromark-core-commonmark "^2.0.0"
micromark-factory-space "^2.0.0"
micromark-util-character "^2.0.0"
micromark-util-normalize-identifier "^2.0.0"
micromark-util-sanitize-uri "^2.0.0"
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
micromark-extension-gfm-strikethrough@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz#86106df8b3a692b5f6a92280d3879be6be46d923"
integrity sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==
dependencies:
devlop "^1.0.0"
micromark-util-chunked "^2.0.0"
micromark-util-classify-character "^2.0.0"
micromark-util-resolve-all "^2.0.0"
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
micromark-extension-gfm-table@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz#fac70bcbf51fe65f5f44033118d39be8a9b5940b"
integrity sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==
dependencies:
devlop "^1.0.0"
micromark-factory-space "^2.0.0"
micromark-util-character "^2.0.0"
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
micromark-extension-gfm-tagfilter@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz#f26d8a7807b5985fba13cf61465b58ca5ff7dc57"
integrity sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==
dependencies:
micromark-util-types "^2.0.0"
micromark-extension-gfm-task-list-item@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz#bcc34d805639829990ec175c3eea12bb5b781f2c"
integrity sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==
dependencies:
devlop "^1.0.0"
micromark-factory-space "^2.0.0"
micromark-util-character "^2.0.0"
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
micromark-extension-gfm@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz#3e13376ab95dd7a5cfd0e29560dfe999657b3c5b"
integrity sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==
dependencies:
micromark-extension-gfm-autolink-literal "^2.0.0"
micromark-extension-gfm-footnote "^2.0.0"
micromark-extension-gfm-strikethrough "^2.0.0"
micromark-extension-gfm-table "^2.0.0"
micromark-extension-gfm-tagfilter "^2.0.0"
micromark-extension-gfm-task-list-item "^2.0.0"
micromark-util-combine-extensions "^2.0.0"
micromark-util-types "^2.0.0"
micromark-factory-destination@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz#8fef8e0f7081f0474fbdd92deb50c990a0264639"
@@ -1485,6 +1649,18 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
remark-gfm@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-4.0.1.tgz#33227b2a74397670d357bf05c098eaf8513f0d6b"
integrity sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==
dependencies:
"@types/mdast" "^4.0.0"
mdast-util-gfm "^3.0.0"
micromark-extension-gfm "^3.0.0"
remark-parse "^11.0.0"
remark-stringify "^11.0.0"
unified "^11.0.0"
remark-parse@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1"
@@ -1506,6 +1682,15 @@ remark-rehype@^11.0.0:
unified "^11.0.0"
vfile "^6.0.0"
remark-stringify@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-11.0.0.tgz#4c5b01dd711c269df1aaae11743eb7e2e7636fd3"
integrity sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==
dependencies:
"@types/mdast" "^4.0.0"
mdast-util-to-markdown "^2.0.0"
unified "^11.0.0"
safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"