const PSD_SUPABASE_URL = "https://fupexuonvzakoguucglk.supabase.co"; const PSD_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZ1cGV4dW9udnpha29ndXVjZ2xrIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc5MDUzNTQsImV4cCI6MjA5MzQ4MTM1NH0.YZF4SBqvDTSOyHDOf_TVhpBXDm0FEma74u32Bdryfjg"; const PSD_GA4_ID = "G-BZMQQZ2SVC"; const PSD_SITE_URL = "https://publicsentimentdash.com"; const PSD_X_PROFILE_URL = "https://x.com/PublicSentDash"; const PSD_VOTE_INSTRUMENTS = [ "S&P 500 / ES","Nasdaq / NQ","Dow / YM","Russell / RTY","VIX", "DAX","FTSE 100","Nikkei 225","Hang Seng","Euro Stoxx 50","CAC 40", "US 2Y Treasury","US 10Y Treasury","Treasury Yields", "US Dollar / DXY","EUR / EURUSD","GBP / GBPUSD","JPY / USDJPY","CHF / USDCHF", "CAD / USDCAD","AUD / AUDUSD","NZD / NZDUSD","EURJPY","EURGBP","GBPJPY", "AUDJPY","CADJPY","EURCHF","EURCAD","AUDCAD","AUDNZD","NZDJPY", "USDTRY","USDMXN","USDZAR", "Bitcoin / BTC","Ethereum / ETH","Solana / SOL","XRP","BNB","Cardano / ADA", "Dogecoin / DOGE","General Crypto", "Gold","Silver","Copper","Crude Oil","Natural Gas", "Fed / FOMC","CPI / Inflation","PPI","Jobs / NFP","US GDP / Growth","Geopolitical / Tariffs" ]; window.PSD_USER_SENTIMENT = window.PSD_USER_SENTIMENT || {}; function psdLoadGA4(){ if(!PSD_GA4_ID || window.PSD_GA4_LOADED) return; window.PSD_GA4_LOADED = true; window.dataLayer = window.dataLayer || []; window.gtag = function(){ window.dataLayer.push(arguments); }; const script = document.createElement("script"); script.async = true; script.src = "https://www.googletagmanager.com/gtag/js?id=" + encodeURIComponent(PSD_GA4_ID); document.head.appendChild(script); window.gtag("js", new Date()); window.gtag("config", PSD_GA4_ID, { page_title: document.title, page_path: window.location.pathname }); } function psdTrack(eventName, params){ if(typeof window.gtag === "function"){ window.gtag("event", eventName, params || {}); } } function psdCanonicalURL(){ const canonical = document.querySelector('link[rel="canonical"]'); if(canonical && canonical.href) return canonical.href; const path = window.location.pathname === "/" ? "/" : window.location.pathname; return PSD_SITE_URL + path; } function psdMetaDescription(){ const meta = document.querySelector('meta[name="description"]'); return meta ? meta.getAttribute("content") || "" : ""; } function psdInjectStructuredData(){ if(document.getElementById("psdStructuredData")) return; const currentUrl = psdCanonicalURL(); const description = psdMetaDescription(); const title = document.title || "Public Sentiment Dash"; const schema = { "@context": "https://schema.org", "@graph": [ { "@type": "Organization", "@id": PSD_SITE_URL + "/#organization", "name": "Public Sentiment Dash", "url": PSD_SITE_URL + "/", "logo": PSD_SITE_URL + "/logo.png", "sameAs": [PSD_X_PROFILE_URL], "description": "AI-assisted public market sentiment dashboard for stocks, forex, crypto, commodities, bonds, macro headlines, and financial news." }, { "@type": "WebSite", "@id": PSD_SITE_URL + "/#website", "url": PSD_SITE_URL + "/", "name": "Public Sentiment Dash", "publisher": {"@id": PSD_SITE_URL + "/#organization"}, "inLanguage": "en-US" }, { "@type": "WebPage", "@id": currentUrl + "#webpage", "url": currentUrl, "name": title, "description": description, "isPartOf": {"@id": PSD_SITE_URL + "/#website"}, "publisher": {"@id": PSD_SITE_URL + "/#organization"}, "inLanguage": "en-US" } ] }; const script = document.createElement("script"); script.id = "psdStructuredData"; script.type = "application/ld+json"; script.textContent = JSON.stringify(schema); document.head.appendChild(script); } function psdEscape(value){ return String(value ?? "") .replaceAll("&","&") .replaceAll("<","<") .replaceAll(">",">") .replaceAll('"',""") .replaceAll("'","'"); } function psdClass(value){ const clean = String(value || "N/A").replace(/[^a-zA-Z]/g,""); return clean || "NA"; } function psdAddHomeLabel(){ const brand = document.querySelector(".brand"); const logo = document.querySelector(".brand .logo"); if(!brand || !logo || document.querySelector(".psd-logo-home-wrap")) return; const style = document.createElement("style"); style.textContent = ` .psd-logo-home-wrap{display:flex;flex-direction:column;align-items:center;gap:4px;flex-shrink:0} .psd-logo-home-word{color:#ffd780;font-size:11px;font-weight:600;line-height:1;letter-spacing:.2px} `; document.head.appendChild(style); const wrap = document.createElement("span"); wrap.className = "psd-logo-home-wrap"; brand.insertBefore(wrap, logo); wrap.appendChild(logo); const word = document.createElement("span"); word.className = "psd-logo-home-word"; word.textContent = "Home"; wrap.appendChild(word); } function psdCreateAdvertiseBanner(){ if(document.getElementById("psdAdvertiseBanner")) return; const header = document.querySelector(".header"); if(!header) return; const style = document.createElement("style"); style.textContent = ` .psd-ad-banner{ max-width:1120px; margin:14px auto 0; padding:11px 14px; border:1px solid rgba(210,153,34,.28); border-radius:999px; background:linear-gradient(90deg,rgba(210,153,34,.14),rgba(88,166,255,.08)); color:#fff; display:flex; align-items:center; justify-content:center; gap:10px; text-align:center; font-size:13px; line-height:1.45; box-shadow:0 10px 26px rgba(0,0,0,.16); } .psd-ad-banner strong{color:#ffd780;font-weight:800} .psd-ad-banner a{ color:#fff; font-weight:800; text-decoration:none; border:1px solid rgba(255,255,255,.16); background:rgba(255,255,255,.07); padding:6px 10px; border-radius:999px; white-space:nowrap; transition:.18s ease; } .psd-ad-banner a:hover{border-color:rgba(210,153,34,.55);transform:translateY(-1px)} @media(max-width:760px){ .psd-ad-banner{border-radius:18px;flex-direction:column;margin:12px 14px 0} } `; document.head.appendChild(style); const banner = document.createElement("div"); banner.id = "psdAdvertiseBanner"; banner.className = "psd-ad-banner"; banner.innerHTML = ` 📣 Advertise on Public Sentiment Dash — reach finance, trading, investing, and market-sentiment readers. Learn More `; header.insertAdjacentElement("afterend", banner); } function psdGetVoterId(){ let id = localStorage.getItem("psd_voter_id"); if(!id){ id = window.crypto && crypto.randomUUID ? crypto.randomUUID() : "voter_" + Math.random().toString(36).slice(2) + Date.now().toString(36); localStorage.setItem("psd_voter_id", id); } return id; } function psdHeaders(){ return { "apikey": PSD_SUPABASE_ANON_KEY, "Authorization": "Bearer " + PSD_SUPABASE_ANON_KEY, "Content-Type": "application/json" }; } function psdFixNavigation(){ const nav = document.querySelector(".nav"); if(!nav) return; const order = [ ["dashboard.html", "Interactive Dashboard"], ["news-articles.html", "News & Articles"], ["market-sentiment.html", "Guides"], ["contact.html", "Get in Touch"], ["how-it-works.html", "Dashboard Works"], ["about.html", "About"] ]; Array.from(nav.querySelectorAll("a")).forEach(link => { const href = link.getAttribute("href") || ""; if(href.includes("index.html")) link.remove(); }); order.forEach(([href, label]) => { const link = Array.from(nav.querySelectorAll("a")).find(a => (a.getAttribute("href") || "").includes(href)); if(link){ link.textContent = label; nav.appendChild(link); } }); const social = nav.querySelector(".social-links"); if(social) nav.appendChild(social); } function psdEnhanceFooterLegalLinks(){ document.querySelectorAll(".footer-links").forEach(footer => { const extraLinks = [ ["advertise.html", "Advertise"], ["privacy.html", "Privacy"], ["terms.html", "Terms"], ["disclaimer.html", "Disclaimer"] ]; extraLinks.forEach(([href, label]) => { const exists = Array.from(footer.querySelectorAll("a")).some(a => (a.getAttribute("href") || "") === href); if(!exists){ const a = document.createElement("a"); a.href = href; a.textContent = label; if(window.location.pathname.toLowerCase().endsWith("/" + href.toLowerCase())){ a.className = "active"; } footer.appendChild(a); } }); }); } function psdEnhanceSocialLinks(){ document.querySelectorAll(".social-links").forEach(social => { const xPill = Array.from(social.querySelectorAll(".social-pill")).find(el => el.textContent.trim().toLowerCase() === "x" ); if(xPill && xPill.tagName.toLowerCase() !== "a"){ const a = document.createElement("a"); a.className = xPill.className; a.textContent = "X"; a.href = PSD_X_PROFILE_URL; a.target = "_blank"; a.rel = "noopener"; xPill.replaceWith(a); }else if(xPill){ xPill.href = PSD_X_PROFILE_URL; xPill.target = "_blank"; xPill.rel = "noopener"; } }); } function psdCreateShareButtons(){ if(document.getElementById("psdShareBox")) return; const noSharePages = ["privacy.html","terms.html","disclaimer.html"].some(page => window.location.pathname.toLowerCase().endsWith(page) ); if(noSharePages) return; const main = document.querySelector("main.page"); if(!main) return; const currentUrl = psdCanonicalURL(); const title = document.title.replace(" — Public Sentiment Dash", "").replace(" - Public Sentiment Dash", ""); const xShareText = `${title}\n\nPublic Sentiment Dash\n${currentUrl}`; const xShareUrl = `https://x.com/intent/post?text=${encodeURIComponent(xShareText)}`; const style = document.createElement("style"); style.textContent = ` .psd-share-box{max-width:1120px;margin:0 auto 18px;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 16px;border:1px solid var(--line);border-radius:16px;background:linear-gradient(180deg,rgba(17,24,33,.92),rgba(13,18,27,.92))} .psd-share-text{color:var(--muted);font-size:14px;line-height:1.5} .psd-share-actions{display:flex;gap:10px;flex-wrap:wrap} .psd-share-btn{display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);background:#111821;color:#fff;border-radius:999px;padding:9px 13px;font-size:13px;font-weight:600;text-decoration:none;cursor:pointer;transition:.18s ease;white-space:nowrap} .psd-share-btn:hover{border-color:rgba(210,153,34,.55);transform:translateY(-1px)} .psd-share-x{background:rgba(88,166,255,.10);border-color:rgba(88,166,255,.25)} @media(max-width:720px){.psd-share-box{align-items:flex-start;flex-direction:column}} `; document.head.appendChild(style); const box = document.createElement("section"); box.id = "psdShareBox"; box.className = "psd-share-box"; box.innerHTML = `
`; const firstPanel = main.querySelector(".panel.hero") || main.querySelector(".panel"); if(firstPanel && firstPanel.nextSibling){ main.insertBefore(box, firstPanel.nextSibling); }else{ main.insertBefore(box, main.firstChild); } const copyBtn = document.getElementById("psdCopyLinkBtn"); if(copyBtn){ copyBtn.addEventListener("click", async () => { try{ await navigator.clipboard.writeText(currentUrl); copyBtn.textContent = "Copied"; psdTrack("copy_share_link", { page_url: currentUrl }); setTimeout(() => copyBtn.textContent = "Copy Link", 1200); }catch(e){ copyBtn.textContent = "Copy Failed"; setTimeout(() => copyBtn.textContent = "Copy Link", 1200); } }); } } function psdFallbackFromElement(el){ const card = el.closest(".instrument-card"); if(card){ const dailyRow = Array.from(card.querySelectorAll(".info-row")).find(row => row.textContent.trim().toLowerCase().startsWith("daily:") ); if(dailyRow){ const text = dailyRow.textContent.toLowerCase(); if(text.includes("bullish")) return "Bullish"; if(text.includes("bearish")) return "Bearish"; if(text.includes("neutral")) return "Neutral"; } } const rail = el.closest(".rail-item"); if(rail){ if(rail.classList.contains("direction-up")) return "Bullish"; if(rail.classList.contains("direction-down")) return "Bearish"; if(rail.classList.contains("direction-neutral")) return "Neutral"; } const newsCard = el.closest(".news-card"); if(newsCard){ const tech = newsCard.querySelector(".tech-chip"); const text = tech ? tech.textContent.toLowerCase() : ""; if(text.includes("bullish")) return "Bullish"; if(text.includes("bearish")) return "Bearish"; if(text.includes("neutral")) return "Neutral"; } return "N/A"; } function psdEffectiveSentiment(instrument, fallback){ const voted = window.PSD_USER_SENTIMENT?.[instrument]; if(voted && voted !== "N/A"){ return voted; } return fallback || "N/A"; } async function psdLoadUserSentiment(){ if(!PSD_SUPABASE_URL || !PSD_SUPABASE_ANON_KEY) return; try{ const response = await fetch(`${PSD_SUPABASE_URL}/rest/v1/rpc/get_user_sentiment`, { method:"POST", headers:psdHeaders(), body:"{}" }); if(!response.ok){ console.warn("User sentiment load failed:", response.status); return; } const rows = await response.json(); const map = {}; rows.forEach(row => { map[row.instrument] = row.user_sentiment || "N/A"; }); window.PSD_USER_SENTIMENT = map; psdApplyUserSentiment(); window.dispatchEvent(new CustomEvent("psdUserSentimentReady", { detail: map })); }catch(error){ console.warn("User sentiment load failed", error); } } function psdApplyUserSentiment(){ document.querySelectorAll("[data-user-sentiment]").forEach(el => { const instrument = el.getAttribute("data-user-sentiment"); const fallback = psdFallbackFromElement(el); const value = psdEffectiveSentiment(instrument, fallback); if(el.classList.contains("user-chip")){ el.textContent = "User: " + value; el.className = "chip user-chip " + psdClass(value); }else{ el.textContent = value; el.className = "psd-user-sentiment-value " + psdClass(value); } }); } async function psdSubmitVote(instrument, vote){ const status = document.getElementById("psdVoteStatus"); if(!status) return; status.textContent = "Submitting..."; status.className = "psd-vote-status"; try{ const response = await fetch(`${PSD_SUPABASE_URL}/rest/v1/rpc/submit_instrument_vote`, { method:"POST", headers:psdHeaders(), body:JSON.stringify({ p_instrument: instrument, p_vote: vote, p_voter_id: psdGetVoterId() }) }); let result = {}; try{ result = await response.json(); }catch(e){ result = {}; } if(!response.ok || !result.ok){ status.textContent = result.error || `Vote failed. Error ${response.status}`; status.className = "psd-vote-status error"; console.warn("Vote failed:", response.status, result); return; } window.PSD_USER_SENTIMENT[instrument] = result.user_sentiment || "N/A"; psdApplyUserSentiment(); psdTrack("instrument_vote", { instrument: instrument, vote: vote, result_sentiment: result.user_sentiment || "N/A" }); status.textContent = "Vote saved."; status.className = "psd-vote-status success"; setTimeout(() => { const panel = document.getElementById("psdVotePanel"); if(panel) panel.classList.remove("open"); }, 700); }catch(error){ status.textContent = "Vote failed."; status.className = "psd-vote-status error"; console.warn("Vote failed:", error); } } function psdCreateVoteWidget(){ if(document.getElementById("psdVoteWidget")) return; const wrap = document.createElement("div"); wrap.id = "psdVoteWidget"; wrap.className = "psd-vote-widget"; wrap.innerHTML = `