Add CodeBlock component

This commit is contained in:
Saoud Rizwan
2024-07-09 20:17:07 -04:00
parent 6f5b0565e0
commit 97faff3ba5
6 changed files with 571 additions and 53 deletions

View File

@@ -19,6 +19,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "5.0.1",
"react-syntax-highlighter": "^15.5.0",
"react-text-truncate": "^0.19.0",
"react-textarea-autosize": "^8.5.3",
"rewire": "^7.0.0",
@@ -26,6 +27,7 @@
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@types/react-syntax-highlighter": "^15.5.13",
"@types/react-text-truncate": "^0.14.4",
"@types/vscode-webview": "^1.57.5"
}
@@ -4421,6 +4423,15 @@
"@types/node": "*"
}
},
"node_modules/@types/hast": {
"version": "2.3.10",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz",
"integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==",
"license": "MIT",
"dependencies": {
"@types/unist": "^2"
}
},
"node_modules/@types/html-minifier-terser": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
@@ -4564,6 +4575,16 @@
"@types/react": "*"
}
},
"node_modules/@types/react-syntax-highlighter": {
"version": "15.5.13",
"resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz",
"integrity": "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-text-truncate": {
"version": "0.14.4",
"resolved": "https://registry.npmjs.org/@types/react-text-truncate/-/react-text-truncate-0.14.4.tgz",
@@ -4655,6 +4676,12 @@
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"license": "MIT"
},
"node_modules/@types/unist": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==",
"license": "MIT"
},
"node_modules/@types/vscode-webview": {
"version": "1.57.5",
"resolved": "https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.5.tgz",
@@ -6328,6 +6355,36 @@
"node": ">=10"
}
},
"node_modules/character-entities": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
"integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/character-entities-legacy": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
"integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/character-reference-invalid": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/check-types": {
"version": "11.2.3",
"resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz",
@@ -6501,6 +6558,16 @@
"node": ">= 0.8"
}
},
"node_modules/comma-separated-tokens": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
"integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/commander": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
@@ -8825,6 +8892,19 @@
"reusify": "^1.0.4"
}
},
"node_modules/fault": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz",
"integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==",
"license": "MIT",
"dependencies": {
"format": "^0.2.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/faye-websocket": {
"version": "0.11.4",
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
@@ -9268,6 +9348,14 @@
"node": ">= 6"
}
},
"node_modules/format": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz",
"integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==",
"engines": {
"node": ">=0.4.x"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -9710,6 +9798,33 @@
"node": ">= 0.4"
}
},
"node_modules/hast-util-parse-selector": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
"integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/hastscript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
"integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==",
"license": "MIT",
"dependencies": {
"@types/hast": "^2.0.0",
"comma-separated-tokens": "^1.0.0",
"hast-util-parse-selector": "^2.0.0",
"property-information": "^5.0.0",
"space-separated-tokens": "^1.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
@@ -9719,6 +9834,15 @@
"he": "bin/he"
}
},
"node_modules/highlight.js": {
"version": "10.7.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
"license": "BSD-3-Clause",
"engines": {
"node": "*"
}
},
"node_modules/hoopy": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
@@ -10153,6 +10277,30 @@
"node": ">= 10"
}
},
"node_modules/is-alphabetical": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
"integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-alphanumerical": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
"integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
"license": "MIT",
"dependencies": {
"is-alphabetical": "^1.0.0",
"is-decimal": "^1.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@@ -10303,6 +10451,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-decimal": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
"integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-docker": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
@@ -10384,6 +10542,16 @@
"node": ">=0.10.0"
}
},
"node_modules/is-hexadecimal": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-map": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
@@ -13307,6 +13475,20 @@
"tslib": "^2.0.3"
}
},
"node_modules/lowlight": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz",
"integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==",
"license": "MIT",
"dependencies": {
"fault": "^1.0.0",
"highlight.js": "~10.7.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -14058,6 +14240,24 @@
"node": ">=6"
}
},
"node_modules/parse-entities": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
"license": "MIT",
"dependencies": {
"character-entities": "^1.0.0",
"character-entities-legacy": "^1.0.0",
"character-reference-invalid": "^1.0.0",
"is-alphanumerical": "^1.0.0",
"is-decimal": "^1.0.0",
"is-hexadecimal": "^1.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
@@ -15629,6 +15829,15 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/prismjs": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -15674,6 +15883,19 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
"node_modules/property-information": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz",
"integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==",
"license": "MIT",
"dependencies": {
"xtend": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -16155,6 +16377,22 @@
}
}
},
"node_modules/react-syntax-highlighter": {
"version": "15.5.0",
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz",
"integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.3.1",
"highlight.js": "^10.4.1",
"lowlight": "^1.17.0",
"prismjs": "^1.27.0",
"refractor": "^3.6.0"
},
"peerDependencies": {
"react": ">= 0.14.0"
}
},
"node_modules/react-text-truncate": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/react-text-truncate/-/react-text-truncate-0.19.0.tgz",
@@ -16266,6 +16504,30 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/refractor": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz",
"integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==",
"license": "MIT",
"dependencies": {
"hastscript": "^6.0.0",
"parse-entities": "^2.0.0",
"prismjs": "~1.27.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/refractor/node_modules/prismjs": {
"version": "1.27.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
"integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -17213,6 +17475,16 @@
"deprecated": "Please use @jridgewell/sourcemap-codec instead",
"license": "MIT"
},
"node_modules/space-separated-tokens": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz",
"integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/spdy": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
@@ -19659,6 +19931,15 @@
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"license": "MIT"
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"license": "MIT",
"engines": {
"node": ">=0.4"
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

View File

@@ -14,6 +14,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "5.0.1",
"react-syntax-highlighter": "^15.5.0",
"react-text-truncate": "^0.19.0",
"react-textarea-autosize": "^8.5.3",
"rewire": "^7.0.0",
@@ -45,6 +46,7 @@
]
},
"devDependencies": {
"@types/react-syntax-highlighter": "^15.5.13",
"@types/react-text-truncate": "^0.14.4",
"@types/vscode-webview": "^1.57.5"
}

View File

@@ -2,6 +2,9 @@ import React, { useState } from "react"
import { ClaudeMessage, ClaudeAsk, ClaudeSay, ClaudeSayTool } from "@shared/ExtensionMessage"
import { VSCodeButton, VSCodeProgressRing, VSCodeBadge } from "@vscode/webview-ui-toolkit/react"
import { COMMAND_OUTPUT_STRING } from "../utilities/combineCommandSequences"
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
import { dark } from "react-syntax-highlighter/dist/esm/styles/prism"
import CodeBlock from "./CodeBlock"
interface ChatRowProps {
message: ClaudeMessage
@@ -45,13 +48,6 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
style={{ color: successColor, marginBottom: "-1.5px" }}></span>,
<span style={{ color: successColor, fontWeight: "bold" }}>Task Completed</span>,
]
case "tool":
return [
<span
className="codicon codicon-tools"
style={{ color: normalColor, marginBottom: "-1.5px" }}></span>,
<span style={{ color: normalColor, fontWeight: "bold" }}>Tool</span>,
]
case "api_req_started":
return [
cost ? (
@@ -123,47 +119,51 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
tool: "editedExistingFile",
path: "/path/to/file",
}
const toolIcon = (name: string) => (
<span
className={`codicon codicon-${name}`}
style={{ color: "var(--vscode-foreground)", marginBottom: "-1.5px" }}></span>
)
switch (tool.tool) {
case "editedExistingFile":
return (
<>
<div style={headerStyle}>
{icon}
Edited File
{toolIcon("edit")}
Edited file...
</div>
<p>Path: {tool.path!}</p>
<p>{tool.diff!}</p>
<CodeBlock diff={tool.diff!} path={tool.path!} />
</>
)
case "newFileCreated":
return (
<>
<div style={headerStyle}>
{icon}
Created New File
{toolIcon("new-file")}
Created new file...
</div>
<p>Path: {tool.path!}</p>
<p>{tool.content!}</p>
<CodeBlock code={tool.content!} path={tool.path!} />
</>
)
case "readFile":
return (
<>
<div style={headerStyle}>
{icon}
Read File
{toolIcon("file-code")}
Read file...
</div>
<p>Path: {tool.path!}</p>
<CodeBlock code={tool.content!} path={tool.path!} />
</>
)
case "listFiles":
return (
<>
<div style={headerStyle}>
{icon}
Viewed Directory
{toolIcon("folder-opened")}
Viewed contents of directory...
</div>
<p>Path: {tool.path!}</p>
<CodeBlock code={tool.content!} path={tool.path!} language="shell-session" />
</>
)
}
@@ -244,14 +244,24 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
{title}
</div>
<div style={contentStyle}>
<p style={contentStyle}>Claude Dev wants to execute the following terminal command. Would you like to proceed?</p>
<p style={contentStyle}>{command}</p>
<p style={contentStyle}>
Claude Dev wants to execute the following terminal command. Would you like to
proceed?
</p>
<div style={{ marginTop: "10px" }}>
<CodeBlock code={command} language="shell-session" />
</div>
{output && (
<>
<p style={{ ...contentStyle, fontWeight: "bold" }}>
<p style={{ ...contentStyle, margin: "10px 0 10px 0" }}>
{COMMAND_OUTPUT_STRING}
</p>
<p style={contentStyle}>{output}</p>
<CodeBlock
code={output}
language="shell-session"
path="src/components/WelcomeView.tsx/src/components/WelcomeView.tsx"
/>
</>
)}
</div>
@@ -300,7 +310,9 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
}}>
{renderContent()}
{isExpanded && message.say === "api_req_started" && (
<p style={{ marginTop: "10px" }}>{JSON.stringify(JSON.parse(message.text || "{}").request)}</p>
<div style={{ marginTop: "10px" }}>
<CodeBlock code={JSON.stringify(JSON.parse(message.text || "{}").request)} language="json" />
</div>
)}
</div>
)

View File

@@ -0,0 +1,143 @@
import React, { useState } from "react"
import SyntaxHighlighter from "react-syntax-highlighter"
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism"
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
/*
const vscodeSyntaxStyle: React.CSSProperties = {
backgroundColor: "var(--vscode-editor-background)",
color: "var(--vscode-editor-foreground)",
fontFamily: "var(--vscode-editor-font-family)",
fontSize: "var(--vscode-editor-font-size)",
lineHeight: "var(--vscode-editor-line-height)",
textAlign: "left",
whiteSpace: "pre",
wordSpacing: "normal",
wordBreak: "normal",
wordWrap: "normal",
tabSize: 4,
hyphens: "none",
padding: "1em",
margin: "0.5em 0",
overflow: "auto",
borderRadius: "6px",
}
const tokenStyles = {
comment: { color: "var(--vscode-editor-foreground)" },
prolog: { color: "var(--vscode-editor-foreground)" },
doctype: { color: "var(--vscode-editor-foreground)" },
cdata: { color: "var(--vscode-editor-foreground)" },
punctuation: { color: "var(--vscode-editor-foreground)" },
property: { color: "var(--vscode-symbolIcon-propertyForeground)" },
tag: { color: "var(--vscode-symbolIcon-colorForeground)" },
boolean: { color: "var(--vscode-symbolIcon-booleanForeground)" },
number: { color: "var(--vscode-symbolIcon-numberForeground)" },
constant: { color: "var(--vscode-symbolIcon-constantForeground)" },
symbol: { color: "var(--vscode-symbolIcon-colorForeground)" },
selector: { color: "var(--vscode-symbolIcon-colorForeground)" },
"attr-name": { color: "var(--vscode-symbolIcon-propertyForeground)" },
string: { color: "var(--vscode-symbolIcon-stringForeground)" },
char: { color: "var(--vscode-symbolIcon-stringForeground)" },
builtin: { color: "var(--vscode-symbolIcon-keywordForeground)" },
inserted: { color: "var(--vscode-gitDecoration-addedResourceForeground)" },
operator: { color: "var(--vscode-symbolIcon-operatorForeground)" },
entity: { color: "var(--vscode-symbolIcon-snippetForeground)", cursor: "help" },
url: { color: "var(--vscode-textLink-foreground)" },
variable: { color: "var(--vscode-symbolIcon-variableForeground)" },
atrule: { color: "var(--vscode-symbolIcon-keywordForeground)" },
"attr-value": { color: "var(--vscode-symbolIcon-stringForeground)" },
keyword: { color: "var(--vscode-symbolIcon-keywordForeground)" },
function: { color: "var(--vscode-symbolIcon-functionForeground)" },
regex: { color: "var(--vscode-symbolIcon-regexForeground)" },
important: { color: "var(--vscode-editorWarning-foreground)", fontWeight: "bold" },
bold: { fontWeight: "bold" },
italic: { fontStyle: "italic" },
deleted: { color: "var(--vscode-gitDecoration-deletedResourceForeground)" },
}
*/
interface CodeBlockProps {
code?: string
diff?: string
language?: string | undefined
path?: string
}
const CodeBlock = ({ code, diff, language, path }: CodeBlockProps) => {
const [isExpanded, setIsExpanded] = useState(false)
const backgroundColor = oneDark['pre[class*="language-"]'].background as string
return (
<div
style={{
borderRadius: "3px",
backgroundColor: backgroundColor,
overflow: "hidden", // This ensures the inner scrollable area doesn't overflow the rounded corners
}}>
{path && (
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
padding: "6px 10px",
}}>
<span
style={{
color: "var(--vscode-descriptionForeground)",
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
marginRight: "8px",
// trick to get ellipsis at beginning of string
direction: "rtl",
textAlign: "left",
}}>
{path}
</span>
<VSCodeButton appearance="icon" aria-label="Toggle Code" onClick={() => setIsExpanded(!isExpanded)}>
<span className={`codicon codicon-chevron-${isExpanded ? "up" : "down"}`}></span>
</VSCodeButton>
</div>
)}
{(!path || isExpanded) && (
<div
className="code-block-scrollable"
style={{
overflowX: "auto",
overflowY: "hidden",
maxWidth: "100%",
}}>
<SyntaxHighlighter
wrapLines={false}
language={language}
style={oneDark}
customStyle={{
margin: 0,
padding: "6px 10px",
borderRadius: 0,
}}
lineProps={
diff != null
? (lineNumber) => {
const line = diff?.split("\n")?.[lineNumber - 1]
let style: React.CSSProperties = { display: "block", width: "100%" }
if (line && line[0] === "+") {
style.backgroundColor = "var(--vscode-diffEditor-insertedTextBackground)"
} else if (line && line[0] === "-") {
style.backgroundColor = "var(--vscode-diffEditor-removedTextBackground)"
}
return { style }
}
: undefined
}>
{code ?? diff ?? ""}
</SyntaxHighlighter>
</div>
)}
</div>
)
}
export default CodeBlock

View File

@@ -34,7 +34,7 @@ body {
}
body.scrollable,
.scrollable {
.scrollable, body.code-block-scrollable, .code-block-scrollable {
border-color: transparent;
transition: border-color 0.7s linear;
}
@@ -42,16 +42,21 @@ body.scrollable,
body:hover.scrollable,
body:hover .scrollable,
body:focus-within.scrollable,
body:focus-within .scrollable {
body:focus-within .scrollable,
body:hover.code-block-scrollable,
body:hover .code-block-scrollable,
body:focus-within.code-block-scrollable,
body:focus-within .code-block-scrollable
{
border-color: var(--vscode-scrollbarSlider-background);
transition: none;
}
::-webkit-scrollbar-corner {
.scrollable::-webkit-scrollbar-corner {
background-color: transparent !important;
}
::-webkit-scrollbar-thumb {
.scrollable::-webkit-scrollbar-thumb {
background-color: transparent;
border-color: inherit;
border-right-style: inset;
@@ -59,11 +64,11 @@ body:focus-within .scrollable {
border-radius: unset !important;
}
::-webkit-scrollbar-thumb:hover {
.scrollable::-webkit-scrollbar-thumb:hover {
border-color: var(--vscode-scrollbarSlider-hoverBackground);
}
::-webkit-scrollbar-thumb:active {
.scrollable::-webkit-scrollbar-thumb:active {
border-color: var(--vscode-scrollbarSlider-activeBackground);
}
@@ -75,4 +80,31 @@ https://github.com/microsoft/vscode/issues/213045
html {
scrollbar-color: unset;
}
}
/*
The above scrollbar styling uses some transparent background color magic to accomplish its animation. However this doesn't play nicely with SyntaxHighlighter, so we need to set a background color for the code blocks' horizontal scrollbar. This actually has the unintended consequence of always showing the scrollbar which I prefer since it makes it more obvious that there is more content to scroll to.
*/
.code-block-scrollable::-webkit-scrollbar-track {
background: transparent;
}
.code-block-scrollable::-webkit-scrollbar-thumb {
background-color: var(--vscode-scrollbarSlider-background);
border-radius: 5px;
border: 2px solid transparent;
background-clip: content-box;
}
.code-block-scrollable::-webkit-scrollbar-thumb:hover {
background-color: var(--vscode-scrollbarSlider-hoverBackground);
}
.code-block-scrollable::-webkit-scrollbar-thumb:active {
background-color: var(--vscode-scrollbarSlider-activeBackground);
}
.code-block-scrollable::-webkit-scrollbar-corner {
background-color: transparent;
}