diff --git a/apps/client/src/widgets/type_widgets/helpers/SplitEditor.css b/apps/client/src/widgets/type_widgets/helpers/SplitEditor.css index 008652b51..d9728d8c5 100644 --- a/apps/client/src/widgets/type_widgets/helpers/SplitEditor.css +++ b/apps/client/src/widgets/type_widgets/helpers/SplitEditor.css @@ -84,5 +84,10 @@ } /* #region SVG */ - +.note-detail-split.svg-editor .render-container, +.note-detail-split.svg-editor .render-container svg { + width: 100%; + height: 100%; + max-width: 100%; +} /* #endregion */ \ No newline at end of file diff --git a/apps/client/src/widgets/type_widgets/helpers/SplitEditor.tsx b/apps/client/src/widgets/type_widgets/helpers/SplitEditor.tsx index 7d7831faf..76b5f35ad 100644 --- a/apps/client/src/widgets/type_widgets/helpers/SplitEditor.tsx +++ b/apps/client/src/widgets/type_widgets/helpers/SplitEditor.tsx @@ -10,6 +10,7 @@ import { ComponentChildren } from "preact"; import ActionButton, { ActionButtonProps } from "../../react/ActionButton"; export interface SplitEditorProps extends EditableCodeProps { + className?: string; error?: string | null; splitOptions?: Split.Options; previewContent: ComponentChildren; @@ -25,7 +26,7 @@ export interface SplitEditorProps extends EditableCodeProps { * - Can display errors to the user via {@link setError}. * - Horizontal or vertical orientation for the editor/preview split, adjustable via the switch split orientation button floating button. */ -export default function SplitEditor({ note, error, splitOptions, previewContent, previewButtons, ...editorProps }: SplitEditorProps) { +export default function SplitEditor({ note, error, splitOptions, previewContent, previewButtons, className, ...editorProps }: SplitEditorProps) { const splitEditorOrientation = useSplitOrientation(); const [ readOnly ] = useNoteLabelBoolean(note, "readOnly"); const containerRef = useRef(null); @@ -72,7 +73,7 @@ export default function SplitEditor({ note, error, splitOptions, previewContent, }, [ readOnly, splitEditorOrientation ]); return ( -
+
{splitEditorOrientation === "horizontal" ? <>{editor}{preview} : <>{preview}{editor}} diff --git a/apps/client/src/widgets/type_widgets/helpers/SvgSplitEditor.tsx b/apps/client/src/widgets/type_widgets/helpers/SvgSplitEditor.tsx index 739422b3b..3f470fe7f 100644 --- a/apps/client/src/widgets/type_widgets/helpers/SvgSplitEditor.tsx +++ b/apps/client/src/widgets/type_widgets/helpers/SvgSplitEditor.tsx @@ -1,8 +1,9 @@ -import { useState } from "preact/hooks"; +import { useEffect, useRef, useState } from "preact/hooks"; import { t } from "../../../services/i18n"; import SplitEditor, { PreviewButton, SplitEditorProps } from "./SplitEditor"; import { RawHtmlBlock } from "../../react/RawHtml"; import server from "../../../services/server"; +import svgPanZoom from "svg-pan-zoom"; interface SvgSplitEditorProps extends Omit { /** @@ -22,6 +23,7 @@ interface SvgSplitEditorProps extends Omit { export default function SvgSplitEditor({ note, attachmentName, renderSvg, ...props }: SvgSplitEditorProps) { const [ svg, setSvg ] = useState(); const [ error, setError ] = useState(); + const containerRef = useRef(null); // Render the SVG. async function onContentChanged(content: string) { @@ -50,14 +52,49 @@ export default function SvgSplitEditor({ note, attachmentName, renderSvg, ...pro server.post(`notes/${note.noteId}/attachments?matchBy=title`, payload); } + // Pan & zoom. + const lastPanZoom = useRef<{ pan: SvgPanZoom.Point, zoom: number }>(); + const lastNoteId = useRef(); + useEffect(() => { + const shouldPreservePanZoom = (lastNoteId.current === note.noteId); + const svgEl = containerRef.current?.querySelector("svg"); + if (!svgEl) return; + const zoomInstance = svgPanZoom(svgEl, { + zoomEnabled: true, + controlIconsEnabled: false + }); + + // Restore the previous pan/zoom if the user updates same note. + if (shouldPreservePanZoom && lastPanZoom.current) { + zoomInstance.zoom(lastPanZoom.current.zoom); + zoomInstance.pan(lastPanZoom.current.pan); + } else { + zoomInstance.resize().center().fit(); + } + + lastNoteId.current = note.noteId; + return () => { + lastPanZoom.current = { + pan: zoomInstance.getPan(), + zoom: zoomInstance.getZoom() + } + zoomInstance.destroy(); + }; + }, [ svg ]); + return ( + )} previewButtons={ <> diff --git a/apps/client/src/widgets/type_widgets_old/abstract_split_type_widget.ts b/apps/client/src/widgets/type_widgets_old/abstract_split_type_widget.ts index 5e7552894..01c4cad8f 100644 --- a/apps/client/src/widgets/type_widgets_old/abstract_split_type_widget.ts +++ b/apps/client/src/widgets/type_widgets_old/abstract_split_type_widget.ts @@ -65,11 +65,6 @@ export default abstract class AbstractSplitTypeWidget extends TypeWidget { super.doRender(); } - cleanup(): void { - this.#destroyResizer(); - this.editorTypeWidget.cleanup(); - } - async doRefresh(note: FNote) { this.#adjustLayoutOrientation(); diff --git a/apps/client/src/widgets/type_widgets_old/abstract_svg_split_type_widget.ts b/apps/client/src/widgets/type_widgets_old/abstract_svg_split_type_widget.ts index 90f84f3bf..e56086c48 100644 --- a/apps/client/src/widgets/type_widgets_old/abstract_svg_split_type_widget.ts +++ b/apps/client/src/widgets/type_widgets_old/abstract_svg_split_type_widget.ts @@ -106,51 +106,6 @@ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTy abstract get attachmentName(): string; - /** - * @param preservePanZoom `true` to keep the pan/zoom settings of the previous image, or `false` to re-center it. - */ - async #setupPanZoom(preservePanZoom: boolean) { - // Clean up - let pan: SvgPanZoom.Point | null = null; - let zoom: number | null = null; - if (preservePanZoom && this.zoomInstance) { - // Store pan and zoom for same note, when the user is editing the note. - pan = this.zoomInstance.getPan(); - zoom = this.zoomInstance.getZoom(); - this.#cleanUpZoom(); - } - - const $svgEl = this.$renderContainer.find("svg"); - - // Fit the image to bounds - $svgEl.attr("width", "100%") - .attr("height", "100%") - .css("max-width", "100%"); - - if (!$svgEl.length) { - return; - } - - const svgPanZoom = (await import("svg-pan-zoom")).default; - const zoomInstance = svgPanZoom($svgEl[0], { - zoomEnabled: true, - controlIconsEnabled: false - }); - - if (preservePanZoom && pan && zoom) { - // Restore the pan and zoom. - zoomInstance.zoom(zoom); - zoomInstance.pan(pan); - } else { - // New instance, reposition properly. - zoomInstance.resize(); - zoomInstance.center(); - zoomInstance.fit(); - } - - this.zoomInstance = zoomInstance; - } - buildSplitExtraOptions(): Split.Options { return { onDrag: () => this.zoomHandler?.()