summaryrefslogtreecommitdiff
path: root/layouts/_partials/posts/action-menu
diff options
context:
space:
mode:
authorEltrac <hi@guhub.cn>2025-10-13 09:34:25 +0800
committerEltrac <hi@guhub.cn>2025-10-13 09:34:25 +0800
commit9b33cfcc8fd8cc52d09c599efd06108b1e35d0d7 (patch)
tree1e2153619859955608bd4d4e7441aad512d5ad02 /layouts/_partials/posts/action-menu
parent459b3fb1230c664f3ee0e6e27a54eb4fb22e2da6 (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.html86
-rw-r--r--layouts/_partials/posts/action-menu/like-button.html122
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>