A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
at lambda-fork/main 654 lines 30 kB view raw
1import {MenuItem} from "./Menu"; 2/// #if !BROWSER 3import {ipcRenderer} from "electron"; 4/// #endif 5import {openHistory} from "../history/history"; 6import {getOpenNotebookCount, originalPath, pathPosix, useShell} from "../util/pathName"; 7import {fetchNewDailyNote, mountHelp, newDailyNote} from "../util/mount"; 8import {fetchPost} from "../util/fetch"; 9import {Constants} from "../constants"; 10import { 11 isInAndroid, 12 isInHarmony, 13 isInIOS, 14 isIPad, 15 setStorageVal, 16 writeText 17} from "../protyle/util/compatibility"; 18import {openCard} from "../card/openCard"; 19import {openSetting} from "../config"; 20import {getAllDocks} from "../layout/getAll"; 21import {exportLayout, getAllLayout} from "../layout/util"; 22import {getDockByType} from "../layout/tabUtil"; 23import {exitSiYuan, lockScreen} from "../dialog/processSystem"; 24import {showMessage} from "../dialog/message"; 25import {unicode2Emoji} from "../emoji"; 26import {Dock} from "../layout/dock"; 27import {escapeHtml} from "../util/escape"; 28import {viewCards} from "../card/viewCards"; 29import {Dialog} from "../dialog"; 30import {hasClosestByClassName} from "../protyle/util/hasClosest"; 31import {confirmDialog} from "../dialog/confirmDialog"; 32import {App} from "../index"; 33import {isBrowser} from "../util/functions"; 34import {openRecentDocs} from "../business/openRecentDocs"; 35import * as dayjs from "dayjs"; 36import {upDownHint} from "../util/upDownHint"; 37 38const editLayout = (layoutName?: string) => { 39 const dialog = new Dialog({ 40 positionId: Constants.DIALOG_SAVEWORKSPACE, 41 title: layoutName ? window.siyuan.languages.edit : window.siyuan.languages.save, 42 content: `<div class="b3-dialog__content"> 43 <input class="b3-text-field fn__block" value="${layoutName || ""}" placeholder="${window.siyuan.languages.memo}"> 44</div> 45<div class="b3-dialog__action"> 46 <button class="b3-button b3-button--remove${layoutName ? "" : " fn__none"}">${window.siyuan.languages.delete}</button><div class="fn__space"></div> 47 <button class="b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button><div class="fn__space"></div> 48 <button class="b3-button b3-button--text${layoutName ? "" : " fn__none"}">${window.siyuan.languages.rename}</button><div class="fn__space"></div> 49 <button class="b3-button b3-button--text">${window.siyuan.languages[layoutName ? "updateLayout" : "confirm"]}</button> 50</div>`, 51 width: "520px", 52 }); 53 dialog.element.setAttribute("data-key", Constants.DIALOG_SAVEWORKSPACE); 54 const btnsElement = dialog.element.querySelectorAll(".b3-button"); 55 const inputElement = dialog.element.querySelector("input"); 56 inputElement.select(); 57 inputElement.focus(); 58 dialog.bindInput(inputElement, () => { 59 btnsElement[3].dispatchEvent(new CustomEvent("click")); 60 }); 61 btnsElement[0].addEventListener("click", () => { 62 window.siyuan.storage[Constants.LOCAL_LAYOUTS].find((layoutItem: ISaveLayout, index: number) => { 63 if (layoutItem.name === layoutName) { 64 window.siyuan.storage[Constants.LOCAL_LAYOUTS].splice(index, 1); 65 setStorageVal(Constants.LOCAL_LAYOUTS, window.siyuan.storage[Constants.LOCAL_LAYOUTS]); 66 return true; 67 } 68 }); 69 dialog.destroy(); 70 }); 71 btnsElement[1].addEventListener("click", () => { 72 dialog.destroy(); 73 }); 74 btnsElement[2].addEventListener("click", () => { 75 const value = inputElement.value; 76 if (!value) { 77 showMessage(window.siyuan.languages["_kernel"]["142"]); 78 return; 79 } 80 dialog.destroy(); 81 window.siyuan.storage[Constants.LOCAL_LAYOUTS].find((layoutItem: ISaveLayout) => { 82 if (layoutItem.name === layoutName) { 83 layoutItem.name = value; 84 layoutItem.time = new Date().getTime(); 85 setStorageVal(Constants.LOCAL_LAYOUTS, window.siyuan.storage[Constants.LOCAL_LAYOUTS]); 86 return true; 87 } 88 }); 89 }); 90 btnsElement[3].addEventListener("click", () => { 91 const value = inputElement.value; 92 if (!value) { 93 showMessage(window.siyuan.languages["_kernel"]["142"]); 94 return; 95 } 96 dialog.destroy(); 97 if (layoutName) { 98 window.siyuan.storage[Constants.LOCAL_LAYOUTS].find((layoutItem: ISaveLayout) => { 99 if (layoutItem.name === layoutName) { 100 layoutItem.name = value; 101 layoutItem.time = new Date().getTime(); 102 layoutItem.layout = getAllLayout(); 103 layoutItem.filesPaths = window.siyuan.storage[Constants.LOCAL_FILESPATHS]; 104 setStorageVal(Constants.LOCAL_LAYOUTS, window.siyuan.storage[Constants.LOCAL_LAYOUTS]); 105 return true; 106 } 107 }); 108 return; 109 } 110 const hadName = window.siyuan.storage[Constants.LOCAL_LAYOUTS].find((item: ISaveLayout) => { 111 if (item.name === value) { 112 confirmDialog(window.siyuan.languages.save, window.siyuan.languages.exportTplTip, () => { 113 item.layout = getAllLayout(); 114 item.time = new Date().getTime(); 115 item.filesPaths = window.siyuan.storage[Constants.LOCAL_FILESPATHS]; 116 setStorageVal(Constants.LOCAL_LAYOUTS, window.siyuan.storage[Constants.LOCAL_LAYOUTS]); 117 }); 118 return true; 119 } 120 }); 121 if (hadName) { 122 return; 123 } 124 window.siyuan.storage[Constants.LOCAL_LAYOUTS].push({ 125 name: value, 126 time: new Date().getTime(), 127 layout: getAllLayout(), 128 filesPaths: window.siyuan.storage[Constants.LOCAL_FILESPATHS] 129 }); 130 setStorageVal(Constants.LOCAL_LAYOUTS, window.siyuan.storage[Constants.LOCAL_LAYOUTS]); 131 }); 132}; 133 134const togglePinDock = (id: string, dock: Dock, icon: string) => { 135 return { 136 id, 137 label: `${dock.pin ? window.siyuan.languages.unpin : window.siyuan.languages.pin}`, 138 icon, 139 current: !dock.pin, 140 click() { 141 dock.togglePin(); 142 } 143 }; 144}; 145 146export const workspaceMenu = (app: App, rect: DOMRect) => { 147 if (!window.siyuan.menus.menu.element.classList.contains("fn__none") && 148 window.siyuan.menus.menu.element.getAttribute("data-name") === Constants.MENU_BAR_WORKSPACE) { 149 window.siyuan.menus.menu.remove(); 150 return; 151 } 152 fetchPost("/api/system/getWorkspaces", {}, (response) => { 153 window.siyuan.menus.menu.remove(); 154 window.siyuan.menus.menu.element.setAttribute("data-name", Constants.MENU_BAR_WORKSPACE); 155 if (!window.siyuan.config.readonly) { 156 window.siyuan.menus.menu.append(new MenuItem({ 157 id: "config", 158 label: window.siyuan.languages.config, 159 icon: "iconSettings", 160 accelerator: window.siyuan.config.keymap.general.config.custom, 161 click: () => { 162 openSetting(app); 163 } 164 }).element); 165 } 166 const dockMenu: IMenu[] = []; 167 getAllDocks().forEach(item => { 168 dockMenu.push({ 169 id: item.type, 170 icon: item.icon, 171 accelerator: item.hotkey, 172 label: item.title, 173 click() { 174 getDockByType(item.type).toggleModel(item.type); 175 } 176 }); 177 }); 178 if (!window.siyuan.config.readonly) { 179 dockMenu.push({id: "separator_1", type: "separator"}); 180 dockMenu.push(togglePinDock("leftDock", window.siyuan.layout.leftDock, "iconLeftTop")); 181 dockMenu.push(togglePinDock("rightDock", window.siyuan.layout.rightDock, "iconRightTop")); 182 dockMenu.push(togglePinDock("bottomDock", window.siyuan.layout.bottomDock, "iconBottomLeft")); 183 } 184 window.siyuan.menus.menu.append(new MenuItem({ 185 id: "panels", 186 label: window.siyuan.languages.panels, 187 icon: "iconDock", 188 type: "submenu", 189 submenu: dockMenu 190 }).element); 191 if (!window.siyuan.config.readonly) { 192 let workspaceSubMenu: IMenu[]; 193 /// #if !BROWSER 194 workspaceSubMenu = [{ 195 id: "newOrOpenBy", 196 label: `${window.siyuan.languages.new} / ${window.siyuan.languages.openBy}`, 197 iconHTML: "", 198 click: async () => { 199 const localPath = await ipcRenderer.invoke(Constants.SIYUAN_GET, { 200 cmd: "showOpenDialog", 201 defaultPath: window.siyuan.config.system.homeDir, 202 properties: ["openDirectory", "createDirectory"], 203 }); 204 if (localPath.filePaths.length === 0) { 205 return; 206 } 207 fetchPost("/api/system/checkWorkspaceDir", {path: localPath.filePaths[0]}, (response) => { 208 if (response.data.isWorkspace) { 209 openWorkspace(localPath.filePaths[0]); 210 } else { 211 confirmDialog("🏗️ " + window.siyuan.languages.createWorkspace, window.siyuan.languages.createWorkspaceTip + `<br><br><code class="fn__code">${localPath.filePaths[0]}</code>`, () => { 212 openWorkspace(localPath.filePaths[0]); 213 }); 214 } 215 }); 216 } 217 }]; 218 workspaceSubMenu.push({id: "separator_1", type: "separator"}); 219 response.data.forEach((item: IWorkspace) => { 220 workspaceSubMenu.push(workspaceItem(item) as IMenu); 221 }); 222 /// #else 223 workspaceSubMenu = [{ 224 id: "new", 225 label: window.siyuan.languages.new, 226 iconHTML: "", 227 click() { 228 const createWorkspaceDialog = new Dialog({ 229 title: window.siyuan.languages.new, 230 content: `<div class="b3-dialog__content"> 231 <input class="b3-text-field fn__block"> 232</div> 233<div class="b3-dialog__action"> 234 <button class="b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button><div class="fn__space"></div> 235 <button class="b3-button b3-button--text">${window.siyuan.languages.confirm}</button> 236</div>`, 237 width: "520px", 238 }); 239 createWorkspaceDialog.element.setAttribute("data-key", Constants.DIALOG_CREATEWORKSPACE); 240 const inputElement = createWorkspaceDialog.element.querySelector("input"); 241 inputElement.focus(); 242 const btnsElement = createWorkspaceDialog.element.querySelectorAll(".b3-button"); 243 btnsElement[0].addEventListener("click", () => { 244 createWorkspaceDialog.destroy(); 245 }); 246 btnsElement[1].addEventListener("click", () => { 247 fetchPost("/api/system/createWorkspaceDir", { 248 path: pathPosix().join(pathPosix().dirname(window.siyuan.config.system.workspaceDir), inputElement.value) 249 }, () => { 250 createWorkspaceDialog.destroy(); 251 }); 252 }); 253 } 254 }, { 255 id: "openBy", 256 label: `${window.siyuan.languages.openBy}...`, 257 iconHTML: "", 258 click() { 259 fetchPost("/api/system/getMobileWorkspaces", {}, (response) => { 260 let selectHTML = ""; 261 response.data.forEach((item: string, index: number) => { 262 selectHTML += `<option value="${item}"${index === 0 ? ' selected="selected"' : ""}>${pathPosix().basename(item)}</option>`; 263 }); 264 const openWorkspaceDialog = new Dialog({ 265 title: window.siyuan.languages.openBy, 266 content: `<div class="b3-dialog__content"> 267 <select class="b3-text-field fn__block">${selectHTML}</select> 268</div> 269<div class="b3-dialog__action"> 270 <button class="b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button><div class="fn__space"></div> 271 <button class="b3-button b3-button--text">${window.siyuan.languages.confirm}</button> 272</div>`, 273 width: "520px", 274 }); 275 openWorkspaceDialog.element.setAttribute("data-key", Constants.DIALOG_OPENWORKSPACE); 276 const btnsElement = openWorkspaceDialog.element.querySelectorAll(".b3-button"); 277 btnsElement[0].addEventListener("click", () => { 278 openWorkspaceDialog.destroy(); 279 }); 280 btnsElement[1].addEventListener("click", () => { 281 const openPath = openWorkspaceDialog.element.querySelector("select").value; 282 if (openPath === window.siyuan.config.system.workspaceDir) { 283 openWorkspaceDialog.destroy(); 284 return; 285 } 286 confirmDialog(window.siyuan.languages.confirm, `${pathPosix().basename(window.siyuan.config.system.workspaceDir)} -> ${pathPosix().basename(openPath)}?`, () => { 287 fetchPost("/api/system/setWorkspaceDir", { 288 path: openPath 289 }, () => { 290 exitSiYuan(); 291 }); 292 }); 293 }); 294 }); 295 } 296 }]; 297 workspaceSubMenu.push({id: "separator_1", type: "separator"}); 298 response.data.forEach((item: IWorkspace) => { 299 workspaceSubMenu.push({ 300 iconHTML: "", 301 action: "iconCloseRound", 302 current: window.siyuan.config.system.workspaceDir === item.path, 303 label: pathPosix().basename(item.path), 304 bind(menuElement) { 305 menuElement.addEventListener("click", (event) => { 306 if (hasClosestByClassName(event.target as Element, "b3-menu__action")) { 307 event.preventDefault(); 308 event.stopPropagation(); 309 fetchPost("/api/system/removeWorkspaceDir", {path: item.path}, () => { 310 confirmDialog(window.siyuan.languages.deleteOpConfirm, window.siyuan.languages.removeWorkspacePhysically.replace("${x}", item.path), () => { 311 fetchPost("/api/system/removeWorkspaceDirPhysically", {path: item.path}); 312 }, undefined, true); 313 }); 314 return; 315 } 316 confirmDialog(window.siyuan.languages.confirm, `${pathPosix().basename(window.siyuan.config.system.workspaceDir)} -> ${pathPosix().basename(item.path)}?`, () => { 317 fetchPost("/api/system/setWorkspaceDir", { 318 path: item.path 319 }, () => { 320 exitSiYuan(); 321 }); 322 }); 323 }); 324 } 325 }); 326 }); 327 /// #endif 328 if (!isBrowser() || isInIOS() || isInAndroid() || isInHarmony()) { 329 window.siyuan.menus.menu.append(new MenuItem({ 330 id: "workspaceList", 331 label: window.siyuan.languages.workspaceList, 332 icon: "iconWorkspace", 333 type: "submenu", 334 submenu: workspaceSubMenu, 335 }).element); 336 } 337 } 338 const layoutSubMenu: IMenu[] = [{ 339 id: "save", 340 iconHTML: "", 341 label: window.siyuan.languages.save, 342 click() { 343 editLayout(); 344 } 345 }]; 346 if (window.siyuan.storage[Constants.LOCAL_LAYOUTS].length > 0) { 347 layoutSubMenu.push({id: "separator_1", type: "separator"}); 348 layoutSubMenu.push({ 349 iconHTML: "", 350 type: "empty", 351 label: `<input class="b3-text-field fn__block" style="margin: 4px 0" placeholder="${window.siyuan.languages.search}"> 352<div class="b3-list b3-list--background" style="max-width: 50vw"></div>`, 353 bind(menuElement) { 354 const genListHTML = () => { 355 let html = ""; 356 window.siyuan.storage[Constants.LOCAL_LAYOUTS].sort((a: ISaveLayout, b: ISaveLayout) => { 357 return a.name.localeCompare(b.name, undefined, {numeric: true}); 358 }).forEach((item: ISaveLayout) => { 359 if (inputElement.value === "" || item.name.toLowerCase().indexOf(inputElement.value.toLowerCase()) > -1) { 360 html += `<div data-name="${item.name}" class="b3-list-item b3-list-item--narrow b3-list-item--hide-action ${html ? "" : "b3-list-item--focus"}"> 361 <div class="b3-list-item__text">${item.name}</div> 362 <span class="b3-list-item__meta">${item.time ? dayjs(item.time).format("YYYY-MM-DD HH:mm") : ""}</span> 363 <span class="b3-list-item__action"> 364 <svg><use xlink:href="#iconEdit"></use></svg> 365 </span> 366</div>`; 367 } 368 }); 369 return html; 370 }; 371 const inputElement = menuElement.querySelector(".b3-text-field") as HTMLInputElement; 372 const listElement = menuElement.querySelector(".b3-list"); 373 inputElement.addEventListener("keydown", (event) => { 374 event.stopPropagation(); 375 if (event.isComposing) { 376 return; 377 } 378 upDownHint(listElement, event); 379 if (event.key === "Escape") { 380 window.siyuan.menus.menu.remove(); 381 } else if (event.key === "Enter") { 382 const currentElement = listElement.querySelector(".b3-list-item--focus"); 383 if (currentElement) { 384 listElement.dispatchEvent(new CustomEvent("click", {detail: currentElement.getAttribute("data-name")})); 385 } 386 } 387 }); 388 inputElement.addEventListener("compositionend", () => { 389 listElement.innerHTML = genListHTML(); 390 }); 391 inputElement.addEventListener("input", (event: InputEvent) => { 392 if (event.isComposing) { 393 return; 394 } 395 event.stopPropagation(); 396 listElement.innerHTML = genListHTML(); 397 }); 398 listElement.addEventListener("click", (event: MouseEvent) => { 399 if (window.siyuan.config.readonly) { 400 return; 401 } 402 const actionElement = hasClosestByClassName(event.target as Element, "b3-list-item__action"); 403 if (actionElement) { 404 event.preventDefault(); 405 event.stopPropagation(); 406 editLayout(actionElement.parentElement.dataset.name); 407 window.siyuan.menus.menu.remove(); 408 return; 409 } 410 const liElement = hasClosestByClassName(event.target as Element, "b3-list-item"); 411 if (liElement || event.detail) { 412 const itemData: ISaveLayout = window.siyuan.storage[Constants.LOCAL_LAYOUTS].find((item: ISaveLayout) => { 413 if (typeof event.detail === "string") { 414 return item.name === event.detail; 415 } else if (liElement) { 416 return item.name === liElement.dataset.name; 417 } 418 }); 419 if (itemData) { 420 fetchPost("/api/system/setUILayout", {layout: itemData.layout}, () => { 421 if (itemData.filesPaths) { 422 window.siyuan.storage[Constants.LOCAL_FILESPATHS] = itemData.filesPaths; 423 setStorageVal(Constants.LOCAL_FILESPATHS, itemData.filesPaths, () => { 424 window.location.reload(); 425 }); 426 } else { 427 window.location.reload(); 428 } 429 }); 430 } 431 event.preventDefault(); 432 event.stopPropagation(); 433 } 434 }); 435 listElement.innerHTML = genListHTML(); 436 } 437 }); 438 } 439 if (!window.siyuan.config.readonly) { 440 window.siyuan.menus.menu.append(new MenuItem({ 441 id: "layout", 442 label: window.siyuan.languages.layout, 443 icon: "iconLayout", 444 type: "submenu", 445 submenu: layoutSubMenu 446 }).element); 447 } 448 window.siyuan.menus.menu.append(new MenuItem({id: "separator_1", type: "separator"}).element); 449 if (!window.siyuan.config.readonly) { 450 if (getOpenNotebookCount() < 2) { 451 window.siyuan.menus.menu.append(new MenuItem({ 452 id: "dailyNote", 453 label: window.siyuan.languages.dailyNote, 454 icon: "iconCalendar", 455 accelerator: window.siyuan.config.keymap.general.dailyNote.custom, 456 click: () => { 457 newDailyNote(app); 458 } 459 }).element); 460 } else { 461 const submenu: IMenu[] = []; 462 window.siyuan.notebooks.forEach(item => { 463 if (!item.closed) { 464 submenu.push({ 465 label: escapeHtml(item.name), 466 iconHTML: unicode2Emoji(item.icon || window.siyuan.storage[Constants.LOCAL_IMAGES].note, "b3-menu__icon", true), 467 accelerator: window.siyuan.storage[Constants.LOCAL_DAILYNOTEID] === item.id ? window.siyuan.config.keymap.general.dailyNote.custom : "", 468 click: () => { 469 fetchNewDailyNote(app, item.id); 470 window.siyuan.storage[Constants.LOCAL_DAILYNOTEID] = item.id; 471 setStorageVal(Constants.LOCAL_DAILYNOTEID, window.siyuan.storage[Constants.LOCAL_DAILYNOTEID]); 472 } 473 }); 474 } 475 }); 476 window.siyuan.menus.menu.append(new MenuItem({ 477 id: "dailyNote", 478 label: window.siyuan.languages.dailyNote, 479 icon: "iconCalendar", 480 type: "submenu", 481 submenu 482 }).element); 483 } 484 if (!window.siyuan.config.readonly) { 485 window.siyuan.menus.menu.append(new MenuItem({ 486 id: "riffCard", 487 label: window.siyuan.languages.riffCard, 488 type: "submenu", 489 icon: "iconRiffCard", 490 submenu: [{ 491 id: "spaceRepetition", 492 iconHTML: "", 493 label: window.siyuan.languages.spaceRepetition, 494 accelerator: window.siyuan.config.keymap.general.riffCard.custom, 495 click: () => { 496 openCard(app); 497 } 498 }, { 499 id: "manage", 500 iconHTML: "", 501 label: window.siyuan.languages.manage, 502 click: () => { 503 viewCards(app, "", window.siyuan.languages.all, ""); 504 } 505 }], 506 }).element); 507 } 508 window.siyuan.menus.menu.append(new MenuItem({ 509 id: "recentDocs", 510 label: window.siyuan.languages.recentDocs, 511 icon: "iconFile", 512 accelerator: window.siyuan.config.keymap.general.recentDocs.custom, 513 click: () => { 514 openRecentDocs(); 515 } 516 }).element); 517 window.siyuan.menus.menu.append(new MenuItem({ 518 id: "lockScreen", 519 label: window.siyuan.languages.lockScreen, 520 icon: "iconLock", 521 accelerator: window.siyuan.config.keymap.general.lockScreen.custom, 522 click: () => { 523 lockScreen(app); 524 } 525 }).element); 526 window.siyuan.menus.menu.append(new MenuItem({ 527 id: "dataHistory", 528 label: window.siyuan.languages.dataHistory, 529 icon: "iconHistory", 530 accelerator: window.siyuan.config.keymap.general.dataHistory.custom, 531 click: () => { 532 openHistory(app); 533 } 534 }).element); 535 window.siyuan.menus.menu.append(new MenuItem({id: "separator_2", type: "separator"}).element); 536 } 537 window.siyuan.menus.menu.append(new MenuItem({ 538 id: "userGuide", 539 label: window.siyuan.languages.userGuide, 540 icon: "iconHelp", 541 ignore: isIPad() || window.siyuan.config.readonly, 542 click: () => { 543 mountHelp(); 544 } 545 }).element); 546 window.siyuan.menus.menu.append(new MenuItem({ 547 id: "feedback", 548 label: window.siyuan.languages.feedback, 549 icon: "iconFeedback", 550 click: () => { 551 if ("zh_CN" === window.siyuan.config.lang || "zh_CHT" === window.siyuan.config.lang) { 552 window.open("https://ld246.com/article/1649901726096"); 553 } else { 554 window.open("https://liuyun.io/article/1686530886208"); 555 } 556 } 557 }).element); 558 /// #if !BROWSER 559 window.siyuan.menus.menu.append(new MenuItem({ 560 id: "debug", 561 label: window.siyuan.languages.debug, 562 icon: "iconBug", 563 click: () => { 564 ipcRenderer.send(Constants.SIYUAN_CMD, "openDevTools"); 565 } 566 }).element); 567 /// #endif 568 if (isIPad() || isInAndroid() || isInHarmony() || !isBrowser()) { 569 window.siyuan.menus.menu.append(new MenuItem({id: "separator_3", type: "separator"}).element); 570 window.siyuan.menus.menu.append(new MenuItem({ 571 id: "safeQuit", 572 label: window.siyuan.languages.safeQuit, 573 icon: "iconQuit", 574 warning: true, 575 click: () => { 576 exportLayout({ 577 errorExit: true, 578 cb: exitSiYuan, 579 }); 580 } 581 }).element); 582 } 583 window.siyuan.menus.menu.popup({x: rect.left, y: rect.bottom}); 584 }); 585}; 586 587const openWorkspace = (workspace: string) => { 588 /// #if !BROWSER 589 if (workspace === window.siyuan.config.system.workspaceDir) { 590 return; 591 } 592 fetchPost("/api/system/setWorkspaceDir", { 593 path: workspace 594 }, () => { 595 ipcRenderer.send(Constants.SIYUAN_OPEN_WORKSPACE, { 596 workspace, 597 lang: window.siyuan.config.appearance.lang 598 }); 599 }); 600 /// #endif 601}; 602 603const workspaceItem = (item: IWorkspace) => { 604 /// #if !BROWSER 605 const submenu = [{ 606 id: "showInFolder", 607 icon: "iconFolder", 608 label: window.siyuan.languages.showInFolder, 609 click() { 610 useShell("showItemInFolder", item.path); 611 } 612 }, { 613 id: "copyPath", 614 icon: "iconCopy", 615 label: window.siyuan.languages.copyPath, 616 click() { 617 writeText(item.path); 618 showMessage(window.siyuan.languages.copied); 619 } 620 }]; 621 if (item.path !== window.siyuan.config.system.workspaceDir) { 622 submenu.splice(0, 0, { 623 id: "openBy", 624 icon: "iconOpenWindow", 625 label: window.siyuan.languages.openBy, 626 click() { 627 openWorkspace(item.path); 628 } 629 }); 630 if (item.closed) { 631 submenu.push({ 632 id: "removeWorkspaceTip", 633 icon: "iconTrashcan", 634 label: window.siyuan.languages.removeWorkspaceTip, 635 click() { 636 fetchPost("/api/system/removeWorkspaceDir", {path: item.path}); 637 } 638 }); 639 } 640 } 641 return { 642 label: `<div aria-label="${item.path}" class="fn__ellipsis ariaLabel" style="max-width: 256px"> 643 ${originalPath().basename(item.path)} 644</div>`, 645 current: !item.closed, 646 iconHTML: "", 647 type: "submenu", 648 submenu, 649 click() { 650 openWorkspace(item.path); 651 }, 652 }; 653 /// #endif 654};