Use Lucide icons and translations in the code block (#3203)

This commit is contained in:
Matt Rubens 2025-05-05 23:19:24 -04:00 committed by GitHub
parent da6c50bf10
commit 8ab0de3d02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 193 additions and 15 deletions

View file

@ -4,6 +4,8 @@ import { useCopyToClipboard } from "@src/utils/clipboard"
import { getHighlighter, isLanguageLoaded, normalizeLanguage, ExtendedLanguage } from "@src/utils/highlighter"
import { bundledLanguages } from "shiki"
import type { ShikiTransformer } from "shiki"
import { ChevronDown, ChevronUp, WrapText, AlignJustify, Copy, Check } from "lucide-react"
import { useAppTranslation } from "@src/i18n/TranslationContext"
export const CODE_BLOCK_BG_COLOR = "var(--vscode-editor-background, --vscode-sideBar-background, rgb(30 30 30))"
export const WRAPPER_ALPHA = "cc" // 80% opacity
// Configuration constants
@ -34,13 +36,6 @@ interface CodeBlockProps {
onLanguageChange?: (language: string) => void
}
const ButtonIcon = styled.span`
display: inline-block;
width: 1.2em;
text-align: center;
vertical-align: middle;
`
const CodeBlockButton = styled.button`
background: transparent;
border: none;
@ -50,16 +45,23 @@ const CodeBlockButton = styled.button`
margin: 0 0px;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.4;
border-radius: 3px;
pointer-events: var(--copy-button-events, none);
margin-left: 4px;
height: 24px;
width: 24px;
&:hover {
background: var(--vscode-toolbar-hoverBackground);
opacity: 1;
}
/* Style for Lucide icons to ensure consistent sizing and positioning */
svg {
display: block;
}
`
const CodeBlockButtonWrapper = styled.div`
@ -229,6 +231,7 @@ const CodeBlock = memo(
const preRef = useRef<HTMLDivElement>(null)
const copyButtonWrapperRef = useRef<HTMLDivElement>(null)
const { showCopyFeedback, copyWithFeedback } = useCopyToClipboard()
const { t } = useAppTranslation()
// Update current language when prop changes, but only if user hasn't made a selection
useEffect(() => {
@ -696,19 +699,17 @@ const CodeBlock = memo(
WINDOW_SHADE_SETTINGS.transitionDelayS * 1000 + 50,
)
}}
title={`${windowShade ? "Expand" : "Collapse"} code block`}>
<ButtonIcon style={{ fontSize: "16px" }}>{windowShade ? "⌄" : "⌃"}</ButtonIcon>
title={t(`chat:codeblock.tooltips.${windowShade ? "expand" : "collapse"}`)}>
{windowShade ? <ChevronDown size={16} /> : <ChevronUp size={16} />}
</CodeBlockButton>
)}
<CodeBlockButton
onClick={() => setWordWrap(!wordWrap)}
title={`${wordWrap ? "Disable" : "Enable"} word wrap`}>
<ButtonIcon style={{ fontSize: "16px", fontWeight: 900 }}>
{wordWrap ? "⟼" : "⤸"}
</ButtonIcon>
title={t(`chat:codeblock.tooltips.${wordWrap ? "disable_wrap" : "enable_wrap"}`)}>
{wordWrap ? <AlignJustify size={16} /> : <WrapText size={16} />}
</CodeBlockButton>
<CodeBlockButton onClick={handleCopy} title="Copy code">
<ButtonIcon className={`codicon codicon-${showCopyFeedback ? "check" : "copy"}`} />
<CodeBlockButton onClick={handleCopy} title={t("chat:codeblock.tooltips.copy_code")}>
{showCopyFeedback ? <Check size={16} /> : <Copy size={16} />}
</CodeBlockButton>
</CodeBlockButtonWrapper>
)}

View file

@ -2,6 +2,23 @@ import { render, screen, fireEvent, act } from "@testing-library/react"
import "@testing-library/jest-dom"
import CodeBlock from "../CodeBlock"
// Mock the translation context
jest.mock("../../../i18n/TranslationContext", () => ({
useAppTranslation: () => ({
t: (key: string) => {
// Return fixed English strings for tests
const translations: { [key: string]: string } = {
"chat:codeblock.tooltips.copy_code": "Copy code",
"chat:codeblock.tooltips.expand": "Expand code block",
"chat:codeblock.tooltips.collapse": "Collapse code block",
"chat:codeblock.tooltips.enable_wrap": "Enable word wrap",
"chat:codeblock.tooltips.disable_wrap": "Disable word wrap",
}
return translations[key] || key
},
}),
}))
// Mock shiki module
jest.mock("shiki", () => ({
bundledLanguages: {
@ -11,6 +28,22 @@ jest.mock("shiki", () => ({
},
}))
// Mock all lucide-react icons with a proxy to handle any icon requested
jest.mock("lucide-react", () => {
return new Proxy(
{},
{
get: function (obj, prop) {
// Return a component factory for any icon that's requested
if (prop === "__esModule") {
return true
}
return () => <div data-testid={`${String(prop)}-icon`}>{String(prop)}</div>
},
},
)
})
// Mock the highlighter utility
jest.mock("../../../utils/highlighter", () => {
const mockHighlighter = {

View file

@ -233,6 +233,15 @@
"close": "Tancar navegador"
}
},
"codeblock": {
"tooltips": {
"expand": "Expandir bloc de codi",
"collapse": "Contraure bloc de codi",
"enable_wrap": "Activar ajustament de línia",
"disable_wrap": "Desactivar ajustament de línia",
"copy_code": "Copiar codi"
}
},
"systemPromptWarning": "ADVERTÈNCIA: S'ha activat una substitució personalitzada d'instruccions del sistema. Això pot trencar greument la funcionalitat i causar un comportament impredictible.",
"shellIntegration": {
"title": "Advertència d'execució d'ordres",

View file

@ -233,6 +233,15 @@
"close": "Browser schließen"
}
},
"codeblock": {
"tooltips": {
"expand": "Code-Block erweitern",
"collapse": "Code-Block reduzieren",
"enable_wrap": "Zeilenumbruch aktivieren",
"disable_wrap": "Zeilenumbruch deaktivieren",
"copy_code": "Code kopieren"
}
},
"systemPromptWarning": "WARNUNG: Benutzerdefinierte Systemaufforderung aktiv. Dies kann die Funktionalität erheblich beeinträchtigen und zu unvorhersehbarem Verhalten führen.",
"shellIntegration": {
"title": "Befehlsausführungswarnung",

View file

@ -233,6 +233,15 @@
"close": "Close browser"
}
},
"codeblock": {
"tooltips": {
"expand": "Expand code block",
"collapse": "Collapse code block",
"enable_wrap": "Enable word wrap",
"disable_wrap": "Disable word wrap",
"copy_code": "Copy code"
}
},
"systemPromptWarning": "WARNING: Custom system prompt override active. This can severely break functionality and cause unpredictable behavior.",
"shellIntegration": {
"title": "Command Execution Warning",

View file

@ -233,6 +233,15 @@
"close": "Cerrar navegador"
}
},
"codeblock": {
"tooltips": {
"expand": "Expandir bloque de código",
"collapse": "Contraer bloque de código",
"enable_wrap": "Activar ajuste de línea",
"disable_wrap": "Desactivar ajuste de línea",
"copy_code": "Copiar código"
}
},
"systemPromptWarning": "ADVERTENCIA: Anulación de instrucciones del sistema personalizada activa. Esto puede romper gravemente la funcionalidad y causar un comportamiento impredecible.",
"shellIntegration": {
"title": "Advertencia de ejecución de comandos",

View file

@ -233,6 +233,15 @@
"close": "Fermer le navigateur"
}
},
"codeblock": {
"tooltips": {
"expand": "Développer le bloc de code",
"collapse": "Réduire le bloc de code",
"enable_wrap": "Activer le retour à la ligne",
"disable_wrap": "Désactiver le retour à la ligne",
"copy_code": "Copier le code"
}
},
"systemPromptWarning": "AVERTISSEMENT : Remplacement d'instructions système personnalisées actif. Cela peut gravement perturber la fonctionnalité et provoquer un comportement imprévisible.",
"shellIntegration": {
"title": "Avertissement d'exécution de commande",

View file

@ -233,6 +233,15 @@
"close": "ब्राउज़र बंद करें"
}
},
"codeblock": {
"tooltips": {
"expand": "कोड ब्लॉक का विस्तार करें",
"collapse": "कोड ब्लॉक को संकुचित करें",
"enable_wrap": "वर्ड रैप सक्षम करें",
"disable_wrap": "वर्ड रैप अक्षम करें",
"copy_code": "कोड कॉपी करें"
}
},
"systemPromptWarning": "चेतावनी: कस्टम सिस्टम प्रॉम्प्ट ओवरराइड सक्रिय है। यह कार्यक्षमता को गंभीर रूप से बाधित कर सकता है और अनियमित व्यवहार का कारण बन सकता है.",
"shellIntegration": {
"title": "कमांड निष्पादन चेतावनी",

View file

@ -233,6 +233,15 @@
"close": "Chiudi browser"
}
},
"codeblock": {
"tooltips": {
"expand": "Espandi blocco di codice",
"collapse": "Comprimi blocco di codice",
"enable_wrap": "Attiva a capo automatico",
"disable_wrap": "Disattiva a capo automatico",
"copy_code": "Copia codice"
}
},
"systemPromptWarning": "ATTENZIONE: Sovrascrittura personalizzata delle istruzioni di sistema attiva. Questo può compromettere gravemente le funzionalità e causare comportamenti imprevedibili.",
"shellIntegration": {
"title": "Avviso di esecuzione comando",

View file

@ -233,6 +233,15 @@
"close": "ブラウザを閉じる"
}
},
"codeblock": {
"tooltips": {
"expand": "コードブロックを展開",
"collapse": "コードブロックを折りたたむ",
"enable_wrap": "折り返しを有効化",
"disable_wrap": "折り返しを無効化",
"copy_code": "コードをコピー"
}
},
"systemPromptWarning": "警告:カスタムシステムプロンプトの上書きが有効です。これにより機能が深刻に損なわれ、予測不可能な動作が発生する可能性があります。",
"shellIntegration": {
"title": "コマンド実行警告",

View file

@ -233,6 +233,15 @@
"close": "브라우저 닫기"
}
},
"codeblock": {
"tooltips": {
"expand": "코드 블록 확장",
"collapse": "코드 블록 축소",
"enable_wrap": "자동 줄바꿈 활성화",
"disable_wrap": "자동 줄바꿈 비활성화",
"copy_code": "코드 복사"
}
},
"systemPromptWarning": "경고: 사용자 정의 시스템 프롬프트 재정의가 활성화되었습니다. 이로 인해 기능이 심각하게 손상되고 예측할 수 없는 동작이 발생할 수 있습니다.",
"shellIntegration": {
"title": "명령 실행 경고",

View file

@ -233,6 +233,15 @@
"close": "Zamknij przeglądarkę"
}
},
"codeblock": {
"tooltips": {
"expand": "Rozwiń blok kodu",
"collapse": "Zwiń blok kodu",
"enable_wrap": "Włącz zawijanie wierszy",
"disable_wrap": "Wyłącz zawijanie wierszy",
"copy_code": "Kopiuj kod"
}
},
"systemPromptWarning": "OSTRZEŻENIE: Aktywne niestandardowe zastąpienie instrukcji systemowych. Może to poważnie zakłócić funkcjonalność i powodować nieprzewidywalne zachowanie.",
"shellIntegration": {
"title": "Ostrzeżenie wykonania polecenia",

View file

@ -233,6 +233,15 @@
"close": "Fechar navegador"
}
},
"codeblock": {
"tooltips": {
"expand": "Expandir bloco de código",
"collapse": "Recolher bloco de código",
"enable_wrap": "Ativar quebra de linha",
"disable_wrap": "Desativar quebra de linha",
"copy_code": "Copiar código"
}
},
"systemPromptWarning": "AVISO: Substituição personalizada de instrução do sistema ativa. Isso pode comprometer gravemente a funcionalidade e causar comportamento imprevisível.",
"shellIntegration": {
"title": "Aviso de execução de comando",

View file

@ -233,6 +233,15 @@
"close": "Закрыть браузер"
}
},
"codeblock": {
"tooltips": {
"expand": "Развернуть блок кода",
"collapse": "Свернуть блок кода",
"enable_wrap": "Включить перенос строк",
"disable_wrap": "Отключить перенос строк",
"copy_code": "Копировать код"
}
},
"systemPromptWarning": "ПРЕДУПРЕЖДЕНИЕ: Активна пользовательская системная подсказка. Это может серьезно нарушить работу и вызвать непредсказуемое поведение.",
"shellIntegration": {
"title": "Предупреждение о выполнении команды",

View file

@ -233,6 +233,15 @@
"close": "Tarayıcıyı kapat"
}
},
"codeblock": {
"tooltips": {
"expand": "Kod bloğunu genişlet",
"collapse": "Kod bloğunu daralt",
"enable_wrap": "Satır kaydırmayı etkinleştir",
"disable_wrap": "Satır kaydırmayı devre dışı bırak",
"copy_code": "Kodu kopyala"
}
},
"systemPromptWarning": "UYARI: Özel sistem komut geçersiz kılma aktif. Bu işlevselliği ciddi şekilde bozabilir ve öngörülemeyen davranışlara neden olabilir.",
"shellIntegration": {
"title": "Komut Çalıştırma Uyarısı",

View file

@ -233,6 +233,15 @@
"close": "Đóng trình duyệt"
}
},
"codeblock": {
"tooltips": {
"expand": "Mở rộng khối mã",
"collapse": "Thu gọn khối mã",
"enable_wrap": "Bật tự động xuống dòng",
"disable_wrap": "Tắt tự động xuống dòng",
"copy_code": "Sao chép mã"
}
},
"systemPromptWarning": "CẢNH BÁO: Đã kích hoạt ghi đè lệnh nhắc hệ thống tùy chỉnh. Điều này có thể phá vỡ nghiêm trọng chức năng và gây ra hành vi không thể dự đoán.",
"shellIntegration": {
"title": "Cảnh báo thực thi lệnh",

View file

@ -233,6 +233,15 @@
"close": "关闭浏览器"
}
},
"codeblock": {
"tooltips": {
"expand": "展开代码块",
"collapse": "收起代码块",
"enable_wrap": "启用自动换行",
"disable_wrap": "禁用自动换行",
"copy_code": "复制代码"
}
},
"systemPromptWarning": "警告:自定义系统提示词覆盖已激活。这可能严重破坏功能并导致不可预测的行为。",
"shellIntegration": {
"title": "命令执行警告",

View file

@ -233,6 +233,15 @@
"close": "關閉瀏覽器"
}
},
"codeblock": {
"tooltips": {
"expand": "展開程式碼區塊",
"collapse": "摺疊程式碼區塊",
"enable_wrap": "啟用自動換行",
"disable_wrap": "停用自動換行",
"copy_code": "複製程式碼"
}
},
"systemPromptWarning": "警告:自訂系統提示詞覆蓋已啟用。這可能嚴重破壞功能並導致不可預測的行為。",
"shellIntegration": {
"title": "命令執行警告",