mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 05:28:59 +01:00 
			
		
		
		
	feat: Make splits resizable
This commit is contained in:
		
							parent
							
								
									ed56ed2be0
								
							
						
					
					
						commit
						3254069999
					
				@ -10,6 +10,10 @@ let leftInstance: ReturnType<typeof Split> | null;
 | 
			
		||||
let rightPaneWidth: number;
 | 
			
		||||
let rightInstance: ReturnType<typeof Split> | null;
 | 
			
		||||
 | 
			
		||||
const noteSplitMap = new Map<string[], ReturnType<typeof Split> | undefined>(); // key: a group of ntxIds, value: the corresponding Split instance
 | 
			
		||||
const noteSplitRafMap = new Map<string[], number>();
 | 
			
		||||
let splitNoteContainer: HTMLElement | undefined;
 | 
			
		||||
 | 
			
		||||
function setupLeftPaneResizer(leftPaneVisible: boolean) {
 | 
			
		||||
    if (leftInstance) {
 | 
			
		||||
        leftInstance.destroy();
 | 
			
		||||
@ -83,7 +87,94 @@ function setupRightPaneResizer() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function findKeyByNtxId(ntxId: string): string[] | undefined {
 | 
			
		||||
    // Find the corresponding key in noteSplitMap based on ntxId
 | 
			
		||||
    for (const key of noteSplitMap.keys()) {
 | 
			
		||||
        if (key.includes(ntxId)) return key;
 | 
			
		||||
    }
 | 
			
		||||
    return undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setupNoteSplitResizer(ntxIds: string[]) {
 | 
			
		||||
    let targetNtxIds: string[] | undefined;
 | 
			
		||||
    for (const ntxId of ntxIds) {
 | 
			
		||||
        targetNtxIds = findKeyByNtxId(ntxId);
 | 
			
		||||
        if (targetNtxIds) break; 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (targetNtxIds) {
 | 
			
		||||
        noteSplitMap.get(targetNtxIds)?.destroy();
 | 
			
		||||
        for (const id of ntxIds) {
 | 
			
		||||
            if (!targetNtxIds.includes(id)) {
 | 
			
		||||
                targetNtxIds.push(id)
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        targetNtxIds = [...ntxIds];
 | 
			
		||||
    }
 | 
			
		||||
    noteSplitMap.set(targetNtxIds, undefined);
 | 
			
		||||
    createSplitInstance(targetNtxIds);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function delNoteSplitResizer(ntxIds: string[]) {
 | 
			
		||||
    let targetNtxIds = findKeyByNtxId(ntxIds[0]);
 | 
			
		||||
 | 
			
		||||
    if (targetNtxIds) {
 | 
			
		||||
        noteSplitMap.get(targetNtxIds)?.destroy();
 | 
			
		||||
        noteSplitMap.delete(targetNtxIds);
 | 
			
		||||
        targetNtxIds = targetNtxIds.filter(id => !ntxIds.includes(id));
 | 
			
		||||
    }
 | 
			
		||||
    if (targetNtxIds && targetNtxIds.length >= 2) {
 | 
			
		||||
        noteSplitMap.set(targetNtxIds, undefined);
 | 
			
		||||
        createSplitInstance(targetNtxIds);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function moveNoteSplitResizer(ntxId: string) {
 | 
			
		||||
    const targetNtxIds = findKeyByNtxId(ntxId);
 | 
			
		||||
 | 
			
		||||
    if (targetNtxIds) {
 | 
			
		||||
        noteSplitMap.get(targetNtxIds)?.destroy();
 | 
			
		||||
        noteSplitMap.set(targetNtxIds, undefined);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (targetNtxIds) {
 | 
			
		||||
        createSplitInstance(targetNtxIds);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createSplitInstance(targetNtxIds: string[]) {
 | 
			
		||||
    const prevRafId = noteSplitRafMap.get(targetNtxIds);
 | 
			
		||||
    if (prevRafId) {
 | 
			
		||||
        cancelAnimationFrame(prevRafId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const rafId = requestAnimationFrame(() => {
 | 
			
		||||
        if (!splitNoteContainer){
 | 
			
		||||
            splitNoteContainer =  $("#center-pane").find(".split-note-container-widget")[0];
 | 
			
		||||
        }
 | 
			
		||||
        const splitPanels: HTMLElement[] = [];
 | 
			
		||||
        for (const el of splitNoteContainer.querySelectorAll(':scope > .note-split')) {
 | 
			
		||||
            const dataId = el.getAttribute('data-ntx-id');
 | 
			
		||||
            if (dataId && targetNtxIds.includes(dataId)) {
 | 
			
		||||
                splitPanels.push(el as HTMLElement);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        const splitInstance = Split(splitPanels, {
 | 
			
		||||
            gutterSize: DEFAULT_GUTTER_SIZE,
 | 
			
		||||
            minSize: 150,
 | 
			
		||||
        });
 | 
			
		||||
        noteSplitMap.set(targetNtxIds, splitInstance);
 | 
			
		||||
        noteSplitRafMap.delete(targetNtxIds);
 | 
			
		||||
    });
 | 
			
		||||
    noteSplitRafMap.set(targetNtxIds, rafId);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    setupLeftPaneResizer,
 | 
			
		||||
    setupRightPaneResizer
 | 
			
		||||
    setupRightPaneResizer,
 | 
			
		||||
    setupNoteSplitResizer,
 | 
			
		||||
    delNoteSplitResizer,
 | 
			
		||||
    moveNoteSplitResizer
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1171,6 +1171,10 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
 | 
			
		||||
    cursor: row-resize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hidden-ext.note-split + .gutter {
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#context-menu-cover.show {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: 0;
 | 
			
		||||
@ -1700,7 +1704,6 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.note-split {
 | 
			
		||||
    flex-basis: 0; /* so that each split has same width */
 | 
			
		||||
    margin-left: auto;
 | 
			
		||||
    margin-right: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -90,7 +90,7 @@ body.background-effects.zen #root-widget {
 | 
			
		||||
 * Gutter
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 .gutter {
 | 
			
		||||
.gutter {
 | 
			
		||||
    background: var(--gutter-color) !important;
 | 
			
		||||
    transition: background 150ms ease-out;
 | 
			
		||||
}
 | 
			
		||||
@ -1092,6 +1092,11 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
 | 
			
		||||
    /* will-change: opacity; -- causes some weird artifacts to the note menu in split view */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.split-note-container-widget > .gutter {
 | 
			
		||||
    background: var(--root-background) !important;
 | 
			
		||||
    transition: background 150ms ease-out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Ribbon & note header
 | 
			
		||||
 */
 | 
			
		||||
@ -1100,10 +1105,6 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
 | 
			
		||||
    margin-bottom: 0 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.note-split:not(.hidden-ext) + .note-split:not(.hidden-ext) {
 | 
			
		||||
    border-left: 4px solid var(--root-background);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes note-entrance {
 | 
			
		||||
    from {
 | 
			
		||||
        opacity: 0;
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ import FlexContainer from "./flex_container.js";
 | 
			
		||||
import appContext, { type CommandData, type CommandListenerData, type EventData, type EventNames, type NoteSwitchedContext } from "../../components/app_context.js";
 | 
			
		||||
import type BasicWidget from "../basic_widget.js";
 | 
			
		||||
import type NoteContext from "../../components/note_context.js";
 | 
			
		||||
import splitService from "../../services/resizer.js";
 | 
			
		||||
 | 
			
		||||
interface NoteContextEvent {
 | 
			
		||||
    noteContext: NoteContext;
 | 
			
		||||
@ -51,6 +52,10 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
 | 
			
		||||
        await widget.handleEvent("setNoteContext", { noteContext });
 | 
			
		||||
 | 
			
		||||
        this.child(widget);
 | 
			
		||||
 | 
			
		||||
        if (noteContext.mainNtxId && noteContext.ntxId) {
 | 
			
		||||
            splitService.setupNoteSplitResizer([noteContext.mainNtxId,noteContext.ntxId]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async openNewNoteSplitEvent({ ntxId, notePath, hoistedNoteId, viewScope }: EventData<"openNewNoteSplit">) {
 | 
			
		||||
@ -94,9 +99,11 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    closeThisNoteSplitCommand({ ntxId }: CommandListenerData<"closeThisNoteSplit">) {
 | 
			
		||||
    async closeThisNoteSplitCommand({ ntxId }: CommandListenerData<"closeThisNoteSplit">) {
 | 
			
		||||
        if (ntxId) {
 | 
			
		||||
            appContext.tabManager.removeNoteContext(ntxId);
 | 
			
		||||
            await appContext.tabManager.removeNoteContext(ntxId);
 | 
			
		||||
            
 | 
			
		||||
            splitService.delNoteSplitResizer([ntxId]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -136,6 +143,8 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
 | 
			
		||||
 | 
			
		||||
        // activate context that now contains the original note
 | 
			
		||||
        await appContext.tabManager.activateNoteContext(isMovingLeft ? ntxIds[leftIndex + 1] : ntxIds[leftIndex]);
 | 
			
		||||
 | 
			
		||||
        splitService.moveNoteSplitResizer(ntxIds[leftIndex]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    activeContextChangedEvent() {
 | 
			
		||||
@ -154,6 +163,8 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
 | 
			
		||||
 | 
			
		||||
            delete this.widgets[ntxId];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        splitService.delNoteSplitResizer(ntxIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    contextsReopenedEvent({ ntxId, afterNtxId }: EventData<"contextsReopened">) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user