mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-02-05 15:11:48 +01:00
Improve tooltip (#13966)
* Improve tooltip * fix: https://github.com/siyuan-note/siyuan/issues/13971 * 重构逻辑,非必要不操作元素 * https://github.com/siyuan-note/siyuan/issues/13971 * fix https://ld246.com/article/1740361496784 * fix https://github.com/siyuan-note/siyuan/issues/13962
This commit is contained in:
parent
bf25fe7ea4
commit
0b4cff93ac
10 changed files with 94 additions and 58 deletions
|
|
@ -284,6 +284,11 @@
|
|||
color: var(--b3-theme-on-background);
|
||||
background-color: var(--b3-list-icon-hover);
|
||||
}
|
||||
|
||||
&--warning:hover {
|
||||
color: var(--b3-theme-error);
|
||||
background-color: var(--b3-list-icon-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.counter {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.clonedTooltip {
|
||||
animation: unset;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.b3-tooltips {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
<div class="b3-menu__items"></div>
|
||||
</div>
|
||||
<div id="message" class="b3-snackbars"></div>
|
||||
<div id="tooltip" class="tooltip fn__none"></div>
|
||||
<script>
|
||||
setTimeout(() => {
|
||||
const refreshElement = document.getElementById("loadingRefresh")
|
||||
|
|
|
|||
|
|
@ -24,10 +24,11 @@ export const initBlockPopover = (app: App) => {
|
|||
hasClosestByAttribute(event.target, "data-type", "tab-header") ||
|
||||
hasClosestByAttribute(event.target, "data-type", "inline-memo") ||
|
||||
hasClosestByClassName(event.target, "av__calc--ashow") ||
|
||||
hasClosestByClassName(event.target, "av__cell");
|
||||
hasClosestByClassName(event.target, "av__cell") ||
|
||||
hasClosestByAttribute(event.target, "data-type", "setRelationCell");
|
||||
if (aElement) {
|
||||
let tooltipClass = "";
|
||||
let tip = aElement.getAttribute("aria-label");
|
||||
let tip = aElement.getAttribute("aria-label") || "";
|
||||
if (aElement.classList.contains("av__cell")) {
|
||||
if (aElement.classList.contains("av__cell--header")) {
|
||||
const textElement = aElement.querySelector(".av__celltext");
|
||||
|
|
@ -65,10 +66,16 @@ export const initBlockPopover = (app: App) => {
|
|||
}
|
||||
}
|
||||
} else if (aElement.classList.contains("av__celltext--url")) {
|
||||
tip = tip ? `<span style="word-break: break-all">${tip.substring(0, Constants.SIZE_TITLE)}</span><div class="fn__hr"></div>${aElement.getAttribute("data-name")}` : aElement.getAttribute("data-name");
|
||||
const title = aElement.getAttribute("data-name") || "";
|
||||
tip = tip ? `<span style="word-break: break-all">${tip.substring(0, Constants.SIZE_TITLE)}</span>${title ? '<div class="fn__hr"></div><span>' + title + "</span>" : ""}` : title;
|
||||
tooltipClass = "href";
|
||||
} else if (aElement.classList.contains("av__calc--ashow") && aElement.clientWidth + 2 < aElement.scrollWidth) {
|
||||
tip = aElement.lastChild.textContent + " " + aElement.firstElementChild.textContent;
|
||||
} else if (aElement.getAttribute("data-type") === "setRelationCell") {
|
||||
const childElement = aElement.querySelector(".b3-menu__label");
|
||||
if (childElement && childElement.clientWidth < childElement.scrollWidth) {
|
||||
tip = childElement.textContent;
|
||||
}
|
||||
}
|
||||
if (!tip) {
|
||||
tip = aElement.getAttribute("data-inline-memo-content");
|
||||
|
|
@ -82,8 +89,6 @@ export const initBlockPopover = (app: App) => {
|
|||
if (href) {
|
||||
tip = `<span style="word-break: break-all">${href.substring(0, Constants.SIZE_TITLE)}</span>`;
|
||||
tooltipClass = "href"; // 为超链接添加 class https://github.com/siyuan-note/siyuan/issues/11440#issuecomment-2119080691
|
||||
} else {
|
||||
tip = "";
|
||||
}
|
||||
const title = aElement.getAttribute("data-title");
|
||||
if (tip && isLocalPath(href) && !aElement.classList.contains("b3-tooltips")) {
|
||||
|
|
@ -91,16 +96,16 @@ export const initBlockPopover = (app: App) => {
|
|||
fetchPost("/api/asset/statAsset", {path: href}, (response) => {
|
||||
if (response.code === 1) {
|
||||
if (title) {
|
||||
assetTip += '<div class="fn__hr"></div>' + title;
|
||||
assetTip += '<div class="fn__hr"></div><span>' + title + "</span>";
|
||||
}
|
||||
} else {
|
||||
assetTip += ` ${response.data.hSize}${title ? '<div class="fn__hr"></div>' + title : ""}<br>${window.siyuan.languages.modifiedAt} ${response.data.hUpdated}<br>${window.siyuan.languages.createdAt} ${response.data.hCreated}`;
|
||||
assetTip += ` ${response.data.hSize}${title ? '<div class="fn__hr"></div><span>' + title + "</span>" : ""}<br>${window.siyuan.languages.modifiedAt} ${response.data.hUpdated}<br>${window.siyuan.languages.createdAt} ${response.data.hCreated}`;
|
||||
}
|
||||
showTooltip(assetTip, aElement, tooltipClass);
|
||||
});
|
||||
tip = "";
|
||||
} else if (title) {
|
||||
tip += '<div class="fn__hr"></div>' + title;
|
||||
tip += '<div class="fn__hr"></div><span>' + title + "</span>";
|
||||
}
|
||||
}
|
||||
if (tip && !aElement.classList.contains("b3-tooltips")) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export const genCardItem = (item: ICardPackage) => {
|
|||
<span data-type="view" class="b3-list-item__action b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.cardPreview}">
|
||||
<svg><use xlink:href="#iconEye"></use></svg>
|
||||
</span>
|
||||
<span data-type="remove" class="b3-list-item__action b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.removeDeck}">
|
||||
<span data-type="remove" class="b3-list-item__action b3-list-item__action--warning b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.removeDeck}">
|
||||
<svg><use xlink:href="#iconMin"></use></svg>
|
||||
</span>
|
||||
<span data-type="add" style="display: flex" class="b3-list-item__action b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.addDeck}">
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ ${unicode2Emoji(item.ial.icon, "b3-list-item__graphic", true)}
|
|||
<span data-position="parentE" data-type="reset" data-id="${item.id}" class="b3-list-item__action ariaLabel" aria-label="${window.siyuan.languages.reset}">
|
||||
<svg><use xlink:href="#iconUndo"></use></svg>
|
||||
</span>
|
||||
<span data-position="parentE" data-type="remove" data-id="${item.id}" class="b3-list-item__action ariaLabel" aria-label="${window.siyuan.languages.removeDeck}">
|
||||
<span data-position="parentE" data-type="remove" data-id="${item.id}" class="b3-list-item__action b3-list-item__action--warning ariaLabel" aria-label="${window.siyuan.languages.removeDeck}">
|
||||
<svg><use xlink:href="#iconTrashcan"></use></svg>
|
||||
</span>
|
||||
</div>`;
|
||||
|
|
@ -273,7 +273,7 @@ ${unicode2Emoji(item.ial.icon, "b3-list-item__graphic", true)}
|
|||
// 块被删除的情况
|
||||
listHTML += `<div data-type="card-item" class="b3-list-item${isMobile() ? "" : " b3-list-item--hide-action"}">
|
||||
<span class="b3-list-item__text">${item.content}</span>
|
||||
<span data-position="parentE" data-type="remove" data-id="${item.id}" class="b3-list-item__action ariaLabel" aria-label="${window.siyuan.languages.removeDeck}">
|
||||
<span data-position="parentE" data-type="remove" data-id="${item.id}" class="b3-list-item__action b3-list-item__action--warning ariaLabel" aria-label="${window.siyuan.languages.removeDeck}">
|
||||
<svg><use xlink:href="#iconTrashcan"></use></svg>
|
||||
</span>
|
||||
</div>`;
|
||||
|
|
|
|||
|
|
@ -10,33 +10,24 @@ export const showTooltip = (message: string, target: Element, tooltipClass?: str
|
|||
return;
|
||||
}
|
||||
|
||||
const className = tooltipClass ? `tooltip tooltip--${tooltipClass}` : "tooltip";
|
||||
let messageElement = document.getElementById("tooltip");
|
||||
if (!messageElement) {
|
||||
document.body.insertAdjacentHTML("beforeend", `<div class="${className}" id="tooltip">${message}</div>`);
|
||||
messageElement = document.getElementById("tooltip");
|
||||
} else {
|
||||
if (messageElement.className !== className) {
|
||||
messageElement.className = className;
|
||||
}
|
||||
if (messageElement.innerHTML !== message) {
|
||||
messageElement.innerHTML = message;
|
||||
}
|
||||
// 避免原本的 top 和 left 影响计算
|
||||
messageElement.removeAttribute("style");
|
||||
}
|
||||
|
||||
let left = targetRect.left;
|
||||
let top = targetRect.bottom;
|
||||
const tooltipElement = document.getElementById("tooltip");
|
||||
const clonedTooltip = tooltipElement.cloneNode(true) as HTMLElement;
|
||||
clonedTooltip.id = "clonedTooltip";
|
||||
clonedTooltip.removeAttribute("style");
|
||||
clonedTooltip.className = "tooltip";
|
||||
clonedTooltip.innerHTML = message;
|
||||
document.body.append(clonedTooltip);
|
||||
|
||||
// position: parentE; parentW; ${number}parentW; ${number}bottom;
|
||||
// right; right${number}bottom; right${number}top; top;
|
||||
const position = target.getAttribute("data-position");
|
||||
const parentRect = target.parentElement.getBoundingClientRect();
|
||||
|
||||
let top, left;
|
||||
|
||||
if (position?.startsWith("right")) {
|
||||
// block icon and background icon
|
||||
left = targetRect.right - messageElement.clientWidth;
|
||||
left = targetRect.right - clonedTooltip.clientWidth + 1;
|
||||
}
|
||||
|
||||
if (position === "parentE") {
|
||||
|
|
@ -46,43 +37,66 @@ export const showTooltip = (message: string, target: Element, tooltipClass?: str
|
|||
} else if (position?.endsWith("parentW")) {
|
||||
// 数据库属性视图
|
||||
top = parentRect.top + (parseInt(position) || 8);
|
||||
left = parentRect.left - messageElement.clientWidth;
|
||||
left = parentRect.left - clonedTooltip.clientWidth;
|
||||
} else if (position?.endsWith("bottom")) {
|
||||
top += parseInt(position.replace("right", "").replace("left", ""));
|
||||
top = targetRect.bottom + parseInt(position.replace("right", "")) + 1;
|
||||
} else if (position?.endsWith("top")) {
|
||||
// 编辑器动态滚动条
|
||||
top = targetRect.top - messageElement.clientHeight;
|
||||
// 数据库视图、编辑器动态滚动条
|
||||
top = targetRect.top - clonedTooltip.clientHeight - 1;
|
||||
} else if (position === "directLeft") {
|
||||
// 关联字段选项
|
||||
top = targetRect.top + (parseInt(position) || 0);
|
||||
left = targetRect.left - clonedTooltip.clientWidth - 8 - 1;
|
||||
}
|
||||
|
||||
top = top >= 0 ? top : targetRect.bottom + 1;
|
||||
left = left >= 0 ? left : targetRect.left;
|
||||
|
||||
const topHeight = position === "parentE" ? top : targetRect.top;
|
||||
const bottomHeight = window.innerHeight - top;
|
||||
|
||||
messageElement.style.maxHeight = Math.max(topHeight, bottomHeight) + "px";
|
||||
clonedTooltip.style.maxHeight = Math.max(topHeight, bottomHeight) + "px";
|
||||
|
||||
// 避免原本的 top 和 left 影响计算
|
||||
messageElement.style.top = "0px";
|
||||
messageElement.style.left = "0px";
|
||||
|
||||
if (top + messageElement.clientHeight > window.innerHeight && topHeight > bottomHeight) {
|
||||
messageElement.style.top = ((position === "parentE" ? parentRect.bottom : targetRect.top) - messageElement.clientHeight) + "px";
|
||||
} else {
|
||||
messageElement.style.top = top + "px";
|
||||
if (top + clonedTooltip.clientHeight > window.innerHeight && topHeight > bottomHeight) {
|
||||
top = (position === "parentE" || position === "directLeft" ? parentRect.bottom : targetRect.top) - clonedTooltip.clientHeight - 1;
|
||||
}
|
||||
|
||||
if (left + messageElement.clientWidth > window.innerWidth) {
|
||||
if (left + clonedTooltip.clientWidth > window.innerWidth) {
|
||||
if (position === "parentE") {
|
||||
messageElement.style.left = (parentRect.left - 8 - messageElement.clientWidth) + "px";
|
||||
left = parentRect.left - 8 - clonedTooltip.clientWidth - 1;
|
||||
} else {
|
||||
messageElement.style.left = (window.innerWidth - 1 - messageElement.clientWidth) + "px";
|
||||
left = window.innerWidth - 1 - clonedTooltip.clientWidth;
|
||||
}
|
||||
} else {
|
||||
messageElement.style.left = Math.max(0, left) + "px";
|
||||
}
|
||||
|
||||
// 确保不会超出屏幕
|
||||
if (top < 0 || left < 0) {
|
||||
top = targetRect.bottom + 1;
|
||||
left = targetRect.left;
|
||||
}
|
||||
|
||||
clonedTooltip.style.top = top + "px";
|
||||
clonedTooltip.style.left = left + "px";
|
||||
|
||||
const cloneStyle = clonedTooltip.getAttribute("style");
|
||||
const className = tooltipClass ? `tooltip tooltip--${tooltipClass}` : "tooltip";
|
||||
|
||||
if (tooltipElement.getAttribute("style") !== cloneStyle) {
|
||||
tooltipElement.setAttribute("style", cloneStyle);
|
||||
}
|
||||
if (tooltipElement.className !== className) {
|
||||
tooltipElement.className = className;
|
||||
}
|
||||
if (tooltipElement.innerHTML !== clonedTooltip.innerHTML) {
|
||||
tooltipElement.innerHTML = clonedTooltip.innerHTML;
|
||||
}
|
||||
|
||||
clonedTooltip.remove();
|
||||
};
|
||||
|
||||
export const hideTooltip = () => {
|
||||
const messageElement = document.getElementById("tooltip");
|
||||
if (messageElement) {
|
||||
messageElement.remove();
|
||||
const tooltipElement = document.getElementById("tooltip");
|
||||
if (tooltipElement && !tooltipElement.classList.contains("fn__none")) {
|
||||
tooltipElement.classList.add("fn__none");
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ export class Files extends Model {
|
|||
item.style.opacity = "";
|
||||
// https://github.com/siyuan-note/siyuan/issues/11587
|
||||
if (index === 0) {
|
||||
const airaLabelElement = item.querySelector(".ariaLabel");
|
||||
const airaLabelElement = item.querySelector(".ariaLabel") || item.querySelector(".b3-list-item__text");
|
||||
if (airaLabelElement) {
|
||||
showTooltip(airaLabelElement.getAttribute("aria-label"), airaLabelElement);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ const genSelectItemHTML = (type: "selected" | "empty" | "unselect", id?: string,
|
|||
</button>`;
|
||||
}
|
||||
if (type == "unselect") {
|
||||
return `<button data-id="${id}" class="b3-menu__item" data-type="setRelationCell">
|
||||
return `<button data-id="${id}" class="b3-menu__item" data-position="directLeft" data-type="setRelationCell">
|
||||
<span class="b3-menu__label fn__ellipsis${isDetached ? "" : " popover__block"}" ${isDetached ? "" : 'style="color:var(--b3-protyle-inline-blockref-color)"'} data-id="${id}">${text}</span>
|
||||
<svg class="b3-menu__action"><use xlink:href="#iconAdd"></use></svg>
|
||||
</button>`;
|
||||
|
|
@ -243,7 +243,9 @@ const filterItem = (menuElement: Element, cellElement: HTMLElement, keyword: str
|
|||
cellElement.querySelectorAll(".av__cell--relation").forEach((relationItem: HTMLElement) => {
|
||||
const item = relationItem.querySelector(".av__celltext") as HTMLElement;
|
||||
hasIds.push(item.dataset.id);
|
||||
selectHTML += `<button data-id="${item.dataset.id}" data-type="setRelationCell" class="b3-menu__item${item.textContent.indexOf(keyword) > -1 ? "" : " fn__none"}" draggable="true">${genSelectItemHTML("selected", item.dataset.id, !item.classList.contains("av__celltext--ref"), Lute.EscapeHTMLStr(item.textContent || window.siyuan.languages.untitled))}</button>`;
|
||||
selectHTML += `<button data-id="${item.dataset.id}" data-position="directLeft" data-type="setRelationCell"
|
||||
class="b3-menu__item${item.textContent.indexOf(keyword) > -1 ? "" : " fn__none"}"
|
||||
draggable="true">${genSelectItemHTML("selected", item.dataset.id, !item.classList.contains("av__celltext--ref"), Lute.EscapeHTMLStr(item.textContent || window.siyuan.languages.untitled))}</button>`;
|
||||
});
|
||||
cells.forEach((item) => {
|
||||
if (!hasIds.includes(item.block.id)) {
|
||||
|
|
@ -275,7 +277,8 @@ export const bindRelationEvent = (options: {
|
|||
options.cellElements[0].querySelectorAll(".av__cell--relation").forEach((relationItem: HTMLElement) => {
|
||||
const item = relationItem.querySelector(".av__celltext") as HTMLElement;
|
||||
hasIds.push(item.dataset.id);
|
||||
selectHTML += `<button data-id="${item.dataset.id}" data-type="setRelationCell" class="b3-menu__item" draggable="true">${genSelectItemHTML("selected", item.dataset.id, !item.classList.contains("av__celltext--ref"), Lute.EscapeHTMLStr(item.textContent || window.siyuan.languages.untitled))}</button>`;
|
||||
selectHTML += `<button data-id="${item.dataset.id}" data-position="directLeft" data-type="setRelationCell" class="b3-menu__item"
|
||||
draggable="true">${genSelectItemHTML("selected", item.dataset.id, !item.classList.contains("av__celltext--ref"), Lute.EscapeHTMLStr(item.textContent || window.siyuan.languages.untitled))}</button>`;
|
||||
});
|
||||
cells.forEach((item) => {
|
||||
if (!hasIds.includes(item.block.id)) {
|
||||
|
|
@ -401,7 +404,8 @@ export const setRelationCell = (protyle: IProtyle, nodeElement: HTMLElement, tar
|
|||
isDetached: !target.firstElementChild.getAttribute("style")
|
||||
});
|
||||
separatorElement.before(target);
|
||||
target.outerHTML = `<button data-id="${targetId}" data-type="setRelationCell" class="b3-menu__item" draggable="true">${genSelectItemHTML("selected", targetId, !target.querySelector(".popover__block"), Lute.EscapeHTMLStr(target.querySelector(".b3-menu__label").textContent))}</button>`;
|
||||
target.outerHTML = `<button data-id="${targetId}" data-type="setRelationCell" class="b3-menu__item"
|
||||
draggable="true">${genSelectItemHTML("selected", targetId, !target.querySelector(".popover__block"), Lute.EscapeHTMLStr(target.querySelector(".b3-menu__label").textContent))}</button>`;
|
||||
if (!separatorElement.nextElementSibling) {
|
||||
separatorElement.insertAdjacentHTML("afterend", genSelectItemHTML("empty"));
|
||||
}
|
||||
|
|
@ -433,7 +437,8 @@ export const setRelationCell = (protyle: IProtyle, nodeElement: HTMLElement, tar
|
|||
},
|
||||
isDetached: true
|
||||
});
|
||||
separatorElement.insertAdjacentHTML("beforebegin", `<button data-id="${rowId}" data-type="setRelationCell" class="b3-menu__item" draggable="true">${genSelectItemHTML("selected", rowId, true, Lute.EscapeHTMLStr(content))}</button>`);
|
||||
separatorElement.insertAdjacentHTML("beforebegin", `<button data-id="${rowId}" data-position="directLeft" data-type="setRelationCell"
|
||||
class="b3-menu__item" draggable="true">${genSelectItemHTML("selected", rowId, true, Lute.EscapeHTMLStr(content))}</button>`);
|
||||
}
|
||||
menuElement.querySelector(".b3-menu__item--current")?.classList.remove("b3-menu__item--current");
|
||||
menuElement.querySelector(".b3-menu__items .b3-menu__item:not(.fn__none)").classList.add("b3-menu__item--current");
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ export const avRender = (element: Element, protyle: IProtyle, cb?: () => void, v
|
|||
}
|
||||
tableHTML += `<div class="av__cell av__cell--header" data-col-id="${column.id}" draggable="true"
|
||||
data-icon="${column.icon}" data-dtype="${column.type}" data-wrap="${column.wrap}" data-pin="${column.pin}"
|
||||
data-desc="${escapeAttr(column.desc)}"
|
||||
data-desc="${escapeAttr(column.desc)}" data-position="top"
|
||||
style="width: ${column.width || "200px"};">
|
||||
${column.icon ? unicode2Emoji(column.icon, "av__cellheadericon", true) : `<svg class="av__cellheadericon"><use xlink:href="#${getColIconByType(column.type)}"></use></svg>`}
|
||||
<span class="av__celltext fn__flex-1">${escapeHtml(column.name)}</span>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue