diff --git a/app/src/assets/scss/_menu.scss b/app/src/assets/scss/_menu.scss index 3492aa156..c7dc63fbc 100644 --- a/app/src/assets/scss/_menu.scss +++ b/app/src/assets/scss/_menu.scss @@ -5,6 +5,12 @@ background-color: var(--b3-menu-background); padding: 8px; z-index: 210; + max-height: 80vh; + overflow: auto; + + &::-webkit-scrollbar { + display: none; + } &--list { overflow: auto; @@ -20,7 +26,7 @@ } &__item { - padding: 0 16px 0 8px; + padding: 0 8px; border-radius: 4px; user-select: none; display: flex; @@ -43,18 +49,8 @@ &--show { background-color: var(--b3-list-hover); - .b3-menu__submenu { + & > .b3-menu__submenu { display: block; - border: 1px solid var(--b3-theme-surface-lighter); - border-radius: 4px; - background-color: var(--b3-menu-background); - padding: 8px; - position: absolute; - left: calc(100% + 8px); - top: -8px; - box-shadow: var(--b3-dialog-shadow); - mix-blend-mode: difference; - &--row { display: flex; @@ -91,7 +87,7 @@ &--current { background-color: var(--b3-list-hover); - .b3-menu__action { + & > .b3-menu__action { opacity: 1; } } @@ -170,6 +166,18 @@ &__submenu { overflow: auto; display: none; + max-height: 80vh; + border: 1px solid var(--b3-theme-surface-lighter); + border-radius: 4px; + background-color: var(--b3-menu-background); + padding: 8px; + position: fixed; + box-shadow: var(--b3-dialog-shadow); + z-index: 1; + + &::-webkit-scrollbar { + display: none; + } } &__accelerator { diff --git a/app/src/layout/status.ts b/app/src/layout/status.ts index 075ee1887..a5c1bd6f4 100644 --- a/app/src/layout/status.ts +++ b/app/src/layout/status.ts @@ -35,9 +35,9 @@ export const initStatus = () => {
${window.siyuan.languages.feedback} + ${window.siyuan.languages["_trayMenu"].officialWebsite} ${window.siyuan.languages["_trayMenu"].openSource} -
`; const dockElement = document.getElementById("barDock"); diff --git a/app/src/menus/Menu.ts b/app/src/menus/Menu.ts index f3e5c9def..ae36749f2 100644 --- a/app/src/menus/Menu.ts +++ b/app/src/menus/Menu.ts @@ -20,9 +20,9 @@ export class Menu { if (itemElement.classList.contains("b3-menu__item--readonly")) { return; } - const subMenuElement = itemElement.querySelector(".b3-menu__submenu"); + const subMenuElement = itemElement.querySelector(".b3-menu__submenu") as HTMLElement; this.element.querySelectorAll(".b3-menu__item--show").forEach((item) => { - if (!item.contains(itemElement)) { + if (!item.contains(itemElement) && !item.isSameNode(itemElement) && !itemElement.contains(item)) { item.classList.remove("b3-menu__item--show"); } }); @@ -38,25 +38,22 @@ export class Menu { }); } - public showSubMenu(subMenuElement: Element) { + public showSubMenu(subMenuElement: HTMLElement) { + const parentRect = subMenuElement.parentElement.getBoundingClientRect(); + subMenuElement.style.top = (parentRect.top - 8) + "px"; + subMenuElement.style.left = (parentRect.right + 8) + "px"; + subMenuElement.style.bottom = "auto"; const rect = subMenuElement.getBoundingClientRect(); - let style = ""; - const leftPosition = rect.left - this.element.clientWidth - rect.width; - if (rect.right > window.innerWidth && ( - leftPosition > 0 || Math.abs(leftPosition) < (rect.right - window.innerWidth))) { - if (leftPosition >= 0) { - style = "left:auto;right:calc(100% + 8px);"; + if (rect.right > window.innerWidth) { + if (parentRect.left - 8 > rect.width) { + subMenuElement.style.left = (parentRect.left - 8 - rect.width) + "px"; } else { - style = `z-index:1;mix-blend-mode: normal;left:-${this.element.style.left};`; + subMenuElement.style.left = (window.innerWidth - rect.width) + "px"; } - } else if (rect.right > window.innerWidth) { - style = `z-index:1;mix-blend-mode: normal;left:${window.innerWidth - rect.width - this.element.offsetLeft}px;`; } if (rect.bottom > window.innerHeight) { - style += `top: auto;bottom:-5px;max-height:${Math.min(rect.top, window.innerHeight * 0.4)}px`; - } - if (style) { - subMenuElement.setAttribute("style", style); + subMenuElement.style.top = "auto"; + subMenuElement.style.bottom = "8px"; } } @@ -87,7 +84,7 @@ export class Menu { this.element.append(element); } - public popup(options: { x: number, y: number, h?: number , w?: number }, isLeft = false) { + public popup(options: { x: number, y: number, h?: number, w?: number }, isLeft = false) { if (this.element.innerHTML === "") { return; } @@ -183,44 +180,46 @@ export const bindMenuKeydown = (event: KeyboardEvent) => { if (window.siyuan.menus.menu.element.classList.contains("fn__none") || event.altKey || event.shiftKey || isCtrl(event)) { return false; } - if (event.code === "ArrowDown") { + if (event.code === "ArrowDown" || event.code === "ArrowUp") { const currentElement = window.siyuan.menus.menu.element.querySelector(".b3-menu__item--current"); let actionMenuElement; if (!currentElement) { - actionMenuElement = getActionMenu(window.siyuan.menus.menu.element.firstElementChild, true); + if (event.code === "ArrowUp") { + actionMenuElement = getActionMenu(window.siyuan.menus.menu.element.lastElementChild, false); + } else { + actionMenuElement = getActionMenu(window.siyuan.menus.menu.element.firstElementChild, true); + } } else { currentElement.classList.remove("b3-menu__item--current", "b3-menu__item--show"); - actionMenuElement = getActionMenu(currentElement.nextElementSibling, true); - if (!actionMenuElement) { - actionMenuElement = getActionMenu(currentElement.parentElement.firstElementChild, true); + if (event.code === "ArrowUp") { + actionMenuElement = getActionMenu(currentElement.previousElementSibling, false); + if (!actionMenuElement) { + actionMenuElement = getActionMenu(currentElement.parentElement.lastElementChild, false); + } + } else { + actionMenuElement = getActionMenu(currentElement.nextElementSibling, true); + if (!actionMenuElement) { + actionMenuElement = getActionMenu(currentElement.parentElement.firstElementChild, true); + } } } if (actionMenuElement) { actionMenuElement.classList.add("b3-menu__item--current"); actionMenuElement.classList.remove("b3-menu__item--show"); - } - } else if (event.code === "ArrowUp") { - const currentElement = window.siyuan.menus.menu.element.querySelector(".b3-menu__item--current"); - let actionMenuElement; - if (!currentElement) { - actionMenuElement = getActionMenu(window.siyuan.menus.menu.element.lastElementChild, false); - } else { - currentElement.classList.remove("b3-menu__item--current", "b3-menu__item--show"); - actionMenuElement = getActionMenu(currentElement.previousElementSibling, false); - if (!actionMenuElement) { - actionMenuElement = getActionMenu(currentElement.parentElement.lastElementChild, false); + + const parentRect = actionMenuElement.parentElement.getBoundingClientRect(); + const actionMenuRect = actionMenuElement.getBoundingClientRect(); + if (parentRect.top > actionMenuRect.top || parentRect.bottom < actionMenuRect.bottom) { + actionMenuElement.scrollIntoView(parentRect.top > actionMenuRect.top); } } - if (actionMenuElement) { - actionMenuElement.classList.add("b3-menu__item--current"); - actionMenuElement.classList.remove("b3-menu__item--show"); - } + return true; } else if (event.code === "ArrowRight") { const currentElement = window.siyuan.menus.menu.element.querySelector(".b3-menu__item--current"); if (!currentElement) { return true; } - const subMenuElement = currentElement.querySelector(".b3-menu__submenu"); + const subMenuElement = currentElement.querySelector(".b3-menu__submenu") as HTMLElement; if (!subMenuElement) { return true; } @@ -231,19 +230,7 @@ export const bindMenuKeydown = (event: KeyboardEvent) => { if (actionMenuElement) { actionMenuElement.classList.add("b3-menu__item--current"); } - - const rect = subMenuElement.getBoundingClientRect(); - let style = ""; - if (rect.right > window.innerWidth && (rect.left - subMenuElement.clientWidth - rect.width > 0 || - Math.abs(rect.left - subMenuElement.clientWidth - rect.width) < (rect.right - window.innerWidth))) { - style = "left:auto;right:calc(100% + 8px);"; - } - if (rect.bottom > window.innerHeight) { - style += `top: auto;bottom:-5px;max-height:${Math.min(rect.top, window.innerHeight * 0.4)}px`; - } - if (style) { - subMenuElement.setAttribute("style", style); - } + window.siyuan.menus.menu.showSubMenu(subMenuElement); return true; } else if (event.code === "ArrowLeft") { const currentElement = window.siyuan.menus.menu.element.querySelector(".b3-menu__submenu .b3-menu__item--current"); @@ -273,18 +260,4 @@ export const bindMenuKeydown = (event: KeyboardEvent) => { } return true; } - - // submenu scroll - if (event.code === "ArrowUp" || event.code === "ArrowDown") { - const currentMenuElement = window.siyuan.menus.menu.element.querySelector(".b3-menu__item--current") as HTMLElement; - const currentParentElement = currentMenuElement.parentElement; - if (currentParentElement.classList.contains("b3-menu__submenu")) { - if (currentMenuElement.offsetTop + currentMenuElement.clientHeight > currentParentElement.scrollTop + currentParentElement.clientHeight) { - currentParentElement.scrollTop = currentMenuElement.offsetTop + currentMenuElement.clientHeight - currentParentElement.clientHeight; - } else if (currentMenuElement.offsetTop < currentParentElement.scrollTop) { - currentParentElement.scrollTop = currentMenuElement.offsetTop; - } - } - return true; - } };