diff --git a/app/src/assets/scss/protyle/_protyle.scss b/app/src/assets/scss/protyle/_protyle.scss index 572fec4dc..9c78faffe 100644 --- a/app/src/assets/scss/protyle/_protyle.scss +++ b/app/src/assets/scss/protyle/_protyle.scss @@ -143,6 +143,24 @@ } } + &__icon { + margin-right: 8px; + opacity: 1; + border: 0; + background-color: transparent; + color: var(--b3-theme-on-surface); + line-height: 24px; + border-radius: var(--b3-border-radius); + align-self: center; + padding: 0 4px; + font-size: 12px; + + &:hover { + color: var(--b3-theme-on-background); + background-color: var(--b3-list-hover); + } + } + &__arrow { height: 10px; width: 10px; @@ -178,6 +196,7 @@ max-width: 70%; border: 0; background-color: transparent; + box-sizing: inherit; &.b3-tooltips svg { margin-right: 0; diff --git a/app/src/block/Panel.ts b/app/src/block/Panel.ts index 9221b0941..de1ee1ead 100644 --- a/app/src/block/Panel.ts +++ b/app/src/block/Panel.ts @@ -180,8 +180,7 @@ export class BlockPanel { hideElements(["gutter"], editor.protyle); }); if (response.data.rootID !== this.nodeIds[index]) { - editor.protyle.breadcrumb.element.parentElement.insertAdjacentHTML("beforeend", ` -
`); + editor.protyle.breadcrumb.element.parentElement.lastElementChild.classList.remove("fn__none"); } } }); diff --git a/app/src/mobile/editor.ts b/app/src/mobile/editor.ts index 91d639852..39cc663df 100644 --- a/app/src/mobile/editor.ts +++ b/app/src/mobile/editor.ts @@ -56,7 +56,6 @@ export const openMobileFileById = (app: App, id: string, action = [Constants.CB_ mode: action.includes(Constants.CB_GET_CONTEXT) ? 3 : 0, }, getResponse => { onGet({data: getResponse, protyle: window.siyuan.mobile.editor.protyle, action}); - window.siyuan.mobile.editor.protyle.breadcrumb?.genMobileIcon(window.siyuan.mobile.editor.protyle.block.rootID); }); window.siyuan.mobile.editor.protyle.undo.clear(); } else { @@ -77,7 +76,6 @@ export const openMobileFileById = (app: App, id: string, action = [Constants.CB_ if (window.siyuan.config.readonly || window.siyuan.config.editor.readOnly) { disabledProtyle(editor.protyle); } - editor.protyle.breadcrumb?.genMobileIcon(editor.protyle.block.rootID); } }); } diff --git a/app/src/mobile/util/MobileBackFoward.ts b/app/src/mobile/util/MobileBackFoward.ts index 4c9dfdd85..88428f967 100644 --- a/app/src/mobile/util/MobileBackFoward.ts +++ b/app/src/mobile/util/MobileBackFoward.ts @@ -97,7 +97,6 @@ const focusStack = (backStack: IBackStack) => { } } protyle.contentElement.scrollTop = backStack.scrollTop; - protyle.breadcrumb?.genMobileIcon(protyle.block.rootID); }); }; diff --git a/app/src/protyle/breadcrumb/index.ts b/app/src/protyle/breadcrumb/index.ts index 09e90ad61..e7669b9fd 100644 --- a/app/src/protyle/breadcrumb/index.ts +++ b/app/src/protyle/breadcrumb/index.ts @@ -3,7 +3,7 @@ import {fetchPost} from "../../util/fetch"; import {Constants} from "../../constants"; import {MenuItem} from "../../menus/Menu"; import {fullscreen, netImg2LocalAssets} from "./action"; -import {exportMd} from "../../menus/commonMenuItem"; +import {exportMd, openFileAttr} from "../../menus/commonMenuItem"; import {setEditMode} from "../util/setEditMode"; import {RecordMedia} from "../util/RecordMedia"; import {hideMessage, showMessage} from "../../dialog/message"; @@ -28,6 +28,7 @@ import {reloadProtyle} from "../util/reload"; import {deleteFile} from "../../editor/deleteFile"; import {Menu} from "../../plugin/Menu"; import {getNoContainerElement} from "../wysiwyg/getBlock"; +import {openTitleMenu} from "../header/openTitleMenu"; export class Breadcrumb { public element: HTMLElement; @@ -38,12 +39,16 @@ export class Breadcrumb { constructor(protyle: IProtyle) { const element = document.createElement("div"); element.className = "protyle-breadcrumb"; - const isFocus = protyle.options.action.includes(Constants.CB_GET_ALL); - element.innerHTML = `
+ element.innerHTML = `${isMobile() ? + `` : + '
'} - - -`; + + + + +`; + this.element = element.firstElementChild as HTMLElement; element.addEventListener("click", (event) => { /// #if !MOBILE @@ -54,10 +59,9 @@ export class Breadcrumb { let target = event.target as HTMLElement; while (target && !target.isEqualNode(element)) { const id = target.getAttribute("data-node-id"); + const type = target.getAttribute("data-type"); if (id) { - /// #if MOBILE - this.genMobileMenu(protyle); - /// #else + /// #if !MOBILE if (protyle.options.render.breadcrumbDocName && window.siyuan.ctrlIsPressed) { openFileById({ app: protyle.app, @@ -70,18 +74,41 @@ export class Breadcrumb { /// #endif event.preventDefault(); break; - } else if (target.getAttribute("data-menu") === "true") { + } else if (type === "mobile-menu") { + this.genMobileMenu(protyle); + event.preventDefault(); + event.stopPropagation(); + break; + } else if (type === "a") { + if (window.siyuan.shiftIsPressed) { + fetchPost("/api/block/getDocInfo", { + id: protyle.block.rootID + }, (response) => { + openFileAttr(response.data.ial, protyle.block.rootID); + }); + } else { + const targetRect = target.getBoundingClientRect(); + openTitleMenu(protyle, {x: targetRect.right, y: targetRect.bottom, isLeft: true}); + } + event.stopPropagation(); + event.preventDefault(); + break; + } else if (type === "more") { + const targetRect = target.getBoundingClientRect(); this.showMenu(protyle, { - x: event.clientX, - y: event.clientY + x: targetRect.right, + y: targetRect.bottom, }); + event.stopPropagation(); event.preventDefault(); break; - } else if (target.getAttribute("data-type") === "exit-focus") { + } else if (type === "exit-focus") { zoomOut({protyle, id: protyle.block.rootID, focusId: protyle.block.id}); + event.stopPropagation(); event.preventDefault(); break; - } else if (target.getAttribute("data-type") === "context") { + } else if (type === "context") { + event.stopPropagation(); event.preventDefault(); if (target.classList.contains("block__icon--active")) { zoomOut({protyle, id: protyle.options.blockId}); @@ -101,6 +128,7 @@ export class Breadcrumb { target = target.parentElement; } }); + /// if !MOBILE element.addEventListener("mouseleave", () => { protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--hl").forEach(item => { item.classList.remove("protyle-wysiwyg--hl"); @@ -125,6 +153,7 @@ export class Breadcrumb { this.element.addEventListener("mousewheel", (event: WheelEvent) => { this.element.scrollLeft = this.element.scrollLeft + event.deltaY; }, {passive: true}); + /// #endif /// #if !BROWSER if ("windows" !== window.siyuan.config.system.os && "linux" !== window.siyuan.config.system.os) { const currentWindow = getCurrentWindow(); @@ -191,24 +220,21 @@ export class Breadcrumb { }); } - public genMobileIcon(rootId: string) { - this.element.innerHTML = ``; - } - public toggleExit(hide: boolean) { const exitFocusElement = this.element.parentElement.querySelector('[data-type="exit-focus"]'); if (hide) { exitFocusElement.classList.add("fn__none"); - exitFocusElement.nextElementSibling.classList.add("fn__none"); } else { exitFocusElement.classList.remove("fn__none"); - exitFocusElement.nextElementSibling.classList.remove("fn__none"); } } public showMenu(protyle: IProtyle, position: { x: number, y: number }) { + if (!window.siyuan.menus.menu.element.classList.contains("fn__none") && + window.siyuan.menus.menu.element.getAttribute("data-name") === "breadcrumbMore") { + window.siyuan.menus.menu.remove(); + return; + } let id; const cursorNodeElement = hasClosestBlock(getEditorRange(protyle.element).startContainer); if (cursorNodeElement) { @@ -216,6 +242,7 @@ export class Breadcrumb { } fetchPost("/api/block/getTreeStat", {id: id || (protyle.block.showAll ? protyle.block.id : protyle.block.rootID)}, (response) => { window.siyuan.menus.menu.remove(); + window.siyuan.menus.menu.element.setAttribute("data-name", "breadcrumbMore") if (!protyle.contentElement.classList.contains("fn__none") && !protyle.disabled) { let uploadHTML = ""; uploadHTML = '${window.siyuan.languages.imgCount}${response.data.imageCount}
${window.siyuan.languages.refCount}${response.data.refCount}
`, }).element); - if (isMobile()) { - window.siyuan.menus.menu.fullscreen(); - } else { - window.siyuan.menus.menu.popup(position); - } + /// #if MOBILE + window.siyuan.menus.menu.fullscreen(); + /// #else + window.siyuan.menus.menu.popup(position, true); + /// #endif }); } diff --git a/app/src/protyle/header/Title.ts b/app/src/protyle/header/Title.ts index 340eda547..c228b9802 100644 --- a/app/src/protyle/header/Title.ts +++ b/app/src/protyle/header/Title.ts @@ -7,36 +7,27 @@ import {fetchPost} from "../../util/fetch"; import {replaceFileName, validateName} from "../../editor/rename"; import {MenuItem} from "../../menus/Menu"; import { - copySubMenu, - movePathToMenu, openFileAttr, - openFileWechatNotify, } from "../../menus/commonMenuItem"; /// #if !BROWSER import {getCurrentWindow} from "@electron/remote"; /// #endif import {Constants} from "../../constants"; import {matchHotKey} from "../util/hotKey"; -import {readText, updateHotkeyTip, writeText} from "../util/compatibility"; +import {readText, writeText} from "../util/compatibility"; import * as dayjs from "dayjs"; import {setPanelFocus} from "../../layout/util"; import {openFileById, updatePanelByEditor} from "../../editor/util"; -import {openBacklink, openGraph, openOutline} from "../../layout/dock/util"; import {setTitle} from "../../dialog/processSystem"; import {getNoContainerElement} from "../wysiwyg/getBlock"; import {commonHotkey} from "../wysiwyg/commonHotkey"; import {code160to32} from "../util/code160to32"; -import {deleteFile} from "../../editor/deleteFile"; import {genEmptyElement} from "../../block/util"; import {transaction} from "../wysiwyg/transaction"; import {hideTooltip} from "../../dialog/tooltip"; -import {transferBlockRef} from "../../menus/block"; -import {openCardByData} from "../../card/openCard"; -import {makeCard, quickMakeCard} from "../../card/makeCard"; -import {viewCards} from "../../card/viewCards"; -import {getNotebookName, pathPosix} from "../../util/pathName"; +import {quickMakeCard} from "../../card/makeCard"; import {commonClick} from "../wysiwyg/commonClick"; -import {emitOpenMenu} from "../../plugin/EventBus"; +import {openTitleMenu} from "./openTitleMenu"; export class Title { public element: HTMLElement; @@ -192,12 +183,12 @@ export class Title { }); } else { const iconRect = iconElement.getBoundingClientRect(); - this.renderMenu(protyle, {x: iconRect.left, y: iconRect.top + 14}); + openTitleMenu(protyle, {x: iconRect.left, y: iconRect.bottom}); } }); this.element.addEventListener("contextmenu", (event) => { if (getSelection().rangeCount === 0) { - this.renderMenu(protyle, {x: event.clientX, y: event.clientY}); + openTitleMenu(protyle, {x: event.clientX, y: event.clientY}); return; } protyle.toolbar?.element.classList.add("fn__none"); @@ -293,137 +284,6 @@ export class Title { }, Constants.TIMEOUT_INPUT); } - private renderMenu(protyle: IProtyle, position: { x: number, y: number }) { - fetchPost("/api/block/getDocInfo", { - id: protyle.block.rootID - }, (response) => { - window.siyuan.menus.menu.remove(); - window.siyuan.menus.menu.append(new MenuItem({ - label: window.siyuan.languages.copy, - icon: "iconCopy", - type: "submenu", - submenu: copySubMenu(protyle.block.rootID) - }).element); - if (!protyle.disabled) { - window.siyuan.menus.menu.append(movePathToMenu([protyle.path])); - window.siyuan.menus.menu.append(new MenuItem({ - icon: "iconTrashcan", - label: window.siyuan.languages.delete, - click: () => { - deleteFile(protyle.notebookId, protyle.path); - } - }).element); - window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); - const countElement = this.element.lastElementChild.querySelector(".protyle-attr--refcount"); - if (countElement && countElement.textContent) { - transferBlockRef(protyle.block.rootID); - } - window.siyuan.menus.menu.append(new MenuItem({ - label: window.siyuan.languages.attr, - accelerator: window.siyuan.config.keymap.editor.general.attr.custom + "/" + updateHotkeyTip("⇧Click"), - click() { - openFileAttr(response.data.ial, protyle.block.rootID); - } - }).element); - } - window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); - window.siyuan.menus.menu.append(new MenuItem({ - icon: "iconAlignCenter", - label: window.siyuan.languages.outline, - accelerator: window.siyuan.config.keymap.editor.general.outline.custom, - click: () => { - openOutline(protyle); - } - }).element); - window.siyuan.menus.menu.append(new MenuItem({ - icon: "iconLink", - label: window.siyuan.languages.backlinks, - accelerator: window.siyuan.config.keymap.editor.general.backlinks.custom, - click: () => { - openBacklink(protyle); - } - }).element); - window.siyuan.menus.menu.append(new MenuItem({ - icon: "iconGraph", - label: window.siyuan.languages.graphView, - accelerator: window.siyuan.config.keymap.editor.general.graphView.custom, - click: () => { - openGraph(protyle); - } - }).element); - window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); - window.siyuan.menus.menu.append(new MenuItem({ - label: window.siyuan.languages.wechatReminder, - icon: "iconMp", - click() { - openFileWechatNotify(protyle); - } - }).element); - const riffCardMenu = [{ - iconHTML: Constants.ZWSP, - label: window.siyuan.languages.spaceRepetition, - accelerator: window.siyuan.config.keymap.editor.general.spaceRepetition.custom, - click: () => { - fetchPost("/api/riff/getTreeRiffDueCards", {rootID: protyle.block.rootID}, (response) => { - openCardByData(protyle.app, response.data, "doc", protyle.block.rootID, this.editElement.textContent || "Untitled"); - }); - } - }, { - iconHTML: Constants.ZWSP, - label: window.siyuan.languages.mgmt, - click: () => { - fetchPost("/api/filetree/getHPathByID", { - id: protyle.block.rootID - }, (response) => { - viewCards(protyle.app, protyle.block.rootID, pathPosix().join(getNotebookName(protyle.notebookId), (response.data)), "Tree"); - }); - } - }, { - iconHTML: Constants.ZWSP, - label: window.siyuan.languages.quickMakeCard, - accelerator: window.siyuan.config.keymap.editor.general.quickMakeCard.custom, - click: () => { - quickMakeCard(protyle, [this.element]); - } - }]; - if (window.siyuan.config.flashcard.deck) { - riffCardMenu.push({ - iconHTML: Constants.ZWSP, - label: window.siyuan.languages.addToDeck, - click: () => { - makeCard(protyle.app, [protyle.block.rootID]); - } - }); - } - window.siyuan.menus.menu.append(new MenuItem({ - label: window.siyuan.languages.riffCard, - type: "submenu", - icon: "iconRiffCard", - submenu: riffCardMenu, - }).element); - - if (protyle?.app?.plugins) { - emitOpenMenu({ - plugins:protyle.app.plugins, - type: "click-editortitleicon", - detail: { - protyle, - data: response.data, - }, - separatorPosition: "top", - }); - } - - window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); - window.siyuan.menus.menu.append(new MenuItem({ - iconHTML: Constants.ZWSP, - type: "readonly", - label: `${window.siyuan.languages.modifiedAt} ${dayjs(response.data.ial.updated).format("YYYY-MM-DD HH:mm:ss")}
-${window.siyuan.languages.createdAt} ${dayjs(response.data.ial.id.substr(0, 14)).format("YYYY-MM-DD HH:mm:ss")}` - }).element); - window.siyuan.menus.menu.popup(position); - }); - } public setTitle(title: string) { if (code160to32(title) !== code160to32(this.editElement.textContent)) { diff --git a/app/src/protyle/header/openTitleMenu.ts b/app/src/protyle/header/openTitleMenu.ts new file mode 100644 index 000000000..94dbf7e02 --- /dev/null +++ b/app/src/protyle/header/openTitleMenu.ts @@ -0,0 +1,164 @@ +import {fetchPost} from "../../util/fetch"; +import {MenuItem} from "../../menus/Menu"; +import {copySubMenu, movePathToMenu, openFileAttr, openFileWechatNotify} from "../../menus/commonMenuItem"; +import {deleteFile} from "../../editor/deleteFile"; +import {transferBlockRef} from "../../menus/block"; +import {updateHotkeyTip} from "../util/compatibility"; +import {openBacklink, openGraph, openOutline} from "../../layout/dock/util"; +import {Constants} from "../../constants"; +import {openCardByData} from "../../card/openCard"; +import {viewCards} from "../../card/viewCards"; +import {getNotebookName, pathPosix} from "../../util/pathName"; +import {makeCard, quickMakeCard} from "../../card/makeCard"; +import {emitOpenMenu} from "../../plugin/EventBus"; +import * as dayjs from "dayjs"; +import {hideTooltip} from "../../dialog/tooltip"; + +export const openTitleMenu = (protyle: IProtyle, position: { + x: number + y: number + isLeft?: boolean +}) => { + hideTooltip(); + if (!window.siyuan.menus.menu.element.classList.contains("fn__none") && + window.siyuan.menus.menu.element.getAttribute("data-name") === "titleMenu") { + window.siyuan.menus.menu.remove(); + return; + } + fetchPost("/api/block/getDocInfo", { + id: protyle.block.rootID + }, (response) => { + window.siyuan.menus.menu.remove(); + window.siyuan.menus.menu.element.setAttribute("data-name", "titleMenu"); + window.siyuan.menus.menu.append(new MenuItem({ + label: window.siyuan.languages.copy, + icon: "iconCopy", + type: "submenu", + submenu: copySubMenu(protyle.block.rootID) + }).element); + if (!protyle.disabled) { + window.siyuan.menus.menu.append(movePathToMenu([protyle.path])); + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconTrashcan", + label: window.siyuan.languages.delete, + click: () => { + deleteFile(protyle.notebookId, protyle.path); + } + }).element); + window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); + if (response.data.refCount && response.data.refCount > 0) { + transferBlockRef(protyle.block.rootID); + } + window.siyuan.menus.menu.append(new MenuItem({ + label: window.siyuan.languages.attr, + accelerator: window.siyuan.config.keymap.editor.general.attr.custom + "/" + updateHotkeyTip("⇧Click"), + click() { + openFileAttr(response.data.ial, protyle.block.rootID); + } + }).element); + } + window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconAlignCenter", + label: window.siyuan.languages.outline, + accelerator: window.siyuan.config.keymap.editor.general.outline.custom, + click: () => { + openOutline(protyle); + } + }).element); + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconLink", + label: window.siyuan.languages.backlinks, + accelerator: window.siyuan.config.keymap.editor.general.backlinks.custom, + click: () => { + openBacklink(protyle); + } + }).element); + window.siyuan.menus.menu.append(new MenuItem({ + icon: "iconGraph", + label: window.siyuan.languages.graphView, + accelerator: window.siyuan.config.keymap.editor.general.graphView.custom, + click: () => { + openGraph(protyle); + } + }).element); + window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); + window.siyuan.menus.menu.append(new MenuItem({ + label: window.siyuan.languages.wechatReminder, + icon: "iconMp", + click() { + openFileWechatNotify(protyle); + } + }).element); + const riffCardMenu = [{ + iconHTML: Constants.ZWSP, + label: window.siyuan.languages.spaceRepetition, + accelerator: window.siyuan.config.keymap.editor.general.spaceRepetition.custom, + click: () => { + fetchPost("/api/riff/getTreeRiffDueCards", {rootID: protyle.block.rootID}, (response) => { + openCardByData(protyle.app, response.data, "doc", protyle.block.rootID, response.data.name); + }); + } + }, { + iconHTML: Constants.ZWSP, + label: window.siyuan.languages.mgmt, + click: () => { + fetchPost("/api/filetree/getHPathByID", { + id: protyle.block.rootID + }, (response) => { + viewCards(protyle.app, protyle.block.rootID, pathPosix().join(getNotebookName(protyle.notebookId), (response.data)), "Tree"); + }); + } + }, { + iconHTML: Constants.ZWSP, + label: window.siyuan.languages.quickMakeCard, + accelerator: window.siyuan.config.keymap.editor.general.quickMakeCard.custom, + click: () => { + let titleElement = protyle.title?.element; + if (!titleElement) { + titleElement = document.createElement("div"); + titleElement.setAttribute("data-node-id", protyle.block.rootID); + titleElement.setAttribute("custom-riff-decks", response.data.ial["custom-riff-decks"]); + } + quickMakeCard(protyle, [titleElement]); + } + }]; + if (window.siyuan.config.flashcard.deck) { + riffCardMenu.push({ + iconHTML: Constants.ZWSP, + label: window.siyuan.languages.addToDeck, + click: () => { + makeCard(protyle.app, [protyle.block.rootID]); + } + }); + } + window.siyuan.menus.menu.append(new MenuItem({ + label: window.siyuan.languages.riffCard, + type: "submenu", + icon: "iconRiffCard", + submenu: riffCardMenu, + }).element); + + if (protyle?.app?.plugins) { + emitOpenMenu({ + plugins: protyle.app.plugins, + type: "click-editortitleicon", + detail: { + protyle, + data: response.data, + }, + separatorPosition: "top", + }); + } + + window.siyuan.menus.menu.append(new MenuItem({type: "separator"}).element); + window.siyuan.menus.menu.append(new MenuItem({ + iconHTML: Constants.ZWSP, + type: "readonly", + label: `${window.siyuan.languages.modifiedAt} ${dayjs(response.data.ial.updated).format("YYYY-MM-DD HH:mm:ss")}
+${window.siyuan.languages.createdAt} ${dayjs(response.data.ial.id.substr(0, 14)).format("YYYY-MM-DD HH:mm:ss")}` + }).element); + window.siyuan.menus.menu.popup(position, position.isLeft); + }); + +}