diff --git a/app/components/Code/Viewer.vue b/app/components/Code/Viewer.vue index 90bcf0c221..ec544b6e83 100644 --- a/app/components/Code/Viewer.vue +++ b/app/components/Code/Viewer.vue @@ -3,6 +3,7 @@ const props = defineProps<{ html: string lines: number selectedLines: { start: number; end: number } | null + wordWrap?: boolean }>() const emit = defineEmits<{ @@ -10,6 +11,7 @@ const emit = defineEmits<{ }>() const codeRef = useTemplateRef('codeRef') +const lineNumbersRef = useTemplateRef('lineNumbersRef') // Generate line numbers array const lineNumbers = computed(() => { @@ -32,6 +34,30 @@ function onLineClick(lineNum: number, event: MouseEvent) { emit('lineClick', lineNum, event) } +// Synchronize line number heights with code line heights (needed for word wrap) +function syncLineHeights() { + if (!props.wordWrap || !codeRef.value || !lineNumbersRef.value) { + // Reset heights if word wrap is disabled + if (lineNumbersRef.value) { + const nums = lineNumbersRef.value.querySelectorAll('.line-number') + nums.forEach(num => (num.style.height = '')) + } + return + } + + const lines = codeRef.value.querySelectorAll('code > .line') + const nums = lineNumbersRef.value.querySelectorAll('.line-number') + + lines.forEach((line, index) => { + const num = nums[index] + if (num) { + // Use getBoundingClientRect for more precision if needed, but offsetHeight is usually enough + const height = line.offsetHeight + num.style.height = `${height}px` + } + }) +} + // Apply highlighting to code lines when selection changes function updateLineHighlighting() { if (!codeRef.value) return @@ -53,11 +79,27 @@ function updateLineHighlighting() { watch( () => [props.selectedLines, props.html] as const, () => { - nextTick(updateLineHighlighting) + nextTick(() => { + updateLineHighlighting() + syncLineHeights() + }) }, { immediate: true }, ) +// Also watch wordWrap specifically +watch( + () => props.wordWrap, + () => { + nextTick(syncLineHeights) + }, +) + +// Sync on resize +if (import.meta.client) { + useEventListener(window, 'resize', syncLineHeights) +} + // Use Nuxt's `navigateTo` for the rendered import links function handleImportLinkNavigate() { if (!codeRef.value) return @@ -86,9 +128,10 @@ watch( diff --git a/i18n/locales/en.json b/i18n/locales/en.json index c187265c73..9b1caf72f3 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -793,6 +793,7 @@ }, "file_path": "File path", "scroll_to_top": "Scroll to top", + "word_wrap": "Word wrap", "binary_file": "Binary file", "binary_rendering_warning": "File type not supported for preview." }, diff --git a/i18n/schema.json b/i18n/schema.json index 1ee624a990..735b332582 100644 --- a/i18n/schema.json +++ b/i18n/schema.json @@ -2383,6 +2383,9 @@ "scroll_to_top": { "type": "string" }, + "word_wrap": { + "type": "string" + }, "binary_file": { "type": "string" },