diff --git a/webui2/src/components/code/file-viewer.module.css b/webui2/src/components/code/file-viewer.module.css index ee4b6baa72702fb061a2ec1eae0c8e96f239191c..b3d5ce0372a6b8fa696c6dcaa60113144aba5f5d 100644 --- a/webui2/src/components/code/file-viewer.module.css +++ b/webui2/src/components/code/file-viewer.module.css @@ -28,9 +28,8 @@ padding-bottom: 0.5rem; } -/* Line numbers via ::before pseudo-element */ -.line::before { - content: attr(data-line-number); +/* Line number gutter — injected as a by the Shiki transformer */ +.line-number { display: inline-block; width: 3rem; margin-right: 1rem; @@ -39,3 +38,7 @@ user-select: none; cursor: pointer; } + +.line-number:hover { + opacity: 0.8; +} diff --git a/webui2/src/components/code/file-viewer.tsx b/webui2/src/components/code/file-viewer.tsx index 85a6bf88224a75e1aba846d7691eb17c14f1911b..81fe268161f740889d09b45ffaed79f751a544aa 100644 --- a/webui2/src/components/code/file-viewer.tsx +++ b/webui2/src/components/code/file-viewer.tsx @@ -96,7 +96,16 @@ function lineNumberTransformer(): ShikiTransformer { line(node, line) { // Replace Shiki's "line" class with our CSS module class node.properties["className"] = [styles["line"]!]; - node.properties["dataLineNumber"] = line; + // Prepend a gutter for the line number — clickable target + node.children.unshift({ + type: "element", + tagName: "span", + properties: { + className: [styles["line-number"]!], + dataLineNumber: line, + }, + children: [{ type: "text", value: String(line) }], + }); // Append a \n text node so copy-paste preserves newlines // (we strip the inter-element whitespace nodes in code() below). node.children.push({ type: "text", value: "\n" });