Skip to content

Commit 2608f2f

Browse files
authored
fix(copiolot-ui): fix code markdown rendering in copilot & table (#2048)
1 parent 96207d8 commit 2608f2f

2 files changed

Lines changed: 109 additions & 100 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/copilot/components/copilot-message/components/markdown-renderer.tsx

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import React, { useEffect, useMemo, useState } from 'react'
44
import { Check, Copy } from 'lucide-react'
55
import ReactMarkdown from 'react-markdown'
66
import remarkGfm from 'remark-gfm'
7-
import { Tooltip } from '@/components/emcn'
7+
import { Code, Tooltip } from '@/components/emcn'
88

99
/**
1010
* Recursively extracts text content from React elements
@@ -28,56 +28,30 @@ const getTextContent = (element: React.ReactNode): string => {
2828
return ''
2929
}
3030

31-
// Fix for code block text rendering issues
31+
// Global layout fixes for markdown content inside the copilot panel
3232
if (typeof document !== 'undefined') {
3333
const styleId = 'copilot-markdown-fix'
3434
if (!document.getElementById(styleId)) {
3535
const style = document.createElement('style')
3636
style.id = styleId
3737
style.textContent = `
38-
.copilot-markdown-wrapper pre {
39-
color: #F5F5F5 !important;
40-
font-weight: 400 !important;
41-
text-shadow: none !important;
42-
filter: none !important;
43-
opacity: 1 !important;
44-
-webkit-font-smoothing: antialiased !important;
45-
-moz-osx-font-smoothing: grayscale !important;
46-
text-rendering: optimizeLegibility !important;
47-
max-width: 100% !important;
48-
overflow: auto !important;
49-
}
50-
51-
.dark .copilot-markdown-wrapper pre {
52-
color: #F0F0F0 !important;
53-
}
54-
55-
.copilot-markdown-wrapper pre code,
56-
.copilot-markdown-wrapper pre code *,
57-
.copilot-markdown-wrapper pre span,
58-
.copilot-markdown-wrapper pre div {
59-
color: inherit !important;
60-
opacity: 1 !important;
61-
font-weight: 400 !important;
62-
text-shadow: none !important;
63-
filter: none !important;
64-
-webkit-font-smoothing: antialiased !important;
65-
-moz-osx-font-smoothing: grayscale !important;
66-
text-rendering: optimizeLegibility !important;
67-
}
68-
6938
/* Prevent any markdown content from expanding beyond the panel */
70-
.copilot-markdown-wrapper, .copilot-markdown-wrapper * {
39+
.copilot-markdown-wrapper,
40+
.copilot-markdown-wrapper * {
7141
max-width: 100% !important;
7242
}
73-
.copilot-markdown-wrapper p, .copilot-markdown-wrapper li {
43+
44+
.copilot-markdown-wrapper p,
45+
.copilot-markdown-wrapper li {
7446
overflow-wrap: anywhere !important;
7547
word-break: break-word !important;
7648
}
49+
7750
.copilot-markdown-wrapper a {
7851
overflow-wrap: anywhere !important;
7952
word-break: break-all !important;
8053
}
54+
8155
.copilot-markdown-wrapper code:not(pre code) {
8256
white-space: normal !important;
8357
overflow-wrap: anywhere !important;
@@ -219,7 +193,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
219193
</li>
220194
),
221195

222-
// Code blocks
196+
// Code blocks - render using shared Code.Viewer for consistent styling
223197
pre: ({ children }: React.HTMLAttributes<HTMLPreElement>) => {
224198
let codeContent: React.ReactNode = children
225199
let language = 'code'
@@ -272,13 +246,24 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
272246
}
273247
}
274248

249+
// Map markdown language tag to Code.Viewer supported languages
250+
const normalizedLanguage = (language || '').toLowerCase()
251+
const viewerLanguage: 'javascript' | 'json' | 'python' =
252+
normalizedLanguage === 'json'
253+
? 'json'
254+
: normalizedLanguage === 'python' || normalizedLanguage === 'py'
255+
? 'python'
256+
: 'javascript'
257+
275258
return (
276-
<div className='my-6 w-0 min-w-full rounded-md bg-gray-900 text-sm dark:bg-black'>
277-
<div className='flex items-center justify-between border-gray-700 border-b px-4 py-1.5 dark:border-gray-800'>
278-
<span className='font-season text-gray-400 text-xs'>{language}</span>
259+
<div className='my-6 w-0 min-w-full overflow-hidden rounded-md border border-[var(--border-strong)] bg-[#1F1F1F] text-sm'>
260+
<div className='flex items-center justify-between border-[var(--border-strong)] border-b px-4 py-1.5'>
261+
<span className='font-season text-[#A3A3A3] text-xs'>
262+
{language === 'code' ? viewerLanguage : language}
263+
</span>
279264
<button
280265
onClick={handleCopy}
281-
className='text-muted-foreground transition-colors hover:text-gray-300'
266+
className='text-[#A3A3A3] transition-colors hover:text-gray-300'
282267
title='Copy'
283268
>
284269
{showCopySuccess ? (
@@ -288,11 +273,12 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
288273
)}
289274
</button>
290275
</div>
291-
<div className='overflow-x-auto'>
292-
<pre className='whitespace-pre p-4 font-mono text-[#F5F5F5] text-sm leading-relaxed dark:text-[#F0F0F0]'>
293-
{actualCodeText}
294-
</pre>
295-
</div>
276+
<Code.Viewer
277+
code={actualCodeText}
278+
showGutter
279+
language={viewerLanguage}
280+
className='m-0 rounded-none border-0 bg-transparent'
281+
/>
296282
</div>
297283
)
298284
},
@@ -307,7 +293,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
307293
if (inline) {
308294
return (
309295
<code
310-
className='whitespace-normal break-all rounded bg-gray-300 px-1 py-0.5 font-mono text-[#707070] text-[0.9em] dark:bg-[var(--surface-11)] dark:text-[#E8E8E8]'
296+
className='whitespace-normal break-all rounded border border-[var(--border-strong)] bg-[#1F1F1F] px-1 py-0.5 font-mono text-[#eeeeee] text-[0.9em]'
311297
{...props}
312298
>
313299
{children}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/copilot/components/inline-tool-call/inline-tool-call.tsx

Lines changed: 77 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -463,30 +463,40 @@ export function InlineToolCall({
463463
const url = params.url || ''
464464
const method = (params.method || '').toUpperCase()
465465
return (
466-
<div className='w-full overflow-hidden rounded border border-muted bg-card'>
467-
<div className='grid grid-cols-2 gap-0 border-muted/60 border-b bg-muted/40 py-1.5'>
468-
<div className='self-start px-2 font-medium font-season text-[#858585] text-[10px] uppercase tracking-wide dark:text-[#E0E0E0]'>
469-
Method
470-
</div>
471-
<div className='self-start px-2 font-medium font-season text-[#858585] text-[10px] uppercase tracking-wide dark:text-[#E0E0E0]'>
472-
Endpoint
473-
</div>
474-
</div>
475-
<div className='grid grid-cols-[auto_1fr] gap-2 py-1.5'>
476-
<div className='self-start px-2'>
477-
<span className='inline-flex rounded bg-muted px-1.5 py-0.5 font-[470] font-mono text-[#707070] text-xs dark:text-[#E8E8E8]'>
478-
{method || 'GET'}
479-
</span>
480-
</div>
481-
<div className='min-w-0 self-start px-2'>
482-
<span
483-
className='block overflow-x-auto whitespace-nowrap font-[470] font-mono text-[#707070] text-xs dark:text-[#E8E8E8]'
484-
title={url}
485-
>
486-
{url || 'URL not provided'}
487-
</span>
488-
</div>
489-
</div>
466+
<div className='w-full overflow-hidden rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F]'>
467+
<table className='w-full table-fixed bg-transparent'>
468+
<thead className='bg-transparent'>
469+
<tr className='border-[var(--border-strong)] border-b bg-transparent'>
470+
<th className='w-[26%] border-[var(--border-strong)] border-r bg-transparent px-[10px] py-[5px] text-left font-medium text-[14px] text-[var(--text-tertiary)]'>
471+
Method
472+
</th>
473+
<th className='w-[74%] bg-transparent px-[10px] py-[5px] text-left font-medium text-[14px] text-[var(--text-tertiary)]'>
474+
Endpoint
475+
</th>
476+
</tr>
477+
</thead>
478+
<tbody className='bg-transparent'>
479+
<tr className='group relative border-[var(--border-strong)] border-t bg-transparent'>
480+
<td className='relative w-[26%] border-[var(--border-strong)] border-r bg-transparent p-0'>
481+
<div className='px-[10px] py-[8px]'>
482+
<span className='font-mono text-muted-foreground text-xs'>
483+
{method || 'GET'}
484+
</span>
485+
</div>
486+
</td>
487+
<td className='relative w-[74%] bg-transparent p-0'>
488+
<div className='min-w-0 px-[10px] py-[8px]'>
489+
<span
490+
className='block break-all font-mono text-muted-foreground text-xs'
491+
title={url}
492+
>
493+
{url || 'URL not provided'}
494+
</span>
495+
</div>
496+
</td>
497+
</tr>
498+
</tbody>
499+
</table>
490500
</div>
491501
)
492502
}
@@ -499,7 +509,7 @@ export function InlineToolCall({
499509
const normalizedEntries: Array<[string, string]> = []
500510
Object.entries(variables).forEach(([key, value]) => {
501511
if (typeof value === 'object' && value !== null && 'name' in value && 'value' in value) {
502-
// Handle {name: "key", value: "val"} format
512+
// Handle { name: "KEY", value: "VAL" } format
503513
normalizedEntries.push([String((value as any).name), String((value as any).value)])
504514
} else {
505515
// Handle direct key-value format
@@ -508,35 +518,48 @@ export function InlineToolCall({
508518
})
509519

510520
return (
511-
<div className='w-full overflow-hidden rounded border border-muted bg-card'>
512-
<div className='grid grid-cols-[160px_1fr] gap-0 border-muted/60 border-b bg-muted/40 py-1.5'>
513-
<div className='self-start px-2 font-medium font-season text-[#858585] text-[11px] uppercase tracking-wide dark:text-[#E0E0E0]'>
514-
Name
515-
</div>
516-
<div className='self-start px-2 font-medium font-season text-[#858585] text-[11px] uppercase tracking-wide dark:text-[#E0E0E0]'>
517-
Value
518-
</div>
519-
</div>
520-
{normalizedEntries.length === 0 ? (
521-
<div className='px-2 py-1.5 font-[470] font-season text-[#707070] text-xs dark:text-[#E8E8E8]'>
522-
No variables provided
523-
</div>
524-
) : (
525-
<div className='divide-y divide-muted/60'>
526-
{normalizedEntries.map(([name, value]) => (
527-
<div key={name} className='grid grid-cols-[160px_1fr] gap-0 py-1.5'>
528-
<div className='self-start px-2 font-medium font-season text-amber-800 text-xs dark:text-amber-200'>
529-
{name}
530-
</div>
531-
<div className='min-w-0 self-start overflow-x-auto px-2'>
532-
<span className='whitespace-nowrap font-[470] font-mono text-amber-700 text-xs dark:text-amber-300'>
533-
{value}
534-
</span>
535-
</div>
536-
</div>
537-
))}
538-
</div>
539-
)}
521+
<div className='w-full overflow-hidden rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F]'>
522+
<table className='w-full table-fixed bg-transparent'>
523+
<thead className='bg-transparent'>
524+
<tr className='border-[var(--border-strong)] border-b bg-transparent'>
525+
<th className='w-[36%] border-[var(--border-strong)] border-r bg-transparent px-[10px] py-[5px] text-left font-medium text-[14px] text-[var(--text-tertiary)]'>
526+
Name
527+
</th>
528+
<th className='w-[64%] bg-transparent px-[10px] py-[5px] text-left font-medium text-[14px] text-[var(--text-tertiary)]'>
529+
Value
530+
</th>
531+
</tr>
532+
</thead>
533+
<tbody className='bg-transparent'>
534+
{normalizedEntries.length === 0 ? (
535+
<tr className='border-[var(--border-strong)] border-t bg-transparent'>
536+
<td colSpan={2} className='px-[10px] py-[8px] text-muted-foreground text-xs'>
537+
No variables provided
538+
</td>
539+
</tr>
540+
) : (
541+
normalizedEntries.map(([name, value]) => (
542+
<tr
543+
key={name}
544+
className='group relative border-[var(--border-strong)] border-t bg-transparent'
545+
>
546+
<td className='relative w-[36%] border-[var(--border-strong)] border-r bg-transparent p-0'>
547+
<div className='px-[10px] py-[8px]'>
548+
<span className='truncate font-medium text-foreground text-xs'>{name}</span>
549+
</div>
550+
</td>
551+
<td className='relative w-[64%] bg-transparent p-0'>
552+
<div className='min-w-0 px-[10px] py-[8px]'>
553+
<span className='block overflow-x-auto whitespace-nowrap font-mono text-muted-foreground text-xs'>
554+
{value}
555+
</span>
556+
</div>
557+
</td>
558+
</tr>
559+
))
560+
)}
561+
</tbody>
562+
</table>
540563
</div>
541564
)
542565
}

0 commit comments

Comments
 (0)