A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
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};