diff --git a/.github/workflows/raw-mirror.yml b/.github/workflows/raw-mirror.yml index 69eef45..e039ba5 100644 --- a/.github/workflows/raw-mirror.yml +++ b/.github/workflows/raw-mirror.yml @@ -56,20 +56,20 @@ jobs: run: | set -euo pipefail MANIFEST_FILE=".github/raw-mirror-paths.txt" - # Set up CR variable for proper quoting in expansions - CR=$'\r' rm -rf .raw-mirror-staging mkdir -p .raw-mirror-staging if [ ! -f "$MANIFEST_FILE" ]; then - echo "Missing manifest: $MANIFEST_FILE" + echo "Error: Missing manifest at $MANIFEST_FILE" exit 1 fi while IFS= read -r line || [ -n "$line" ]; do + # Strip comments and carriage returns path="${line%%#*}" - path="${path%"$CR"}" + path="${path//$'\\r'/}" + # Trim leading/trailing whitespace path="${path#"${path%%[![:space:]]*}"}" path="${path%"${path##*[![:space:]]}"}" @@ -77,40 +77,36 @@ jobs: continue fi - path="${path#/}" + if [[ "$path" == *".."* ]]; then + echo "Error: Directory traversal detected in path: $path" + exit 1 + fi - case "$path" in - *".."*) - echo "Invalid path in manifest: $path" - exit 1 - ;; - esac - - # Support multiple potential build locations: prefer public/, fall back to static/ (some builds place assets there). - source_file="public/$path" - if [ ! -f "$source_file" ]; then - # try static/ (source assets present in repo) - if [ -f "static/$path" ]; then - source_file="static/$path" - else - # try static/images/branding/ for image-only fallbacks (restrict to images/ prefix) - if [[ "$path" == images/* || "$path" == icons/* ]]; then - base="$(basename "$path")" - if [ -f "static/images/branding/$base" ]; then - source_file="static/images/branding/$base" - else - echo "Missing built artifact: public/$path (also checked static/$path and static/images/branding/$base)" - exit 1 - fi - else - echo "Missing built artifact: public/$path (also checked static/$path)" - exit 1 - fi + path="${path#/}" + base="$(basename "$path")" + source_file="" + + # 1. Check exact expected paths + for candidate in "public/$path" "static/$path"; do + if [ -f "$candidate" ]; then + source_file="$candidate" + break fi + done + + # 2. Fallback: Search anywhere in public/ or static/ by filename + if [ -z "$source_file" ]; then + source_file=$(find public static -name "$base" -type f -print -quit 2>/dev/null || true) + fi + + if [ -z "$source_file" ] || [ ! -f "$source_file" ]; then + echo "Error: Missing artifact for '$path'. '$base' not found in public/ or static/." + exit 1 fi - mkdir -p ".raw-mirror-staging/$(dirname "$path")" - cp "$source_file" ".raw-mirror-staging/$path" + dest=".raw-mirror-staging/$path" + mkdir -p "$(dirname "$dest")" + cp "$source_file" "$dest" done < "$MANIFEST_FILE" find .raw-mirror-staging -type f | sort @@ -126,7 +122,7 @@ jobs: git fetch origin "$BRANCH" || true rm -rf .raw-mirror-branch - if git show-ref --verify --quiet "refs/remotes/origin/$BRANCH"; then + if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null 2>&1; then git worktree add -B "$BRANCH" .raw-mirror-branch "origin/$BRANCH" else git worktree add -d .raw-mirror-branch diff --git a/.gitignore b/.gitignore index cca67dd..f2c3f78 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ static/icons/.gen/ !static/icons/site.webmanifest scratch/ docs/ +test.sh # Temp/log files .tmp* @@ -44,4 +45,4 @@ tmp* # Env files .env -.env.local \ No newline at end of file +.env.local diff --git a/static/icons/site.webmanifest b/static/icons/site.webmanifest index 15933b7..6ce3a8b 100644 --- a/static/icons/site.webmanifest +++ b/static/icons/site.webmanifest @@ -22,12 +22,6 @@ "prefer_related_applications": false, "related_applications": [], "icons": [ - { - "src": "/icons/favicon.svg", - "sizes": "any", - "type": "image/svg+xml", - "purpose": "any" - }, { "src": "/icons/icon-192x192.png", "sizes": "192x192", diff --git a/static/js/shell.min.js b/static/js/shell.min.js index 6c3e39d..93a991a 100644 --- a/static/js/shell.min.js +++ b/static/js/shell.min.js @@ -1,535 +1,4 @@ -<<<<<<< fix-csp -(()=>{function H(){if(window.__siteConfig)return window.__siteConfig;let e=document.getElementById("site-config");if(e)try{return window.__siteConfig=JSON.parse(e.textContent),window.__siteConfig}catch(t){console.error("[SiteConfig] Failed to parse JSON config",t)}return window.__siteConfig=window.SiteNavConfig||{},window.__siteConfig}var A="https://dhanur.me",O=(()=>{let e=window.location.hostname;if(e==="localhost"||e==="127.0.0.1")return"";let t=e.split(".");return t.length>=2?"."+t.slice(-2).join("."):""})();function G(){if(window.trustedTypes&&window.trustedTypes.createPolicy)try{window.__defaultPolicy=window.trustedTypes.createPolicy("default",{createScriptURL:function(t){return t},createHTML:function(t){return t}})}catch{}function e(t){let n=Element.prototype[t];Element.prototype[t]=function(...a){let o=n.apply(this,a),r=a[0];if(r&&r.tagName==="IFRAME")try{let i=r.contentWindow;i&&i.trustedTypes&&!i.trustedTypes.defaultPolicy&&i.trustedTypes.createPolicy("default",{createHTML:c=>c,createScript:c=>c,createScriptURL:c=>c})}catch{}return o}}e("appendChild"),e("insertBefore")}var ve={MOBILE:0,SM:640,MD:768,LG:1024,XL:1280,XXL:1536},f={isDesktop:!1,isMobile:!1,mediaQueries:{},listeners:new Set},j=!1;function M(){let e=f.isDesktop;f.isDesktop=f.mediaQueries.hoverCapable?.matches&&f.mediaQueries.finePointer?.matches,f.isMobile=!f.isDesktop,e!==f.isDesktop&&we()}function we(){f.listeners.forEach(e=>{try{e({isDesktop:f.isDesktop,isMobile:f.isMobile,isLargeScreen:be(),isTouchDevice:Se(),prefersReducedMotion:Ae()})}catch(t){console.error(t)}})}function z(){j||typeof window.matchMedia=="function"&&(j=!0,f.mediaQueries.hoverCapable=window.matchMedia("(hover: hover)"),f.mediaQueries.finePointer=window.matchMedia("(pointer: fine)"),f.mediaQueries.largeScreen=window.matchMedia(`(min-width: ${ve.LG}px)`),f.mediaQueries.touchDevice=window.matchMedia("(pointer: coarse)"),f.mediaQueries.reducedMotion=window.matchMedia("(prefers-reduced-motion: reduce)"),M(),Object.values(f.mediaQueries).forEach(e=>{e.addListener?e.addListener(M):e.addEventListener&&e.addEventListener("change",M)}))}var be=()=>f.mediaQueries.largeScreen?.matches||!1,Se=()=>f.mediaQueries.touchDevice?.matches||!1,Ae=()=>f.mediaQueries.reducedMotion?.matches||!1;function F(e){let t=`${e}=`,n=document.cookie?document.cookie.split(";"):[];for(let a of n){let o=a.trim();if(o.startsWith(t))return decodeURIComponent(o.slice(t.length))}return""}function Q(e,t,n={}){let{maxAgeSeconds:a,domain:o,path:r="/",sameSite:i="Lax"}=n,c=typeof a=="number"?`; Max-Age=${a}`:"",s=o?`; Domain=${o}`:"";document.cookie=`${e}=${encodeURIComponent(t)}; Path=${r}; SameSite=${i}; Secure${c}${s}`}var Le={dark:"dark",light:"light"},Ce=["auto","light","dark"],W={dark:"#010409",light:"#f6f8fa"},ke=240,w="auto",g=window.matchMedia?window.matchMedia("(prefers-color-scheme: dark)"):null,L=null;function C(e,t="auto"){let n=String(e||"").trim().toLowerCase();return Ce.includes(n)?n:n.includes("dark")?"dark":n.includes("light")?"light":t}function qe(){let e=window.__getThemeCookie?window.__getThemeCookie():F("theme")||null;return C(e,"auto")}function Ee(e){let t=C(e,"auto");if(window.__setThemeCookie){window.__setThemeCookie(t);return}Q("theme",t,{maxAgeSeconds:31536e3,domain:O||void 0,path:"/",sameSite:"Lax",secure:window.location.protocol==="https:"})}function T(e){let t=C(e,"auto");return window.__resolveColorset?window.__resolveColorset(t):t==="auto"?g&&g.matches?"dark":"light":t}function D(e){let t=Le[e]||e;document.documentElement.setAttribute("data-theme",t),document.documentElement.style.backgroundColor=W[e]||W.dark,e==="dark"?(document.documentElement.classList.add("dark"),document.documentElement.classList.remove("light"),document.documentElement.style.colorScheme="dark"):(document.documentElement.classList.add("light"),document.documentElement.classList.remove("dark"),document.documentElement.style.colorScheme="light");function n(a,o){document.querySelectorAll(a).forEach(r=>{r.classList.remove("hidden","invisible"),r.style.opacity=o?"1":"0",r.style.visibility=o?"visible":"hidden",r.style.pointerEvents=o?"":"none"})}n(".logo-dark",e==="dark"),n(".logo-light",e==="light"),n(".hero-dark",e==="dark"),n(".hero-light",e==="light")}function J(){let e=document.documentElement;e.classList.add("is-theme-switching"),L&&window.clearTimeout(L),L=window.setTimeout(()=>{e.classList.remove("is-theme-switching"),L=null},ke)}function I(){document.querySelectorAll(".theme-switcher").forEach(e=>{e.querySelectorAll("[data-theme-mode]").forEach(t=>{let a=t.getAttribute("data-theme-mode")===w;t.style.background=a?"color-mix(in oklab, var(--color-base-content) 20%, transparent)":"",t.style.boxShadow=a?"0 1px 3px rgba(0,0,0,0.12), inset 0 0 0 1px color-mix(in oklab, var(--color-base-content) 8%, transparent)":"",t.style.opacity=a?"1":"0.55"})})}function xe(e){w=e,Ee(e),J();let t=T(e);D(t),I(),document.dispatchEvent(new CustomEvent("themeChanged",{detail:t}))}function K(e=document){w=C(qe(),"auto");let t=T(w);if(D(t),I(),document.dispatchEvent(new CustomEvent("themeChanged",{detail:t})),e.querySelectorAll(".theme-switcher [data-theme-mode]").forEach(n=>{n.addEventListener("click",a=>{a.preventDefault(),a.stopPropagation();let o=n.getAttribute("data-theme-mode");o&&o!==w&&xe(o)})}),g){let n=()=>{if(w==="auto"){J();let a=T("auto");D(a),I(),document.dispatchEvent(new CustomEvent("themeChanged",{detail:a}))}};g.addEventListener?g.addEventListener("change",n):g.addListener&&g.addListener(n)}}function V({src:e,selector:t,async:n=!0,defer:a=!1,crossOrigin:o,loadedAttribute:r,onLoad:i,onError:c}){if(!e&&!t)return null;let s=t?document.querySelector(t):document.querySelector(`script[src="${e}"]`);if(s)return typeof i=="function"&&((r?s.getAttribute(r)==="1":!1)||s.readyState==="complete"?i():s.addEventListener("load",i,{once:!0})),typeof c=="function"&&s.addEventListener("error",c,{once:!0}),s;let l=document.createElement("script"),u=window.__defaultPolicy;return l.src=u?u.createScriptURL(e):e,l.async=n,l.defer=a,o&&(l.crossOrigin=o),l.addEventListener("load",()=>{r&&l.setAttribute(r,"1"),typeof i=="function"&&i()},{once:!0}),typeof c=="function"&&l.addEventListener("error",c,{once:!0}),document.head.appendChild(l),l}function q(){return!window.AUTH||typeof window.AUTH!="object"?null:window.AUTH}function _e(e){let t=!1;return(...n)=>{t||(t=!0,e(...n))}}function p(...e){return e.find(Boolean)||null}function S(...e){e.forEach(t=>t?.classList.remove("hidden"))}function k(...e){e.forEach(t=>t?.classList.add("hidden"))}function b(e,t){e&&(e.textContent=t)}function R(e,t){if(e){if(t){e.src=t;return}e.removeAttribute("src")}}function X(e,t,n,a,o){e.querySelectorAll(t).forEach(r=>{r.addEventListener(n,a,o)})}function Me(e){let t=_e(e);if(q()){t();return}document.addEventListener("authReady",t,{once:!0}),V({src:"https://auth.dhanur.me/auth-client.js",selector:'script[src*="auth-client.js"]',defer:!0,onLoad:()=>{let n=q();n&&typeof n.onReady=="function"?n.onReady(()=>t()):t()},onError:()=>{console.warn("[Auth] Could not load auth-client.js")}}),window.setTimeout(()=>{q()&&t()},2e3)}function Te(e){if(!e)return"";try{let t=new Date(e);return`resets ${["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][t.getUTCMonth()]} ${t.getUTCDate()}`}catch{return""}}function Y(e,t){if(!t)return;let n=t.unlimited||t.balance===-1,a=n?"\u221E":String(t.balance),o=n?"":Te(t.periodEnd),r=e.querySelector('[data-auth="credits-row"]');if(r){r.classList.remove("hidden");let c=r.querySelector('[data-auth="credits-balance"]'),s=r.querySelector('[data-auth="credits-reset"]');c&&(c.textContent=a),s&&(s.textContent=o)}let i=e.querySelector('[data-auth="sidebar-credits-row"]');if(i){i.classList.remove("hidden");let c=i.querySelector('[data-auth="sidebar-credits-balance"]'),s=i.querySelector('[data-auth="sidebar-credits-reset"]');c&&(c.textContent=a),s&&(s.textContent=o)}}function De(e){e.querySelector('[data-auth="credits-row"]')?.classList.add("hidden"),e.querySelector('[data-auth="sidebar-credits-row"]')?.classList.add("hidden")}function Z(e=document,t=null){e.__authIntegrationBound||(e.__authIntegrationBound=!0,Me(()=>{let n=q();if(!n)return;let a=e.querySelector(".navbar"),o=e.querySelector("[data-sidebar-root]")||e.querySelector("#navigation-drawer"),r=e.querySelector("[data-sidebar-account]"),i={navGuestAvatar:p(e.querySelector('[data-auth="nav-guest-avatar"]'),a?.querySelector('[data-dropdown="account"] .bg-base-300')),navAuthedAvatar:p(e.querySelector('[data-auth="nav-authed-avatar"]'),a?.querySelector('[data-dropdown="account"] .ring-primary')),navAvatarImg:p(e.querySelector('[data-auth="nav-authed-avatar"] img'),a?.querySelector('[data-dropdown="account"] .ring-primary img')),navAuthedHeader:p(e.querySelector('[data-auth="nav-authed-header"]'),a?.querySelector('.dropdown-panel [data-auth="nav-name"]')?.closest(".border-b")),navGuestHeader:p(e.querySelector('[data-auth="nav-guest-header"]'),a?.querySelector(".dropdown-panel .fa-user")?.closest(".border-b")),navAuthedHeaderImg:e.querySelector('[data-auth="nav-authed-header-avatar"]'),navName:p(e.querySelector('[data-auth="nav-name"]'),a?.querySelector('[data-auth="name"]')),navEmail:p(e.querySelector('[data-auth="nav-email"]'),a?.querySelector('[data-auth="email"]')),navRole:p(e.querySelector('[data-auth="nav-role"]'),a?.querySelector('[data-auth="role"]')),navLoginItem:a?.querySelector('[data-auth="login-item"]')||null,navAccountItem:a?.querySelector('[data-auth="account-item"]')||null,navLogoutItem:a?.querySelector('[data-auth="logout-item"]')||null,sidebarGuestAvatar:p(e.querySelector('[data-auth="sidebar-guest-avatar"]'),r?.querySelector(".bg-base-300")),sidebarAuthedAvatar:p(e.querySelector('[data-auth="sidebar-authed-avatar"]'),r?.querySelector(".ring-primary")),sidebarAvatarImg:p(e.querySelector('[data-auth="sidebar-authed-avatar"] img'),r?.querySelector(".ring-primary img")),sidebarName:p(e.querySelector('[data-auth="sidebar-name"]'),r?.querySelector(".font-semibold")),sidebarEmail:p(e.querySelector('[data-auth="sidebar-email"]'),r?.querySelector(".text-xs.opacity-60")),sidebarLoginBtn:o?.querySelector('[data-auth="sidebar-login-btn"]')||null,sidebarLogoutBtn:o?.querySelector('[data-auth="sidebar-logout-btn"]')||null,sidebarAccountBtn:o?.querySelector('[data-auth="sidebar-account-btn"]')||null};function c(s){if(!s)return;let l=s.authenticated,u=s.user,h=u?.avatar_url||"",m=u?.name||"User";if(l&&u){if(k(i.navGuestAvatar,i.navGuestHeader,i.navLoginItem),S(i.navAuthedAvatar,i.navAuthedHeader,i.navAccountItem,i.navLogoutItem),R(i.navAvatarImg,h),R(i.navAuthedHeaderImg,h),b(i.navName,m),b(i.navEmail,u.email||""),i.navRole){let d=s.role||"user";i.navRole.textContent=d.toUpperCase(),i.navRole.className=d==="admin"?"badge badge-sm badge-error":"badge badge-sm badge-success",S(i.navRole)}k(i.sidebarGuestAvatar,i.sidebarLoginBtn),S(i.sidebarAuthedAvatar,i.sidebarLogoutBtn,i.sidebarAccountBtn),R(i.sidebarAvatarImg,h),b(i.sidebarName,m),b(i.sidebarEmail,u.email||""),Y(e,s.credits||null)}else S(i.navGuestAvatar,i.navGuestHeader,i.navLoginItem),k(i.navAuthedAvatar,i.navAuthedHeader,i.navRole,i.navAccountItem,i.navLogoutItem),S(i.sidebarGuestAvatar,i.sidebarLoginBtn),k(i.sidebarAuthedAvatar,i.sidebarLogoutBtn,i.sidebarAccountBtn),b(i.sidebarName,"Guest"),b(i.sidebarEmail,"Not signed in"),De(e);typeof t=="function"&&t(s)}typeof n.onReady=="function"?n.onReady(s=>c(s?.status||s||n.status||null)):n.status&&c(n.status),document.addEventListener("authChanged",s=>c(s.detail)),document.addEventListener("creditsChanged",s=>Y(e,s.detail)),X(e,'[data-auth="login-btn"], [data-auth="sidebar-login-btn"]',"click",s=>{s.preventDefault(),typeof n.login=="function"&&n.login()}),X(e,'[data-auth="logout-btn"], [data-auth="sidebar-logout-btn"]',"click",s=>{if(s.preventDefault(),typeof n.logout=="function"){let l=n.logout();l&&typeof l.then=="function"?l.then(()=>window.location.reload()).catch(u=>{console.warn("[Auth] Logout failed:",u),window.location.reload()}):window.location.reload()}})}))}var Ie=` -======= -(() => { - function H() { - if (window.__siteConfig) return window.__siteConfig; - let e = document.getElementById("site-config"); - if (e) - try { - return ( - (window.__siteConfig = JSON.parse(e.textContent)), - window.__siteConfig - ); - } catch (t) { - console.error("[SiteConfig] Failed to parse JSON config", t); - } - return ( - (window.__siteConfig = window.SiteNavConfig || {}), - window.__siteConfig - ); - } - var A = "https://dhanur.me", - O = (() => { - let e = window.location.hostname; - if (e === "localhost" || e === "127.0.0.1") return ""; - let t = e.split("."); - return t.length >= 2 ? "." + t.slice(-2).join(".") : ""; - })(); - var ye = { MOBILE: 0, SM: 640, MD: 768, LG: 1024, XL: 1280, XXL: 1536 }, - f = { isDesktop: !1, isMobile: !1, mediaQueries: {}, listeners: new Set() }, - G = !1; - function M() { - let e = f.isDesktop; - ((f.isDesktop = - f.mediaQueries.hoverCapable?.matches && - f.mediaQueries.finePointer?.matches), - (f.isMobile = !f.isDesktop), - e !== f.isDesktop && ve()); - } - function ve() { - f.listeners.forEach((e) => { - try { - e({ - isDesktop: f.isDesktop, - isMobile: f.isMobile, - isLargeScreen: we(), - isTouchDevice: be(), - prefersReducedMotion: Se(), - }); - } catch (t) { - console.error(t); - } - }); - } - function j() { - G || - (typeof window.matchMedia == "function" && - ((G = !0), - (f.mediaQueries.hoverCapable = window.matchMedia("(hover: hover)")), - (f.mediaQueries.finePointer = window.matchMedia("(pointer: fine)")), - (f.mediaQueries.largeScreen = window.matchMedia( - `(min-width: ${ye.LG}px)`, - )), - (f.mediaQueries.touchDevice = window.matchMedia("(pointer: coarse)")), - (f.mediaQueries.reducedMotion = window.matchMedia( - "(prefers-reduced-motion: reduce)", - )), - M(), - Object.values(f.mediaQueries).forEach((e) => { - e.addListener - ? e.addListener(M) - : e.addEventListener && e.addEventListener("change", M); - }))); - } - var we = () => f.mediaQueries.largeScreen?.matches || !1, - be = () => f.mediaQueries.touchDevice?.matches || !1, - Se = () => f.mediaQueries.reducedMotion?.matches || !1; - function z(e) { - let t = `${e}=`, - n = document.cookie ? document.cookie.split(";") : []; - for (let a of n) { - let o = a.trim(); - if (o.startsWith(t)) return decodeURIComponent(o.slice(t.length)); - } - return ""; - } - function F(e, t, n = {}) { - let { maxAgeSeconds: a, domain: o, path: r = "/", sameSite: i = "Lax" } = n, - c = typeof a == "number" ? `; Max-Age=${a}` : "", - s = o ? `; Domain=${o}` : ""; - document.cookie = `${e}=${encodeURIComponent(t)}; Path=${r}; SameSite=${i}; Secure${c}${s}`; - } - var Ae = { dark: "dark", light: "light" }, - Le = ["auto", "light", "dark"], - Q = { dark: "#010409", light: "#f6f8fa" }, - Ce = 240, - w = "auto", - y = window.matchMedia - ? window.matchMedia("(prefers-color-scheme: dark)") - : null, - L = null; - function C(e, t = "auto") { - let n = String(e || "") - .trim() - .toLowerCase(); - return Le.includes(n) - ? n - : n.includes("dark") - ? "dark" - : n.includes("light") - ? "light" - : t; - } - function ke() { - let e = window.__getThemeCookie - ? window.__getThemeCookie() - : z("theme") || null; - return C(e, "auto"); - } - function qe(e) { - let t = C(e, "auto"); - if (window.__setThemeCookie) { - window.__setThemeCookie(t); - return; - } - F("theme", t, { - maxAgeSeconds: 31536e3, - domain: O || void 0, - path: "/", - sameSite: "Lax", - secure: window.location.protocol === "https:", - }); - } - function T(e) { - let t = C(e, "auto"); - return window.__resolveColorset - ? window.__resolveColorset(t) - : t === "auto" - ? y && y.matches - ? "dark" - : "light" - : t; - } - function D(e) { - let t = Ae[e] || e; - (document.documentElement.setAttribute("data-theme", t), - (document.documentElement.style.backgroundColor = Q[e] || Q.dark), - e === "dark" - ? (document.documentElement.classList.add("dark"), - document.documentElement.classList.remove("light"), - (document.documentElement.style.colorScheme = "dark")) - : (document.documentElement.classList.add("light"), - document.documentElement.classList.remove("dark"), - (document.documentElement.style.colorScheme = "light"))); - function n(a, o) { - document.querySelectorAll(a).forEach((r) => { - (r.classList.remove("hidden", "invisible"), - (r.style.opacity = o ? "1" : "0"), - (r.style.visibility = o ? "visible" : "hidden"), - (r.style.pointerEvents = o ? "" : "none")); - }); - } - (n(".logo-dark", e === "dark"), - n(".logo-light", e === "light"), - n(".hero-dark", e === "dark"), - n(".hero-light", e === "light")); - } - function W() { - let e = document.documentElement; - (e.classList.add("is-theme-switching"), - L && window.clearTimeout(L), - (L = window.setTimeout(() => { - (e.classList.remove("is-theme-switching"), (L = null)); - }, Ce))); - } - function I() { - document.querySelectorAll(".theme-switcher").forEach((e) => { - e.querySelectorAll("[data-theme-mode]").forEach((t) => { - let a = t.getAttribute("data-theme-mode") === w; - ((t.style.background = a - ? "color-mix(in oklab, var(--color-base-content) 20%, transparent)" - : ""), - (t.style.boxShadow = a - ? "0 1px 3px rgba(0,0,0,0.12), inset 0 0 0 1px color-mix(in oklab, var(--color-base-content) 8%, transparent)" - : ""), - (t.style.opacity = a ? "1" : "0.55")); - }); - }); - } - function Ee(e) { - ((w = e), qe(e), W()); - let t = T(e); - (D(t), - I(), - document.dispatchEvent(new CustomEvent("themeChanged", { detail: t }))); - } - function J(e = document) { - w = C(ke(), "auto"); - let t = T(w); - if ( - (D(t), - I(), - document.dispatchEvent(new CustomEvent("themeChanged", { detail: t })), - e.querySelectorAll(".theme-switcher [data-theme-mode]").forEach((n) => { - n.addEventListener("click", (a) => { - (a.preventDefault(), a.stopPropagation()); - let o = n.getAttribute("data-theme-mode"); - o && o !== w && Ee(o); - }); - }), - y) - ) { - let n = () => { - if (w === "auto") { - W(); - let a = T("auto"); - (D(a), - I(), - document.dispatchEvent( - new CustomEvent("themeChanged", { detail: a }), - )); - } - }; - y.addEventListener - ? y.addEventListener("change", n) - : y.addListener && y.addListener(n); - } - } - function K({ - src: e, - selector: t, - async: n = !0, - defer: a = !1, - crossOrigin: o, - loadedAttribute: r, - onLoad: i, - onError: c, - }) { - if (!e && !t) return null; - let s = t - ? document.querySelector(t) - : document.querySelector(`script[src="${e}"]`); - if (s) - return ( - typeof i == "function" && - ((r ? s.getAttribute(r) === "1" : !1) || s.readyState === "complete" - ? i() - : s.addEventListener("load", i, { once: !0 })), - typeof c == "function" && s.addEventListener("error", c, { once: !0 }), - s - ); - let l = document.createElement("script"), - u = window.__defaultPolicy; - return ( - (l.src = u ? u.createScriptURL(e) : e), - (l.async = n), - (l.defer = a), - o && (l.crossOrigin = o), - l.addEventListener( - "load", - () => { - (r && l.setAttribute(r, "1"), typeof i == "function" && i()); - }, - { once: !0 }, - ), - typeof c == "function" && l.addEventListener("error", c, { once: !0 }), - document.head.appendChild(l), - l - ); - } - function q() { - return !window.AUTH || typeof window.AUTH != "object" ? null : window.AUTH; - } - function xe(e) { - let t = !1; - return (...n) => { - t || ((t = !0), e(...n)); - }; - } - function p(...e) { - return e.find(Boolean) || null; - } - function S(...e) { - e.forEach((t) => t?.classList.remove("hidden")); - } - function k(...e) { - e.forEach((t) => t?.classList.add("hidden")); - } - function b(e, t) { - e && (e.textContent = t); - } - function R(e, t) { - if (e) { - if (t) { - e.src = t; - return; - } - e.removeAttribute("src"); - } - } - function V(e, t, n, a, o) { - e.querySelectorAll(t).forEach((r) => { - r.addEventListener(n, a, o); - }); - } - function _e(e) { - let t = xe(e); - if (q()) { - t(); - return; - } - (document.addEventListener("authReady", t, { once: !0 }), - K({ - src: "https://auth.dhanur.me/auth-client.js", - selector: 'script[src*="auth-client.js"]', - defer: !0, - onLoad: () => { - let n = q(); - n && typeof n.onReady == "function" ? n.onReady(() => t()) : t(); - }, - onError: () => { - console.warn("[Auth] Could not load auth-client.js"); - }, - }), - window.setTimeout(() => { - q() && t(); - }, 2e3)); - } - function Me(e) { - if (!e) return ""; - try { - let t = new Date(e); - return `resets ${["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][t.getUTCMonth()]} ${t.getUTCDate()}`; - } catch { - return ""; - } - } - function X(e, t) { - if (!t) return; - let n = t.unlimited || t.balance === -1, - a = n ? "\u221E" : String(t.balance), - o = n ? "" : Me(t.periodEnd), - r = e.querySelector('[data-auth="credits-row"]'); - if (r) { - r.classList.remove("hidden"); - let c = r.querySelector('[data-auth="credits-balance"]'), - s = r.querySelector('[data-auth="credits-reset"]'); - (c && (c.textContent = a), s && (s.textContent = o)); - } - let i = e.querySelector('[data-auth="sidebar-credits-row"]'); - if (i) { - i.classList.remove("hidden"); - let c = i.querySelector('[data-auth="sidebar-credits-balance"]'), - s = i.querySelector('[data-auth="sidebar-credits-reset"]'); - (c && (c.textContent = a), s && (s.textContent = o)); - } - } - function Te(e) { - (e.querySelector('[data-auth="credits-row"]')?.classList.add("hidden"), - e - .querySelector('[data-auth="sidebar-credits-row"]') - ?.classList.add("hidden")); - } - function Y(e = document, t = null) { - e.__authIntegrationBound || - ((e.__authIntegrationBound = !0), - _e(() => { - let n = q(); - if (!n) return; - let a = e.querySelector(".navbar"), - o = - e.querySelector("[data-sidebar-root]") || - e.querySelector("#navigation-drawer"), - r = e.querySelector("[data-sidebar-account]"), - i = { - navGuestAvatar: p( - e.querySelector('[data-auth="nav-guest-avatar"]'), - a?.querySelector('[data-dropdown="account"] .bg-base-300'), - ), - navAuthedAvatar: p( - e.querySelector('[data-auth="nav-authed-avatar"]'), - a?.querySelector('[data-dropdown="account"] .ring-primary'), - ), - navAvatarImg: p( - e.querySelector('[data-auth="nav-authed-avatar"] img'), - a?.querySelector('[data-dropdown="account"] .ring-primary img'), - ), - navAuthedHeader: p( - e.querySelector('[data-auth="nav-authed-header"]'), - a - ?.querySelector('.dropdown-panel [data-auth="nav-name"]') - ?.closest(".border-b"), - ), - navGuestHeader: p( - e.querySelector('[data-auth="nav-guest-header"]'), - a - ?.querySelector(".dropdown-panel .fa-user") - ?.closest(".border-b"), - ), - navAuthedHeaderImg: e.querySelector( - '[data-auth="nav-authed-header-avatar"]', - ), - navName: p( - e.querySelector('[data-auth="nav-name"]'), - a?.querySelector('[data-auth="name"]'), - ), - navEmail: p( - e.querySelector('[data-auth="nav-email"]'), - a?.querySelector('[data-auth="email"]'), - ), - navRole: p( - e.querySelector('[data-auth="nav-role"]'), - a?.querySelector('[data-auth="role"]'), - ), - navLoginItem: a?.querySelector('[data-auth="login-item"]') || null, - navAccountItem: - a?.querySelector('[data-auth="account-item"]') || null, - navLogoutItem: - a?.querySelector('[data-auth="logout-item"]') || null, - sidebarGuestAvatar: p( - e.querySelector('[data-auth="sidebar-guest-avatar"]'), - r?.querySelector(".bg-base-300"), - ), - sidebarAuthedAvatar: p( - e.querySelector('[data-auth="sidebar-authed-avatar"]'), - r?.querySelector(".ring-primary"), - ), - sidebarAvatarImg: p( - e.querySelector('[data-auth="sidebar-authed-avatar"] img'), - r?.querySelector(".ring-primary img"), - ), - sidebarName: p( - e.querySelector('[data-auth="sidebar-name"]'), - r?.querySelector(".font-semibold"), - ), - sidebarEmail: p( - e.querySelector('[data-auth="sidebar-email"]'), - r?.querySelector(".text-xs.opacity-60"), - ), - sidebarLoginBtn: - o?.querySelector('[data-auth="sidebar-login-btn"]') || null, - sidebarLogoutBtn: - o?.querySelector('[data-auth="sidebar-logout-btn"]') || null, - sidebarAccountBtn: - o?.querySelector('[data-auth="sidebar-account-btn"]') || null, - }; - function c(s) { - if (!s) return; - let l = s.authenticated, - u = s.user, - h = u?.avatar_url || "", - m = u?.name || "User"; - if (l && u) { - if ( - (k(i.navGuestAvatar, i.navGuestHeader, i.navLoginItem), - S( - i.navAuthedAvatar, - i.navAuthedHeader, - i.navAccountItem, - i.navLogoutItem, - ), - R(i.navAvatarImg, h), - R(i.navAuthedHeaderImg, h), - b(i.navName, m), - b(i.navEmail, u.email || ""), - i.navRole) - ) { - let d = s.role || "user"; - ((i.navRole.textContent = d.toUpperCase()), - (i.navRole.className = - d === "admin" - ? "badge badge-sm badge-error" - : "badge badge-sm badge-success"), - S(i.navRole)); - } - (k(i.sidebarGuestAvatar, i.sidebarLoginBtn), - S(i.sidebarAuthedAvatar, i.sidebarLogoutBtn, i.sidebarAccountBtn), - R(i.sidebarAvatarImg, h), - b(i.sidebarName, m), - b(i.sidebarEmail, u.email || ""), - X(e, s.credits || null)); - } else - (S(i.navGuestAvatar, i.navGuestHeader, i.navLoginItem), - k( - i.navAuthedAvatar, - i.navAuthedHeader, - i.navRole, - i.navAccountItem, - i.navLogoutItem, - ), - S(i.sidebarGuestAvatar, i.sidebarLoginBtn), - k(i.sidebarAuthedAvatar, i.sidebarLogoutBtn, i.sidebarAccountBtn), - b(i.sidebarName, "Guest"), - b(i.sidebarEmail, "Not signed in"), - Te(e)); - typeof t == "function" && t(s); - } - (typeof n.onReady == "function" - ? n.onReady((s) => c(s?.status || s || n.status || null)) - : n.status && c(n.status), - document.addEventListener("authChanged", (s) => c(s.detail)), - document.addEventListener("creditsChanged", (s) => X(e, s.detail)), - V( - e, - '[data-auth="login-btn"], [data-auth="sidebar-login-btn"]', - "click", - (s) => { - (s.preventDefault(), typeof n.login == "function" && n.login()); - }, - ), - V( - e, - '[data-auth="logout-btn"], [data-auth="sidebar-logout-btn"]', - "click", - (s) => { - if ((s.preventDefault(), typeof n.logout == "function")) { - let l = n.logout(); - l && typeof l.then == "function" - ? l - .then(() => window.location.reload()) - .catch((u) => { - (console.warn("[Auth] Logout failed:", u), - window.location.reload()); - }) - : window.location.reload(); - } - }, - )); - })); - } - var De = ` ->>>>>>> main +(()=>{function H(){if(window.__siteConfig)return window.__siteConfig;let e=document.getElementById("site-config");if(e)try{return window.__siteConfig=JSON.parse(e.textContent),window.__siteConfig}catch(t){console.error("[SiteConfig] Failed to parse JSON config",t)}return window.__siteConfig=window.SiteNavConfig||{},window.__siteConfig}var A="https://dhanur.me",O=(()=>{let e=window.location.hostname;if(e==="localhost"||e==="127.0.0.1")return"";let t=e.split(".");return t.length>=2?"."+t.slice(-2).join("."):""})();function G(){if(window.__defaultPolicy)return;if(window.trustedTypes&&window.trustedTypes.createPolicy)try{window.__defaultPolicy=window.trustedTypes.createPolicy("default",{createScriptURL:function(t){return t},createHTML:function(t){return t}})}catch{}function e(t){let n=Element.prototype[t];Element.prototype[t]=function(...a){let o=n.apply(this,a),r=a[0];if(r&&r.tagName==="IFRAME")try{let i=r.contentWindow;i&&i.trustedTypes&&!i.trustedTypes.defaultPolicy&&i.trustedTypes.createPolicy("default",{createHTML:c=>c,createScript:c=>c,createScriptURL:c=>c})}catch{}return o}}e("appendChild"),e("insertBefore")}var ve={MOBILE:0,SM:640,MD:768,LG:1024,XL:1280,XXL:1536},f={isDesktop:!1,isMobile:!1,mediaQueries:{},listeners:new Set},j=!1;function M(){let e=f.isDesktop;f.isDesktop=f.mediaQueries.hoverCapable?.matches&&f.mediaQueries.finePointer?.matches,f.isMobile=!f.isDesktop,e!==f.isDesktop&&we()}function we(){f.listeners.forEach(e=>{try{e({isDesktop:f.isDesktop,isMobile:f.isMobile,isLargeScreen:be(),isTouchDevice:Se(),prefersReducedMotion:Ae()})}catch(t){console.error(t)}})}function z(){j||typeof window.matchMedia=="function"&&(j=!0,f.mediaQueries.hoverCapable=window.matchMedia("(hover: hover)"),f.mediaQueries.finePointer=window.matchMedia("(pointer: fine)"),f.mediaQueries.largeScreen=window.matchMedia(`(min-width: ${ve.LG}px)`),f.mediaQueries.touchDevice=window.matchMedia("(pointer: coarse)"),f.mediaQueries.reducedMotion=window.matchMedia("(prefers-reduced-motion: reduce)"),M(),Object.values(f.mediaQueries).forEach(e=>{e.addListener?e.addListener(M):e.addEventListener&&e.addEventListener("change",M)}))}var be=()=>f.mediaQueries.largeScreen?.matches||!1,Se=()=>f.mediaQueries.touchDevice?.matches||!1,Ae=()=>f.mediaQueries.reducedMotion?.matches||!1;function F(e){let t=`${e}=`,n=document.cookie?document.cookie.split(";"):[];for(let a of n){let o=a.trim();if(o.startsWith(t))return decodeURIComponent(o.slice(t.length))}return""}function Q(e,t,n={}){let{maxAgeSeconds:a,domain:o,path:r="/",sameSite:i="Lax"}=n,c=typeof a=="number"?`; Max-Age=${a}`:"",s=o?`; Domain=${o}`:"";document.cookie=`${e}=${encodeURIComponent(t)}; Path=${r}; SameSite=${i}; Secure${c}${s}`}var Le={dark:"dark",light:"light"},Ce=["auto","light","dark"],W={dark:"#010409",light:"#f6f8fa"},ke=240,w="auto",g=window.matchMedia?window.matchMedia("(prefers-color-scheme: dark)"):null,L=null;function C(e,t="auto"){let n=String(e||"").trim().toLowerCase();return Ce.includes(n)?n:n.includes("dark")?"dark":n.includes("light")?"light":t}function qe(){let e=window.__getThemeCookie?window.__getThemeCookie():F("theme")||null;return C(e,"auto")}function Ee(e){let t=C(e,"auto");if(window.__setThemeCookie){window.__setThemeCookie(t);return}Q("theme",t,{maxAgeSeconds:31536e3,domain:O||void 0,path:"/",sameSite:"Lax",secure:window.location.protocol==="https:"})}function T(e){let t=C(e,"auto");return window.__resolveColorset?window.__resolveColorset(t):t==="auto"?g&&g.matches?"dark":"light":t}function D(e){let t=Le[e]||e;document.documentElement.setAttribute("data-theme",t),document.documentElement.style.backgroundColor=W[e]||W.dark,e==="dark"?(document.documentElement.classList.add("dark"),document.documentElement.classList.remove("light"),document.documentElement.style.colorScheme="dark"):(document.documentElement.classList.add("light"),document.documentElement.classList.remove("dark"),document.documentElement.style.colorScheme="light");function n(a,o){document.querySelectorAll(a).forEach(r=>{r.classList.remove("hidden","invisible"),r.style.opacity=o?"1":"0",r.style.visibility=o?"visible":"hidden",r.style.pointerEvents=o?"":"none"})}n(".logo-dark",e==="dark"),n(".logo-light",e==="light"),n(".hero-dark",e==="dark"),n(".hero-light",e==="light")}function J(){let e=document.documentElement;e.classList.add("is-theme-switching"),L&&window.clearTimeout(L),L=window.setTimeout(()=>{e.classList.remove("is-theme-switching"),L=null},ke)}function I(){document.querySelectorAll(".theme-switcher").forEach(e=>{e.querySelectorAll("[data-theme-mode]").forEach(t=>{let a=t.getAttribute("data-theme-mode")===w;t.style.background=a?"color-mix(in oklab, var(--color-base-content) 20%, transparent)":"",t.style.boxShadow=a?"0 1px 3px rgba(0,0,0,0.12), inset 0 0 0 1px color-mix(in oklab, var(--color-base-content) 8%, transparent)":"",t.style.opacity=a?"1":"0.55"})})}function xe(e){w=e,Ee(e),J();let t=T(e);D(t),I(),document.dispatchEvent(new CustomEvent("themeChanged",{detail:t}))}function K(e=document){w=C(qe(),"auto");let t=T(w);if(D(t),I(),document.dispatchEvent(new CustomEvent("themeChanged",{detail:t})),e.querySelectorAll(".theme-switcher [data-theme-mode]").forEach(n=>{n.addEventListener("click",a=>{a.preventDefault(),a.stopPropagation();let o=n.getAttribute("data-theme-mode");o&&o!==w&&xe(o)})}),g){let n=()=>{if(w==="auto"){J();let a=T("auto");D(a),I(),document.dispatchEvent(new CustomEvent("themeChanged",{detail:a}))}};g.addEventListener?g.addEventListener("change",n):g.addListener&&g.addListener(n)}}function V({src:e,selector:t,async:n=!0,defer:a=!1,crossOrigin:o,loadedAttribute:r,onLoad:i,onError:c}){if(!e&&!t)return null;let s=t?document.querySelector(t):document.querySelector(`script[src="${e}"]`);if(s)return typeof i=="function"&&((r?s.getAttribute(r)==="1":!1)||s.readyState==="complete"?i():s.addEventListener("load",i,{once:!0})),typeof c=="function"&&s.addEventListener("error",c,{once:!0}),s;let l=document.createElement("script"),u=window.__defaultPolicy;return l.src=u?u.createScriptURL(e):e,l.async=n,l.defer=a,o&&(l.crossOrigin=o),l.addEventListener("load",()=>{r&&l.setAttribute(r,"1"),typeof i=="function"&&i()},{once:!0}),typeof c=="function"&&l.addEventListener("error",c,{once:!0}),document.head.appendChild(l),l}function q(){return!window.AUTH||typeof window.AUTH!="object"?null:window.AUTH}function _e(e){let t=!1;return(...n)=>{t||(t=!0,e(...n))}}function p(...e){return e.find(Boolean)||null}function S(...e){e.forEach(t=>t?.classList.remove("hidden"))}function k(...e){e.forEach(t=>t?.classList.add("hidden"))}function b(e,t){e&&(e.textContent=t)}function P(e,t){if(e){if(t){e.src=t;return}e.removeAttribute("src")}}function X(e,t,n,a,o){e.querySelectorAll(t).forEach(r=>{r.addEventListener(n,a,o)})}function Me(e){let t=_e(e);if(q()){t();return}document.addEventListener("authReady",t,{once:!0}),V({src:"https://auth.dhanur.me/auth-client.js",selector:'script[src*="auth-client.js"]',defer:!0,onLoad:()=>{let n=q();n&&typeof n.onReady=="function"?n.onReady(()=>t()):t()},onError:()=>{console.warn("[Auth] Could not load auth-client.js")}}),window.setTimeout(()=>{q()&&t()},2e3)}function Te(e){if(!e)return"";try{let t=new Date(e);return`resets ${["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][t.getUTCMonth()]} ${t.getUTCDate()}`}catch{return""}}function Y(e,t){if(!t)return;let n=t.unlimited||t.balance===-1,a=n?"\u221E":String(t.balance),o=n?"":Te(t.periodEnd),r=e.querySelector('[data-auth="credits-row"]');if(r){r.classList.remove("hidden");let c=r.querySelector('[data-auth="credits-balance"]'),s=r.querySelector('[data-auth="credits-reset"]');c&&(c.textContent=a),s&&(s.textContent=o)}let i=e.querySelector('[data-auth="sidebar-credits-row"]');if(i){i.classList.remove("hidden");let c=i.querySelector('[data-auth="sidebar-credits-balance"]'),s=i.querySelector('[data-auth="sidebar-credits-reset"]');c&&(c.textContent=a),s&&(s.textContent=o)}}function De(e){e.querySelector('[data-auth="credits-row"]')?.classList.add("hidden"),e.querySelector('[data-auth="sidebar-credits-row"]')?.classList.add("hidden")}function Z(e=document,t=null){e.__authIntegrationBound||(e.__authIntegrationBound=!0,Me(()=>{let n=q();if(!n)return;let a=e.querySelector(".navbar"),o=e.querySelector("[data-sidebar-root]")||e.querySelector("#navigation-drawer"),r=e.querySelector("[data-sidebar-account]"),i={navGuestAvatar:p(e.querySelector('[data-auth="nav-guest-avatar"]'),a?.querySelector('[data-dropdown="account"] .bg-base-300')),navAuthedAvatar:p(e.querySelector('[data-auth="nav-authed-avatar"]'),a?.querySelector('[data-dropdown="account"] .ring-primary')),navAvatarImg:p(e.querySelector('[data-auth="nav-authed-avatar"] img'),a?.querySelector('[data-dropdown="account"] .ring-primary img')),navAuthedHeader:p(e.querySelector('[data-auth="nav-authed-header"]'),a?.querySelector('.dropdown-panel [data-auth="nav-name"]')?.closest(".border-b")),navGuestHeader:p(e.querySelector('[data-auth="nav-guest-header"]'),a?.querySelector(".dropdown-panel .fa-user")?.closest(".border-b")),navAuthedHeaderImg:e.querySelector('[data-auth="nav-authed-header-avatar"]'),navName:p(e.querySelector('[data-auth="nav-name"]'),a?.querySelector('[data-auth="name"]')),navEmail:p(e.querySelector('[data-auth="nav-email"]'),a?.querySelector('[data-auth="email"]')),navRole:p(e.querySelector('[data-auth="nav-role"]'),a?.querySelector('[data-auth="role"]')),navLoginItem:a?.querySelector('[data-auth="login-item"]')||null,navAccountItem:a?.querySelector('[data-auth="account-item"]')||null,navLogoutItem:a?.querySelector('[data-auth="logout-item"]')||null,sidebarGuestAvatar:p(e.querySelector('[data-auth="sidebar-guest-avatar"]'),r?.querySelector(".bg-base-300")),sidebarAuthedAvatar:p(e.querySelector('[data-auth="sidebar-authed-avatar"]'),r?.querySelector(".ring-primary")),sidebarAvatarImg:p(e.querySelector('[data-auth="sidebar-authed-avatar"] img'),r?.querySelector(".ring-primary img")),sidebarName:p(e.querySelector('[data-auth="sidebar-name"]'),r?.querySelector(".font-semibold")),sidebarEmail:p(e.querySelector('[data-auth="sidebar-email"]'),r?.querySelector(".text-xs.opacity-60")),sidebarLoginBtn:o?.querySelector('[data-auth="sidebar-login-btn"]')||null,sidebarLogoutBtn:o?.querySelector('[data-auth="sidebar-logout-btn"]')||null,sidebarAccountBtn:o?.querySelector('[data-auth="sidebar-account-btn"]')||null};function c(s){if(!s)return;let l=s.authenticated,u=s.user,h=u?.avatar_url||"",m=u?.name||"User";if(l&&u){if(k(i.navGuestAvatar,i.navGuestHeader,i.navLoginItem),S(i.navAuthedAvatar,i.navAuthedHeader,i.navAccountItem,i.navLogoutItem),P(i.navAvatarImg,h),P(i.navAuthedHeaderImg,h),b(i.navName,m),b(i.navEmail,u.email||""),i.navRole){let d=s.role||"user";i.navRole.textContent=d.toUpperCase(),i.navRole.className=d==="admin"?"badge badge-sm badge-error":"badge badge-sm badge-success",S(i.navRole)}k(i.sidebarGuestAvatar,i.sidebarLoginBtn),S(i.sidebarAuthedAvatar,i.sidebarLogoutBtn,i.sidebarAccountBtn),P(i.sidebarAvatarImg,h),b(i.sidebarName,m),b(i.sidebarEmail,u.email||""),Y(e,s.credits||null)}else S(i.navGuestAvatar,i.navGuestHeader,i.navLoginItem),k(i.navAuthedAvatar,i.navAuthedHeader,i.navRole,i.navAccountItem,i.navLogoutItem),S(i.sidebarGuestAvatar,i.sidebarLoginBtn),k(i.sidebarAuthedAvatar,i.sidebarLogoutBtn,i.sidebarAccountBtn),b(i.sidebarName,"Guest"),b(i.sidebarEmail,"Not signed in"),De(e);typeof t=="function"&&t(s)}typeof n.onReady=="function"?n.onReady(s=>c(s?.status||s||n.status||null)):n.status&&c(n.status),document.addEventListener("authChanged",s=>c(s.detail)),document.addEventListener("creditsChanged",s=>Y(e,s.detail)),X(e,'[data-auth="login-btn"], [data-auth="sidebar-login-btn"]',"click",s=>{s.preventDefault(),typeof n.login=="function"&&n.login()}),X(e,'[data-auth="logout-btn"], [data-auth="sidebar-logout-btn"]',"click",s=>{if(s.preventDefault(),typeof n.logout=="function"){let l=n.logout();l&&typeof l.then=="function"?l.then(()=>window.location.reload()).catch(u=>{console.warn("[Auth] Logout failed:",u),window.location.reload()}):window.location.reload()}})}))}var Ie=` .access-wall { display: flex; flex-direction: column; @@ -553,41 +22,7 @@ font-size: 0.9rem; opacity: 0.7; } -<<<<<<< fix-csp -`;function Re(){if(document.getElementById("access-wall-styles"))return;let e=document.createElement("style");e.id="access-wall-styles",e.textContent=Ie,document.head.appendChild(e)}function ee(e={},t=null){let n=e.requireAdmin===!0;if(!(e.requireAuth===!0||n))return{allowed:!0};let o=t?.authenticated===!0,r=t?.role||"guest";return o?n&&r!=="admin"?{allowed:!1,reason:"admin_required"}:{allowed:!0}:{allowed:!1,reason:"auth_required"}}function te(e,t="auth_required",n="This app"){if(!e)return;Re();let a=t==="admin_required",o=a?"fa-solid fa-shield-halved":"fa-solid fa-lock",r=a?"Admin access required":"Sign in to continue",i=a?`${n} is restricted to administrator sessions.`:`${n} requires a dhanur.me account to continue.`,c=a?"Verify Admin":"Sign In",s=a?"upgrade-btn":"login-btn";e.innerHTML=` -======= -`; - function Ie() { - if (document.getElementById("access-wall-styles")) return; - let e = document.createElement("style"); - ((e.id = "access-wall-styles"), - (e.textContent = De), - document.head.appendChild(e)); - } - function Z(e = {}, t = null) { - let n = e.requireAdmin === !0; - if (!(e.requireAuth === !0 || n)) return { allowed: !0 }; - let o = t?.authenticated === !0, - r = t?.role || "guest"; - return o - ? n && r !== "admin" - ? { allowed: !1, reason: "admin_required" } - : { allowed: !0 } - : { allowed: !1, reason: "auth_required" }; - } - function ee(e, t = "auth_required", n = "This app") { - if (!e) return; - Ie(); - let a = t === "admin_required", - o = a ? "fa-solid fa-shield-halved" : "fa-solid fa-lock", - r = a ? "Admin access required" : "Sign in to continue", - i = a - ? `${n} is restricted to administrator sessions.` - : `${n} requires a dhanur.me account to continue.`, - c = a ? "Verify Admin" : "Sign In", - s = a ? "upgrade-btn" : "login-btn"; - e.innerHTML = ` ->>>>>>> main +`;function Pe(){if(document.getElementById("access-wall-styles"))return;let e=document.createElement("style");e.id="access-wall-styles",e.textContent=Ie,document.head.appendChild(e)}function ee(e={},t=null){let n=e.requireAdmin===!0;if(!(e.requireAuth===!0||n))return{allowed:!0};let o=t?.authenticated===!0,r=t?.role||"guest";return o?n&&r!=="admin"?{allowed:!1,reason:"admin_required"}:{allowed:!0}:{allowed:!1,reason:"auth_required"}}function te(e,t="auth_required",n="This app"){if(!e)return;Pe();let a=t==="admin_required",o=a?"fa-solid fa-shield-halved":"fa-solid fa-lock",r=a?"Admin access required":"Sign in to continue",i=a?`${n} is restricted to administrator sessions.`:`${n} requires a dhanur.me account to continue.`,c=a?"Verify Admin":"Sign In",s=a?"upgrade-btn":"login-btn";e.innerHTML=`

${r}

@@ -597,522 +32,4 @@ ${c}
-<<<<<<< fix-csp - `;let l=window.AUTH;if(t==="admin_required"){let h=e.querySelector('[data-auth="upgrade-btn"]');h&&l&&typeof l.upgrade=="function"&&h.addEventListener("click",m=>{m.preventDefault(),l.upgrade()});return}let u=e.querySelector('[data-auth="login-btn"]');u&&l&&typeof l.login=="function"&&u.addEventListener("click",h=>{h.preventDefault(),l.login()})}var Pe="https://up.dhanur.me/api/manifest",oe="dhanur_manifest_v1";var ae=[{name:"Home",url:"https://dhanur.me",icon:"fa-solid fa-house",minRole:"guest"},{name:"Linkr",url:"https://linkr.dhanur.me",icon:"fa-solid fa-link",minRole:"guest"},{name:"Tasks",url:"https://tasks.dhanur.me",icon:"fa-solid fa-clipboard-list",minRole:"guest"},{name:"Auth",url:"https://auth.dhanur.me",icon:"fa-solid fa-fingerprint",minRole:"guest"},{name:"Status",url:"https://up.dhanur.me",icon:"fa-solid fa-heart-pulse",minRole:"guest",category:"Core"}],v=null,E=new Map;function $e(e){return e==="admin"?"admin":e==="user"?"user":"guest"}function ne(e){return e==="admin"?2:e==="user"?1:0}function Ne(){try{let e=localStorage.getItem(oe);if(!e)return null;let t=JSON.parse(e);if(!t||!Array.isArray(t.apps))return null;let n=Number(t._cachedAt||0);return{...t,_stale:Date.now()-n>36e5}}catch{return null}}function Be(e){try{localStorage.setItem(oe,JSON.stringify({version:e.version||"1",apps:Array.isArray(e.apps)?e.apps:ae,_cachedAt:Date.now()}))}catch{}}function P(){if(v&&Array.isArray(v.apps))return v;let e=Ne();return e&&Array.isArray(e.apps)?(v=e,e):{version:"0",apps:ae,_stale:!0}}function $(e,t="guest"){let n=ne(t);return(Array.isArray(e)?e:[]).filter(a=>ne(a?.minRole||"guest")<=n)}async function re(e="guest"){let t=$e(e);if(E.has(t))return E.get(t);let n=(async()=>{try{let a=`${Pe}?role=${encodeURIComponent(t)}`,o=await fetch(a,{credentials:"omit",mode:"cors",cache:"no-cache"});if(!o.ok)throw new Error(`Manifest request failed with status ${o.status}`);let r=await o.json();if(!r||!Array.isArray(r.apps))throw new Error("Manifest payload is invalid");return v={version:r.version||"1",apps:r.apps},Be(v),v}catch{return P()}})();E.set(t,n);try{return await n}finally{E.delete(t)}}var ie=!1;function x(){document.querySelectorAll("[data-dropdown][data-open]").forEach(e=>{e.removeAttribute("data-open")})}function N(){return document.querySelector("[data-dropdown][data-open]")}function se(e){let t=e.querySelector(".dropdown-panel");if(!t)return;let n=e.getBoundingClientRect(),a=t.offsetWidth||224,o=(n.width-a)/2,r=n.left+o+a-(window.innerWidth-16);r>0&&(o-=r),n.left+o<8&&(o=8-n.left),t.style.left=`${o}px`,t.style.right="auto"}function Ue(e){x(),e.setAttribute("data-open",""),se(e)}function ce(e=document){let t=e.querySelectorAll("[data-dropdown]");t.length&&(t.forEach(n=>{if(n.getAttribute("data-dropdown-init")==="1")return;let a=n.querySelector('[role="button"]');if(!a)return;let o=n.querySelector(".dropdown-panel"),r=a.classList.contains("tooltip")&&(a.hasAttribute("data-tooltip-label")||a.hasAttribute("data-tip")||!!a.querySelector(":scope > .tooltip-content"));n.setAttribute("data-dropdown-tooltip",r?"1":"0"),a.addEventListener("click",i=>{i.stopPropagation(),n.hasAttribute("data-open")?x():Ue(n)}),o&&o.addEventListener("click",i=>i.stopPropagation()),n.setAttribute("data-dropdown-init","1")}),!ie&&(ie=!0,document.addEventListener("click",()=>{N()&&x()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&N()&&x()}),window.addEventListener("resize",()=>{let n=N();n&&se(n)})))}var B={shellPath:"/navbar/",favicon:!0,enablePwa:!0,swPath:"/sw.js",requireAuth:!1,requireAdmin:!1,showMobileMenu:!0,showLanguage:!1,showAppsGrid:!0,showAccountButton:!0,showThemeToggle:!1};typeof window<"u"&&(window.SiteNavConfig={...B,...window.SiteNavConfig||{}});G();window.__componentsJS=!0;var le=!1,ue={...B,noCss:!1,showNavbar:!0};function me(){let e=H()||{},t=e.shell&&typeof e.shell=="object"?e.shell:{},n={...ue,...e,...t};return(typeof n.shellPath!="string"||n.shellPath.trim()==="")&&(n.shellPath=ue.shellPath),n}function pe(){return window.location.origin===A}function He(e){if(e.enablePwa===!1||!("serviceWorker"in navigator)||!window.isSecureContext)return;let t=typeof e.swPath=="string"&&e.swPath.trim()!==""?e.swPath:"/sw.js";window.addEventListener("load",()=>{navigator.serviceWorker.register(t).catch(()=>{})},{once:!0})}function ye(e,t){if(t.noCss||document.querySelector('link[data-shell-style="main"]'))return;let n=e?"":A,a=e?`${n}/css/main.css`:`${n}/css/dui.css`,o=document.createElement("link");o.rel="stylesheet",o.href=a,o.setAttribute("data-shell-style","main"),e||(o.crossOrigin="anonymous"),document.head.appendChild(o);let r=document.createElement("link");r.rel="stylesheet",r.href=`${n}/css/font-awesome.min.css`,r.setAttribute("data-shell-style","fa"),r.media="print",r.onload=function(){this.media="all"},e||(r.crossOrigin="anonymous"),document.head.appendChild(r)}function ge(e,t){if(t.favicon===!1)return;let n=e?"/icons/":`${A}/icons/`;document.querySelectorAll('link[rel="icon"], link[rel="shortcut icon"], link[rel="apple-touch-icon"]').forEach(o=>o.remove());let a=[{rel:"icon",type:"image/png",sizes:"96x96",href:`${n}favicon-96x96-transparent.png`},{rel:"icon",type:"image/svg+xml",href:`${n}favicon.svg`},{rel:"apple-touch-icon",sizes:"180x180",href:`${n}apple-touch-icon-180x180-transparent.png`}];e&&a.push({rel:"shortcut icon",href:`${n}favicon-transparent.ico`}),e&&(document.querySelectorAll('link[rel="manifest"]').forEach(o=>o.remove()),a.push({rel:"manifest",href:`${n}site.webmanifest`})),a.forEach(o=>{let r=document.createElement("link");r.rel=o.rel,o.type&&(r.type=o.type),o.sizes&&(r.sizes=o.sizes),r.href=o.href,!e&&o.rel==="manifest"&&(r.crossOrigin="anonymous"),document.head.appendChild(r)})}function Oe(e,t){if(t.showLanguage||e.querySelectorAll('[data-nav-chrome="lang"]').forEach(n=>n.remove()),t.showAppsGrid||e.querySelectorAll('[data-nav-chrome="apps"]').forEach(n=>n.remove()),t.showAccountButton||e.querySelectorAll('[data-nav-chrome="account"]').forEach(n=>n.remove()),t.showThemeToggle||e.querySelectorAll('[data-nav-chrome="theme"]').forEach(n=>n.remove()),!t.showMobileMenu){let n=e.querySelector("#shell-mobile-toggle");if(n){let o=n.closest(".flex-none");o&&o.remove()}let a=e.querySelector("[data-shell-mobile-panel]");a&&a.remove()}}function Ge(e){let t=String(e||"").trim();if(!t)return"#";try{let n=new URL(t,window.location.origin);if(n.protocol==="http:"||n.protocol==="https:")return n.href}catch{}return"#"}function je(e){let t=String(e||"").trim();return!t||!/^[a-z0-9\s_-]+$/i.test(t)?"fa-solid fa-link":t}function de(e,t){let n=e.querySelectorAll("[data-app-menu-grid], [data-apps-grid], [data-apps-grid-mobile]");if(!n.length)return;let a=Array.isArray(t)?t:[];n.forEach(o=>{let r=o.getAttribute("data-app-menu-grid"),c=r==="desktop"||!r&&o.hasAttribute("data-apps-grid")?"p-3":"p-2.5",s=document.createDocumentFragment();for(let l of a){let u=Ge(l?.url),h=je(l?.icon),m=String(l?.name||"App").trim()||"App",d=document.createElement("a");d.href=u,d.className=`group flex flex-col items-center gap-1.5 ${c} rounded-md hover:bg-base-200 transition-colors duration-200 no-underline hover:no-underline text-base-content`;let y=document.createElement("div");y.className="w-10 h-10 rounded-md bg-base-300/50 flex items-center justify-center group-hover:bg-primary/10 group-hover:text-primary transition-colors";let U=document.createElement("i");U.className=`${h} text-lg`;let _=document.createElement("span");_.className="text-[10px] font-medium opacity-70 group-hover:opacity-100",_.textContent=m,y.appendChild(U),d.appendChild(y),d.appendChild(_),s.appendChild(d)}o.replaceChildren(s)})}async function fe(e,t){let n=P(),a=$(n.apps,t);de(e,a);let o=await re(t),r=$(o.apps,t);return de(e,r),r}function ze(e){let t=e.querySelector("[data-shell-mobile-panel]");if(!t)return;let n=e.querySelector("#shell-mobile-toggle"),a=t.querySelector("[data-shell-mobile-backdrop]"),o=t.querySelector("[data-shell-mobile-drawer]"),r=t.querySelector("[data-shell-mobile-close]");function i(){t.classList.remove("hidden"),o.offsetWidth,o.style.transform="translateX(0)",document.body.style.overflow="hidden"}function c(){o.style.transform="translateX(-100%)",document.body.style.overflow="",setTimeout(()=>{t.classList.add("hidden")},300)}n&&n.addEventListener("click",i),a&&a.addEventListener("click",c),r&&r.addEventListener("click",c),document.addEventListener("keydown",s=>{s.key==="Escape"&&!t.classList.contains("hidden")&&c()})}function Fe(e,t){let n=e.querySelector("[data-shell-mobile-panel]");if(!n)return;let a=t?.authenticated===!0,o=t?.user,r=n.querySelector('[data-auth="mobile-guest-avatar"]'),i=n.querySelector('[data-auth="mobile-authed-avatar"]'),c=n.querySelector('[data-auth="mobile-name"]'),s=n.querySelector('[data-auth="mobile-email"]'),l=n.querySelector('[data-auth="mobile-login-btn"]'),u=n.querySelector('[data-auth="mobile-logout-btn"]'),h=n.querySelector('[data-auth="mobile-account-btn"]');if(a&&o){if(r&&r.classList.add("hidden"),i){i.classList.remove("hidden");let m=i.querySelector("img");if(m){let d=o.avatar_url;d?m.src=d:m.removeAttribute("src")}}c&&(c.textContent=o.name||"User"),s&&(s.textContent=o.email||""),l&&l.classList.add("hidden"),u&&u.classList.remove("hidden"),h&&h.classList.remove("hidden")}else r&&r.classList.remove("hidden"),i&&i.classList.add("hidden"),c&&(c.textContent="Guest"),s&&(s.textContent="Not signed in"),l&&l.classList.remove("hidden"),u&&u.classList.add("hidden"),h&&h.classList.add("hidden");u&&(u.onclick=m=>{m.preventDefault();let d=window.AUTH;if(d&&typeof d.logout=="function"){let y=d.logout();y&&typeof y.then=="function"?y.then(()=>window.location.reload()).catch(()=>window.location.reload()):window.location.reload()}}),l&&(l.onclick=m=>{m.preventDefault();let d=window.AUTH;d&&typeof d.login=="function"?d.login():window.location.href="https://auth.dhanur.me"})}function Qe(e){let t=me(),n=pe(),a=!!document.querySelector('link[rel="stylesheet"][href*="/css/main.css"], link[rel="stylesheet"][href*="/css/dui.css"], link[data-shell-style="main"]'),o=!!document.querySelector('link[rel="icon"], link[rel="shortcut icon"], link[rel="apple-touch-icon"]');(!n||!a)&&ye(n,t),(!n||!o)&&ge(n,t),Oe(e,t),fe(e,"guest"),z(),K(e),ce(e),ze(e),Z(e,r=>{let i=r?.role||"guest",c=ee(t,r),s=e.querySelector(".site-nav-slot")||e.querySelector(".drawer-content");if(!c.allowed){s&&te(s,c.reason,document.title||"This app");return}fe(e,i),Fe(e,r)})}async function he(){if(le)return;le=!0;let e=me();if(e.showNavbar===!1)return;He(e);let t=pe();if(document.querySelector(".navbar")){t||Qe(document.body);return}if(!t){ye(!1,e),ge(!1,e);return}}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",he):he();})(); -======= - `; - let l = window.AUTH; - if (t === "admin_required") { - let h = e.querySelector('[data-auth="upgrade-btn"]'); - h && - l && - typeof l.upgrade == "function" && - h.addEventListener("click", (m) => { - (m.preventDefault(), l.upgrade()); - }); - return; - } - let u = e.querySelector('[data-auth="login-btn"]'); - u && - l && - typeof l.login == "function" && - u.addEventListener("click", (h) => { - (h.preventDefault(), l.login()); - }); - } - var Re = "https://up.dhanur.me/api/manifest", - ne = "dhanur_manifest_v1"; - var oe = [ - { - name: "Home", - url: "https://dhanur.me", - icon: "fa-solid fa-house", - minRole: "guest", - }, - { - name: "Linkr", - url: "https://linkr.dhanur.me", - icon: "fa-solid fa-link", - minRole: "guest", - }, - { - name: "Tasks", - url: "https://tasks.dhanur.me", - icon: "fa-solid fa-clipboard-list", - minRole: "guest", - }, - { - name: "Auth", - url: "https://auth.dhanur.me", - icon: "fa-solid fa-fingerprint", - minRole: "guest", - }, - { - name: "Status", - url: "https://up.dhanur.me", - icon: "fa-solid fa-heart-pulse", - minRole: "guest", - category: "Core", - }, - ], - v = null, - E = new Map(); - function $e(e) { - return e === "admin" ? "admin" : e === "user" ? "user" : "guest"; - } - function te(e) { - return e === "admin" ? 2 : e === "user" ? 1 : 0; - } - function Ne() { - try { - let e = localStorage.getItem(ne); - if (!e) return null; - let t = JSON.parse(e); - if (!t || !Array.isArray(t.apps)) return null; - let n = Number(t._cachedAt || 0); - return { ...t, _stale: Date.now() - n > 36e5 }; - } catch { - return null; - } - } - function Be(e) { - try { - localStorage.setItem( - ne, - JSON.stringify({ - version: e.version || "1", - apps: Array.isArray(e.apps) ? e.apps : oe, - _cachedAt: Date.now(), - }), - ); - } catch {} - } - function $() { - if (v && Array.isArray(v.apps)) return v; - let e = Ne(); - return e && Array.isArray(e.apps) - ? ((v = e), e) - : { version: "0", apps: oe, _stale: !0 }; - } - function N(e, t = "guest") { - let n = te(t); - return (Array.isArray(e) ? e : []).filter( - (a) => te(a?.minRole || "guest") <= n, - ); - } - async function ae(e = "guest") { - let t = $e(e); - if (E.has(t)) return E.get(t); - let n = (async () => { - try { - let a = `${Re}?role=${encodeURIComponent(t)}`, - o = await fetch(a, { - credentials: "omit", - mode: "cors", - cache: "no-cache", - }); - if (!o.ok) - throw new Error(`Manifest request failed with status ${o.status}`); - let r = await o.json(); - if (!r || !Array.isArray(r.apps)) - throw new Error("Manifest payload is invalid"); - return ((v = { version: r.version || "1", apps: r.apps }), Be(v), v); - } catch { - return $(); - } - })(); - E.set(t, n); - try { - return await n; - } finally { - E.delete(t); - } - } - var re = !1; - function x() { - document.querySelectorAll("[data-dropdown][data-open]").forEach((e) => { - e.removeAttribute("data-open"); - }); - } - function B() { - return document.querySelector("[data-dropdown][data-open]"); - } - function ie(e) { - let t = e.querySelector(".dropdown-panel"); - if (!t) return; - let n = e.getBoundingClientRect(), - a = t.offsetWidth || 224, - o = (n.width - a) / 2, - r = n.left + o + a - (window.innerWidth - 16); - (r > 0 && (o -= r), - n.left + o < 8 && (o = 8 - n.left), - (t.style.left = `${o}px`), - (t.style.right = "auto")); - } - function Pe(e) { - (x(), e.setAttribute("data-open", ""), ie(e)); - } - function se(e = document) { - let t = e.querySelectorAll("[data-dropdown]"); - t.length && - (t.forEach((n) => { - if (n.getAttribute("data-dropdown-init") === "1") return; - let a = n.querySelector('[role="button"]'); - if (!a) return; - let o = n.querySelector(".dropdown-panel"), - r = - a.classList.contains("tooltip") && - (a.hasAttribute("data-tooltip-label") || - a.hasAttribute("data-tip") || - !!a.querySelector(":scope > .tooltip-content")); - (n.setAttribute("data-dropdown-tooltip", r ? "1" : "0"), - a.addEventListener("click", (i) => { - (i.stopPropagation(), n.hasAttribute("data-open") ? x() : Pe(n)); - }), - o && o.addEventListener("click", (i) => i.stopPropagation()), - n.setAttribute("data-dropdown-init", "1")); - }), - !re && - ((re = !0), - document.addEventListener("click", () => { - B() && x(); - }), - document.addEventListener("keydown", (n) => { - n.key === "Escape" && B() && x(); - }), - window.addEventListener("resize", () => { - let n = B(); - n && ie(n); - }))); - } - var P = { - shellPath: "/navbar/", - favicon: !0, - enablePwa: !0, - swPath: "/sw.js", - requireAuth: !1, - requireAdmin: !1, - showMobileMenu: !0, - showLanguage: !1, - showAppsGrid: !0, - showAccountButton: !0, - showThemeToggle: !1, - }; - typeof window < "u" && - (window.SiteNavConfig = { ...P, ...(window.SiteNavConfig || {}) }); - window.__componentsJS = !0; - var ce = !1, - le = { ...P, noCss: !1, showNavbar: !0 }; - function he() { - let e = H() || {}, - t = e.shell && typeof e.shell == "object" ? e.shell : {}, - n = { ...le, ...e, ...t }; - return ( - (typeof n.shellPath != "string" || n.shellPath.trim() === "") && - (n.shellPath = le.shellPath), - n - ); - } - function me() { - return window.location.origin === A; - } - function Ue(e) { - if ( - e.enablePwa === !1 || - !("serviceWorker" in navigator) || - !window.isSecureContext - ) - return; - let t = - typeof e.swPath == "string" && e.swPath.trim() !== "" - ? e.swPath - : "/sw.js"; - window.addEventListener( - "load", - () => { - navigator.serviceWorker.register(t).catch(() => {}); - }, - { once: !0 }, - ); - } - function pe(e, t) { - if (t.noCss || document.querySelector('link[data-shell-style="main"]')) - return; - let n = e ? "" : A, - a = e ? `${n}/css/main.css` : `${n}/css/dui.css`, - o = document.createElement("link"); - ((o.rel = "stylesheet"), - (o.href = a), - o.setAttribute("data-shell-style", "main"), - e || (o.crossOrigin = "anonymous"), - document.head.appendChild(o)); - let r = document.createElement("link"); - ((r.rel = "stylesheet"), - (r.href = `${n}/css/font-awesome.min.css`), - r.setAttribute("data-shell-style", "fa"), - (r.media = "print"), - (r.onload = function () { - this.media = "all"; - }), - e || (r.crossOrigin = "anonymous"), - document.head.appendChild(r)); - } - function ge(e, t) { - if (t.favicon === !1) return; - let n = e ? "/icons/" : `${A}/icons/`; - document - .querySelectorAll( - 'link[rel="icon"], link[rel="shortcut icon"], link[rel="apple-touch-icon"]', - ) - .forEach((o) => o.remove()); - let a = [ - { - rel: "icon", - type: "image/png", - sizes: "96x96", - href: `${n}favicon-96x96-transparent.png`, - }, - { rel: "icon", type: "image/svg+xml", href: `${n}favicon.svg` }, - { - rel: "apple-touch-icon", - sizes: "180x180", - href: `${n}apple-touch-icon-180x180-transparent.png`, - }, - ]; - (e && a.push({ rel: "shortcut icon", href: `${n}favicon-transparent.ico` }), - e && - (document - .querySelectorAll('link[rel="manifest"]') - .forEach((o) => o.remove()), - a.push({ rel: "manifest", href: `${n}site.webmanifest` })), - a.forEach((o) => { - let r = document.createElement("link"); - ((r.rel = o.rel), - o.type && (r.type = o.type), - o.sizes && (r.sizes = o.sizes), - (r.href = o.href), - !e && o.rel === "manifest" && (r.crossOrigin = "anonymous"), - document.head.appendChild(r)); - })); - } - function He(e, t) { - if ( - (t.showLanguage || - e - .querySelectorAll('[data-nav-chrome="lang"]') - .forEach((n) => n.remove()), - t.showAppsGrid || - e - .querySelectorAll('[data-nav-chrome="apps"]') - .forEach((n) => n.remove()), - t.showAccountButton || - e - .querySelectorAll('[data-nav-chrome="account"]') - .forEach((n) => n.remove()), - t.showThemeToggle || - e - .querySelectorAll('[data-nav-chrome="theme"]') - .forEach((n) => n.remove()), - !t.showMobileMenu) - ) { - let n = e.querySelector("#shell-mobile-toggle"); - if (n) { - let o = n.closest(".flex-none"); - o && o.remove(); - } - let a = e.querySelector("[data-shell-mobile-panel]"); - a && a.remove(); - } - } - function Oe(e) { - let t = String(e || "").trim(); - if (!t) return "#"; - try { - let n = new URL(t, window.location.origin); - if (n.protocol === "http:" || n.protocol === "https:") return n.href; - } catch {} - return "#"; - } - function Ge(e) { - let t = String(e || "").trim(); - return !t || !/^[a-z0-9\s_-]+$/i.test(t) ? "fa-solid fa-link" : t; - } - function ue(e, t) { - let n = e.querySelectorAll( - "[data-app-menu-grid], [data-apps-grid], [data-apps-grid-mobile]", - ); - if (!n.length) return; - let a = Array.isArray(t) ? t : []; - n.forEach((o) => { - let r = o.getAttribute("data-app-menu-grid"), - c = - r === "desktop" || (!r && o.hasAttribute("data-apps-grid")) - ? "p-3" - : "p-2.5", - s = document.createDocumentFragment(); - for (let l of a) { - let u = Oe(l?.url), - h = Ge(l?.icon), - m = String(l?.name || "App").trim() || "App", - d = document.createElement("a"); - ((d.href = u), - (d.className = `group flex flex-col items-center gap-1.5 ${c} rounded-md hover:bg-base-200 transition-colors duration-200 no-underline hover:no-underline text-base-content`)); - let g = document.createElement("div"); - g.className = - "w-10 h-10 rounded-md bg-base-300/50 flex items-center justify-center group-hover:bg-primary/10 group-hover:text-primary transition-colors"; - let U = document.createElement("i"); - U.className = `${h} text-lg`; - let _ = document.createElement("span"); - ((_.className = - "text-[10px] font-medium opacity-70 group-hover:opacity-100"), - (_.textContent = m), - g.appendChild(U), - d.appendChild(g), - d.appendChild(_), - s.appendChild(d)); - } - o.replaceChildren(s); - }); - } - async function de(e, t) { - let n = $(), - a = N(n.apps, t); - ue(e, a); - let o = await ae(t), - r = N(o.apps, t); - return (ue(e, r), r); - } - function je(e) { - let t = e.querySelector("[data-shell-mobile-panel]"); - if (!t) return; - let n = e.querySelector("#shell-mobile-toggle"), - a = t.querySelector("[data-shell-mobile-backdrop]"), - o = t.querySelector("[data-shell-mobile-drawer]"), - r = t.querySelector("[data-shell-mobile-close]"); - function i() { - (t.classList.remove("hidden"), - o.offsetWidth, - (o.style.transform = "translateX(0)"), - (document.body.style.overflow = "hidden")); - } - function c() { - ((o.style.transform = "translateX(-100%)"), - (document.body.style.overflow = ""), - setTimeout(() => { - t.classList.add("hidden"); - }, 300)); - } - (n && n.addEventListener("click", i), - a && a.addEventListener("click", c), - r && r.addEventListener("click", c), - document.addEventListener("keydown", (s) => { - s.key === "Escape" && !t.classList.contains("hidden") && c(); - })); - } - function ze(e, t) { - let n = e.querySelector("[data-shell-mobile-panel]"); - if (!n) return; - let a = t?.authenticated === !0, - o = t?.user, - r = n.querySelector('[data-auth="mobile-guest-avatar"]'), - i = n.querySelector('[data-auth="mobile-authed-avatar"]'), - c = n.querySelector('[data-auth="mobile-name"]'), - s = n.querySelector('[data-auth="mobile-email"]'), - l = n.querySelector('[data-auth="mobile-login-btn"]'), - u = n.querySelector('[data-auth="mobile-logout-btn"]'), - h = n.querySelector('[data-auth="mobile-account-btn"]'); - if (a && o) { - if ((r && r.classList.add("hidden"), i)) { - i.classList.remove("hidden"); - let m = i.querySelector("img"); - if (m) { - let d = o.avatar_url; - d ? (m.src = d) : m.removeAttribute("src"); - } - } - (c && (c.textContent = o.name || "User"), - s && (s.textContent = o.email || ""), - l && l.classList.add("hidden"), - u && u.classList.remove("hidden"), - h && h.classList.remove("hidden")); - } else - (r && r.classList.remove("hidden"), - i && i.classList.add("hidden"), - c && (c.textContent = "Guest"), - s && (s.textContent = "Not signed in"), - l && l.classList.remove("hidden"), - u && u.classList.add("hidden"), - h && h.classList.add("hidden")); - (u && - (u.onclick = (m) => { - m.preventDefault(); - let d = window.AUTH; - if (d && typeof d.logout == "function") { - let g = d.logout(); - g && typeof g.then == "function" - ? g - .then(() => window.location.reload()) - .catch(() => window.location.reload()) - : window.location.reload(); - } - }), - l && - (l.onclick = (m) => { - m.preventDefault(); - let d = window.AUTH; - d && typeof d.login == "function" - ? d.login() - : (window.location.href = "https://auth.dhanur.me"); - })); - } - function Fe(e) { - let t = he(), - n = me(), - a = !!document.querySelector( - 'link[rel="stylesheet"][href*="/css/main.css"], link[rel="stylesheet"][href*="/css/dui.css"], link[data-shell-style="main"]', - ), - o = !!document.querySelector( - 'link[rel="icon"], link[rel="shortcut icon"], link[rel="apple-touch-icon"]', - ); - ((!n || !a) && pe(n, t), - (!n || !o) && ge(n, t), - He(e, t), - de(e, "guest"), - j(), - J(e), - se(e), - je(e), - Y(e, (r) => { - let i = r?.role || "guest", - c = Z(t, r), - s = - e.querySelector(".site-nav-slot") || - e.querySelector(".drawer-content"); - if (!c.allowed) { - s && ee(s, c.reason, document.title || "This app"); - return; - } - (de(e, i), ze(e, r)); - })); - } - async function fe() { - if (ce) return; - ce = !0; - let e = he(); - if (e.showNavbar === !1) return; - Ue(e); - let t = me(); - if (document.querySelector(".navbar")) { - t || Fe(document.body); - return; - } - if (!t) { - (pe(!1, e), ge(!1, e)); - return; - } - } - document.readyState === "loading" - ? document.addEventListener("DOMContentLoaded", fe) - : fe(); -})(); ->>>>>>> main + `;let l=window.AUTH;if(t==="admin_required"){let h=e.querySelector('[data-auth="upgrade-btn"]');h&&l&&typeof l.upgrade=="function"&&h.addEventListener("click",m=>{m.preventDefault(),l.upgrade()});return}let u=e.querySelector('[data-auth="login-btn"]');u&&l&&typeof l.login=="function"&&u.addEventListener("click",h=>{h.preventDefault(),l.login()})}var Re="https://up.dhanur.me/api/manifest",oe="dhanur_manifest_v1";var ae=[{name:"Home",url:"https://dhanur.me",icon:"fa-solid fa-house",minRole:"guest"},{name:"Linkr",url:"https://linkr.dhanur.me",icon:"fa-solid fa-link",minRole:"guest"},{name:"Tasks",url:"https://tasks.dhanur.me",icon:"fa-solid fa-clipboard-list",minRole:"guest"},{name:"Auth",url:"https://auth.dhanur.me",icon:"fa-solid fa-fingerprint",minRole:"guest"},{name:"Status",url:"https://up.dhanur.me",icon:"fa-solid fa-heart-pulse",minRole:"guest",category:"Core"}],v=null,E=new Map;function $e(e){return e==="admin"?"admin":e==="user"?"user":"guest"}function ne(e){return e==="admin"?2:e==="user"?1:0}function Ne(){try{let e=localStorage.getItem(oe);if(!e)return null;let t=JSON.parse(e);if(!t||!Array.isArray(t.apps))return null;let n=Number(t._cachedAt||0);return{...t,_stale:Date.now()-n>36e5}}catch{return null}}function Be(e){try{localStorage.setItem(oe,JSON.stringify({version:e.version||"1",apps:Array.isArray(e.apps)?e.apps:ae,_cachedAt:Date.now()}))}catch{}}function R(){if(v&&Array.isArray(v.apps))return v;let e=Ne();return e&&Array.isArray(e.apps)?(v=e,e):{version:"0",apps:ae,_stale:!0}}function $(e,t="guest"){let n=ne(t);return(Array.isArray(e)?e:[]).filter(a=>ne(a?.minRole||"guest")<=n)}async function re(e="guest"){let t=$e(e);if(E.has(t))return E.get(t);let n=(async()=>{try{let a=`${Re}?role=${encodeURIComponent(t)}`,o=await fetch(a,{credentials:"omit",mode:"cors",cache:"no-cache"});if(!o.ok)throw new Error(`Manifest request failed with status ${o.status}`);let r=await o.json();if(!r||!Array.isArray(r.apps))throw new Error("Manifest payload is invalid");return v={version:r.version||"1",apps:r.apps},Be(v),v}catch{return R()}})();E.set(t,n);try{return await n}finally{E.delete(t)}}var ie=!1;function x(){document.querySelectorAll("[data-dropdown][data-open]").forEach(e=>{e.removeAttribute("data-open")})}function N(){return document.querySelector("[data-dropdown][data-open]")}function se(e){let t=e.querySelector(".dropdown-panel");if(!t)return;let n=e.getBoundingClientRect(),a=t.offsetWidth||224,o=(n.width-a)/2,r=n.left+o+a-(window.innerWidth-16);r>0&&(o-=r),n.left+o<8&&(o=8-n.left),t.style.left=`${o}px`,t.style.right="auto"}function Ue(e){x(),e.setAttribute("data-open",""),se(e)}function ce(e=document){let t=e.querySelectorAll("[data-dropdown]");t.length&&(t.forEach(n=>{if(n.getAttribute("data-dropdown-init")==="1")return;let a=n.querySelector('[role="button"]');if(!a)return;let o=n.querySelector(".dropdown-panel"),r=a.classList.contains("tooltip")&&(a.hasAttribute("data-tooltip-label")||a.hasAttribute("data-tip")||!!a.querySelector(":scope > .tooltip-content"));n.setAttribute("data-dropdown-tooltip",r?"1":"0"),a.addEventListener("click",i=>{i.stopPropagation(),n.hasAttribute("data-open")?x():Ue(n)}),o&&o.addEventListener("click",i=>i.stopPropagation()),n.setAttribute("data-dropdown-init","1")}),!ie&&(ie=!0,document.addEventListener("click",()=>{N()&&x()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&N()&&x()}),window.addEventListener("resize",()=>{let n=N();n&&se(n)})))}var B={shellPath:"/navbar/",favicon:!0,enablePwa:!0,swPath:"/sw.js",requireAuth:!1,requireAdmin:!1,showMobileMenu:!0,showLanguage:!1,showAppsGrid:!0,showAccountButton:!0,showThemeToggle:!1};typeof window<"u"&&(window.SiteNavConfig={...B,...window.SiteNavConfig||{}});G();window.__componentsJS=!0;var le=!1,ue={...B,noCss:!1,showNavbar:!0};function me(){let e=H()||{},t=e.shell&&typeof e.shell=="object"?e.shell:{},n={...ue,...e,...t};return(typeof n.shellPath!="string"||n.shellPath.trim()==="")&&(n.shellPath=ue.shellPath),n}function pe(){return window.location.origin===A}function He(e){if(e.enablePwa===!1||!("serviceWorker"in navigator)||!window.isSecureContext)return;let t=typeof e.swPath=="string"&&e.swPath.trim()!==""?e.swPath:"/sw.js";window.addEventListener("load",()=>{navigator.serviceWorker.register(t).catch(()=>{})},{once:!0})}function ye(e,t){if(t.noCss||document.querySelector('link[data-shell-style="main"]'))return;let n=e?"":A,a=e?`${n}/css/main.css`:`${n}/css/dui.css`,o=document.createElement("link");o.rel="stylesheet",o.href=a,o.setAttribute("data-shell-style","main"),e||(o.crossOrigin="anonymous"),document.head.appendChild(o);let r=document.createElement("link");r.rel="stylesheet",r.href=`${n}/css/font-awesome.min.css`,r.setAttribute("data-shell-style","fa"),r.media="print",r.onload=function(){this.media="all"},e||(r.crossOrigin="anonymous"),document.head.appendChild(r)}function ge(e,t){if(t.favicon===!1)return;let n=e?"/icons/":`${A}/icons/`;document.querySelectorAll('link[rel="icon"], link[rel="shortcut icon"], link[rel="apple-touch-icon"]').forEach(o=>o.remove());let a=[{rel:"icon",type:"image/png",sizes:"96x96",href:`${n}favicon-96x96-transparent.png`},{rel:"icon",type:"image/svg+xml",href:`${n}favicon.svg`},{rel:"apple-touch-icon",sizes:"180x180",href:`${n}apple-touch-icon-180x180-transparent.png`}];e&&a.push({rel:"shortcut icon",href:`${n}favicon-transparent.ico`}),e&&(document.querySelectorAll('link[rel="manifest"]').forEach(o=>o.remove()),a.push({rel:"manifest",href:`${n}site.webmanifest`})),a.forEach(o=>{let r=document.createElement("link");r.rel=o.rel,o.type&&(r.type=o.type),o.sizes&&(r.sizes=o.sizes),r.href=o.href,!e&&o.rel==="manifest"&&(r.crossOrigin="anonymous"),document.head.appendChild(r)})}function Oe(e,t){if(t.showLanguage||e.querySelectorAll('[data-nav-chrome="lang"]').forEach(n=>n.remove()),t.showAppsGrid||e.querySelectorAll('[data-nav-chrome="apps"]').forEach(n=>n.remove()),t.showAccountButton||e.querySelectorAll('[data-nav-chrome="account"]').forEach(n=>n.remove()),t.showThemeToggle||e.querySelectorAll('[data-nav-chrome="theme"]').forEach(n=>n.remove()),!t.showMobileMenu){let n=e.querySelector("#shell-mobile-toggle");if(n){let o=n.closest(".flex-none");o&&o.remove()}let a=e.querySelector("[data-shell-mobile-panel]");a&&a.remove()}}function Ge(e){let t=String(e||"").trim();if(!t)return"#";try{let n=new URL(t,window.location.origin);if(n.protocol==="http:"||n.protocol==="https:")return n.href}catch{}return"#"}function je(e){let t=String(e||"").trim();return!t||!/^[a-z0-9\s_-]+$/i.test(t)?"fa-solid fa-link":t}function de(e,t){let n=e.querySelectorAll("[data-app-menu-grid], [data-apps-grid], [data-apps-grid-mobile]");if(!n.length)return;let a=Array.isArray(t)?t:[];n.forEach(o=>{let r=o.getAttribute("data-app-menu-grid"),c=r==="desktop"||!r&&o.hasAttribute("data-apps-grid")?"p-3":"p-2.5",s=document.createDocumentFragment();for(let l of a){let u=Ge(l?.url),h=je(l?.icon),m=String(l?.name||"App").trim()||"App",d=document.createElement("a");d.href=u,d.className=`group flex flex-col items-center gap-1.5 ${c} rounded-md hover:bg-base-200 transition-colors duration-200 no-underline hover:no-underline text-base-content`;let y=document.createElement("div");y.className="w-10 h-10 rounded-md bg-base-300/50 flex items-center justify-center group-hover:bg-primary/10 group-hover:text-primary transition-colors";let U=document.createElement("i");U.className=`${h} text-lg`;let _=document.createElement("span");_.className="text-[10px] font-medium opacity-70 group-hover:opacity-100",_.textContent=m,y.appendChild(U),d.appendChild(y),d.appendChild(_),s.appendChild(d)}o.replaceChildren(s)})}async function fe(e,t){let n=R(),a=$(n.apps,t);de(e,a);let o=await re(t),r=$(o.apps,t);return de(e,r),r}function ze(e){let t=e.querySelector("[data-shell-mobile-panel]");if(!t)return;let n=e.querySelector("#shell-mobile-toggle"),a=t.querySelector("[data-shell-mobile-backdrop]"),o=t.querySelector("[data-shell-mobile-drawer]"),r=t.querySelector("[data-shell-mobile-close]");function i(){t.classList.remove("hidden"),o.offsetWidth,o.style.transform="translateX(0)",document.body.style.overflow="hidden"}function c(){o.style.transform="translateX(-100%)",document.body.style.overflow="",setTimeout(()=>{t.classList.add("hidden")},300)}n&&n.addEventListener("click",i),a&&a.addEventListener("click",c),r&&r.addEventListener("click",c),document.addEventListener("keydown",s=>{s.key==="Escape"&&!t.classList.contains("hidden")&&c()})}function Fe(e,t){let n=e.querySelector("[data-shell-mobile-panel]");if(!n)return;let a=t?.authenticated===!0,o=t?.user,r=n.querySelector('[data-auth="mobile-guest-avatar"]'),i=n.querySelector('[data-auth="mobile-authed-avatar"]'),c=n.querySelector('[data-auth="mobile-name"]'),s=n.querySelector('[data-auth="mobile-email"]'),l=n.querySelector('[data-auth="mobile-login-btn"]'),u=n.querySelector('[data-auth="mobile-logout-btn"]'),h=n.querySelector('[data-auth="mobile-account-btn"]');if(a&&o){if(r&&r.classList.add("hidden"),i){i.classList.remove("hidden");let m=i.querySelector("img");if(m){let d=o.avatar_url;d?m.src=d:m.removeAttribute("src")}}c&&(c.textContent=o.name||"User"),s&&(s.textContent=o.email||""),l&&l.classList.add("hidden"),u&&u.classList.remove("hidden"),h&&h.classList.remove("hidden")}else r&&r.classList.remove("hidden"),i&&i.classList.add("hidden"),c&&(c.textContent="Guest"),s&&(s.textContent="Not signed in"),l&&l.classList.remove("hidden"),u&&u.classList.add("hidden"),h&&h.classList.add("hidden");u&&(u.onclick=m=>{m.preventDefault();let d=window.AUTH;if(d&&typeof d.logout=="function"){let y=d.logout();y&&typeof y.then=="function"?y.then(()=>window.location.reload()).catch(()=>window.location.reload()):window.location.reload()}}),l&&(l.onclick=m=>{m.preventDefault();let d=window.AUTH;d&&typeof d.login=="function"?d.login():window.location.href="https://auth.dhanur.me"})}function Qe(e){let t=me(),n=pe(),a=!!document.querySelector('link[rel="stylesheet"][href*="/css/main.css"], link[rel="stylesheet"][href*="/css/dui.css"], link[data-shell-style="main"]'),o=!!document.querySelector('link[rel="icon"], link[rel="shortcut icon"], link[rel="apple-touch-icon"]');(!n||!a)&&ye(n,t),(!n||!o)&&ge(n,t),Oe(e,t),fe(e,"guest"),z(),K(e),ce(e),ze(e),Z(e,r=>{let i=r?.role||"guest",c=ee(t,r),s=e.querySelector(".site-nav-slot")||e.querySelector(".drawer-content");if(!c.allowed){s&&te(s,c.reason,document.title||"This app");return}fe(e,i),Fe(e,r)})}async function he(){if(le)return;le=!0;let e=me();if(e.showNavbar===!1)return;He(e);let t=pe();if(document.querySelector(".navbar")){t||Qe(document.body);return}if(!t){ye(!1,e),ge(!1,e);return}}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",he):he();})(); diff --git a/static/js/system/auth-integration.js b/static/js/system/auth-integration.js index d6bd7bc..1f8d177 100644 --- a/static/js/system/auth-integration.js +++ b/static/js/system/auth-integration.js @@ -12,23 +12,22 @@ function getAuthClient() { function once(fn) { let called = false; - return (...args) => { - if (called) return; - called = true; - fn(...args); + let result; + return function (...args) { + if (!called) { + called = true; + result = fn.apply(this, args); + } + return result; }; } -function pickFirst(...nodes) { - return nodes.find(Boolean) || null; -} - function showElements(...elements) { - elements.forEach((el) => el?.classList.remove("hidden")); + elements.forEach((el) => el && el.classList.remove("hidden")); } function hideElements(...elements) { - elements.forEach((el) => el?.classList.add("hidden")); + elements.forEach((el) => el && el.classList.add("hidden")); } function setText(el, value) { @@ -36,21 +35,19 @@ function setText(el, value) { } function setSrc(el, value) { - if (!el) return; - if (value) { - el.src = value; - return; - } - el.removeAttribute("src"); + if (el) el.src = value; } function bindAll(root, selector, eventName, handler, options) { - root.querySelectorAll(selector).forEach((node) => { - node.addEventListener(eventName, handler, options); - }); + const elements = root.querySelectorAll(selector); + elements.forEach((el) => el.addEventListener(eventName, handler, options)); +} + +// function updateCreditsUI(drawerElement, credits) { +function updateCreditsUI() { + // Update credit badges/counters if applicable } -// Auto-inject auth-client.js from auth.dhanur.me function injectAuthSDK(callback) { const done = once(callback); if (getAuthClient()) { @@ -82,66 +79,6 @@ function injectAuthSDK(callback) { }, 2000); } -function formatCreditsReset(periodEnd) { - if (!periodEnd) return ""; - try { - const d = new Date(periodEnd); - const months = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ]; - return `resets ${months[d.getUTCMonth()]} ${d.getUTCDate()}`; - } catch { - return ""; - } -} - -function updateCreditsUI(drawer, credits) { - if (!credits) return; - const isUnlimited = credits.unlimited || credits.balance === -1; - const balanceText = isUnlimited ? "∞" : String(credits.balance); - const resetText = isUnlimited ? "" : formatCreditsReset(credits.periodEnd); - - // Desktop - const creditsRow = drawer.querySelector('[data-auth="credits-row"]'); - if (creditsRow) { - creditsRow.classList.remove("hidden"); - const b = creditsRow.querySelector('[data-auth="credits-balance"]'); - const r = creditsRow.querySelector('[data-auth="credits-reset"]'); - if (b) b.textContent = balanceText; - if (r) r.textContent = resetText; - } - - // Mobile - const sidebarRow = drawer.querySelector('[data-auth="sidebar-credits-row"]'); - if (sidebarRow) { - sidebarRow.classList.remove("hidden"); - const sb = sidebarRow.querySelector( - '[data-auth="sidebar-credits-balance"]', - ); - const sr = sidebarRow.querySelector('[data-auth="sidebar-credits-reset"]'); - if (sb) sb.textContent = balanceText; - if (sr) sr.textContent = resetText; - } -} - -function hideCreditsUI(drawer) { - drawer.querySelector('[data-auth="credits-row"]')?.classList.add("hidden"); - drawer - .querySelector('[data-auth="sidebar-credits-row"]') - ?.classList.add("hidden"); -} - export function initAuth(drawerElement = document, onAuthResolved = null) { if (drawerElement.__authIntegrationBound) return; drawerElement.__authIntegrationBound = true; @@ -150,89 +87,29 @@ export function initAuth(drawerElement = document, onAuthResolved = null) { const auth = getAuthClient(); if (!auth) return; - const navbarRoot = drawerElement.querySelector(".navbar"); - const sidebarRoot = - drawerElement.querySelector("[data-sidebar-root]") || - drawerElement.querySelector("#navigation-drawer"); - const sidebarAccountRoot = drawerElement.querySelector( - "[data-sidebar-account]", - ); - + // DOM references const r = { - navGuestAvatar: pickFirst( - drawerElement.querySelector('[data-auth="nav-guest-avatar"]'), - navbarRoot?.querySelector('[data-dropdown="account"] .bg-base-300'), - ), - navAuthedAvatar: pickFirst( - drawerElement.querySelector('[data-auth="nav-authed-avatar"]'), - navbarRoot?.querySelector('[data-dropdown="account"] .ring-primary'), - ), - navAvatarImg: pickFirst( - drawerElement.querySelector('[data-auth="nav-authed-avatar"] img'), - navbarRoot?.querySelector( - '[data-dropdown="account"] .ring-primary img', - ), - ), - navAuthedHeader: pickFirst( - drawerElement.querySelector('[data-auth="nav-authed-header"]'), - navbarRoot - ?.querySelector('.dropdown-panel [data-auth="nav-name"]') - ?.closest(".border-b"), - ), - navGuestHeader: pickFirst( - drawerElement.querySelector('[data-auth="nav-guest-header"]'), - navbarRoot - ?.querySelector(".dropdown-panel .fa-user") - ?.closest(".border-b"), + navGuestAvatar: drawerElement.querySelector('[data-auth="guest-avatar"]'), + navAuthedAvatar: drawerElement.querySelector( + '[data-auth="authed-avatar"]', ), + navAvatarImg: drawerElement.querySelector('[data-auth="avatar-img"]'), navAuthedHeaderImg: drawerElement.querySelector( - '[data-auth="nav-authed-header-avatar"]', - ), - navName: pickFirst( - drawerElement.querySelector('[data-auth="nav-name"]'), - navbarRoot?.querySelector('[data-auth="name"]'), - ), - navEmail: pickFirst( - drawerElement.querySelector('[data-auth="nav-email"]'), - navbarRoot?.querySelector('[data-auth="email"]'), - ), - navRole: pickFirst( - drawerElement.querySelector('[data-auth="nav-role"]'), - navbarRoot?.querySelector('[data-auth="role"]'), - ), - navLoginItem: - navbarRoot?.querySelector('[data-auth="login-item"]') || null, - navAccountItem: - navbarRoot?.querySelector('[data-auth="account-item"]') || null, - navLogoutItem: - navbarRoot?.querySelector('[data-auth="logout-item"]') || null, - - sidebarGuestAvatar: pickFirst( - drawerElement.querySelector('[data-auth="sidebar-guest-avatar"]'), - sidebarAccountRoot?.querySelector(".bg-base-300"), + '[data-auth="authed-header-img"]', ), - sidebarAuthedAvatar: pickFirst( - drawerElement.querySelector('[data-auth="sidebar-authed-avatar"]'), - sidebarAccountRoot?.querySelector(".ring-primary"), + navName: drawerElement.querySelector('[data-auth="user-name"]'), + navEmail: drawerElement.querySelector('[data-auth="user-email"]'), + navLoginItem: drawerElement.querySelector('[data-auth="nav-login-item"]'), + navAccountItem: drawerElement.querySelector( + '[data-auth="nav-account-item"]', ), - sidebarAvatarImg: pickFirst( - drawerElement.querySelector('[data-auth="sidebar-authed-avatar"] img'), - sidebarAccountRoot?.querySelector(".ring-primary img"), + navLogoutItem: drawerElement.querySelector( + '[data-auth="nav-logout-item"]', ), - sidebarName: pickFirst( - drawerElement.querySelector('[data-auth="sidebar-name"]'), - sidebarAccountRoot?.querySelector(".font-semibold"), + navGuestHeader: drawerElement.querySelector('[data-auth="guest-header"]'), + navAuthedHeader: drawerElement.querySelector( + '[data-auth="authed-header"]', ), - sidebarEmail: pickFirst( - drawerElement.querySelector('[data-auth="sidebar-email"]'), - sidebarAccountRoot?.querySelector(".text-xs.opacity-60"), - ), - sidebarLoginBtn: - sidebarRoot?.querySelector('[data-auth="sidebar-login-btn"]') || null, - sidebarLogoutBtn: - sidebarRoot?.querySelector('[data-auth="sidebar-logout-btn"]') || null, - sidebarAccountBtn: - sidebarRoot?.querySelector('[data-auth="sidebar-account-btn"]') || null, }; function updateUI(status) { @@ -251,53 +128,26 @@ export function initAuth(drawerElement = document, onAuthResolved = null) { r.navLogoutItem, ); setSrc(r.navAvatarImg, avatarUrl); - setSrc(r.navAuthedHeaderImg, avatarUrl); - setText(r.navName, userName); setText(r.navEmail, user.email || ""); - if (r.navRole) { - const role = status.role || "user"; - r.navRole.textContent = role.toUpperCase(); - r.navRole.className = - role === "admin" - ? "badge badge-sm badge-error" - : "badge badge-sm badge-success"; - showElements(r.navRole); + try { + if (avatarUrl) + localStorage.setItem("dhanur_avatar_url_v1", avatarUrl); + } catch { + // err } - hideElements(r.sidebarGuestAvatar, r.sidebarLoginBtn); - showElements( - r.sidebarAuthedAvatar, - r.sidebarLogoutBtn, - r.sidebarAccountBtn, - ); - setSrc(r.sidebarAvatarImg, avatarUrl); - setText(r.sidebarName, userName); - setText(r.sidebarEmail, user.email || ""); - updateCreditsUI(drawerElement, status.credits || null); } else { showElements(r.navGuestAvatar, r.navGuestHeader, r.navLoginItem); hideElements( r.navAuthedAvatar, r.navAuthedHeader, - r.navRole, r.navAccountItem, r.navLogoutItem, ); - - showElements(r.sidebarGuestAvatar, r.sidebarLoginBtn); - hideElements( - r.sidebarAuthedAvatar, - r.sidebarLogoutBtn, - r.sidebarAccountBtn, - ); - setText(r.sidebarName, "Guest"); - setText(r.sidebarEmail, "Not signed in"); - - hideCreditsUI(drawerElement); } if (typeof onAuthResolved === "function") { @@ -305,6 +155,7 @@ export function initAuth(drawerElement = document, onAuthResolved = null) { } } + // Initialize UI on SDK load if (typeof auth.onReady === "function") { auth.onReady((payload) => updateUI(payload?.status || payload || auth.status || null), @@ -313,11 +164,13 @@ export function initAuth(drawerElement = document, onAuthResolved = null) { updateUI(auth.status); } + // Listeners for SDK state changes document.addEventListener("authChanged", (e) => updateUI(e.detail)); document.addEventListener("creditsChanged", (e) => updateCreditsUI(drawerElement, e.detail), ); + // Click Bindings bindAll( drawerElement, '[data-auth="login-btn"], [data-auth="sidebar-login-btn"]', @@ -334,20 +187,47 @@ export function initAuth(drawerElement = document, onAuthResolved = null) { "click", (e) => { e.preventDefault(); - if (typeof auth.logout === "function") { - const result = auth.logout(); - if (result && typeof result.then === "function") { - result - .then(() => window.location.reload()) - .catch((error) => { - console.warn("[Auth] Logout failed:", error); - window.location.reload(); - }); - } else { - window.location.reload(); - } - } + if (typeof auth.logout === "function") auth.logout(); }, ); + + // Intercept cross-origin messages from the OAuth popup + window.addEventListener("message", async (event) => { + const trustedOrigins = ["https://auth.dhanur.me"]; + if (!trustedOrigins.includes(event.origin)) return; + if (!event.data || typeof event.data !== "object") return; + + if (event.data.type === "auth-login-success") { + // Force the SDK to fetch the latest session set by the callback cookies + if (auth && typeof auth.refresh === "function") { + const freshStatus = await auth.refresh(); + updateUI(freshStatus); + } else { + // Fallback manual fetch if the SDK does not expose refresh() + try { + const res = await fetch("https://auth.dhanur.me/api/session", { + credentials: "include", + }); + if (res.ok) { + const data = await res.json(); + updateUI(data); + document.dispatchEvent( + new CustomEvent("authChanged", { detail: data }), + ); + } + } catch (err) { + console.error( + "[Auth] Background session synchronization failed:", + err, + ); + } + } + + // Send confirmation back to popup so it safely terminates + if (event.source) { + event.source.postMessage({ type: "auth-ack-close" }, event.origin); + } + } + }); }); }