feat(window): restore recently closed windows from tray
|
After Width: | Height: | Size: 545 B |
|
After Width: | Height: | Size: 727 B |
|
After Width: | Height: | Size: 828 B |
|
After Width: | Height: | Size: 931 B |
BIN
apps/desktop/src/assets/images/tray/closed-windowsTemplate.png
Normal file
|
After Width: | Height: | Size: 292 B |
|
After Width: | Height: | Size: 355 B |
|
After Width: | Height: | Size: 434 B |
|
After Width: | Height: | Size: 492 B |
@ -382,6 +382,8 @@
|
||||
"tooltip": "Trilium Notes",
|
||||
"close": "Quit Trilium",
|
||||
"recents": "Recent notes",
|
||||
"recently-closed-windows": "Recently closed windows",
|
||||
"tabs-total": "total {{number}} tabs",
|
||||
"bookmarks": "Bookmarks",
|
||||
"today": "Open today's journal note",
|
||||
"new-note": "New note",
|
||||
|
||||
@ -196,6 +196,44 @@ function updateTrayMenu() {
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
function buildClosedWindowsMenu() {
|
||||
const savedOpenNoteContexts = JSON.parse(optionService.getOption("openNoteContexts") || "[]");
|
||||
const openedWindowIds = windowService.getAllWindowIds();
|
||||
const closedWindows = savedOpenNoteContexts
|
||||
.filter(win => !openedWindowIds.includes(win.windowId))
|
||||
.sort((a, b) => {
|
||||
// If closedAt is null, it indicates an abnormal closure and should be placed at the end
|
||||
if (a.closedAt === null && b.closedAt === null) return 0;
|
||||
if (a.closedAt === null) return 1;
|
||||
if (b.closedAt === null) return -1;
|
||||
// Otherwise, sort by time in descending order
|
||||
return b.closedAt - a.closedAt;
|
||||
});
|
||||
const menuItems: Electron.MenuItemConstructorOptions[] = [];
|
||||
for (const win of closedWindows) {
|
||||
const activeCtx = win.contexts.find(c => c.active === true);
|
||||
const activateNotePath = (activeCtx ?? win.contexts[0])?.notePath;
|
||||
const activateNoteId = activateNotePath?.split("/").pop() ?? null;
|
||||
|
||||
// Get the title of the closed window
|
||||
const rawTitle = activateNoteId ? becca_service.getNoteTitle(activateNoteId) : "";
|
||||
let winTitle = rawTitle.length > 20 ? `${rawTitle.slice(0, 17)}...` : rawTitle;
|
||||
const mainTabCount = win.contexts.filter(ctx => ctx.mainNtxId === null).length;
|
||||
if (mainTabCount > 1) {
|
||||
const tabSuffix = t("tray.tabs-total", { number: mainTabCount });
|
||||
winTitle += ` (${tabSuffix})`;
|
||||
}
|
||||
|
||||
menuItems.push({
|
||||
label: winTitle,
|
||||
type: "normal",
|
||||
click: () => win.windowId !== "main" ? windowService.createExtraWindow(win.windowId, "") : windowService.createMainWindow()
|
||||
});
|
||||
}
|
||||
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
const windowVisibilityMenuItems: Electron.MenuItemConstructorOptions[] = [];
|
||||
|
||||
// Only call getWindowTitle if windowVisibilityMap has more than one window
|
||||
@ -258,6 +296,12 @@ function updateTrayMenu() {
|
||||
icon: getIconPath("recents"),
|
||||
submenu: buildRecentNotesMenu()
|
||||
},
|
||||
{
|
||||
label: t("tray.recently-closed-windows"),
|
||||
type: "submenu",
|
||||
icon: getIconPath("closed-windows"),
|
||||
submenu: buildClosedWindowsMenu()
|
||||
},
|
||||
{ type: "separator" },
|
||||
{
|
||||
label: t("tray.close"),
|
||||
|
||||