diff options
| author | Eltrac <hi@guhub.cn> | 2025-10-13 09:34:25 +0800 |
|---|---|---|
| committer | Eltrac <hi@guhub.cn> | 2025-10-13 09:34:25 +0800 |
| commit | 9b33cfcc8fd8cc52d09c599efd06108b1e35d0d7 (patch) | |
| tree | 1e2153619859955608bd4d4e7441aad512d5ad02 /layouts/_partials/posts/action-menu | |
| parent | 459b3fb1230c664f3ee0e6e27a54eb4fb22e2da6 (diff) | |
refactor: move all action menu js to individual modules
Diffstat (limited to 'layouts/_partials/posts/action-menu')
| -rw-r--r-- | layouts/_partials/posts/action-menu/comment-button.html | 86 | ||||
| -rw-r--r-- | layouts/_partials/posts/action-menu/like-button.html | 122 |
2 files changed, 177 insertions, 31 deletions
diff --git a/layouts/_partials/posts/action-menu/comment-button.html b/layouts/_partials/posts/action-menu/comment-button.html index 563bf4bd..d646ca27 100644 --- a/layouts/_partials/posts/action-menu/comment-button.html +++ b/layouts/_partials/posts/action-menu/comment-button.html @@ -1,4 +1,3 @@ -{{ /* button html */}} <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="{{ T "actionMenu.comment" }}" data-tooltip> <img src="/img/comments.svg" width="20" height="20" @@ -7,32 +6,67 @@ <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> </button> -{{ /* button functionality */}} <script> +// initialize button features and comment count document.addEventListener('DOMContentLoaded', () => { - const commentsToggle = document.getElementById('comments-toggle'); - const commentsSection = document.getElementById('comments-section'); - - if (!commentsToggle || !commentsSection) return; - - // click on toggle - commentsToggle.addEventListener('click', function() { - const isHidden = commentsSection.classList.contains('hidden'); - const entranceAnimation = 'animate-slide-in-down'; - const exitAnimation = 'animate-slide-out-up'; - - if (isHidden) { - // swtich on - commentsSection.classList.remove('hidden', exitAnimation); - commentsSection.classList.add(entranceAnimation); - } else { - // switch off - commentsSection.classList.remove(entranceAnimation); - commentsSection.classList.add(exitAnimation); - setTimeout(() => { - commentsSection.classList.add('hidden'); - }, 200); - } - }); + + function initButtonFeature() { + const commentsToggle = document.getElementById('comments-toggle'); + const commentsSection = document.getElementById('comments-section'); + + if (!commentsToggle || !commentsSection) return; + + // click on toggle + commentsToggle.addEventListener('click', function() { + const isHidden = commentsSection.classList.contains('hidden'); + const entranceAnimation = 'animate-slide-in-down'; + const exitAnimation = 'animate-slide-out-up'; + + if (isHidden) { + // swtich on + commentsSection.classList.remove('hidden', exitAnimation); + commentsSection.classList.add(entranceAnimation); + } else { + // switch off + commentsSection.classList.remove(entranceAnimation); + commentsSection.classList.add(exitAnimation); + setTimeout(() => { + commentsSection.classList.add('hidden'); + }, 200); + } + }); + } + + function initCommentCount() { + const commentCountEl = document.getElementById('comment-count'); + if (!commentCountEl) return; + + const observer = new MutationObserver(() => { + // check if giscus is loaded + const giscusIframe = document.querySelector('iframe.giscus-frame'); + if (!giscusIframe) return; + + giscusIframe.addEventListener('load', () => { + // receive message from giscus iframe + window.addEventListener('message', function(event) { + if (event.origin !== 'https://giscus.app') return; + const giscusData = event.data; + if (giscusData.giscus?.discussion) { + const discussion = giscusData.giscus.discussion; + const totalComments = (discussion.totalCommentCount || 0) + (discussion.totalReplyCount || 0); + // set comment count + commentCountEl.textContent = totalComments.toString(); + // if no discussion found, set to 0 + } else commentCountEl.textContent = '0'; + }); + }); + + observer.disconnect(); + }); + observer.observe(document.body, { childList: true, subtree: true }); + } + + initButtonFeature(); + initCommentCount(); }); </script> diff --git a/layouts/_partials/posts/action-menu/like-button.html b/layouts/_partials/posts/action-menu/like-button.html index c4c50c91..c9e793b8 100644 --- a/layouts/_partials/posts/action-menu/like-button.html +++ b/layouts/_partials/posts/action-menu/like-button.html @@ -1,17 +1,18 @@ +{{ $pageID := .File.UniqueID | urlize }} <!-- 点赞按钮 --> -<div class="relative" id="like-container-{{ .File.UniqueID | urlize }}"> +<div class="relative" id="like-container-{{ $pageID }}"> <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 }}" + onclick="sendLike('{{ $pageID }}')" + id="like-btn-{{ $pageID }}" title="{{ T "actionMenu.like" }}" data-liked-title="{{ T "actionMenu.liked" }}" data-tooltip> <img src="/img/heart-organ.svg" width="20" height="20" alt="{{ T "actionMenu.like" }}" - 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> + class="brightness-40 flex-shrink-0 transition-all duration-300 dark:brightness-70 dark:contrast-120" id="like-icon-{{ $pageID }}" /> + <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-{{ $pageID }}">...</span> </button> </div> @@ -24,3 +25,114 @@ color: #8B0000 !important; } </style> + +<script> +document.addEventListener('DOMContentLoaded', () => { + // get page ID to fetch and update like data + const pageId = "{{ $pageID }}"; + + // get required elements + const elements = { + count: document.getElementById("like-count-" + pageId), + btn: document.getElementById("like-btn-" + pageId), + container: document.getElementById("like-container-" + pageId), + icon: document.getElementById("like-icon-" + pageId) + }; + + // return if no page ID found or not in production or no elements + if ( + !pageId || window.location.host !== 'www.geedea.pro' || + !elements.count || !elements.btn || !elements.container + ) return; + + function setLikedState() { + // update classes + 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'); + // update tooltip + elements.btn.setAttribute('title', + elements.container.classList.contains('liked') + ? elements.btn.getAttribute('data-liked-title') + : '为这篇文章献上心脏' + ); + } + + async function fetchLikes() { + try { + const response = await fetch("https://like.guhub.cn/like/" + pageId); + const data = await response.json(); + elements.count.innerText = data.likes ?? 0; + if (localStorage.getItem("liked_" + pageId)) { + setLikedState(); + updateOrganFarm(data.likes); + } + } catch(e) { + console.log(e); + elements.count.innerText = "❌"; + } + } + + window.sendLike = async function(pageId) { + if (localStorage.getItem("liked_" + pageId)) return; + + try { + const response = await fetch("https://like.guhub.cn/like/" + pageId, { method: "POST" }); + const data = await response.json(); + localStorage.setItem("liked_" + pageId, "1"); + elements.count.innerText = data.likes ?? 1; + updateOrganFarm(data.likes); + setLikedState(); + } catch(e) { + console.log(e); + alert("点赞失败,请稍后再试"); + } + }; + + function updateOrganFarm(count) { + const organFarm = document.getElementById("organ-farm"); + const organCount = count || parseInt(elements.count.innerText); + const organImages = [ + "https://image.guhub.cn/picgo2025/oragn-3.png", + "https://image.guhub.cn/picgo2025/organ-1.png", + "https://image.guhub.cn/picgo2025/organ-2.png" + ]; + + if (!organFarm) return; + if (organFarm.classList.contains("hidden")) { + organFarm.classList.remove("hidden"); + organFarm.classList.add("animate-slide-in-down"); + } + + organFarm.innerHTML = ""; + for (let i = 0; i < organCount; i++) { + const img = document.createElement("img"); + img.className = "transition hover:scale-150 dark:invert"; + + const sizeRange = [6, 10]; + const size = Math.floor(Math.random() * (sizeRange[1] - sizeRange[0] + 1)) + sizeRange[0]; + img.classList.add(`w-${size}`, `h-${size}`); + + img.src = organImages[Math.floor(Math.random() * organImages.length)]; + // randomly offset and rotate + img.classList.add("rotate-" + Math.floor(Math.random() * 5)); + img.classList.add("translate-x-" + Math.floor(Math.random() * 5)); + img.classList.add("translate-y-" + Math.floor(Math.random() * 5)); + img.classList.add("opacity" + (100 - Math.floor(Math.random() * 3)*10)); + + organFarm.appendChild(img); + } + } + + // fetch likes when action menu is visible + const observer = new IntersectionObserver((entries, obs) => { + if (entries[0].isIntersecting) { + fetchLikes(); + obs.disconnect(); + } + }); + observer.observe(document.getElementById("action-menu")); +}); +</script> |
