feat(split_editor): make the two panes resizable

This commit is contained in:
Elian Doran 2025-03-21 22:02:08 +02:00
parent 395d76a156
commit 8952ff512f
No known key found for this signature in database
2 changed files with 44 additions and 30 deletions

View File

@ -6,9 +6,6 @@ import utils from "../services/utils.js";
import { loadElkIfNeeded, postprocessMermaidSvg } from "../services/mermaid.js"; import { loadElkIfNeeded, postprocessMermaidSvg } from "../services/mermaid.js";
import type FNote from "../entities/fnote.js"; import type FNote from "../entities/fnote.js";
import type { EventData } from "../components/app_context.js"; import type { EventData } from "../components/app_context.js";
import ScrollingContainer from "./containers/scrolling_container.js";
import Split from "split.js";
import { DEFAULT_GUTTER_SIZE } from "../services/resizer.js";
const TPL = `<div class="mermaid-widget"> const TPL = `<div class="mermaid-widget">
<style> <style>
@ -58,7 +55,6 @@ export default class MermaidWidget extends NoteContextAwareWidget {
private dirtyAttachment?: boolean; private dirtyAttachment?: boolean;
private zoomHandler?: () => void; private zoomHandler?: () => void;
private zoomInstance?: SvgPanZoom.Instance; private zoomInstance?: SvgPanZoom.Instance;
private splitInstance?: Split.Instance;
private lastNote?: FNote; private lastNote?: FNote;
isEnabled() { isEnabled() {
@ -126,7 +122,6 @@ export default class MermaidWidget extends NoteContextAwareWidget {
this.$errorContainer.show(); this.$errorContainer.show();
} }
this.#setupResizer();
this.lastNote = note; this.lastNote = note;
} }
@ -206,28 +201,6 @@ export default class MermaidWidget extends NoteContextAwareWidget {
$(window).on("resize", this.zoomHandler); $(window).on("resize", this.zoomHandler);
} }
#setupResizer() {
if (!utils.isDesktop()) {
return;
}
const selfEl = this.$widget;
const scrollingContainer = this.parent?.children.find((ch) => ch instanceof ScrollingContainer)?.$widget;
if (!selfEl.length || !scrollingContainer?.length) {
return;
}
if (!this.splitInstance) {
this.splitInstance = Split([ selfEl[0], scrollingContainer[0] ], {
sizes: [ 50, 50 ],
direction: "vertical",
gutterSize: DEFAULT_GUTTER_SIZE,
onDragEnd: () => this.zoomHandler?.()
});
}
}
async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) { async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
if (this.noteId && loadResults.isNoteContentReloaded(this.noteId)) { if (this.noteId && loadResults.isNoteContentReloaded(this.noteId)) {
this.dirtyAttachment = true; this.dirtyAttachment = true;

View File

@ -1,6 +1,9 @@
import type FNote from "../../entities/fnote.js"; import type FNote from "../../entities/fnote.js";
import utils from "../../services/utils.js";
import EditableCodeTypeWidget from "./editable_code.js"; import EditableCodeTypeWidget from "./editable_code.js";
import TypeWidget from "./type_widget.js"; import TypeWidget from "./type_widget.js";
import Split from "split.js";
import { DEFAULT_GUTTER_SIZE } from "../../services/resizer.js";
const TPL = `\ const TPL = `\
<div class="note-detail-split note-detail-printable split-horizontal"> <div class="note-detail-split note-detail-printable split-horizontal">
@ -17,21 +20,39 @@ const TPL = `\
height: 100%; height: 100%;
} }
.note-detail-split .note-detail-split-editor {
width: 100%;
}
/* Horizontal layout */
.note-detail-split.split-horizontal > .note-detail-split-editor {
border-left: 1px solid var(--main-border-color);
}
.note-detail-split.split-horizontal > div { .note-detail-split.split-horizontal > div {
height: 100%; height: 100%;
width: 50%; width: 50%;
} }
.note-detail-split .note-detail-split-editor { /* Vertical layout */
width: 100%;
}
</style> </style>
</div> </div>
`; `;
/**
* Abstract `TypeWidget` which contains a preview and editor pane, each displayed on half of the available screen.
*
* Features:
*
* - The two panes are resizeable via a split, on desktop.
*/
export default class SplitTypeEditor extends TypeWidget { export default class SplitTypeEditor extends TypeWidget {
private splitInstance?: Split.Instance;
private $preview!: JQuery<HTMLElement>; private $preview!: JQuery<HTMLElement>;
private $editor!: JQuery<HTMLElement>; private $editor!: JQuery<HTMLElement>;
private editorTypeWidget: EditableCodeTypeWidget; private editorTypeWidget: EditableCodeTypeWidget;
@ -48,10 +69,16 @@ export default class SplitTypeEditor extends TypeWidget {
this.$preview = this.$widget.find(".note-detail-split-preview"); this.$preview = this.$widget.find(".note-detail-split-preview");
this.$editor = this.$widget.find(".note-detail-split-editor"); this.$editor = this.$widget.find(".note-detail-split-editor");
this.$editor.append(this.editorTypeWidget.render()); this.$editor.append(this.editorTypeWidget.render());
this.#setupResizer();
super.doRender(); super.doRender();
} }
cleanup(): void {
this.splitInstance?.destroy();
this.splitInstance = undefined;
}
async doRefresh(note: FNote | null | undefined) { async doRefresh(note: FNote | null | undefined) {
await this.editorTypeWidget.initialized; await this.editorTypeWidget.initialized;
@ -62,6 +89,20 @@ export default class SplitTypeEditor extends TypeWidget {
} }
} }
#setupResizer() {
if (!utils.isDesktop()) {
return;
}
this.splitInstance?.destroy();
this.splitInstance = Split([ this.$preview[0], this.$editor[0] ], {
sizes: [ 50, 50 ],
direction: "horizontal",
gutterSize: DEFAULT_GUTTER_SIZE,
// onDragEnd: () => this.zoomHandler?.()
});
}
getData() { getData() {
return this.editorTypeWidget.getData(); return this.editorTypeWidget.getData();
} }