mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-16 14:40:12 +01:00
Merge 1a0599d858 into db4fb41024
This commit is contained in:
commit
33bf2f8570
5 changed files with 83 additions and 34 deletions
|
|
@ -169,7 +169,6 @@
|
|||
}
|
||||
|
||||
&__items {
|
||||
max-height: 80vh;
|
||||
overflow: auto;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
|
@ -367,7 +366,6 @@
|
|||
&__submenu {
|
||||
overflow: auto;
|
||||
display: none;
|
||||
max-height: 80vh;
|
||||
border: 1px solid var(--b3-theme-surface-lighter);
|
||||
border-radius: var(--b3-border-radius-b);
|
||||
background-color: var(--b3-menu-background);
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ export const onGetConfig = (isStart: boolean, app: App) => {
|
|||
adjustLayout();
|
||||
resizeTabs();
|
||||
resizeTopBar();
|
||||
window.siyuan.menus.menu.resetPosition();
|
||||
firstResize = true;
|
||||
}, 200);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -60,23 +60,47 @@ export class Menu {
|
|||
});
|
||||
}
|
||||
|
||||
public showSubMenu(subMenuElement: HTMLElement) {
|
||||
public showSubMenu(subMenuElement: HTMLElement | null) {
|
||||
if (!subMenuElement) {
|
||||
return;
|
||||
}
|
||||
const itemsMenuElement = subMenuElement.lastElementChild as HTMLElement;
|
||||
if (itemsMenuElement) {
|
||||
itemsMenuElement.style.maxHeight = "";
|
||||
}
|
||||
const itemRect = subMenuElement.parentElement.getBoundingClientRect();
|
||||
subMenuElement.style.top = (itemRect.top - 8) + "px";
|
||||
subMenuElement.style.left = (itemRect.right + 8) + "px";
|
||||
subMenuElement.style.bottom = "auto";
|
||||
const rect = subMenuElement.getBoundingClientRect();
|
||||
if (rect.right > window.innerWidth) {
|
||||
if (itemRect.left - 8 > rect.width) {
|
||||
subMenuElement.style.left = (itemRect.left - 8 - rect.width) + "px";
|
||||
const subMenuRect = subMenuElement.getBoundingClientRect();
|
||||
|
||||
// 垂直方向位置调整
|
||||
// 减 9px 是为了尽量对齐菜单选项(b3-menu__submenu 的默认 padding-top 加上子菜单首个 b3-menu__item 的默认 margin-top)
|
||||
// 减 1px 是为了避免在特定情况下渲染出不应存在的滚动条而做的兼容处理
|
||||
const top = Math.min(itemRect.top - 9, window.innerHeight - subMenuRect.height - 1);
|
||||
subMenuElement.style.top = Math.max(Constants.SIZE_TOOLBAR_HEIGHT, top) + "px";
|
||||
|
||||
// 水平方向位置调整
|
||||
if (subMenuRect.right <= window.innerWidth) {
|
||||
// 8px 是 b3-menu__items 的默认 padding-right
|
||||
subMenuElement.style.left = (itemRect.right + 8) + "px";
|
||||
} else {
|
||||
if (itemRect.left - 8 > subMenuRect.width) {
|
||||
subMenuElement.style.left = (itemRect.left - 8 - subMenuRect.width) + "px";
|
||||
} else {
|
||||
subMenuElement.style.left = (window.innerWidth - rect.width) + "px";
|
||||
subMenuElement.style.left = (window.innerWidth - subMenuRect.width) + "px";
|
||||
}
|
||||
}
|
||||
if (rect.bottom > window.innerHeight) {
|
||||
subMenuElement.style.top = "auto";
|
||||
subMenuElement.style.bottom = "8px";
|
||||
|
||||
this.updateMaxHeight(subMenuElement, itemsMenuElement);
|
||||
}
|
||||
|
||||
private updateMaxHeight(menuElement: HTMLElement, itemsMenuElement: HTMLElement) {
|
||||
if (!menuElement || !itemsMenuElement) {
|
||||
return;
|
||||
}
|
||||
const menuRect = menuElement.getBoundingClientRect();
|
||||
const itemsMenuRect = itemsMenuElement.getBoundingClientRect();
|
||||
// 加 1px 是为了避免在特定情况下渲染出不应存在的滚动条而做的兼容处理
|
||||
const availableHeight = (window.innerHeight - menuRect.top) - (menuRect.height - itemsMenuRect.height) + 1;
|
||||
itemsMenuElement.style.maxHeight = Math.max(availableHeight, 0) + "px";
|
||||
}
|
||||
|
||||
private preventDefault(event: KeyboardEvent) {
|
||||
|
|
@ -149,6 +173,20 @@ export class Menu {
|
|||
this.element.style.zIndex = (++window.siyuan.zIndex).toString();
|
||||
this.element.classList.remove("fn__none");
|
||||
setPosition(this.element, options.x - (options.isLeft ? this.element.clientWidth : 0), options.y, options.h, options.w);
|
||||
this.updateMaxHeight(this.element, this.element.lastElementChild as HTMLElement);
|
||||
}
|
||||
|
||||
public resetPosition() {
|
||||
if (this.element.classList.contains("fn__none")) {
|
||||
return;
|
||||
}
|
||||
setPosition(this.element, parseFloat(this.element.style.left), parseFloat(this.element.style.top), 0, 0); // 如果不存在 left 或 top,则得到 NaN
|
||||
this.updateMaxHeight(this.element, this.element.lastElementChild as HTMLElement);
|
||||
const subMenuElements = this.element.querySelectorAll(".b3-menu__item--show .b3-menu__submenu") as NodeListOf<HTMLElement>;
|
||||
subMenuElements.forEach((subMenuElement) => {
|
||||
// 可能有多层子菜单,都要重新定位
|
||||
this.showSubMenu(subMenuElement);
|
||||
});
|
||||
}
|
||||
|
||||
public fullscreen(position: "bottom" | "all" = "all") {
|
||||
|
|
|
|||
|
|
@ -1,28 +1,39 @@
|
|||
import {Constants} from "../constants";
|
||||
|
||||
export const setPosition = (element: HTMLElement, x: number, y: number, targetHeight = 0, targetLeft = 0) => {
|
||||
element.style.top = y + "px";
|
||||
element.style.left = x + "px";
|
||||
export const setPosition = (element: HTMLElement, left: number, top: number, targetHeight = 0, targetLeft = 0) => {
|
||||
const isTopValid = !isNaN(top); // 存在 top 时调整垂直方向位置
|
||||
const isLeftValid = !isNaN(left); // 存在 left 时调整水平方向位置
|
||||
if (isTopValid) {
|
||||
element.style.top = top + "px";
|
||||
}
|
||||
if (isLeftValid) {
|
||||
element.style.left = left + "px";
|
||||
}
|
||||
const rect = element.getBoundingClientRect();
|
||||
// 上下超出屏幕
|
||||
if (rect.bottom > window.innerHeight || rect.top < Constants.SIZE_TOOLBAR_HEIGHT) {
|
||||
const top = y - rect.height - targetHeight;
|
||||
if (top > Constants.SIZE_TOOLBAR_HEIGHT && (top + rect.height) < window.innerHeight) {
|
||||
// 上部
|
||||
element.style.top = top + "px";
|
||||
} else if (top <= Constants.SIZE_TOOLBAR_HEIGHT) {
|
||||
// 位置超越到屏幕上方外时,需移动到屏幕顶部。eg:光标在第一个块,然后滚动到上方看不见的位置,按 ctrl+a
|
||||
|
||||
if (isTopValid) {
|
||||
if (rect.top < Constants.SIZE_TOOLBAR_HEIGHT) {
|
||||
// 如果元素接触顶栏,向下移
|
||||
element.style.top = Constants.SIZE_TOOLBAR_HEIGHT + "px";
|
||||
} else {
|
||||
// 依旧展现在下部,只是位置上移
|
||||
element.style.top = Math.max(Constants.SIZE_TOOLBAR_HEIGHT, window.innerHeight - rect.height) + "px";
|
||||
} else if (rect.bottom > window.innerHeight) {
|
||||
// 如果元素底部超出窗口(下方空间不够),向上移
|
||||
if (top - Constants.SIZE_TOOLBAR_HEIGHT >= rect.height) {
|
||||
// 如果上方空间足够,向上移
|
||||
element.style.top = (top - rect.height - targetHeight) + "px";
|
||||
} else {
|
||||
// 如果上下空间都不够,向上移,但尽量靠底部
|
||||
element.style.top = Math.max(Constants.SIZE_TOOLBAR_HEIGHT, window.innerHeight - rect.height) + "px";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rect.right > window.innerWidth) {
|
||||
// 展现在左侧
|
||||
element.style.left = `${window.innerWidth - rect.width - targetLeft}px`;
|
||||
} else if (rect.left < 0) {
|
||||
// 依旧展现在左侧,只是位置右移
|
||||
element.style.left = "0";
|
||||
|
||||
if (isLeftValid) {
|
||||
if (rect.right > window.innerWidth) {
|
||||
// 展现在左侧
|
||||
element.style.left = window.innerWidth - rect.width - targetLeft + "px";
|
||||
} else if (rect.left < 0) {
|
||||
// 依旧展现在左侧,只是位置右移
|
||||
element.style.left = "0";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ export const init = (app: App) => {
|
|||
resizeTimeout = window.setTimeout(() => {
|
||||
adjustLayout(window.siyuan.layout.centerLayout);
|
||||
resizeTabs();
|
||||
window.siyuan.menus.menu.resetPosition();
|
||||
}, 200);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue