summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEltrac <hi@guhub.cn>2025-07-27 09:56:40 +0800
committerEltrac <hi@guhub.cn>2025-07-27 09:56:40 +0800
commit50dbd00f57e72c54ed93c54d39a3969769bd4388 (patch)
treec62378f6f4aa0a8b8ff9b71b60d62c502a337719
parent7e7d95f85995d2df66ec47144d16d663eeb3eea0 (diff)
refactor: extract tooltip feature as a global script
Former-commit-id: b64e0b67a1a425bb79055c1e42b12f5807836d66
-rw-r--r--assets/js/tooltip.js54
-rw-r--r--layouts/_partials/posts/action-menu.html23
-rw-r--r--layouts/_partials/scripts.html4
-rw-r--r--uno.config.js1
4 files changed, 72 insertions, 10 deletions
diff --git a/assets/js/tooltip.js b/assets/js/tooltip.js
new file mode 100644
index 00000000..c90658a2
--- /dev/null
+++ b/assets/js/tooltip.js
@@ -0,0 +1,54 @@
+(() => {
+ const allTooltipped = document.querySelectorAll('[data-tooltip], [title]');
+
+ const createOrUpdateTooltip = (element) => {
+ const tooltipText = element.getAttribute('data-tooltip') || element.getAttribute('title');
+
+ if (!tooltipText) return;
+
+ let tooltipElement = element.querySelector('.__generated-tooltip');
+ if (!tooltipElement) {
+ element.classList.add('group', 'relative', 'tooltipped');
+
+ tooltipElement = document.createElement('div');
+ tooltipElement.classList.add(
+ '__generated-tooltip',
+ ...'absolute bottom-full left-1/2 transform -translate-x-1/2 translate-y-1 bg-black/80 text-white px-2.5 py-1.5 rounded text-xs whitespace-nowrap opacity-0 invisible transition-all duration-300 pointer-events-none mb-2 z-1000 group-hover:opacity-100 group-hover:visible group-hover:translate-y-0 dark:bg-white/90 dark:text-black'.split(' ')
+ );
+ element.appendChild(tooltipElement);
+ }
+
+ tooltipElement.textContent = tooltipText;
+ };
+
+ const observer = new IntersectionObserver((entries, obs) => {
+ entries.forEach(entry => {
+ if (!entry.isIntersecting) return;
+
+ const element = entry.target;
+ createOrUpdateTooltip(element);
+
+ // listen to tooltip text changes
+ const mutationObserver = new MutationObserver(mutations => {
+ for (const mutation of mutations) {
+ if (mutation.type === 'attributes' &&
+ (mutation.attributeName === 'title' || mutation.attributeName === 'data-tooltip')) {
+ createOrUpdateTooltip(element);
+ }
+ }
+ });
+
+ mutationObserver.observe(element, {
+ attributes: true,
+ attributeFilter: ['title', 'data-tooltip'],
+ });
+
+ obs.unobserve(element); // 不再需要 Intersection 监听
+ });
+ }, {
+ rootMargin: '100px',
+ threshold: 0.1,
+ });
+
+ allTooltipped.forEach(el => observer.observe(el));
+})();
diff --git a/layouts/_partials/posts/action-menu.html b/layouts/_partials/posts/action-menu.html
index 9f3a88a5..dcc881d3 100644
--- a/layouts/_partials/posts/action-menu.html
+++ b/layouts/_partials/posts/action-menu.html
@@ -2,10 +2,10 @@
<!-- 操作按钮组 -->
<div class="flex justify-between items-center mb-6">
<div class="flex gap-2">
- <button class="dark:invert flex items-center justify-center gap-1.5 min-w-12 h-12 px-2 border-none bg-transparent text-gray-600 cursor-pointer relative transition-all duration-200 hover:bg-black/5 hover:rounded-lg group" id="comments-toggle" title="评论">
+ <button class="dark:invert flex items-center justify-center gap-1.5 min-w-12 h-12 px-2 border-none bg-transparent text-gray-600 cursor-pointer relative transition-all duration-200 hover:bg-black/5 hover:rounded-lg group"
+ id="comments-toggle" title="评论" data-tooltip>
<img src="/img/comments.svg" width="20" height="20" alt="评论" class="brightness-40 flex-shrink-0 dark:brightness-70 dark:contrast-120" />
<span class="text-xs font-bold text-gray-600 min-w-4 text-center bg-white/90 rounded-xl px-1.5 py-0.5 shadow-sm dark:text-gray-400 dark:bg-black/70" id="comment-count">...</span>
- <div class="absolute bottom-full left-1/2 transform -translate-x-1/2 translate-y-1 bg-black/80 text-white px-2.5 py-1.5 rounded text-xs whitespace-nowrap opacity-0 invisible transition-all duration-300 pointer-events-none mb-2 z-1000 group-hover:opacity-100 group-hover:visible group-hover:translate-y-0 dark:bg-white/90 dark:text-black">评论</div>
</button>
<!-- 点赞按钮 -->
@@ -13,23 +13,25 @@
<button class="dark:invert flex items-center justify-center gap-1.5 min-w-12 h-12 px-2
border-none bg-transparent text-gray-600 cursor-pointer relative transition-all duration-200
hover:bg-black/5 hover:rounded-lg group animate-count-infinite"
- onclick="sendLike('{{ .File.UniqueID | urlize }}')"
- id="like-btn-{{ .File.UniqueID | urlize }}"
- title="为这篇文章献上心脏"
- data-liked-title="你已经献上心脏了">
+ onclick="sendLike('{{ .File.UniqueID | urlize }}')"
+ id="like-btn-{{ .File.UniqueID | urlize }}"
+ title="为这篇文章献上心脏"
+ data-liked-title="你已经献上心脏了"
+ data-tooltip>
<img src="/img/heart-organ.svg" width="20" height="20" alt="点赞" class="brightness-40 flex-shrink-0 transition-all duration-300 dark:brightness-70 dark:contrast-120" id="like-icon-{{ .File.UniqueID | urlize }}" />
<span class="text-xs font-bold text-gray-600 min-w-4 text-center bg-white/90 rounded-xl px-1.5 py-0.5 shadow-sm dark:text-gray-400 dark:bg-black/70" id="like-count-{{ .File.UniqueID | urlize }}">...</span>
- <div class="absolute bottom-full left-1/2 transform -translate-x-1/2 translate-y-1 bg-black/80 text-white px-2.5 py-1.5 rounded text-xs whitespace-nowrap opacity-0 invisible transition-all duration-300 pointer-events-none mb-2 z-1000 group-hover:opacity-100 group-hover:visible group-hover:translate-y-0 dark:bg-white/90 dark:text-black">为这篇文章献上心脏</div>
</button>
</div>
</div>
<div class="flex gap-1">
- <a href="https://t.me/teaparty418" target="_blank" class="dark:invert flex items-center justify-center gap-1.5 min-w-8 h-8 px-1 border-none bg-transparent text-gray-600 cursor-pointer relative transition-all duration-200 hover:opacity-70 group" title="Telegram 群组" data-umami-event="✈️ Click Telegram link from post tabs">
+ <a href="https://t.me/teaparty418" target="_blank" data-tooltip
+ class="dark:invert flex items-center justify-center gap-1.5 min-w-8 h-8 px-1 border-none bg-transparent text-gray-600 cursor-pointer relative transition-all duration-200 hover:opacity-70 group" title="Telegram 群组" data-umami-event="✈️ Click Telegram link from post tabs">
<img src="/img/paper-plane.svg" width="16" height="16" alt="Telegram" class="brightness-40 flex-shrink-0 dark:brightness-70 dark:contrast-120" />
<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 translate-y-1 bg-black/80 text-white px-2.5 py-1.5 rounded text-xs whitespace-nowrap opacity-0 invisible transition-all duration-300 pointer-events-none mb-2 z-1000 group-hover:opacity-100 group-hover:visible group-hover:translate-y-0 dark:bg-white/90 dark:text-black">Telegram 群组</div>
</a>
- <a href="/sponsor" class="dark:invert flex items-center justify-center gap-1.5 min-w-8 h-8 px-1 border-none bg-transparent text-gray-600 cursor-pointer relative transition-all duration-200 hover:opacity-70 group" title="赞助作者" data-umami-event="💗 Click sponsor button from post tabs">
+ <a href="/sponsor" data-tooltip
+ class="dark:invert flex items-center justify-center gap-1.5 min-w-8 h-8 px-1 border-none bg-transparent text-gray-600 cursor-pointer relative transition-all duration-200 hover:opacity-70 group" title="赞助作者" data-umami-event="💗 Click sponsor button from post tabs">
<img src="/img/coffee.svg" width="16" height="16" alt="赞助" class="brightness-40 flex-shrink-0 dark:brightness-70 dark:contrast-120" />
<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 translate-y-1 bg-black/80 text-white px-2.5 py-1.5 rounded text-xs whitespace-nowrap opacity-0 invisible transition-all duration-300 pointer-events-none mb-2 z-1000 group-hover:opacity-100 group-hover:visible group-hover:translate-y-0 dark:bg-white/90 dark:text-black">赞助作者</div>
</a>
@@ -120,7 +122,8 @@ function initializeLikes(pageId) {
}
function setLikedState() {
- elements.icon?.classList.add('liked-heart', 'animate-heart-beat');
+ elements.icon?.classList.add('liked-heart');
+ elements.icon?.classList.add('animate-heart-beat');
elements.count?.classList.add('liked-count');
elements.btn.disabled = true;
elements.container.classList.add('liked');
diff --git a/layouts/_partials/scripts.html b/layouts/_partials/scripts.html
index ac62974b..6dc0080b 100644
--- a/layouts/_partials/scripts.html
+++ b/layouts/_partials/scripts.html
@@ -6,3 +6,7 @@
{{ partial "scripts/littlefoot-js" . }}
{{ partial "scripts/fancybox-js" . }}
{{ partial "scripts/aplayer-js" . }}
+
+{{ with resources.Get "js/tooltip.js" }}
+<script>{{ .Content | safeJS }}</script>
+{{ end }}
diff --git a/uno.config.js b/uno.config.js
index 55bc001c..959514bd 100644
--- a/uno.config.js
+++ b/uno.config.js
@@ -47,6 +47,7 @@ export default defineConfig({
'text-base!',
'animate-heart-beat', 'animate-fade-in',
+ ...'absolute bottom-full left-1/2 transform -translate-x-1/2 translate-y-1 bg-black/80 text-white px-2.5 py-1.5 rounded text-xs whitespace-nowrap opacity-0 invisible transition-all duration-300 pointer-events-none mb-2 z-1000 group-hover:opacity-100 group-hover:visible group-hover:translate-y-0 dark:bg-white/90 dark:text-black'.split(' '),
...range(10, i => `opacity-${i * 10}`),
...rangeWithPrefixes(5, 'rotate', ['', '-']),