From 94f940cddc9ca39d484996616f9f4b322c1ff7f8 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 1 Mar 2026 11:49:55 +0900 Subject: fix(frontend): render line numbers before syntax highlighting to prevent layout shift Show plaintext with Shiki-compatible line structure (.shiki > code > .line) from the start, so CSS line-number counters apply immediately. This prevents the popover from jittering when Shiki replaces the content. If Shiki fails, the plaintext with line numbers remains as a natural fallback. Co-Authored-By: Claude Opus 4.6 --- frontend/app/components/Gaming/CodeBlock.tsx | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/frontend/app/components/Gaming/CodeBlock.tsx b/frontend/app/components/Gaming/CodeBlock.tsx index 49ef01e..2107f94 100644 --- a/frontend/app/components/Gaming/CodeBlock.tsx +++ b/frontend/app/components/Gaming/CodeBlock.tsx @@ -8,12 +8,30 @@ type Props = { language: BundledLanguage; }; +function Plaintext({ code }: { code: string }) { + const lines = code.split("\n"); + return ( +
+			
+				{lines.map((line, i) => (
+					
+						{line}
+						{i < lines.length - 1 ? "\n" : ""}
+					
+				))}
+			
+		
+ ); +} + export default function CodeBlock({ code, language }: Props) { const [nodes, setNodes] = useState(null); const [showCopied, setShowCopied] = useState(false); useLayoutEffect(() => { - highlight(code, language).then(setNodes); + highlight(code, language) + .then(setNodes) + .catch(() => setNodes(null)); }, [code, language]); const handleCopy = () => { @@ -37,9 +55,9 @@ export default function CodeBlock({ code, language }: Props) { )} )} -
-				{nodes === null ? {code} : nodes}
-			
+
+ {nodes ?? } + </div> </div> ); } -- cgit v1.3.1