-
-
Notifications
You must be signed in to change notification settings - Fork 360
feat(ui): added word wrap to code viewer #2028
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
ca13cca
e64a6b5
95848e8
e14b94f
c2108ea
1e3ed27
72c3c6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,13 +3,15 @@ const props = defineProps<{ | |
| html: string | ||
| lines: number | ||
| selectedLines: { start: number; end: number } | null | ||
| wordWrap?: boolean | ||
| }>() | ||
|
|
||
| const emit = defineEmits<{ | ||
| lineClick: [lineNum: number, event: MouseEvent] | ||
| }>() | ||
|
|
||
| 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<HTMLElement>('.line-number') | ||
| nums.forEach(num => (num.style.height = '')) | ||
| } | ||
| return | ||
| } | ||
|
|
||
| const lines = codeRef.value.querySelectorAll<HTMLElement>('code > .line') | ||
| const nums = lineNumbersRef.value.querySelectorAll<HTMLElement>('.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` | ||
| } | ||
| }) | ||
| } | ||
|
Comment on lines
+37
to
+61
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify that markdown files default to preview mode, that CodeViewer is mounted with v-show,
# and that syncLineHeights currently only reruns on html/wordWrap/resize.
rg -n -C3 "const markdownViewMode|<CodeViewer|v-show=\"!fileContent.markdownHtml \\|\\| markdownViewMode === 'code'\"" "app/pages/package-code/[[org]]/[packageName]/v/[version]/[...filePath].vue"
rg -n -C3 "function syncLineHeights|offsetHeight|watch\\(|props.wordWrap|useEventListener\\(window, 'resize'" "app/components/Code/Viewer.vue"Repository: npmx-dev/npmx.dev Length of output: 2129 Re-sync wrapped line heights after the viewer becomes visible. The parent component mounts Add visibility detection to skip measurement while hidden, or use a 🧰 Tools🪛 Biome (2.4.6)[error] 43-43: This callback passed to forEach() iterable method should not return a value. (lint/suspicious/useIterableCallbackReturn) |
||
|
|
||
| // 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( | |
| </script> | ||
|
|
||
| <template> | ||
| <div class="code-viewer flex min-h-full max-w-full"> | ||
| <div class="code-viewer flex min-h-full max-w-full" :class="{ 'is-wrapped': wordWrap }"> | ||
| <!-- Line numbers column --> | ||
| <div | ||
| ref="lineNumbersRef" | ||
| class="line-numbers shrink-0 bg-bg-subtle border-ie border-solid border-border text-end select-none relative" | ||
| :style="{ '--line-digits': lineDigits }" | ||
| aria-hidden="true" | ||
|
|
@@ -155,6 +198,12 @@ watch( | |
| transition: background-color 0.1s; | ||
| } | ||
|
|
||
| .is-wrapped .code-content :deep(.line) { | ||
| white-space: pre-wrap; | ||
| word-break: break-all; | ||
| max-height: none; | ||
| } | ||
|
|
||
| /* Highlighted lines in code content - extend full width with negative margin */ | ||
| .code-content :deep(.line.highlighted) { | ||
| @apply bg-yellow-500/20; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.