summaryrefslogtreecommitdiff
path: root/assets
diff options
context:
space:
mode:
authoreltrac <hi@eltr.ac>2026-05-01 10:52:35 +0800
committereltrac <hi@eltr.ac>2026-05-01 10:52:35 +0800
commit2b61a6c07bcd2978d3145f975ba667d707553ab2 (patch)
tree92fb0c5939d046a0f18f55cd6bf7378c8187fa56 /assets
parentb365a8174f391a5bc2bee459ed2358c773d82ac5 (diff)
chore: replace iine.js with unminified version
Diffstat (limited to 'assets')
-rw-r--r--assets/js/iine.js204
1 files changed, 203 insertions, 1 deletions
diff --git a/assets/js/iine.js b/assets/js/iine.js
index 2a26e1e..460451f 100644
--- a/assets/js/iine.js
+++ b/assets/js/iine.js
@@ -1 +1,203 @@
-(()=>{const p="https://vhiweeypifbwacashxjz.supabase.co",b="sb_publishable_EoB7MFJhCmb6PiAk-GPJ4w_PGhQ44Ru",g="heart",v="Send your appreciation",m={heart:"Send a heart",thumbs_up:"Send a thumbs up",upvote:"Send an upvote"},y={heart:'<svg width="16" height="16" viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" aria-hidden="true"><path d="M15 8C8.925 8 4 12.925 4 19c0 11 13 21 20 23.326C31 40 44 30 44 19c0-6.075-4.925-11-11-11c-3.72 0-7.01 1.847-9 4.674A10.99 10.99 0 0 0 15 8"/></svg>',thumbs_up:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"></path></svg>',upvote:'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 17l-6-6-6 6"/><path d="M18 11l-6-6-6 6"/></svg>'},f=e=>" "+e,w=(e,t)=>{var a=e.querySelector("svg");a&&("upvote"===(e.closest(".iine-button")?.dataset.icon||g)?a.setAttribute("stroke-width",t?"3":"2"):a.querySelectorAll("path, polygon, circle").forEach(e=>{e.setAttribute("fill",t?"currentColor":"none")}))};document.addEventListener("DOMContentLoaded",()=>{const n=document.querySelectorAll(".iine-button");if(0!==n.length){var e=Array.from(n).map(e=>e.dataset.slug||window.location.pathname);const o=[...new Set(e)],h=new Map;(async()=>{if(0!==o.length)try{var e=await fetch(p+"/rest/v1/rpc/get_hits",{method:"POST",headers:{"Content-Type":"application/json",apikey:b,Authorization:"Bearer "+b},body:JSON.stringify({page_slugs:o})});if(!e.ok)throw new Error("Failed to fetch counts");var t=await e.json();if(t&&"object"==typeof t&&!t.error)for(const r in t){var a=t[r];h.set(r,"number"==typeof a?a:0)}}catch(e){console.error("Error fetching iine counts:",e)}await 0,n.forEach(t=>{const a=t.dataset.slug||window.location.pathname,r="iine-clicked-"+a;let n=t.querySelector(".icon"),o=t.querySelector(".counter"),i=(n||(t.textContent="",(n=document.createElement("span")).className="icon",t.appendChild(n)),o||((o=document.createElement("span")).className="counter",t.appendChild(o)),h.get(a)||0);o.textContent=f(i);const s=t.dataset.icon||g;t.getAttribute("aria-label")||(c=t,e=s,c=c.dataset.ariaLabel||c.dataset.label||m[e]||v,t.setAttribute("aria-label",c),t.setAttribute("title",c)),t.removeAttribute("aria-hidden");var e=!!localStorage.getItem(r);t.setAttribute("aria-pressed",e.toString());const d="iine-description-"+a.replace(/\W/g,"-");var c=document.getElementById(d);c||((c=document.createElement("span")).id=d,c.style.display="none",c.textContent="Already clicked.",document.body.appendChild(c)),y[s]?n.innerHTML=y[s]:n.textContent=s,localStorage.getItem(r)&&(t.classList.add("clicked"),t.setAttribute("aria-disabled","true"),t.setAttribute("aria-describedby",d),y[s])&&w(n,!0);const l=async e=>{localStorage.getItem(r)||"true"===t.getAttribute("aria-disabled")||(e&&e.preventDefault(),t.setAttribute("aria-disabled","true"),localStorage.setItem(r,"true"),i++,t.classList.add("clicked"),t.setAttribute("aria-pressed","true"),t.setAttribute("aria-describedby",d),o.textContent=f(i),y[s]&&w(n,!0),fetch(p+"/rest/v1/rpc/increment_hits",{method:"POST",headers:{"Content-Type":"application/json",apikey:b,Authorization:"Bearer "+b},body:JSON.stringify({page_slug:a})}).catch(e=>{console.error("Failed to increment page hits:",e)}))};var u=t.closest("form");u?u.addEventListener("submit",e=>{e.preventDefault(),l(e)}):t.addEventListener("click",l),t.addEventListener("keydown",e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),l(e))})})})()}})})();
+(() => {
+ const SUPABASE_URL = 'https://vhiweeypifbwacashxjz.supabase.co';
+ const SUPABASE_KEY = 'sb_publishable_EoB7MFJhCmb6PiAk-GPJ4w_PGhQ44Ru';
+ const DEFAULT_ICON = 'heart';
+ const FALLBACK_LABEL = 'Send your appreciation';
+ const DEFAULT_LABELS = {
+ heart: 'Send a heart',
+ thumbs_up: 'Send a thumbs up',
+ upvote: 'Send an upvote'
+ };
+
+ const BUILTIN_ICONS = {
+ heart:
+ '<svg width="16" height="16" viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" aria-hidden="true"><path d="M15 8C8.925 8 4 12.925 4 19c0 11 13 21 20 23.326C31 40 44 30 44 19c0-6.075-4.925-11-11-11c-3.72 0-7.01 1.847-9 4.674A10.99 10.99 0 0 0 15 8"/></svg>',
+ thumbs_up:
+ '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"></path></svg>',
+ upvote:
+ '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 17l-6-6-6 6"/><path d="M18 11l-6-6-6 6"/></svg>',
+ };
+
+ const formatCount = (count) => ` ${count}`;
+
+ const getAccessibleLabel = (button, iconValue) => {
+ if (button.dataset.ariaLabel) {
+ return button.dataset.ariaLabel;
+ }
+ if (button.dataset.label) {
+ return button.dataset.label;
+ }
+ return DEFAULT_LABELS[iconValue] || FALLBACK_LABEL;
+ };
+
+ const toggleFill = (icon, filled) => {
+ const svg = icon.querySelector("svg");
+ if (svg) {
+ const iconType = icon.closest('.iine-button')?.dataset.icon || DEFAULT_ICON;
+ if (iconType === 'upvote') {
+ svg.setAttribute("stroke-width", filled ? "3" : "2");
+ } else {
+ const paths = svg.querySelectorAll("path, polygon, circle");
+ paths.forEach((path) => {
+ path.setAttribute("fill", filled ? "currentColor" : "none");
+ });
+ }
+ }
+ };
+
+ document.addEventListener("DOMContentLoaded", () => {
+ const iineButtons = document.querySelectorAll(".iine-button");
+ if (iineButtons.length === 0) {
+ return;
+ }
+ const slugs = Array.from(iineButtons).map(
+ (button) => button.dataset.slug || window.location.pathname
+ );
+ const uniqueSlugs = [...new Set(slugs)];
+ const counts = new Map();
+ const fetchCounts = async () => {
+ if (uniqueSlugs.length === 0) {
+ return;
+ }
+ try {
+ const response = await fetch(
+ `${SUPABASE_URL}/rest/v1/rpc/get_hits`,
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ apikey: SUPABASE_KEY,
+ Authorization: `Bearer ${SUPABASE_KEY}`,
+ },
+ body: JSON.stringify({
+ page_slugs: uniqueSlugs,
+ }),
+ }
+ );
+ if (!response.ok) throw new Error("Failed to fetch counts");
+ const countsData = await response.json();
+ if (countsData && typeof countsData === 'object' && !countsData.error) {
+ for (const slug in countsData) {
+ const count = countsData[slug];
+ counts.set(slug, typeof count === 'number' ? count : 0);
+ }
+ }
+ } catch (error) {
+ console.error("Error fetching iine counts:", error);
+ }
+ };
+
+ const initializeButtons = async () => {
+ await fetchCounts();
+
+ iineButtons.forEach((button) => {
+ const slug = button.dataset.slug || window.location.pathname;
+ const storageKey = `iine-clicked-${slug}`;
+ let icon = button.querySelector(".icon");
+ let counter = button.querySelector(".counter");
+
+ if (!icon) {
+ // Clear fallback content (e.g. <noscript> text) before building JS structure.
+ button.textContent = "";
+ icon = document.createElement("span");
+ icon.className = "icon";
+ button.appendChild(icon);
+ }
+
+ if (!counter) {
+ counter = document.createElement("span");
+ counter.className = "counter";
+ button.appendChild(counter);
+ }
+
+ let count = counts.get(slug) || 0;
+ counter.textContent = formatCount(count);
+
+ const iconValue = button.dataset.icon || DEFAULT_ICON;
+
+ if (!button.getAttribute('aria-label')) {
+ const accessibleLabel = getAccessibleLabel(button, iconValue);
+ button.setAttribute('aria-label', accessibleLabel);
+ button.setAttribute('title', accessibleLabel);
+ }
+ button.removeAttribute('aria-hidden');
+ const isPressed = !!localStorage.getItem(storageKey);
+ button.setAttribute('aria-pressed', isPressed.toString());
+
+ const descriptionId = `iine-description-${slug.replace(/\W/g, '-')}`;
+ let description = document.getElementById(descriptionId);
+ if (!description) {
+ description = document.createElement('span');
+ description.id = descriptionId;
+ description.style.display = 'none';
+ description.textContent = 'Already clicked.';
+ document.body.appendChild(description);
+ }
+
+ if (BUILTIN_ICONS[iconValue]) {
+ icon.innerHTML = BUILTIN_ICONS[iconValue];
+ } else {
+ icon.textContent = iconValue;
+ }
+
+ if (localStorage.getItem(storageKey)) {
+ button.classList.add("clicked");
+ button.setAttribute('aria-disabled', 'true');
+ button.setAttribute('aria-describedby', descriptionId);
+ if (BUILTIN_ICONS[iconValue]) {
+ toggleFill(icon, true);
+ }
+ }
+
+ const handleInteraction = async (event) => {
+ if (localStorage.getItem(storageKey) || button.getAttribute('aria-disabled') === 'true') {
+ return;
+ }
+ if (event) {
+ event.preventDefault();
+ }
+ button.setAttribute('aria-disabled', 'true');
+ localStorage.setItem(storageKey, "true");
+ count++;
+ button.classList.add("clicked");
+ button.setAttribute('aria-pressed', 'true');
+ button.setAttribute('aria-describedby', descriptionId);
+ counter.textContent = formatCount(count);
+ if (BUILTIN_ICONS[iconValue]) {
+ toggleFill(icon, true);
+ }
+ fetch(`${SUPABASE_URL}/rest/v1/rpc/increment_hits`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ apikey: SUPABASE_KEY,
+ Authorization: `Bearer ${SUPABASE_KEY}`,
+ },
+ body: JSON.stringify({ page_slug: slug }),
+ }).catch(error => {
+ console.error("Failed to increment page hits:", error);
+ });
+ };
+ // Progressive enhancement: if button is in a form, intercept form submission.
+ // This allows no-JS users to submit forms while JS users get smooth interactions.
+ const form = button.closest('form');
+ if (form) {
+ form.addEventListener('submit', (event) => {
+ event.preventDefault();
+ handleInteraction(event);
+ });
+ } else {
+ button.addEventListener("click", handleInteraction);
+ }
+ button.addEventListener("keydown", (event) => {
+ if (event.key === "Enter" || event.key === " ") {
+ event.preventDefault();
+ handleInteraction(event);
+ }
+ });
+ });
+ };
+
+ initializeButtons();
+ });
+})();