From 44475853df09da630d82475f701da6a48184804e Mon Sep 17 00:00:00 2001 From: SiriusXT <1160925501@qq.com> Date: Sun, 16 Nov 2025 20:12:56 +0800 Subject: [PATCH 1/6] feat(split): allow closing any split pane --- .../src/widgets/buttons/close_pane_button.tsx | 2 +- .../widgets/containers/split_note_container.ts | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/client/src/widgets/buttons/close_pane_button.tsx b/apps/client/src/widgets/buttons/close_pane_button.tsx index c171d0d8e..726c5c49e 100644 --- a/apps/client/src/widgets/buttons/close_pane_button.tsx +++ b/apps/client/src/widgets/buttons/close_pane_button.tsx @@ -8,7 +8,7 @@ export default function ClosePaneButton() { const [ isEnabled, setIsEnabled ] = useState(false); function refresh() { - setIsEnabled(!!(noteContext && !!noteContext.mainNtxId)); + setIsEnabled(!!noteContext); } useTriliumEvent("noteContextReorder", refresh); diff --git a/apps/client/src/widgets/containers/split_note_container.ts b/apps/client/src/widgets/containers/split_note_container.ts index 8298d5989..90e77c021 100644 --- a/apps/client/src/widgets/containers/split_note_container.ts +++ b/apps/client/src/widgets/containers/split_note_container.ts @@ -100,9 +100,23 @@ export default class SplitNoteContainer extends FlexContainer { } async closeThisNoteSplitCommand({ ntxId }: CommandListenerData<"closeThisNoteSplit">) { - if (ntxId) { - await appContext.tabManager.removeNoteContext(ntxId); + if (!ntxId) return; + const contexts = appContext.tabManager.noteContexts; + + const currentIndex = contexts.findIndex((c) => c.ntxId === ntxId); + if (currentIndex === -1) return; + + const isRemoveMainContext = !contexts[currentIndex].mainNtxId; + if (isRemoveMainContext && currentIndex + 1 <= contexts.length) { + const ntxIds = contexts.map((c) => c.ntxId).filter((c) => !!c) as string[]; + this.triggerCommand("noteContextReorder", { + ntxIdsInOrder: ntxIds, + oldMainNtxId: ntxId, + newMainNtxId: ntxIds[currentIndex + 1] + }); } + + await appContext.tabManager.removeNoteContext(ntxId); } async moveThisNoteSplitCommand({ ntxId, isMovingLeft }: CommandListenerData<"moveThisNoteSplit">) { From be19d1f5b54a4aa339ecaa5672bd703b347c46ac Mon Sep 17 00:00:00 2001 From: SiriusXT <1160925501@qq.com> Date: Mon, 17 Nov 2025 09:24:18 +0800 Subject: [PATCH 2/6] fix(split pane): hide the close button when no split panes exist --- .../client/src/widgets/buttons/close_pane_button.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/client/src/widgets/buttons/close_pane_button.tsx b/apps/client/src/widgets/buttons/close_pane_button.tsx index 726c5c49e..7ffae309d 100644 --- a/apps/client/src/widgets/buttons/close_pane_button.tsx +++ b/apps/client/src/widgets/buttons/close_pane_button.tsx @@ -1,18 +1,20 @@ import { useEffect, useState } from "preact/hooks"; import { t } from "../../services/i18n"; import ActionButton from "../react/ActionButton"; -import { useNoteContext, useTriliumEvent } from "../react/hooks"; +import { useNoteContext, useTriliumEvents } from "../react/hooks"; +import appContext from "../../components/app_context"; export default function ClosePaneButton() { const { noteContext, ntxId, parentComponent } = useNoteContext(); - const [ isEnabled, setIsEnabled ] = useState(false); + const [isEnabled, setIsEnabled] = useState(false); function refresh() { - setIsEnabled(!!noteContext); + const isMainOfSomeContext = appContext.tabManager.noteContexts.some(c => c.mainNtxId === ntxId); + setIsEnabled(!!(noteContext && (!!noteContext.mainNtxId || isMainOfSomeContext))); } - useTriliumEvent("noteContextReorder", refresh); - useEffect(refresh, [ ntxId ]); + useTriliumEvents(["noteContextRemoved", "noteContextReorder", "newNoteContextCreated"], refresh); + useEffect(refresh, [ntxId]); return ( Date: Mon, 17 Nov 2025 21:00:27 +0800 Subject: [PATCH 3/6] fix(tab_manager): correct order when reopening tabs --- apps/client/src/widgets/tab_row.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/client/src/widgets/tab_row.ts b/apps/client/src/widgets/tab_row.ts index c2405aaed..b78952faf 100644 --- a/apps/client/src/widgets/tab_row.ts +++ b/apps/client/src/widgets/tab_row.ts @@ -820,12 +820,15 @@ export default class TabRowWidget extends BasicWidget { } contextsReopenedEvent({ mainNtxId, tabPosition }: EventData<"contextsReopened">) { - if (!mainNtxId || !tabPosition) { + if (!mainNtxId || tabPosition < 0) { // no tab reopened return; } const tabEl = this.getTabById(mainNtxId)[0]; - tabEl.parentNode?.insertBefore(tabEl, this.tabEls[tabPosition]); + + if ( tabEl && tabEl.parentNode ){ + tabEl.parentNode.insertBefore(tabEl, this.tabEls[tabPosition]); + } } updateTabById(ntxId: string | null) { From 5a5d242ea00dd25ef6a47ac3f725b9c0fa8d4dc6 Mon Sep 17 00:00:00 2001 From: SiriusXT <1160925501@qq.com> Date: Mon, 17 Nov 2025 21:01:21 +0800 Subject: [PATCH 4/6] fix(tab_manager): correct order when reopening split pane --- apps/client/src/components/tab_manager.ts | 27 ++++++++++++++++++- .../containers/split_note_container.ts | 12 +++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/apps/client/src/components/tab_manager.ts b/apps/client/src/components/tab_manager.ts index 517ff2501..127ec30b7 100644 --- a/apps/client/src/components/tab_manager.ts +++ b/apps/client/src/components/tab_manager.ts @@ -647,7 +647,32 @@ export default class TabManager extends Component { ...this.noteContexts.slice(-noteContexts.length), ...this.noteContexts.slice(lastClosedTab.position, -noteContexts.length) ]; - this.noteContextReorderEvent({ ntxIdsInOrder: ntxsInOrder.map((nc) => nc.ntxId).filter((id) => id !== null) }); + + // Update mainNtxId if the restored pane is the main pane in the split pane + const { oldMainNtxId, newMainNtxId } = (() => { + if (noteContexts.length !== 1) { + return { oldMainNtxId: undefined, newMainNtxId: undefined }; + } + + const mainNtxId = noteContexts[0]?.mainNtxId; + const index = this.noteContexts.findIndex(c => c.ntxId === mainNtxId); + + // No need to update if the restored position is after mainNtxId + if (index === -1 || lastClosedTab.position > index) { + return { oldMainNtxId: undefined, newMainNtxId: undefined }; + } + + return { + oldMainNtxId: this.noteContexts[index].ntxId ?? undefined, + newMainNtxId: noteContexts[0]?.ntxId ?? undefined + }; + })(); + + this.triggerCommand("noteContextReorder", { + ntxIdsInOrder: ntxsInOrder.map((nc) => nc.ntxId).filter((id) => id !== null), + oldMainNtxId, + newMainNtxId + }); let mainNtx = noteContexts.find((nc) => nc.isMainContext()); if (mainNtx) { diff --git a/apps/client/src/widgets/containers/split_note_container.ts b/apps/client/src/widgets/containers/split_note_container.ts index 90e77c021..c370cc4eb 100644 --- a/apps/client/src/widgets/containers/split_note_container.ts +++ b/apps/client/src/widgets/containers/split_note_container.ts @@ -181,12 +181,14 @@ export default class SplitNoteContainer extends FlexContainer { splitService.delNoteSplitResizer(ntxIds); } - contextsReopenedEvent({ ntxId, afterNtxId }: EventData<"contextsReopened">) { - if (ntxId === undefined || afterNtxId === undefined) { - // no single split reopened - return; + contextsReopenedEvent({ ntxId, mainNtxId, tabPosition, afterNtxId }: EventData<"contextsReopened">) { + if (ntxId !== undefined && afterNtxId !== undefined) { + this.$widget.find(`[data-ntx-id="${ntxId}"]`).insertAfter(this.$widget.find(`[data-ntx-id="${afterNtxId}"]`)); + } else if (mainNtxId && tabPosition >= 0) { + const contexts = appContext.tabManager.noteContexts; + const beforeNtxId = contexts.find(c => c.mainNtxId === mainNtxId)?.ntxId || null; + this.$widget.find(`[data-ntx-id="${mainNtxId}"]`).insertBefore(this.$widget.find(`[data-ntx-id="${beforeNtxId}"]`)); } - this.$widget.find(`[data-ntx-id="${ntxId}"]`).insertAfter(this.$widget.find(`[data-ntx-id="${afterNtxId}"]`)); } async refresh() { From 13afe33244ec79fddd0859d5f4ae33ac757042d9 Mon Sep 17 00:00:00 2001 From: SiriusXT <1160925501@qq.com> Date: Tue, 18 Nov 2025 09:05:18 +0800 Subject: [PATCH 5/6] fix(tab_manager): correct order when reopening split pane --- .../client/src/widgets/containers/split_note_container.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/client/src/widgets/containers/split_note_container.ts b/apps/client/src/widgets/containers/split_note_container.ts index c370cc4eb..f29a5fad5 100644 --- a/apps/client/src/widgets/containers/split_note_container.ts +++ b/apps/client/src/widgets/containers/split_note_container.ts @@ -181,12 +181,14 @@ export default class SplitNoteContainer extends FlexContainer { splitService.delNoteSplitResizer(ntxIds); } - contextsReopenedEvent({ ntxId, mainNtxId, tabPosition, afterNtxId }: EventData<"contextsReopened">) { + contextsReopenedEvent({ ntxId, mainNtxId, afterNtxId }: EventData<"contextsReopened">) { if (ntxId !== undefined && afterNtxId !== undefined) { this.$widget.find(`[data-ntx-id="${ntxId}"]`).insertAfter(this.$widget.find(`[data-ntx-id="${afterNtxId}"]`)); - } else if (mainNtxId && tabPosition >= 0) { + } else if (mainNtxId) { const contexts = appContext.tabManager.noteContexts; - const beforeNtxId = contexts.find(c => c.mainNtxId === mainNtxId)?.ntxId || null; + const nextIndex = contexts.findIndex(c => c.ntxId === mainNtxId); + const beforeNtxId = (nextIndex !== -1 && nextIndex + 1 < contexts.length) ? contexts[nextIndex + 1].ntxId : null; + this.$widget.find(`[data-ntx-id="${mainNtxId}"]`).insertBefore(this.$widget.find(`[data-ntx-id="${beforeNtxId}"]`)); } } From 6b0bcf93d369895c21aac151b7d3516ab1b4b6d9 Mon Sep 17 00:00:00 2001 From: SiriusXT <1160925501@qq.com> Date: Tue, 18 Nov 2025 09:14:50 +0800 Subject: [PATCH 6/6] feat(split): improve support for closing any split pane --- apps/client/src/widgets/containers/split_note_container.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/client/src/widgets/containers/split_note_container.ts b/apps/client/src/widgets/containers/split_note_container.ts index f29a5fad5..02ed8cf04 100644 --- a/apps/client/src/widgets/containers/split_note_container.ts +++ b/apps/client/src/widgets/containers/split_note_container.ts @@ -102,12 +102,11 @@ export default class SplitNoteContainer extends FlexContainer { async closeThisNoteSplitCommand({ ntxId }: CommandListenerData<"closeThisNoteSplit">) { if (!ntxId) return; const contexts = appContext.tabManager.noteContexts; - const currentIndex = contexts.findIndex((c) => c.ntxId === ntxId); if (currentIndex === -1) return; - const isRemoveMainContext = !contexts[currentIndex].mainNtxId; - if (isRemoveMainContext && currentIndex + 1 <= contexts.length) { + const isRemoveMainContext = contexts[currentIndex].isMainContext(); + if (isRemoveMainContext && currentIndex + 1 < contexts.length) { const ntxIds = contexts.map((c) => c.ntxId).filter((c) => !!c) as string[]; this.triggerCommand("noteContextReorder", { ntxIdsInOrder: ntxIds,