${
@@ -1345,12 +1346,12 @@ export function openCenteredOverlay({ map, post, theme, fullScreen = false }) {
${!isCamera ? `
-
+
${truth}
-
+
` : ''}
@@ -1944,32 +1945,71 @@ export function openCenteredOverlay({ map, post, theme, fullScreen = false }) {
const rail = modalWrap.querySelector(".sw-truth-rail");
if (rail && postID > 0 && !rail.hasAttribute("data-vote-bound")) {
rail.setAttribute("data-vote-bound", "1");
+ // Track current user vote to prevent duplicate API calls
+ let currentVote = null; // "true", "false", or null
+ let isVoting = false;
+
const doVote = async (vote) => {
if (!isAuthed()) {
requestAuth("Please sign in or create a free account to vote on truth.");
return;
}
- if (rail.classList.contains("sw-truth-vote-disabled")) {
- return; // Already voting
+ // Skip if already voted same way
+ if (currentVote === vote) {
+ return;
}
+ if (isVoting) {
+ return;
+ }
+ isVoting = true;
+ rail.style.opacity = "0.5";
+ rail.style.pointerEvents = "none";
try {
- rail.classList.add("sw-truth-vote-disabled");
const stats = await votePostTruth(postID, vote);
if (stats) {
+ currentVote = vote;
updateTruthVoteUI(modalWrap, stats, true);
- } else {
- console.warn("votePostTruth returned no stats for post", postID);
}
} catch (err) {
- console.error("Truth vote error:", err);
+ // Silently fail - don't update UI
} finally {
- rail.classList.remove("sw-truth-vote-disabled");
+ isVoting = false;
+ rail.style.opacity = "1";
+ rail.style.pointerEvents = "auto";
}
};
const voteUp = rail.querySelector(".sw-truth-rail-btn-up");
const voteDown = rail.querySelector(".sw-truth-rail-btn-down");
- if (voteUp) voteUp.addEventListener("click", (e) => { e.stopPropagation(); doVote("true"); });
- if (voteDown) voteDown.addEventListener("click", (e) => { e.stopPropagation(); doVote("false"); });
+ let touchFired = false;
+ const handleVote = (vote) => (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ // Prevent touch+click double fire
+ if (e.type === "touchend") {
+ touchFired = true;
+ setTimeout(() => { touchFired = false; }, 400);
+ } else if (e.type === "click" && touchFired) {
+ return;
+ }
+ if (isVoting || currentVote === vote) return;
+ doVote(vote);
+ };
+ if (voteUp) {
+ voteUp.addEventListener("click", handleVote("true"), { passive: false });
+ voteUp.addEventListener("touchend", handleVote("true"), { passive: false });
+ }
+ if (voteDown) {
+ voteDown.addEventListener("click", handleVote("false"), { passive: false });
+ voteDown.addEventListener("touchend", handleVote("false"), { passive: false });
+ }
+ // Fetch initial vote state
+ if (isAuthed()) {
+ fetchPostTruth(postID).then((stats) => {
+ if (stats?.user_vote || stats?.UserVote) {
+ currentVote = (stats.user_vote || stats.UserVote).toString();
+ }
+ }).catch(() => {});
+ }
}
applyAuthUI();
@@ -2145,6 +2185,14 @@ export function createMarkerForPost(post, mapRef, markersRef, expandedElRef, the
renderCompact();
root.__renderCompact = renderCompact;
+ // Bring marker to front on hover so card is above other markers (compact cards = 200)
+ root.addEventListener("mouseenter", () => {
+ root.style.zIndex = "200";
+ });
+ root.addEventListener("mouseleave", () => {
+ root.style.zIndex = "1";
+ });
+
if (HEATMAP_ENABLED && isClusterMainPost(post)) {
const handleEnter = () => {
dispatchClusterHeatmap(root.__post || post, { mode: "hover", skipPan: true });
@@ -2499,8 +2547,9 @@ export function createSimpleMarkerForPost(post, mapRef, markersRef, expandedElRe
const markerEl = root.querySelector(".sw-simple-marker");
const hoverCard = root.querySelector(".sw-simple-hover-card");
- // Hover effects
+ // Hover effects - bring marker to front so hover card is above other markers (simple pins = 150)
root.addEventListener("mouseenter", () => {
+ root.style.zIndex = "150";
if (isCluster) {
dispatchClusterHeatmap(root.__post || post, { mode: "hover", skipPan: true });
}
@@ -2515,6 +2564,7 @@ export function createSimpleMarkerForPost(post, mapRef, markersRef, expandedElRe
});
root.addEventListener("mouseleave", () => {
+ root.style.zIndex = isWeatherPost ? "10" : "2";
if (isCluster) {
dispatchClusterHeatmapClear();
}