async function postJson(url, payload) {
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload || {})
});
const data = await res.json().catch(() => ({}));
if (!res.ok) {
const msg = data && data.error ? data.error : "Request failed";
throw new Error(msg);
}
return data;
}
function fmtDate(isoOrStr) {
try {
const d = new Date(isoOrStr);
return d.toLocaleString();
} catch (_) {
return "";
}
}
document.addEventListener("DOMContentLoaded", () => {
const likeBtn = document.getElementById("likeBtn");
const likeCount = document.getElementById("likeCount");
const postIdEl = document.getElementById("postId");
const commentForm = document.getElementById("commentForm");
const commentError = document.getElementById("commentError");
const postId = postIdEl ? postIdEl.value : null;
if (likeBtn && likeCount && postId) {
likeBtn.addEventListener("click", async () => {
likeBtn.disabled = true;
try {
const data = await postJson(`/api/blog/${postId}/like`, {});
likeCount.textContent = String(data.count);
likeBtn.dataset.liked = data.liked ? "1" : "0";
likeBtn.classList.toggle("is-liked", !!data.liked);
} catch (e) {
alert(e.message || "Could not update like");
} finally {
likeBtn.disabled = false;
}
});
}
const copyBtn = document.getElementById("copyLinkBtn");
if (copyBtn) {
copyBtn.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(window.location.href);
// Create floating "Copied!" notification
const toast = document.createElement("div");
toast.className = "copy-toast";
toast.textContent = "Copied!";
document.body.appendChild(toast);
// Position near the button
const rect = copyBtn.getBoundingClientRect();
toast.style.position = "fixed";
toast.style.top = `${rect.top - 40}px`;
toast.style.left = `${rect.left + rect.width / 2}px`;
toast.style.transform = "translateX(-50%)";
// Trigger animation
setTimeout(() => toast.classList.add("show"), 10);
// Remove after 1 second
setTimeout(() => {
toast.classList.remove("show");
setTimeout(() => toast.remove(), 300);
}, 1000);
} catch (err) {
console.error("Failed to copy:", err);
}
});
}
if (commentForm && postId) {
commentForm.addEventListener("submit", async (e) => {
e.preventDefault();
commentError.textContent = "";
const fd = new FormData(commentForm);
const display_name = (fd.get("display_name") || "").toString();
const content = (fd.get("content") || "").toString();
const submitBtn = commentForm.querySelector("button[type='submit']");
if (submitBtn) submitBtn.disabled = true;
try {
await postJson(`/api/blog/${postId}/comment`, { display_name, content });
window.location.reload();
} catch (err) {
commentError.textContent = err.message || "Could not post comment";
} finally {
if (submitBtn) submitBtn.disabled = false;
}
});
}
});