Add @tailwindcss/typography plugin and update MessageBubble component for improved Markdown rendering

This commit is contained in:
ecwu
2025-02-07 21:32:14 +00:00
parent a5f7447f4f
commit d18040dca1
4 changed files with 74 additions and 67 deletions

View File

@@ -38,6 +38,7 @@
"@radix-ui/react-toggle": "^1.1.1", "@radix-ui/react-toggle": "^1.1.1",
"@radix-ui/react-toggle-group": "^1.1.1", "@radix-ui/react-toggle-group": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.6", "@radix-ui/react-tooltip": "^1.1.6",
"@tailwindcss/typography": "^0.5.16",
"@types/react": "^18.0.0", "@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0", "@types/react-dom": "^18.0.0",
"@types/ungap__structured-clone": "^1.2.0", "@types/ungap__structured-clone": "^1.2.0",

40
pnpm-lock.yaml generated
View File

@@ -95,6 +95,9 @@ importers:
'@radix-ui/react-tooltip': '@radix-ui/react-tooltip':
specifier: ^1.1.6 specifier: ^1.1.6
version: 1.1.8(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 1.1.8(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@tailwindcss/typography':
specifier: ^0.5.16
version: 0.5.16(tailwindcss@3.4.17)
'@types/react': '@types/react':
specifier: ^18.0.0 specifier: ^18.0.0
version: 18.3.18 version: 18.3.18
@@ -1697,6 +1700,11 @@ packages:
'@surma/rollup-plugin-off-main-thread@2.2.3': '@surma/rollup-plugin-off-main-thread@2.2.3':
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
'@tailwindcss/typography@0.5.16':
resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
'@types/babel__core@7.20.5': '@types/babel__core@7.20.5':
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
@@ -2620,9 +2628,18 @@ packages:
lines-and-columns@1.2.4: lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
lodash.castarray@4.4.0:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
lodash.debounce@4.0.8: lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
lodash.sortby@4.7.0: lodash.sortby@4.7.0:
resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
@@ -2902,6 +2919,10 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.2.14 postcss: ^8.2.14
postcss-selector-parser@6.0.10:
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
engines: {node: '>=4'}
postcss-selector-parser@6.1.2: postcss-selector-parser@6.1.2:
resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -5205,6 +5226,14 @@ snapshots:
magic-string: 0.25.9 magic-string: 0.25.9
string.prototype.matchall: 4.0.12 string.prototype.matchall: 4.0.12
'@tailwindcss/typography@0.5.16(tailwindcss@3.4.17)':
dependencies:
lodash.castarray: 4.4.0
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
tailwindcss: 3.4.17
'@types/babel__core@7.20.5': '@types/babel__core@7.20.5':
dependencies: dependencies:
'@babel/parser': 7.26.7 '@babel/parser': 7.26.7
@@ -6227,8 +6256,14 @@ snapshots:
lines-and-columns@1.2.4: {} lines-and-columns@1.2.4: {}
lodash.castarray@4.4.0: {}
lodash.debounce@4.0.8: {} lodash.debounce@4.0.8: {}
lodash.isplainobject@4.0.6: {}
lodash.merge@4.6.2: {}
lodash.sortby@4.7.0: {} lodash.sortby@4.7.0: {}
lodash@4.17.21: {} lodash@4.17.21: {}
@@ -6631,6 +6666,11 @@ snapshots:
postcss: 8.5.1 postcss: 8.5.1
postcss-selector-parser: 6.1.2 postcss-selector-parser: 6.1.2
postcss-selector-parser@6.0.10:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
postcss-selector-parser@6.1.2: postcss-selector-parser@6.1.2:
dependencies: dependencies:
cssesc: 3.0.0 cssesc: 3.0.0

View File

@@ -305,7 +305,7 @@ export default function Message(props: { messageIndex: number }) {
</div> </div>
)} )}
{chat.role === "assistant" ? ( {chat.role === "assistant" ? (
<div className="border-b border-border dark:border-border-dark pb-4"> <div className="pb-4">
{chat.reasoning_content ? ( {chat.reasoning_content ? (
<Card className="bg-muted hover:bg-muted/80 mb-5 w-full lg:w-[65%]"> <Card className="bg-muted hover:bg-muted/80 mb-5 w-full lg:w-[65%]">
<Collapsible> <Collapsible>
@@ -336,74 +336,33 @@ export default function Message(props: { messageIndex: number }) {
) : chat.tool_calls ? ( ) : chat.tool_calls ? (
<MessageToolCall chat={chat} copyToClipboard={copyToClipboard} /> <MessageToolCall chat={chat} copyToClipboard={copyToClipboard} />
) : renderMarkdown ? ( ) : renderMarkdown ? (
<div className="message-content max-w-full md:max-w-[100%]"> <div className="max-w-full md:max-w-[100%]">
<Markdown <Markdown
remarkPlugins={[remarkMath]} remarkPlugins={[remarkMath]}
rehypePlugins={[rehypeKatex]} rehypePlugins={[rehypeKatex]}
//break={true} disallowedElements={[
components={{ "script",
strong: ({ children }) => ( "iframe",
<strong className="font-semibold">{children}</strong> "object",
), "embed",
em: ({ children }) => ( "hr",
<em className="italic text-primary">{children}</em> ]}
), // allowElement={(element) => {
code: ({ children }) => ( // return [
<code className="bg-muted px-1 py-0.5 rounded"> // "p",
{children} // "em",
</code> // "strong",
), // "del",
pre: ({ children }) => ( // "code",
<pre className="bg-muted p-4 rounded-lg overflow-auto"> // "inlineCode",
{children} // "blockquote",
</pre> // "ul",
), // "ol",
a: ({ href, children }) => ( // "li",
<a // "pre",
href={href} // ].includes(element.tagName);
target="_blank" // }}
rel="noopener noreferrer" className={"prose"}
className="text-primary hover:underline"
>
{children}
</a>
),
ol: ({ children }) => (
<ol className="list-decimal ml-6 space-y-2">
{children}
</ol>
),
ul: ({ children }) => (
<ul className="list-disc ml-6 space-y-2">{children}</ul>
),
li: ({ children }) => <li>{children}</li>,
p: ({ children, node }: any) => {
if (node?.parent?.type === "listItem") {
return <>{children}</>;
}
return <p>{children}</p>;
},
h1: ({ children }) => (
<h1 className="text-2xl font-bold mt-6 mb-4">
{children}
</h1>
),
h2: ({ children }) => (
<h2 className="text-xl font-bold mt-5 mb-3">
{children}
</h2>
),
h3: ({ children }) => (
<h3 className="text-lg font-semibold mt-4 mb-2">
{children}
</h3>
),
blockquote: ({ children }) => (
<blockquote className="border-l-4 border-muted pl-4 italic">
{children}
</blockquote>
),
}}
> >
{getMessageText(chat)} {getMessageText(chat)}
</Markdown> </Markdown>

View File

@@ -4,6 +4,13 @@ module.exports = {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: { theme: {
extend: { extend: {
typography: (theme) => ({
DEFAULT: {
css: {
},
},
}),
borderRadius: { borderRadius: {
lg: 'var(--radius)', lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)', md: 'calc(var(--radius) - 2px)',
@@ -85,5 +92,5 @@ module.exports = {
} }
} }
}, },
plugins: [require("tailwindcss-animate")], plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
}; };