mirror of
https://github.com/andrepimenta/claude-code-chat.git
synced 2025-12-11 20:59:43 +00:00
Copy code block
This commit is contained in:
@@ -856,6 +856,59 @@ const styles = `
|
|||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Code block container and header */
|
||||||
|
.code-block-container {
|
||||||
|
margin: 8px 0;
|
||||||
|
border: 1px solid var(--vscode-panel-border);
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: var(--vscode-textCodeBlock-background);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-block-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px 6px;
|
||||||
|
background-color: var(--vscode-editor-background);
|
||||||
|
border-bottom: 1px solid var(--vscode-panel-border);
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-block-language {
|
||||||
|
color: var(--vscode-descriptionForeground);
|
||||||
|
font-family: var(--vscode-editor-font-family);
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-copy-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--vscode-descriptionForeground);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-copy-btn:hover {
|
||||||
|
background-color: var(--vscode-list-hoverBackground);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-block-container .code-block {
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Inline code */
|
/* Inline code */
|
||||||
.message-content code {
|
.message-content code {
|
||||||
background-color: var(--vscode-textCodeBlock-background);
|
background-color: var(--vscode-textCodeBlock-background);
|
||||||
|
|||||||
52
src/ui.ts
52
src/ui.ts
@@ -1815,6 +1815,32 @@ const html = `<!DOCTYPE html>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function copyCodeBlock(codeId) {
|
||||||
|
const codeElement = document.getElementById(codeId);
|
||||||
|
if (codeElement) {
|
||||||
|
const rawCode = codeElement.getAttribute('data-raw-code');
|
||||||
|
if (rawCode) {
|
||||||
|
// Decode HTML entities
|
||||||
|
const decodedCode = rawCode.replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
|
||||||
|
navigator.clipboard.writeText(decodedCode).then(() => {
|
||||||
|
// Show temporary feedback
|
||||||
|
const copyBtn = codeElement.closest('.code-block-container').querySelector('.code-copy-btn');
|
||||||
|
if (copyBtn) {
|
||||||
|
const originalInnerHTML = copyBtn.innerHTML;
|
||||||
|
copyBtn.innerHTML = '<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>';
|
||||||
|
copyBtn.style.color = '#4caf50';
|
||||||
|
setTimeout(() => {
|
||||||
|
copyBtn.innerHTML = originalInnerHTML;
|
||||||
|
copyBtn.style.color = '';
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Failed to copy code:', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
window.addEventListener('message', event => {
|
window.addEventListener('message', event => {
|
||||||
const message = event.data;
|
const message = event.data;
|
||||||
@@ -2263,6 +2289,9 @@ const html = `<!DOCTYPE html>
|
|||||||
// First, handle code blocks before line-by-line processing
|
// First, handle code blocks before line-by-line processing
|
||||||
let processedMarkdown = markdown;
|
let processedMarkdown = markdown;
|
||||||
|
|
||||||
|
// Store code blocks temporarily to protect them from further processing
|
||||||
|
const codeBlockPlaceholders = [];
|
||||||
|
|
||||||
// Handle multi-line code blocks with triple backticks
|
// Handle multi-line code blocks with triple backticks
|
||||||
// Using RegExp constructor to avoid backtick conflicts in template literal
|
// Using RegExp constructor to avoid backtick conflicts in template literal
|
||||||
const codeBlockRegex = new RegExp('\\\`\\\`\\\`(\\\\w*)\\n([\\\\s\\\\S]*?)\\\`\\\`\\\`', 'g');
|
const codeBlockRegex = new RegExp('\\\`\\\`\\\`(\\\\w*)\\n([\\\\s\\\\S]*?)\\\`\\\`\\\`', 'g');
|
||||||
@@ -2277,7 +2306,16 @@ const html = `<!DOCTYPE html>
|
|||||||
codeHtml += '<div class="code-line">' + escapedLine + '</div>';
|
codeHtml += '<div class="code-line">' + escapedLine + '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return '\\n<pre class="code-block"><code class="language-' + language + '">' + codeHtml + '</code></pre>\\n';
|
// Create unique ID for this code block
|
||||||
|
const codeId = 'code_' + Math.random().toString(36).substr(2, 9);
|
||||||
|
const escapedCode = escapeHtml(code);
|
||||||
|
|
||||||
|
const codeBlockHtml = '<div class="code-block-container"><div class="code-block-header"><span class="code-block-language">' + language + '</span><button class="code-copy-btn" onclick="copyCodeBlock(\\\'' + codeId + '\\\')" title="Copy code"><svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg></button></div><pre class="code-block"><code class="language-' + language + '" id="' + codeId + '" data-raw-code="' + escapedCode.replace(/"/g, '"') + '">' + codeHtml + '</code></pre></div>';
|
||||||
|
|
||||||
|
// Store the code block and return a placeholder
|
||||||
|
const placeholder = '__CODEBLOCK_' + codeBlockPlaceholders.length + '__';
|
||||||
|
codeBlockPlaceholders.push(codeBlockHtml);
|
||||||
|
return placeholder;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle inline code with single backticks
|
// Handle inline code with single backticks
|
||||||
@@ -2292,9 +2330,9 @@ const html = `<!DOCTYPE html>
|
|||||||
for (let line of lines) {
|
for (let line of lines) {
|
||||||
line = line.trim();
|
line = line.trim();
|
||||||
|
|
||||||
// Check if this is a code block
|
// Check if this is a code block placeholder
|
||||||
if (line.includes('<pre class="code-block"><code')) {
|
if (line.startsWith('__CODEBLOCK_') && line.endsWith('__')) {
|
||||||
// This is a complete code block on potentially multiple lines
|
// This is a code block placeholder, don't process it
|
||||||
html += line;
|
html += line;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2363,6 +2401,12 @@ const html = `<!DOCTYPE html>
|
|||||||
if (inUnorderedList) html += '</ul>';
|
if (inUnorderedList) html += '</ul>';
|
||||||
if (inOrderedList) html += '</ol>';
|
if (inOrderedList) html += '</ol>';
|
||||||
|
|
||||||
|
// Restore code block placeholders
|
||||||
|
for (let i = 0; i < codeBlockPlaceholders.length; i++) {
|
||||||
|
const placeholder = '__CODEBLOCK_' + i + '__';
|
||||||
|
html = html.replace(placeholder, codeBlockPlaceholders[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user