diff --git a/CHANGELOG.md b/CHANGELOG.md index d5806f1..c64506c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V ## [Unreleased] +### Added +- Code-Blöcke: Zeilennummernspalte links mit synchronem Scrollen (wächst dynamisch bei 100+ Zeilen, zählt auch leere Endzeilen mit); horizontaler Bildlauf bei langen Zeilen ohne automatischen Zeilenumbruch (`white-space: pre`). + ### Fixed - Light-Theme: Kontraste für Code-Blöcke (`--bg-code`), Callouts (`--bg-panel-elevated`), Zitate und Rahmen auf Notizhintergründen geschärft; VS Code Light+ Syntaxfarben für hohe Lesbarkeit optimiert. diff --git a/frontend/src/features/workspace/CodeBlockEditor.tsx b/frontend/src/features/workspace/CodeBlockEditor.tsx index 8f314b7..c4e436b 100644 --- a/frontend/src/features/workspace/CodeBlockEditor.tsx +++ b/frontend/src/features/workspace/CodeBlockEditor.tsx @@ -347,6 +347,7 @@ export const CodeBlockEditor: React.FC = ({ const copyTimerRef = useRef(null); const localTextareaRef = useRef(null); const preRef = useRef(null); + const lineNumbersRef = useRef(null); useEffect(() => { return () => { @@ -506,18 +507,42 @@ export const CodeBlockEditor: React.FC = ({ }; const handleScroll = (e: React.UIEvent) => { + const target = e.currentTarget; if (preRef.current) { - preRef.current.scrollTop = e.currentTarget.scrollTop; - preRef.current.scrollLeft = e.currentTarget.scrollLeft; + preRef.current.scrollTop = target.scrollTop; + preRef.current.scrollLeft = target.scrollLeft; + } + if (lineNumbersRef.current) { + lineNumbersRef.current.scrollTop = target.scrollTop; } }; + const handleLineNumbersScroll = (e: React.UIEvent) => { + const target = e.currentTarget; + if (localTextareaRef.current) { + localTextareaRef.current.scrollTop = target.scrollTop; + } + if (preRef.current) { + preRef.current.scrollTop = target.scrollTop; + } + }; + + const handleLineNumbersWheel = (e: React.WheelEvent) => { + if (localTextareaRef.current) { + localTextareaRef.current.scrollTop += e.deltaY; + } + }; + + const lineCount = useMemo(() => { + return currentContent.split('\n').length; + }, [currentContent]); + const rawLang = block.lang || ''; const selectValue = rawLang ? resolveLanguageId(rawLang) || rawLang : ''; const hasCustomUnknownLang = Boolean(selectValue && !KNOWN_OPTION_IDS.has(selectValue)); return ( -
+
{/* Code Block Header */}
@@ -584,41 +609,60 @@ export const CodeBlockEditor: React.FC = ({
- {/* Live Highlighted Overlay + Textarea */} -
-
+        {/* Line Numbers Column */}
+        
+
+        {/* Code Content (Overlay + Textarea) */}
+        
+ +