fix(copiolot-ui): fix code markdown rendering in copilot & table (#2048)

This commit is contained in:
Waleed
2025-11-18 18:06:18 -08:00
committed by GitHub
parent 96207d85a7
commit 2608f2f12c
2 changed files with 109 additions and 100 deletions

View File

@@ -4,7 +4,7 @@ import React, { useEffect, useMemo, useState } from 'react'
import { Check, Copy } from 'lucide-react'
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import { Tooltip } from '@/components/emcn'
import { Code, Tooltip } from '@/components/emcn'
/**
* Recursively extracts text content from React elements
@@ -28,56 +28,30 @@ const getTextContent = (element: React.ReactNode): string => {
return ''
}
// Fix for code block text rendering issues
// Global layout fixes for markdown content inside the copilot panel
if (typeof document !== 'undefined') {
const styleId = 'copilot-markdown-fix'
if (!document.getElementById(styleId)) {
const style = document.createElement('style')
style.id = styleId
style.textContent = `
.copilot-markdown-wrapper pre {
color: #F5F5F5 !important;
font-weight: 400 !important;
text-shadow: none !important;
filter: none !important;
opacity: 1 !important;
-webkit-font-smoothing: antialiased !important;
-moz-osx-font-smoothing: grayscale !important;
text-rendering: optimizeLegibility !important;
/* Prevent any markdown content from expanding beyond the panel */
.copilot-markdown-wrapper,
.copilot-markdown-wrapper * {
max-width: 100% !important;
overflow: auto !important;
}
.dark .copilot-markdown-wrapper pre {
color: #F0F0F0 !important;
}
.copilot-markdown-wrapper pre code,
.copilot-markdown-wrapper pre code *,
.copilot-markdown-wrapper pre span,
.copilot-markdown-wrapper pre div {
color: inherit !important;
opacity: 1 !important;
font-weight: 400 !important;
text-shadow: none !important;
filter: none !important;
-webkit-font-smoothing: antialiased !important;
-moz-osx-font-smoothing: grayscale !important;
text-rendering: optimizeLegibility !important;
}
/* Prevent any markdown content from expanding beyond the panel */
.copilot-markdown-wrapper, .copilot-markdown-wrapper * {
max-width: 100% !important;
}
.copilot-markdown-wrapper p, .copilot-markdown-wrapper li {
.copilot-markdown-wrapper p,
.copilot-markdown-wrapper li {
overflow-wrap: anywhere !important;
word-break: break-word !important;
}
.copilot-markdown-wrapper a {
overflow-wrap: anywhere !important;
word-break: break-all !important;
}
.copilot-markdown-wrapper code:not(pre code) {
white-space: normal !important;
overflow-wrap: anywhere !important;
@@ -219,7 +193,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
</li>
),
// Code blocks
// Code blocks - render using shared Code.Viewer for consistent styling
pre: ({ children }: React.HTMLAttributes<HTMLPreElement>) => {
let codeContent: React.ReactNode = children
let language = 'code'
@@ -272,13 +246,24 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
}
}
// Map markdown language tag to Code.Viewer supported languages
const normalizedLanguage = (language || '').toLowerCase()
const viewerLanguage: 'javascript' | 'json' | 'python' =
normalizedLanguage === 'json'
? 'json'
: normalizedLanguage === 'python' || normalizedLanguage === 'py'
? 'python'
: 'javascript'
return (
<div className='my-6 w-0 min-w-full rounded-md bg-gray-900 text-sm dark:bg-black'>
<div className='flex items-center justify-between border-gray-700 border-b px-4 py-1.5 dark:border-gray-800'>
<span className='font-season text-gray-400 text-xs'>{language}</span>
<div className='my-6 w-0 min-w-full overflow-hidden rounded-md border border-[var(--border-strong)] bg-[#1F1F1F] text-sm'>
<div className='flex items-center justify-between border-[var(--border-strong)] border-b px-4 py-1.5'>
<span className='font-season text-[#A3A3A3] text-xs'>
{language === 'code' ? viewerLanguage : language}
</span>
<button
onClick={handleCopy}
className='text-muted-foreground transition-colors hover:text-gray-300'
className='text-[#A3A3A3] transition-colors hover:text-gray-300'
title='Copy'
>
{showCopySuccess ? (
@@ -288,11 +273,12 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
)}
</button>
</div>
<div className='overflow-x-auto'>
<pre className='whitespace-pre p-4 font-mono text-[#F5F5F5] text-sm leading-relaxed dark:text-[#F0F0F0]'>
{actualCodeText}
</pre>
</div>
<Code.Viewer
code={actualCodeText}
showGutter
language={viewerLanguage}
className='m-0 rounded-none border-0 bg-transparent'
/>
</div>
)
},
@@ -307,7 +293,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
if (inline) {
return (
<code
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]'
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]'
{...props}
>
{children}

View File

@@ -463,30 +463,40 @@ export function InlineToolCall({
const url = params.url || ''
const method = (params.method || '').toUpperCase()
return (
<div className='w-full overflow-hidden rounded border border-muted bg-card'>
<div className='grid grid-cols-2 gap-0 border-muted/60 border-b bg-muted/40 py-1.5'>
<div className='self-start px-2 font-medium font-season text-[#858585] text-[10px] uppercase tracking-wide dark:text-[#E0E0E0]'>
Method
</div>
<div className='self-start px-2 font-medium font-season text-[#858585] text-[10px] uppercase tracking-wide dark:text-[#E0E0E0]'>
Endpoint
</div>
</div>
<div className='grid grid-cols-[auto_1fr] gap-2 py-1.5'>
<div className='self-start px-2'>
<span className='inline-flex rounded bg-muted px-1.5 py-0.5 font-[470] font-mono text-[#707070] text-xs dark:text-[#E8E8E8]'>
{method || 'GET'}
</span>
</div>
<div className='min-w-0 self-start px-2'>
<span
className='block overflow-x-auto whitespace-nowrap font-[470] font-mono text-[#707070] text-xs dark:text-[#E8E8E8]'
title={url}
>
{url || 'URL not provided'}
</span>
</div>
</div>
<div className='w-full overflow-hidden rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F]'>
<table className='w-full table-fixed bg-transparent'>
<thead className='bg-transparent'>
<tr className='border-[var(--border-strong)] border-b bg-transparent'>
<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)]'>
Method
</th>
<th className='w-[74%] bg-transparent px-[10px] py-[5px] text-left font-medium text-[14px] text-[var(--text-tertiary)]'>
Endpoint
</th>
</tr>
</thead>
<tbody className='bg-transparent'>
<tr className='group relative border-[var(--border-strong)] border-t bg-transparent'>
<td className='relative w-[26%] border-[var(--border-strong)] border-r bg-transparent p-0'>
<div className='px-[10px] py-[8px]'>
<span className='font-mono text-muted-foreground text-xs'>
{method || 'GET'}
</span>
</div>
</td>
<td className='relative w-[74%] bg-transparent p-0'>
<div className='min-w-0 px-[10px] py-[8px]'>
<span
className='block break-all font-mono text-muted-foreground text-xs'
title={url}
>
{url || 'URL not provided'}
</span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
)
}
@@ -499,7 +509,7 @@ export function InlineToolCall({
const normalizedEntries: Array<[string, string]> = []
Object.entries(variables).forEach(([key, value]) => {
if (typeof value === 'object' && value !== null && 'name' in value && 'value' in value) {
// Handle {name: "key", value: "val"} format
// Handle { name: "KEY", value: "VAL" } format
normalizedEntries.push([String((value as any).name), String((value as any).value)])
} else {
// Handle direct key-value format
@@ -508,35 +518,48 @@ export function InlineToolCall({
})
return (
<div className='w-full overflow-hidden rounded border border-muted bg-card'>
<div className='grid grid-cols-[160px_1fr] gap-0 border-muted/60 border-b bg-muted/40 py-1.5'>
<div className='self-start px-2 font-medium font-season text-[#858585] text-[11px] uppercase tracking-wide dark:text-[#E0E0E0]'>
Name
</div>
<div className='self-start px-2 font-medium font-season text-[#858585] text-[11px] uppercase tracking-wide dark:text-[#E0E0E0]'>
Value
</div>
</div>
{normalizedEntries.length === 0 ? (
<div className='px-2 py-1.5 font-[470] font-season text-[#707070] text-xs dark:text-[#E8E8E8]'>
No variables provided
</div>
) : (
<div className='divide-y divide-muted/60'>
{normalizedEntries.map(([name, value]) => (
<div key={name} className='grid grid-cols-[160px_1fr] gap-0 py-1.5'>
<div className='self-start px-2 font-medium font-season text-amber-800 text-xs dark:text-amber-200'>
{name}
</div>
<div className='min-w-0 self-start overflow-x-auto px-2'>
<span className='whitespace-nowrap font-[470] font-mono text-amber-700 text-xs dark:text-amber-300'>
{value}
</span>
</div>
</div>
))}
</div>
)}
<div className='w-full overflow-hidden rounded-[4px] border border-[var(--border-strong)] bg-[#1F1F1F]'>
<table className='w-full table-fixed bg-transparent'>
<thead className='bg-transparent'>
<tr className='border-[var(--border-strong)] border-b bg-transparent'>
<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)]'>
Name
</th>
<th className='w-[64%] bg-transparent px-[10px] py-[5px] text-left font-medium text-[14px] text-[var(--text-tertiary)]'>
Value
</th>
</tr>
</thead>
<tbody className='bg-transparent'>
{normalizedEntries.length === 0 ? (
<tr className='border-[var(--border-strong)] border-t bg-transparent'>
<td colSpan={2} className='px-[10px] py-[8px] text-muted-foreground text-xs'>
No variables provided
</td>
</tr>
) : (
normalizedEntries.map(([name, value]) => (
<tr
key={name}
className='group relative border-[var(--border-strong)] border-t bg-transparent'
>
<td className='relative w-[36%] border-[var(--border-strong)] border-r bg-transparent p-0'>
<div className='px-[10px] py-[8px]'>
<span className='truncate font-medium text-foreground text-xs'>{name}</span>
</div>
</td>
<td className='relative w-[64%] bg-transparent p-0'>
<div className='min-w-0 px-[10px] py-[8px]'>
<span className='block overflow-x-auto whitespace-nowrap font-mono text-muted-foreground text-xs'>
{value}
</span>
</div>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
)
}