diff options
| -rw-r--r-- | assets/js/tooltip.js | 54 | ||||
| -rw-r--r-- | layouts/_partials/posts/action-menu.html | 23 | ||||
| -rw-r--r-- | layouts/_partials/scripts.html | 4 | ||||
| -rw-r--r-- | uno.config.js | 1 |
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', ['', '-']), |
