diff --git a/webui2/src/components/code/file-viewer.module.css b/webui2/src/components/code/file-viewer.module.css new file mode 100644 index 0000000000000000000000000000000000000000..0df9b0fffcb32c3f4f2428c7518361a4e333807e --- /dev/null +++ b/webui2/src/components/code/file-viewer.module.css @@ -0,0 +1,50 @@ +.code_block { + overflow-x: auto; + font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; + font-size: 0.75rem; + line-height: 1.25rem; +} + +.code_content pre { + margin: 0 !important; + padding: 0 !important; +} + +.code_content code { + display: block; +} + +.code_content code > .line { + display: block; + min-width: 100%; + padding-right: 1rem; +} + +.code_content code > .line:first-child { + padding-top: 0.5rem; +} + +.code_content code > .line:last-child { + padding-bottom: 0.5rem; +} + +/* Line numbers via ::before pseudo-element */ +.code_content code > .line::before { + content: attr(data-line-number); + display: inline-block; + width: 3rem; + margin-right: 1rem; + text-align: right; + opacity: 0.4; + user-select: none; + cursor: pointer; +} + +/* Line highlighting */ +.code_content code > .line.highlighted { + background-color: rgba(255, 235, 59, 0.3); +} + +:global(.dark) .code_content code > .line.highlighted { + background-color: rgba(255, 235, 59, 0.15); +} diff --git a/webui2/src/components/code/file-viewer.tsx b/webui2/src/components/code/file-viewer.tsx index a4c5b925bb5f71d2a57097fcad9695183ce9d2fe..9549357ef8b1d75c3d23027a60284c926c7f541d 100644 --- a/webui2/src/components/code/file-viewer.tsx +++ b/webui2/src/components/code/file-viewer.tsx @@ -12,7 +12,8 @@ import { createOnigurumaEngine } from "shiki/engine/oniguruma"; import type { GitBlob } from "@/__generated__/graphql"; import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; -import { cn } from "@/lib/utils"; + +import styles from "./file-viewer.module.css"; // ── Shiki highlighter (lazy singleton) ──────────────────────────────────────── @@ -284,24 +285,23 @@ interface CodeBlockProps { } function CodeBlock({ selectedRange, onLineClick, children }: CodeBlockProps) { - // Build CSS for highlighted lines via nth-child selectors + // Build a scoped - ); + const rule = selectors.join(","); + return ; })(); return (
{ - // Handle clicks on line number elements (data-line-number) const target = e.target as HTMLElement; const lineEl = target.closest("[data-line-number]"); if (lineEl) { @@ -312,16 +312,7 @@ function CodeBlock({ selectedRange, onLineClick, children }: CodeBlockProps) { }} > {highlightStyle} -
.line]:block [&_code>.line]:min-w-full [&_code>.line]:pr-4", - "[&_code>.line:first-child]:pt-2 [&_code>.line:last-child]:pb-2", - "[&_code>.line::before]:inline-block [&_code>.line::before]:w-12 [&_code>.line::before]:mr-4 [&_code>.line::before]:text-right [&_code>.line::before]:select-none [&_code>.line::before]:cursor-pointer [&_code>.line::before]:content-[attr(data-line-number)]", - "[&_code>.line::before]:opacity-40", - )} - > +
{children}