From 81ac66f104648fb283d8d3c5952a37db9285c8c3 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Thu, 9 Apr 2026 11:35:27 -0700 Subject: [PATCH] fix code block --- .../message/components/markdown-renderer.tsx | 5 +- .../components/file-viewer/preview-panel.tsx | 4 - .../components/chat-content/chat-content.tsx | 82 +++++++++++++++---- apps/sim/package.json | 1 - bun.lock | 17 ---- 5 files changed, 66 insertions(+), 43 deletions(-) diff --git a/apps/sim/app/chat/components/message/components/markdown-renderer.tsx b/apps/sim/app/chat/components/message/components/markdown-renderer.tsx index d2b45a8e09..0a4bd2bf98 100644 --- a/apps/sim/app/chat/components/message/components/markdown-renderer.tsx +++ b/apps/sim/app/chat/components/message/components/markdown-renderer.tsx @@ -1,5 +1,4 @@ import React, { type HTMLAttributes, memo, type ReactNode, useMemo } from 'react' -import { code } from '@streamdown/code' import { Streamdown } from 'streamdown' import 'streamdown/styles.css' import { Tooltip } from '@/components/emcn' @@ -26,8 +25,6 @@ export function LinkWithPreview({ href, children }: { href: string; children: Re ) } -const STREAMDOWN_PLUGINS = { code } - function createCustomComponents(LinkComponent: typeof LinkWithPreview) { return { p: ({ children }: React.HTMLAttributes) => ( @@ -195,7 +192,7 @@ const MarkdownRenderer = memo(function MarkdownRenderer({ return (
- + {processedContent}
diff --git a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-panel.tsx b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-panel.tsx index 0c9867b85b..24a74a9265 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-panel.tsx +++ b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-panel.tsx @@ -1,7 +1,6 @@ 'use client' import { createContext, memo, useCallback, useContext, useEffect, useMemo, useRef } from 'react' -import { code } from '@streamdown/code' import { useRouter } from 'next/navigation' import rehypeSlug from 'rehype-slug' import remarkBreaks from 'remark-breaks' @@ -77,7 +76,6 @@ export const PreviewPanel = memo(function PreviewPanel({ const REMARK_PLUGINS = [remarkBreaks] const REHYPE_PLUGINS = [rehypeSlug] -const STREAMDOWN_PLUGINS = { code } /** * Carries the contentRef and toggle handler from MarkdownPreview down to the @@ -380,7 +378,6 @@ const MarkdownPreview = memo(function MarkdownPreview({ mode='static' remarkPlugins={REMARK_PLUGINS} rehypePlugins={REHYPE_PLUGINS} - plugins={STREAMDOWN_PLUGINS} components={MARKDOWN_COMPONENTS} > {content} @@ -398,7 +395,6 @@ const MarkdownPreview = memo(function MarkdownPreview({ mode='static' remarkPlugins={REMARK_PLUGINS} rehypePlugins={REHYPE_PLUGINS} - plugins={STREAMDOWN_PLUGINS} components={MARKDOWN_COMPONENTS} > {content} diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx index 2ba6cd922f..3fe7dcd02e 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx @@ -1,11 +1,17 @@ 'use client' import { type ComponentPropsWithoutRef, useMemo } from 'react' -import { code } from '@streamdown/code' import { Streamdown } from 'streamdown' import 'streamdown/styles.css' -import { Checkbox } from '@/components/emcn' +import 'prismjs/components/prism-typescript' +import 'prismjs/components/prism-bash' +import 'prismjs/components/prism-css' +import 'prismjs/components/prism-markup' +import '@/components/emcn/components/code/code.css' +import { Checkbox, highlight, languages } from '@/components/emcn' +import { CopyCodeButton } from '@/components/ui/copy-code-button' import { cn } from '@/lib/core/utils/cn' +import { extractTextContent } from '@/lib/core/utils/react-node-text' import { PendingTagIndicator, parseSpecialTags, @@ -13,6 +19,19 @@ import { } from '@/app/workspace/[workspaceId]/home/components/message-content/components/special-tags' import { useStreamingText } from '@/hooks/use-streaming-text' +const LANG_ALIASES: Record = { + js: 'javascript', + ts: 'typescript', + tsx: 'typescript', + jsx: 'javascript', + sh: 'bash', + shell: 'bash', + html: 'markup', + xml: 'markup', + yml: 'yaml', + py: 'python', +} + const PROSE_CLASSES = cn( 'prose prose-base dark:prose-invert max-w-none', 'font-[family-name:var(--font-inter)] antialiased break-words font-[430] tracking-[0]', @@ -24,8 +43,6 @@ const PROSE_CLASSES = cn( 'prose-ul:my-4 prose-ol:my-4', 'prose-strong:font-[600] prose-strong:text-[var(--text-primary)]', 'prose-a:text-[var(--text-primary)] prose-a:underline prose-a:decoration-dashed prose-a:underline-offset-4', - 'prose-code:rounded prose-code:bg-[var(--surface-5)] prose-code:px-1.5 prose-code:py-0.5 prose-code:text-small prose-code:font-mono prose-code:font-[400] prose-code:text-[var(--text-primary)]', - 'prose-code:before:content-none prose-code:after:content-none', 'prose-hr:border-[var(--divider)] prose-hr:my-6', 'prose-table:my-0' ) @@ -33,8 +50,6 @@ const PROSE_CLASSES = cn( type TdProps = ComponentPropsWithoutRef<'td'> type ThProps = ComponentPropsWithoutRef<'th'> -const STREAMDOWN_PLUGINS = { code } - const MARKDOWN_COMPONENTS = { table({ children }: { children?: React.ReactNode }) { return ( @@ -68,6 +83,41 @@ const MARKDOWN_COMPONENTS = { ) }, + code({ children, className }: { children?: React.ReactNode; className?: string }) { + const langMatch = className?.match(/language-(\w+)/) + const language = langMatch ? langMatch[1] : '' + const codeString = extractTextContent(children) + + if (!codeString) { + return ( +
+          {children}
+        
+ ) + } + + const resolved = LANG_ALIASES[language] || language || 'javascript' + const grammar = languages[resolved] || languages.javascript + const html = highlight(codeString.trimEnd(), grammar, resolved) + + return ( +
+
+ {language || 'code'} + +
+
+
+        
+
+ ) + }, a({ children, href }: { children?: React.ReactNode; href?: string }) { return ( ) }, + inlineCode({ children }: { children?: React.ReactNode }) { + return ( + + {children} + + ) + }, input({ type, checked }: { type?: string; checked?: boolean }) { if (type === 'checkbox') { return @@ -133,11 +190,7 @@ export function ChatContent({ content, isStreaming = false, onOptionSelect }: Ch key={`${segment.type}-${i}`} className={cn(PROSE_CLASSES, '[&>:first-child]:mt-0 [&>:last-child]:mb-0')} > - + {segment.content} @@ -154,12 +207,7 @@ export function ChatContent({ content, isStreaming = false, onOptionSelect }: Ch return (
:first-child]:mt-0 [&>:last-child]:mb-0')}> - + {rendered}
diff --git a/apps/sim/package.json b/apps/sim/package.json index 97cf8a5db1..525c8e6b97 100644 --- a/apps/sim/package.json +++ b/apps/sim/package.json @@ -92,7 +92,6 @@ "@react-email/render": "2.0.0", "@sim/logger": "workspace:*", "@socket.io/redis-adapter": "8.3.0", - "@streamdown/code": "1.1.1", "@t3-oss/env-nextjs": "0.13.4", "@tanstack/react-query": "5.90.8", "@tanstack/react-query-devtools": "5.90.2", diff --git a/bun.lock b/bun.lock index fabaa256c4..4a60c0668f 100644 --- a/bun.lock +++ b/bun.lock @@ -113,7 +113,6 @@ "@react-email/render": "2.0.0", "@sim/logger": "workspace:*", "@socket.io/redis-adapter": "8.3.0", - "@streamdown/code": "1.1.1", "@t3-oss/env-nextjs": "0.13.4", "@tanstack/react-query": "5.90.8", "@tanstack/react-query-devtools": "5.90.2", @@ -1458,8 +1457,6 @@ "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], - "@streamdown/code": ["@streamdown/code@1.1.1", "", { "dependencies": { "shiki": "^3.19.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-i7HTNuDgZWb+VdrNVOam9gQhIc5MSSDXKWXgbUrn/4vSRaSMM+Rtl10MQj4wLWPNpF7p80waJsAqFP8HZfb0Jg=="], - "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], "@t3-oss/env-core": ["@t3-oss/env-core@0.13.4", "", { "peerDependencies": { "arktype": "^2.1.0", "typescript": ">=5.0.0", "valibot": "^1.0.0-beta.7 || ^1.0.0", "zod": "^3.24.0 || ^4.0.0-beta.0" }, "optionalPeers": ["typescript", "valibot", "zod"] }, "sha512-zVOiYO0+CF7EnBScz8s0O5JnJLPTU0lrUi8qhKXfIxIJXvI/jcppSiXXsEJwfB4A6XZawY/Wg/EQGKANi/aPmQ=="], @@ -4630,8 +4627,6 @@ "@socket.io/redis-adapter/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], - "@streamdown/code/shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="], - "@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="], @@ -5298,18 +5293,6 @@ "@shikijs/rehype/shiki/@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="], - "@streamdown/code/shiki/@shikijs/core": ["@shikijs/core@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA=="], - - "@streamdown/code/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="], - - "@streamdown/code/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="], - - "@streamdown/code/shiki/@shikijs/langs": ["@shikijs/langs@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg=="], - - "@streamdown/code/shiki/@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="], - - "@streamdown/code/shiki/@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="], - "@trigger.dev/core/@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="], "@trigger.dev/core/@opentelemetry/exporter-logs-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-transformer": "0.203.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Wbxf7k+87KyvxFr5D7uOiSq/vHXWommvdnNE7vECO3tAhsA2GfOlpWINCMWUEPdHZ7tCXxw6Epp3vgx3jU7llQ=="],