From a68fcf8caf71168aa1c18d3009b52205f2588a4d Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Thu, 6 Nov 2025 15:37:40 +0100 Subject: [PATCH 1/2] feat(review): ability to resize review card editor --- .../components/content/ContentCardReview.vue | 50 ++++++- src/app/src/composables/useMonaco.ts | 7 - src/app/src/composables/useMonacoDiff.ts | 15 +-- src/app/src/composables/useMonacoMinimal.ts | 125 ------------------ 4 files changed, 55 insertions(+), 142 deletions(-) delete mode 100644 src/app/src/composables/useMonacoMinimal.ts diff --git a/src/app/src/components/content/ContentCardReview.vue b/src/app/src/components/content/ContentCardReview.vue index a8db88fd..229a8a47 100644 --- a/src/app/src/components/content/ContentCardReview.vue +++ b/src/app/src/components/content/ContentCardReview.vue @@ -25,6 +25,34 @@ const isLoadingContent = ref(false) const isOpen = ref(false) const isAutomaticFormattingDetected = ref(false) +const height = ref(200) +const isResizing = ref(false) +const MIN_HEIGHT = 200 +const MAX_HEIGHT = 600 + +function startResize(event: MouseEvent) { + event.preventDefault() + isResizing.value = true + + const startY = event.clientY + const startHeight = height.value + + function handleMouseMove(e: MouseEvent) { + const deltaY = e.clientY - startY + const newHeight = Math.min(MAX_HEIGHT, Math.max(MIN_HEIGHT, startHeight + deltaY)) + height.value = newHeight + } + + function handleMouseUp() { + isResizing.value = false + document.removeEventListener('mousemove', handleMouseMove) + document.removeEventListener('mouseup', handleMouseUp) + } + + document.addEventListener('mousemove', handleMouseMove) + document.addEventListener('mouseup', handleMouseUp) +} + const language = computed(() => { const ext = getFileExtension(props.draftItem.fsPath) switch (ext) { @@ -65,7 +93,7 @@ async function initializeEditor() { language: language.value, colorMode: ui.colorMode.value, editorOptions: { - // hide unchanged regions + automaticLayout: true, hideUnchangedRegions: { enabled: true, }, @@ -78,6 +106,9 @@ async function initializeEditor() { initialContent: modified! || gitHubOriginal!, readOnly: true, colorMode: ui.colorMode, + editorOptions: { + automaticLayout: true, + }, }) } @@ -91,7 +122,10 @@ async function initializeEditor() { :draft-item="draftItem" > diff --git a/src/app/src/composables/useMonaco.ts b/src/app/src/composables/useMonaco.ts index 6c1bbfd7..6274f029 100644 --- a/src/app/src/composables/useMonaco.ts +++ b/src/app/src/composables/useMonaco.ts @@ -41,13 +41,6 @@ export function useMonaco(target: Ref, options: UseMona lineNumbers: 'off', readOnly: options.readOnly ?? false, wordWrap: 'on', - scrollbar: options.readOnly - ? { - vertical: 'hidden', - horizontal: 'hidden', - handleMouseWheel: false, - } - : undefined, ...options.editorOptions, }) diff --git a/src/app/src/composables/useMonacoDiff.ts b/src/app/src/composables/useMonacoDiff.ts index de271e6a..cd6078d2 100644 --- a/src/app/src/composables/useMonacoDiff.ts +++ b/src/app/src/composables/useMonacoDiff.ts @@ -1,4 +1,4 @@ -import { watch, unref, type Ref } from 'vue' +import { watch, unref, type Ref, shallowRef } from 'vue' import type { editor as Editor } from 'modern-monaco/editor-core' import { setupMonaco } from '../utils/monaco/index' @@ -11,7 +11,7 @@ export interface UseMonacoDiffOptions { } export function useMonacoDiff(target: Ref, options: UseMonacoDiffOptions) { - let editor: Editor.IStandaloneDiffEditor | null = null + const editor = shallowRef(null) let isInitialized = false const getTheme = (mode: 'light' | 'dark' = 'dark') => { @@ -24,7 +24,7 @@ export function useMonacoDiff(target: Ref, options: UseMonacoDiffOptions) { const monaco = await setupMonaco() - editor = monaco.createDiffEditor(el, { + editor.value = monaco.createDiffEditor(el, { theme: getTheme(options.colorMode), lineNumbers: 'off', readOnly: true, @@ -32,11 +32,10 @@ export function useMonacoDiff(target: Ref, options: UseMonacoDiffOptions) { renderSideBySideInlineBreakpoint: 0, wordWrap: 'on', scrollBeyondLastLine: false, - automaticLayout: true, ...options.editorOptions, }) - editor.setModel({ + editor.value.setModel({ original: monaco.editor.createModel(options.original, options.language), modified: monaco.editor.createModel(options.modified, options.language), }) @@ -54,15 +53,15 @@ export function useMonacoDiff(target: Ref, options: UseMonacoDiffOptions) { } else if (!el && isInitialized) { isInitialized = false - editor?.dispose() - editor = null + editor.value?.dispose() + editor.value = null } }, { immediate: true, flush: 'post' }, ) const setOptions = (opts: Editor.IStandaloneDiffEditorConstructionOptions) => { - editor?.updateOptions(opts) + editor.value?.updateOptions(opts) } return { diff --git a/src/app/src/composables/useMonacoMinimal.ts b/src/app/src/composables/useMonacoMinimal.ts deleted file mode 100644 index 06eaf4a1..00000000 --- a/src/app/src/composables/useMonacoMinimal.ts +++ /dev/null @@ -1,125 +0,0 @@ -// import { computed, ref, watch, unref } from 'vue' -// import type { editor as Editor } from 'modern-monaco/editor-core' -// import type { Ref } from 'vue' -// import { omit } from '../utils/object' -// import { setupMonaco, setupTheme, baseEditorOptions } from '../utils/monaco/index' - -// export function useMonacoMinimal(target: Ref, options: { -// code: string -// language: string -// readOnly?: boolean -// height?: { minLines: number, maxLines: number } -// resolvedTheme?: Ref -// onChange?: (content: string) => void -// }) { -// const isSetup = ref(false) -// let monaco: Awaited> -// let editor: Editor.IStandaloneCodeEditor - -// // // const colorMode = useColorMode() - -// const resolvedTheme = computed(() => { -// if (options.resolvedTheme) { -// return options.resolvedTheme.value -// } -// return baseEditorOptions.theme.dark // colorMode.value === 'dark' ? baseEditorOptions.theme.dark : baseEditorOptions.theme.light -// }) - -// // // watch([() => colorMode.value, () => options.resolvedTheme?.value], () => setOptions({ theme: resolvedTheme.value })) - -// const setContent = (content: string, preserveCursor = true) => { -// if (!isSetup.value) return -// const position = preserveCursor ? editor?.getPosition() : undefined - -// editor?.setValue(content) - -// if (position) { -// editor?.setPosition(position) -// } -// } - -// const getContent = () => editor?.getValue() - -// const init = async () => { -// monaco = await setupMonaco() - -// watch( -// target, -// () => { -// const el = unref(target) - -// if (!el) return - -// setupTheme(monaco) - -// const model = monaco.editor.createModel(options.code, options.language) - -// editor = monaco.editor.create(el, { -// ...baseEditorOptions as unknown as Editor.IEditorOptions, -// theme: resolvedTheme.value, -// ...omit(options, 'resolvedTheme'), -// model, -// tabSize: 2, -// wordWrap: 'on', -// insertSpaces: true, -// autoClosingQuotes: 'always', -// detectIndentation: false, -// stickyScroll: { -// enabled: false, -// }, -// }) - -// model.onDidChangeContent(() => { -// options.onChange?.(model.getValue()) -// }) - -// if (options.height) { -// const lineHeight = 18 -// let editingLayout = false -// const updateHeight = () => { -// if (editingLayout) { -// return -// } - -// if (options.height) { -// const contentHeight = Math.min((options.height.maxLines + 2) * lineHeight, Math.max((options.height.minLines + 2) * lineHeight, editor.getContentHeight() + lineHeight)) -// const { height: layoutHeight } = editor.getLayoutInfo() -// if (layoutHeight === contentHeight) { -// return -// } - -// try { -// editingLayout = true -// editor.layout({ height: contentHeight, width: el.clientWidth }) -// } -// catch { -// // Ignore -// } -// } -// editingLayout = false -// } -// editor.onDidContentSizeChange(updateHeight) -// updateHeight() -// } - -// isSetup.value = true -// }, -// { -// flush: 'post', -// immediate: true, -// }, -// ) -// } - -// init() - -// const setOptions = (opts: Editor.IEditorOverrideServices) => { -// editor?.updateOptions(opts) -// } - -// return { -// getContent, -// setOptions, -// setContent, -// } -// } From 4ac103d5fa86ae35a341f24d52cb2db109df37f3 Mon Sep 17 00:00:00 2001 From: Baptiste Leproux Date: Thu, 6 Nov 2025 15:55:08 +0100 Subject: [PATCH 2/2] remove event listener on unmount --- .../components/content/ContentCardReview.vue | 44 +++++++++++-------- src/app/src/composables/useMonaco.ts | 1 + src/app/src/composables/useMonacoDiff.ts | 1 + 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/app/src/components/content/ContentCardReview.vue b/src/app/src/components/content/ContentCardReview.vue index 201fcc1e..fc817971 100644 --- a/src/app/src/components/content/ContentCardReview.vue +++ b/src/app/src/components/content/ContentCardReview.vue @@ -1,7 +1,7 @@