Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎨 Improve tooltip #13476

Open
wants to merge 24 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d036d82
:art: Improve tooltip
TCOTC Dec 15, 2024
c55e39a
Merge branch 'dev' into dev-tooltip
TCOTC Dec 18, 2024
87469e6
:art: Improve tooltip
TCOTC Dec 18, 2024
0c2280e
:art: Improve tooltip
TCOTC Dec 18, 2024
5a64707
:art: Improve tooltip
TCOTC Dec 18, 2024
6c859f2
Merge branch 'dev' into dev-tooltip
TCOTC Dec 19, 2024
d9cd42a
警告提示 https://github.com/siyuan-note/siyuan/issues/13536
TCOTC Dec 19, 2024
cd63a04
tooltip 支持多个类名、添加警告提示 https://github.com/siyuan-note/siyuan/issues/13536
TCOTC Dec 19, 2024
1d5f2f8
:art: Improve tooltip
TCOTC Dec 19, 2024
821cc2b
:art: Improve tooltip
TCOTC Dec 19, 2024
f4f2918
Merge branch 'dev' into dev-tooltip
TCOTC Dec 20, 2024
161e87e
:art: Improve tooltip
TCOTC Dec 20, 2024
75af479
:art: Improve tooltip
TCOTC Dec 20, 2024
2ff40bd
:art: Improve tooltip
TCOTC Dec 20, 2024
337a5bf
:art: 新增 data-tooltipclass 属性用于自定义 tooltip 的额外类名
TCOTC Dec 21, 2024
4bba65f
:art: 新增 .tooltip--emoji
TCOTC Dec 21, 2024
0949efb
:art: 笔记本拖回原处时重新显示悬浮提示
TCOTC Dec 22, 2024
88a3ffc
:art: 关联字段选项文本过长的条目加上悬浮提示
TCOTC Dec 25, 2024
7ad134a
:art: Improve tooltip
TCOTC Dec 25, 2024
4b1b505
Merge branch 'dev' into dev-tooltip
TCOTC Dec 30, 2024
0bbea4a
Merge branch 'dev' into dev-tooltip
TCOTC Jan 6, 2025
0733806
Merge branch 'dev' into dev-tooltip
TCOTC Jan 6, 2025
e75010b
Merge branch 'dev' into dev-tooltip
TCOTC Jan 6, 2025
ba1316d
:art: Improve tooltip
TCOTC Jan 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/src/assets/scss/component/_list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,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 {
Expand Down
41 changes: 24 additions & 17 deletions app/src/block/popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ export const initBlockPopover = (app: App) => {
}
const aElement = hasClosestByAttribute(event.target, "data-type", "a", true) ||
hasClosestByClassName(event.target, "ariaLabel") ||
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");
const tooltipClasses: string[] = [];
let tip = aElement.getAttribute("aria-label") || "";
TCOTC marked this conversation as resolved.
Show resolved Hide resolved
if (aElement.hasAttribute("data-tooltipclass")) {
tooltipClasses.push(...aElement.getAttribute("data-tooltipclass").split(" "));
}
if (aElement.classList.contains("av__cell")) {
if (aElement.classList.contains("av__cell--header")) {
const textElement = aElement.querySelector(".av__celltext");
Expand All @@ -43,7 +46,7 @@ export const initBlockPopover = (app: App) => {
if (aElement.firstElementChild?.getAttribute("data-type") === "url") {
if (aElement.firstElementChild.textContent.indexOf("...") > -1) {
tip = Lute.EscapeHTMLStr(aElement.firstElementChild.getAttribute("data-href"));
tooltipClass = "href";
tooltipClasses.push("href");
}
}
if (!tip && aElement.dataset.wrap !== "true" && event.target.dataset.type !== "block-more" && !hasClosestByClassName(event.target, "block__icon")) {
Expand All @@ -65,51 +68,55 @@ 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");
tooltipClass = "href";
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;
tooltipClasses.push("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");
if (tip) {
tooltipClass = "memo"; // 为行级备注添加 class https://github.com/siyuan-note/siyuan/issues/6161
tooltipClasses.push("memo"); // 为行级备注添加 class https://github.com/siyuan-note/siyuan/issues/6161
}
}
if (!tip) {
const href = aElement.getAttribute("data-href") || "";
// 链接地址强制换行 https://github.com/siyuan-note/siyuan/issues/11539
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 = "";
tooltipClasses.push("href"); // 为超链接添加 class https://github.com/siyuan-note/siyuan/issues/11440#issuecomment-2119080691
}
const title = aElement.getAttribute("data-title");
if (tip && isLocalPath(href) && !aElement.classList.contains("b3-tooltips")) {
let assetTip = tip;
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);
showTooltip(assetTip, aElement, tooltipClasses);
});
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")) {
// https://github.com/siyuan-note/siyuan/issues/11294
try {
showTooltip(decodeURIComponent(tip), aElement, tooltipClass);
showTooltip(decodeURIComponent(tip), aElement, tooltipClasses);
} catch (e) {
// https://ld246.com/article/1718235737991
showTooltip(tip, aElement, tooltipClass);
showTooltip(tip, aElement, tooltipClasses);
}
event.stopPropagation();
} else {
Expand Down
2 changes: 1 addition & 1 deletion app/src/card/makeCard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}">
Expand Down
4 changes: 2 additions & 2 deletions app/src/card/viewCards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>`;
Expand All @@ -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>`;
Expand Down
24 changes: 13 additions & 11 deletions app/src/dialog/tooltip.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {isMobile} from "../util/functions";
import {Constants} from "../constants";

export const showTooltip = (message: string, target: Element, tooltipClass?: string) => {
export const showTooltip = (message: string, target: Element, tooltipClasses?: string[]) => {
if (isMobile()) {
return;
}
Expand All @@ -11,7 +10,10 @@ export const showTooltip = (message: string, target: Element, tooltipClass?: str
return;
}

const className = tooltipClass ? `tooltip tooltip--${tooltipClass}` : "tooltip";
// 合并默认类名和额外类名
const additionalClasses = tooltipClasses ? tooltipClasses.map(cls => `tooltip--${cls}`).join(" ") : "";
const className = ["tooltip", additionalClasses].filter(Boolean).join(" ");

let messageElement = document.getElementById("tooltip");
if (!messageElement) {
document.body.insertAdjacentHTML("beforeend", `<div class="${className}" id="tooltip">${message}</div>`);
Expand All @@ -22,9 +24,9 @@ export const showTooltip = (message: string, target: Element, tooltipClass?: str
}
if (messageElement.innerHTML !== message) {
messageElement.innerHTML = message;
// 避免原本的 top 和 left 影响计算
messageElement.removeAttribute("style");
}
// 避免原本的 top 和 left 影响计算
messageElement.removeAttribute("style");
}

let left = targetRect.left;
Expand Down Expand Up @@ -53,19 +55,19 @@ export const showTooltip = (message: string, target: Element, tooltipClass?: str
} else if (position?.endsWith("top")) {
// 编辑器动态滚动条
top = targetRect.top - messageElement.clientHeight;
} else if (position === "west") {
// 数据库属性视图 移除条目按钮
top = targetRect.top + (parseInt(position) || 0);
left = targetRect.left - messageElement.clientWidth - 8;
}

const topHeight = position === "parentE" ? top : targetRect.top;
const bottomHeight = window.innerHeight - top;

messageElement.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";
messageElement.style.top = ((position === "parentE" || position === "west" ? parentRect.bottom : targetRect.top) - messageElement.clientHeight) + "px";
} else {
messageElement.style.top = top + "px";
}
Expand All @@ -84,6 +86,6 @@ export const showTooltip = (message: string, target: Element, tooltipClass?: str
export const hideTooltip = () => {
const messageElement = document.getElementById("tooltip");
if (messageElement) {
messageElement.remove();
messageElement.classList.add("fn__none");
}
};
4 changes: 2 additions & 2 deletions app/src/editor/rename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ import {getAllEditor} from "../layout/getAll";
export const validateName = (name: string, targetElement?: HTMLElement) => {
if (/\r\n|\r|\n|\u2028|\u2029|\t|\//.test(name)) {
if (targetElement) {
showTooltip(window.siyuan.languages.fileNameRule, targetElement, "error");
showTooltip(window.siyuan.languages.fileNameRule, targetElement, ["error"]);
} else {
showMessage(window.siyuan.languages.fileNameRule);
}
return false;
}
if (name.length > Constants.SIZE_TITLE) {
if (targetElement) {
showTooltip(window.siyuan.languages["_kernel"]["106"], targetElement, "error");
showTooltip(window.siyuan.languages["_kernel"]["106"], targetElement, ["error"]);
} else {
showMessage(window.siyuan.languages["_kernel"]["106"]);
}
Expand Down
14 changes: 7 additions & 7 deletions app/src/emoji/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const lazyLoadEmoji = (element: HTMLElement) => {
if ((typeof entrie.isIntersecting === "undefined" ? entrie.intersectionRatio !== 0 : entrie.isIntersecting) && index) {
let html = "";
window.siyuan.emojis[parseInt(index)].items.forEach(emoji => {
html += `<button data-unicode="${emoji.unicode}" class="emojis__item ariaLabel" aria-label="${getEmojiDesc(emoji)}">
html += `<button data-unicode="${emoji.unicode}" class="emojis__item ariaLabel" data-tooltipclass="emoji" aria-label="${getEmojiDesc(emoji)}">
${unicode2Emoji(emoji.unicode)}</button>`;
});
entrie.target.innerHTML = html;
Expand Down Expand Up @@ -124,7 +124,7 @@ export const filterEmoji = (key = "", max?: number) => {
if (category.id === "custom") {
customStore.push(emoji);
} else {
keyHTML += `<button data-unicode="${emoji.unicode}" class="emojis__item ariaLabel" aria-label="${getEmojiDesc(emoji)}">
keyHTML += `<button data-unicode="${emoji.unicode}" class="emojis__item ariaLabel" data-tooltipclass="emoji" aria-label="${getEmojiDesc(emoji)}">
${unicode2Emoji(emoji.unicode, undefined, false, true)}</button>`;
}
maxCount++;
Expand All @@ -134,7 +134,7 @@ ${unicode2Emoji(emoji.unicode, undefined, false, true)}</button>`;
recentEmojis.push(emoji);
}
if (index < 2) {
html += `<button data-unicode="${emoji.unicode}" class="emojis__item ariaLabel" aria-label="${getEmojiDesc(emoji)}">
html += `<button data-unicode="${emoji.unicode}" class="emojis__item ariaLabel" data-tooltipclass="emoji" aria-label="${getEmojiDesc(emoji)}">
${unicode2Emoji(emoji.unicode, undefined, false, true)}</button>`;
}
}
Expand All @@ -159,7 +159,7 @@ ${unicode2Emoji(emoji.unicode, undefined, false, true)}</button>`;
}
return 0;
}).forEach(item => {
html += `<button data-unicode="${item.unicode}" class="emojis__item ariaLabel" aria-label="${getEmojiDesc(item)}">
html += `<button data-unicode="${item.unicode}" class="emojis__item ariaLabel" data-tooltipclass="emoji" aria-label="${getEmojiDesc(item)}">
${unicode2Emoji(item.unicode, undefined, false, true)}</button>`;
});
html = html + keyHTML + "</div>";
Expand All @@ -170,7 +170,7 @@ ${unicode2Emoji(item.unicode, undefined, false, true)}</button>`;
window.siyuan.config.editor.emoji.forEach(emojiUnicode => {
const emoji = recentEmojis.filter((item) => item.unicode === emojiUnicode);
if (emoji[0]) {
recentHTML += `<button data-unicode="${emoji[0].unicode}" class="emojis__item ariaLabel" aria-label="${getEmojiDesc(emoji[0])}">
recentHTML += `<button data-unicode="${emoji[0].unicode}" class="emojis__item ariaLabel" data-tooltipclass="emoji" aria-label="${getEmojiDesc(emoji[0])}">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个 emoji 样式添加的作用是使用这个 css ?

image

Copy link
Contributor Author

@TCOTC TCOTC Jan 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data-tooltipclass="emoji" 的作用是给 tooltip 元素添加一个 .tooltip--emoji 的类名,思源没有对应的样式,因为这个是我做主题需要用的。

冲突我解决了。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这样侵入性太强了,而且不是通用的。能否使用其他方式?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

主要是想复用这段逻辑:

image

否则每次需要加类名都只能多加一个 else if:

image

${unicode2Emoji(emoji[0].unicode, undefined, false, true)}
</button>`;
}
Expand Down Expand Up @@ -222,7 +222,7 @@ const renderEmojiContent = (previousIndex: string, previousContentElement: Eleme
}
let html = "";
window.siyuan.emojis[parseInt(previousIndex)].items.forEach(emoji => {
html += `<button data-unicode="${emoji.unicode}" class="emojis__item ariaLabel" aria-label="${getEmojiDesc(emoji)}">${unicode2Emoji(emoji.unicode)}</button>`;
html += `<button data-unicode="${emoji.unicode}" class="emojis__item ariaLabel" data-tooltipclass="emoji" aria-label="${getEmojiDesc(emoji)}">${unicode2Emoji(emoji.unicode)}</button>`;
});
previousContentElement.innerHTML = html;
previousContentElement.removeAttribute("data-index");
Expand Down Expand Up @@ -299,7 +299,7 @@ export const openEmojiPanel = (id: string, type: "doc" | "notebook" | "av", posi
["267e-fe0f", getEmojiTitle(7)],
["1f6a9", getEmojiTitle(8)],
].map(([unicode, title], index) =>
`<div data-type="${index}" class="emojis__type ariaLabel" aria-label="${title}">${unicode2Emoji(unicode)}</div>`
`<div data-type="${index}" class="emojis__type ariaLabel" data-tooltipclass="emoji" aria-label="${title}">${unicode2Emoji(unicode)}</div>`
).join("")}
</div>
</div>
Expand Down
5 changes: 3 additions & 2 deletions app/src/layout/Tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export class Tab {
this.headElement.setAttribute("data-type", "tab-header");
this.headElement.setAttribute("draggable", "true");
this.headElement.setAttribute("data-id", this.id);
this.headElement.classList.add("item", "item--focus");
this.headElement.setAttribute("data-tooltipclass", "tab_header");
this.headElement.classList.add("item", "item--focus", "ariaLabel");
let iconHTML = "";
if (options.icon) {
iconHTML = `<svg class="item__graphic"><use xlink:href="#${options.icon}"></use></svg>`;
Expand Down Expand Up @@ -72,7 +73,7 @@ export class Tab {
id
}, (response) => {
if (!this.headElement.getAttribute("aria-label")) {
showTooltip(escapeGreat(response.data), this.headElement);
showTooltip(escapeGreat(response.data), this.headElement, ["tab_header"]);
}
this.headElement.setAttribute("aria-label", escapeGreat(response.data));
});
Expand Down
2 changes: 1 addition & 1 deletion app/src/layout/dock/Files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,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);
}
Expand Down
Loading