@fynd-design-engineering/fynd-one-v2 3.3.60 → 3.3.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../bin/live-reload.js", "../../src/global/popup-video.ts"],
|
|
4
|
-
"sourcesContent": ["// Only enable live reload when running on localhost\nif (\n window.location.hostname === \"localhost\" ||\n window.location.hostname === \"127.0.0.1\"\n) {\n new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener(\"change\", () =>\n location.reload()\n );\n} else {\n // console.log(\"Live reload disabled: not running on localhost\");\n}\n", "// Smooth video modal with GSAP + optional YouTube support\n// Assumes GSAP is loaded via CDN and available as a global `gsap`\n// Loads YouTube IFrame API on demand\n\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n const gsap = (window as any).gsap;\n if (!gsap) {\n console.error(\n \"GSAP is not loaded. Please ensure the GSAP CDN is included.\"\n );\n return;\n }\n\n const wrapper = document.querySelector<HTMLElement>(\n '[data-popup-video=\"wrapper\"]'\n );\n const content = document.querySelector<HTMLElement>(\n '[data-popup-video=\"content\"]'\n );\n const overlay = document.querySelector<HTMLElement>(\n '[data-popup-video=\"overlay\"]'\n );\n\n const openTriggers = document.querySelectorAll<HTMLElement>(\n '[data-popup-video-trigger=\"open\"]'\n );\n const closeTriggers = document.querySelectorAll<HTMLElement>(\n '[data-popup-video-trigger=\"close\"]'\n );\n\n if (!wrapper) console.error('Missing [data-popup-video=\"wrapper\"] element.');\n if (!content) console.error('Missing [data-popup-video=\"content\"] element.');\n if (!overlay) console.error('Missing [data-popup-video=\"overlay\"] element.');\n if (!openTriggers.length)\n console.warn('No [data-popup-video=\"open-trigger\"] elements found.');\n if (!closeTriggers.length)\n console.warn('No [data-popup-video=\"close-trigger\"] elements found.');\n\n if (!wrapper || !content || !overlay) return;\n\n // Initial state\n gsap.set(wrapper, { display: \"none\" });\n gsap.set([overlay, content], { opacity: 0 });\n gsap.set(content, { scale: 0.9 });\n\n // ---------------------------\n // YouTube helpers and state\n // ---------------------------\n let ytPlayer: any | null = null;\n let ytContainer: HTMLDivElement | null = null;\n\n function extractYouTubeId(url: string): string | null {\n try {\n const u = new URL(url);\n if (u.hostname.includes(\"youtube.com\")) {\n // https://www.youtube.com/watch?v=VIDEOID or /embed/VIDEOID\n if (u.searchParams.get(\"v\")) return u.searchParams.get(\"v\");\n const parts = u.pathname.split(\"/\").filter(Boolean);\n const embedIdx = parts.indexOf(\"embed\");\n if (embedIdx !== -1 && parts[embedIdx + 1]) return parts[embedIdx + 1];\n }\n if (u.hostname === \"youtu.be\") {\n const parts = u.pathname.split(\"/\").filter(Boolean);\n if (parts[0]) return parts[0];\n }\n return null;\n } catch {\n return null;\n }\n }\n\n let ytApiReadyPromise: Promise<void> | null = null;\n\n function ensureYouTubeAPI(): Promise<void> {\n if ((window as any).YT && (window as any).YT.Player) {\n return Promise.resolve();\n }\n if (ytApiReadyPromise) return ytApiReadyPromise;\n\n ytApiReadyPromise = new Promise<void>((resolve) => {\n const callbackName = \"onYouTubeIframeAPIReady\";\n const w = window as any;\n\n if (w.YT && w.YT.Player) {\n resolve();\n return;\n }\n\n const script = document.createElement(\"script\");\n script.src = \"https://www.youtube.com/iframe_api\";\n script.async = true;\n\n // If another loader already installed the callback, chain it\n const prev = (w as any)[callbackName];\n (w as any)[callbackName] = function () {\n if (typeof prev === \"function\") prev();\n resolve();\n };\n\n document.head.appendChild(script);\n });\n\n return ytApiReadyPromise;\n }\n\n function removeYouTube(): void {\n if (ytPlayer && typeof ytPlayer.destroy === \"function\") {\n try {\n ytPlayer.stopVideo?.();\n ytPlayer.destroy();\n } catch {}\n }\n ytPlayer = null;\n\n if (ytContainer && ytContainer.parentElement) {\n ytContainer.parentElement.removeChild(ytContainer);\n }\n ytContainer = null;\n }\n\n // ---------------------------\n // HTML5 video helpers\n // ---------------------------\n function removeInjectedVideo(): void {\n if (!content) return;\n const existing = content.querySelector<HTMLVideoElement>(\n 'video[data-popup-video=\"injected\"]'\n );\n if (existing) {\n try {\n existing.pause();\n existing.removeAttribute(\"src\");\n existing.querySelectorAll(\"source\").forEach((s) => s.remove());\n existing.load();\n } catch {}\n existing.remove();\n }\n }\n\n function createVideoElement(\n linkMP4?: string | null,\n linkWebm?: string | null\n ): HTMLVideoElement | null {\n const hasMP4 = !!(linkMP4 && linkMP4.trim());\n const hasWebm = !!(linkWebm && linkWebm.trim());\n\n if (!hasMP4 && !hasWebm) {\n console.error(\n \"openVideoModal requires at least one of linkMP4 or linkWebm when no YouTube URL is provided.\"\n );\n return null;\n }\n\n const video = document.createElement(\"video\");\n video.setAttribute(\"data-popup-video\", \"injected\");\n video.setAttribute(\"playsinline\", \"\");\n video.setAttribute(\"controls\", \"\");\n video.setAttribute(\"autoplay\", \"\");\n // For more reliable autoplay across mobile, consider uncommenting\n // video.muted = true;\n\n if (hasWebm) {\n const s = document.createElement(\"source\");\n s.src = linkWebm!.trim();\n s.type = \"video/webm\";\n video.appendChild(s);\n }\n\n if (hasMP4) {\n const s = document.createElement(\"source\");\n s.src = linkMP4!.trim();\n s.type = \"video/mp4\";\n video.appendChild(s);\n }\n\n return video;\n }\n\n // ---------------------------\n // Modal open and close\n // ---------------------------\n async function openVideoModal(\n linkMP4?: string | null,\n linkWebm?: string | null,\n youtubeUrl?: string | null\n ): Promise<void> {\n if (!wrapper || !content || !overlay) {\n console.error(\"Modal elements missing. Cannot open modal.\");\n return;\n }\n\n // Clean previous media\n removeYouTube();\n removeInjectedVideo();\n\n // Decide mode: YouTube takes precedence if provided\n const useYouTube = !!(youtubeUrl && youtubeUrl.trim());\n let openOk = true;\n\n if (useYouTube) {\n const id = extractYouTubeId(youtubeUrl!.trim());\n if (!id) {\n console.error(\"Invalid YouTube URL on trigger.\");\n openOk = false;\n } else {\n // Prepare container\n ytContainer = document.createElement(\"div\");\n ytContainer.setAttribute(\"data-popup-video\", \"youtube-container\");\n ytContainer.style.width = \"100%\";\n ytContainer.style.aspectRatio = \"16 / 9\";\n content.appendChild(ytContainer);\n\n try {\n await ensureYouTubeAPI();\n // Build the player\n ytPlayer = new (window as any).YT.Player(ytContainer, {\n width: \"100%\",\n height: \"100%\",\n videoId: id,\n playerVars: {\n autoplay: 1,\n controls: 1,\n rel: 0,\n modestbranding: 1,\n playsinline: 1,\n origin: window.location.origin,\n },\n events: {\n onReady: (ev: any) => {\n try {\n // Make sure sound is on\n ev.target.unMute?.();\n ev.target.setVolume?.(100);\n ev.target.playVideo?.();\n } catch {}\n },\n },\n });\n } catch (e) {\n console.error(\"Failed to initialize YouTube player:\", e);\n removeYouTube();\n openOk = false;\n }\n }\n } else {\n // HTML5 video fallback\n const videoEl = createVideoElement(linkMP4, linkWebm);\n if (!videoEl) {\n openOk = false;\n } else {\n content.appendChild(videoEl);\n }\n }\n\n if (!openOk) return;\n\n // Reset starting animation state on each open\n gsap.set([overlay, content], { opacity: 0 });\n gsap.set(content, { scale: 0.9 });\n\n // Show wrapper\n gsap.set(wrapper, { display: \"flex\" });\n\n // Animate overlay in\n gsap.to(overlay, {\n opacity: 1,\n duration: 0.3,\n ease: \"power2.out\",\n });\n\n // Animate content in with 0.2s delay\n gsap.to(content, {\n opacity: 1,\n scale: 1,\n duration: 0.35,\n delay: 0.3,\n ease: \"power2.out\",\n });\n\n console.log(\"Video modal opened.\");\n }\n\n function closeVideoModal(): void {\n if (!wrapper || !content || !overlay) {\n console.error(\"Modal elements missing. Cannot close modal.\");\n return;\n }\n\n // Reverse: fade/scale content down and fade overlay out\n const tl = gsap.timeline({\n defaults: { ease: \"power2.inOut\" },\n onComplete: () => {\n // Remove media after animation completes\n removeYouTube();\n removeInjectedVideo();\n\n gsap.set(wrapper, { display: \"none\" });\n console.log(\"Video modal closed.\");\n },\n });\n\n tl.to(content, { opacity: 0, scale: 0.9, duration: 0.25 }, 0).to(\n overlay,\n { opacity: 0, duration: 0.25 },\n 0\n );\n }\n\n // Bind triggers\n openTriggers.forEach((el) =>\n el.addEventListener(\"click\", () => {\n if (!wrapper) {\n console.error(\"Wrapper not found. Cannot open modal.\");\n return;\n }\n const mp4 = el.getAttribute(\"data-video-mp4\");\n const webm = el.getAttribute(\"data-video-webm\");\n const youtubeUrl = el.getAttribute(\"data-youtube-url\");\n // YouTube takes precedence when provided\n void openVideoModal(mp4, webm, youtubeUrl);\n })\n );\n\n closeTriggers.forEach((el) =>\n el.addEventListener(\"click\", () => {\n if (!wrapper) {\n console.error(\"Wrapper not found. Cannot close modal.\");\n return;\n }\n closeVideoModal();\n })\n );\n\n // Expose to window if you want to call manually\n (window as any).openVideoModal = openVideoModal;\n (window as any).closeVideoModal = closeVideoModal;\n});\n"],
|
|
5
|
-
"mappings": ";;;AACA,MACE,OAAO,SAAS,aAAa,eAC7B,OAAO,SAAS,aAAa,aAC7B;AACA,QAAI,YAAY,GAAG,uBAAY,UAAU,EAAE;AAAA,MAAiB;AAAA,MAAU,MACpE,SAAS,OAAO;AAAA,IAClB;AAAA,EACF,OAAO;AAAA,EAEP;;;
|
|
3
|
+
"sources": ["../../bin/live-reload.js", "../../src/utils/is-staging.ts", "../../src/global/popup-video.ts"],
|
|
4
|
+
"sourcesContent": ["// Only enable live reload when running on localhost\nif (\n window.location.hostname === \"localhost\" ||\n window.location.hostname === \"127.0.0.1\"\n) {\n new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener(\"change\", () =>\n location.reload()\n );\n} else {\n // console.log(\"Live reload disabled: not running on localhost\");\n}\n", "export function IsStaging(): boolean {\n return window.location.hostname === 'fynd-one-master.webflow.io';\n}", "// Smooth video modal with GSAP + optional YouTube support\n// Assumes GSAP is loaded via CDN and available as a global `gsap`\n// Loads YouTube IFrame API on demand\n\nimport { IsStaging } from \"$utils/is-staging\";\n\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n const gsap = (window as any).gsap;\n if (!gsap) {\n console.error(\n \"GSAP is not loaded. Please ensure the GSAP CDN is included.\"\n );\n return;\n }\n\n const wrapper = document.querySelector<HTMLElement>(\n '[data-popup-video=\"wrapper\"]'\n );\n const content = document.querySelector<HTMLElement>(\n '[data-popup-video=\"content\"]'\n );\n const overlay = document.querySelector<HTMLElement>(\n '[data-popup-video=\"overlay\"]'\n );\n\n const openTriggers = document.querySelectorAll<HTMLElement>(\n '[data-popup-video-trigger=\"open\"]'\n );\n const closeTriggers = document.querySelectorAll<HTMLElement>(\n '[data-popup-video-trigger=\"close\"]'\n );\n\n if (IsStaging()) {\n if (!wrapper) console.error('Missing [data-popup-video=\"wrapper\"] element.');\n if (!content) console.error('Missing [data-popup-video=\"content\"] element.');\n if (!overlay) console.error('Missing [data-popup-video=\"overlay\"] element.');\n }\n\n if (!openTriggers.length)\n console.warn('No [data-popup-video=\"open-trigger\"] elements found.');\n if (!closeTriggers.length)\n console.warn('No [data-popup-video=\"close-trigger\"] elements found.');\n\n if (!wrapper || !content || !overlay) return;\n\n // Initial state\n gsap.set(wrapper, { display: \"none\" });\n gsap.set([overlay, content], { opacity: 0 });\n gsap.set(content, { scale: 0.9 });\n\n // ---------------------------\n // YouTube helpers and state\n // ---------------------------\n let ytPlayer: any | null = null;\n let ytContainer: HTMLDivElement | null = null;\n\n function extractYouTubeId(url: string): string | null {\n try {\n const u = new URL(url);\n if (u.hostname.includes(\"youtube.com\")) {\n // https://www.youtube.com/watch?v=VIDEOID or /embed/VIDEOID\n if (u.searchParams.get(\"v\")) return u.searchParams.get(\"v\");\n const parts = u.pathname.split(\"/\").filter(Boolean);\n const embedIdx = parts.indexOf(\"embed\");\n if (embedIdx !== -1 && parts[embedIdx + 1]) return parts[embedIdx + 1];\n }\n if (u.hostname === \"youtu.be\") {\n const parts = u.pathname.split(\"/\").filter(Boolean);\n if (parts[0]) return parts[0];\n }\n return null;\n } catch {\n return null;\n }\n }\n\n let ytApiReadyPromise: Promise<void> | null = null;\n\n function ensureYouTubeAPI(): Promise<void> {\n if ((window as any).YT && (window as any).YT.Player) {\n return Promise.resolve();\n }\n if (ytApiReadyPromise) return ytApiReadyPromise;\n\n ytApiReadyPromise = new Promise<void>((resolve) => {\n const callbackName = \"onYouTubeIframeAPIReady\";\n const w = window as any;\n\n if (w.YT && w.YT.Player) {\n resolve();\n return;\n }\n\n const script = document.createElement(\"script\");\n script.src = \"https://www.youtube.com/iframe_api\";\n script.async = true;\n\n // If another loader already installed the callback, chain it\n const prev = (w as any)[callbackName];\n (w as any)[callbackName] = function () {\n if (typeof prev === \"function\") prev();\n resolve();\n };\n\n document.head.appendChild(script);\n });\n\n return ytApiReadyPromise;\n }\n\n function removeYouTube(): void {\n if (ytPlayer && typeof ytPlayer.destroy === \"function\") {\n try {\n ytPlayer.stopVideo?.();\n ytPlayer.destroy();\n } catch { }\n }\n ytPlayer = null;\n\n if (ytContainer && ytContainer.parentElement) {\n ytContainer.parentElement.removeChild(ytContainer);\n }\n ytContainer = null;\n }\n\n // ---------------------------\n // HTML5 video helpers\n // ---------------------------\n function removeInjectedVideo(): void {\n if (!content) return;\n const existing = content.querySelector<HTMLVideoElement>(\n 'video[data-popup-video=\"injected\"]'\n );\n if (existing) {\n try {\n existing.pause();\n existing.removeAttribute(\"src\");\n existing.querySelectorAll(\"source\").forEach((s) => s.remove());\n existing.load();\n } catch { }\n existing.remove();\n }\n }\n\n function createVideoElement(\n linkMP4?: string | null,\n linkWebm?: string | null\n ): HTMLVideoElement | null {\n const hasMP4 = !!(linkMP4 && linkMP4.trim());\n const hasWebm = !!(linkWebm && linkWebm.trim());\n\n if (!hasMP4 && !hasWebm) {\n console.error(\n \"openVideoModal requires at least one of linkMP4 or linkWebm when no YouTube URL is provided.\"\n );\n return null;\n }\n\n const video = document.createElement(\"video\");\n video.setAttribute(\"data-popup-video\", \"injected\");\n video.setAttribute(\"playsinline\", \"\");\n video.setAttribute(\"controls\", \"\");\n video.setAttribute(\"autoplay\", \"\");\n // For more reliable autoplay across mobile, consider uncommenting\n // video.muted = true;\n\n if (hasWebm) {\n const s = document.createElement(\"source\");\n s.src = linkWebm!.trim();\n s.type = \"video/webm\";\n video.appendChild(s);\n }\n\n if (hasMP4) {\n const s = document.createElement(\"source\");\n s.src = linkMP4!.trim();\n s.type = \"video/mp4\";\n video.appendChild(s);\n }\n\n return video;\n }\n\n // ---------------------------\n // Modal open and close\n // ---------------------------\n async function openVideoModal(\n linkMP4?: string | null,\n linkWebm?: string | null,\n youtubeUrl?: string | null\n ): Promise<void> {\n if (!wrapper || !content || !overlay) {\n console.error(\"Modal elements missing. Cannot open modal.\");\n return;\n }\n\n // Clean previous media\n removeYouTube();\n removeInjectedVideo();\n\n // Decide mode: YouTube takes precedence if provided\n const useYouTube = !!(youtubeUrl && youtubeUrl.trim());\n let openOk = true;\n\n if (useYouTube) {\n const id = extractYouTubeId(youtubeUrl!.trim());\n if (!id) {\n console.error(\"Invalid YouTube URL on trigger.\");\n openOk = false;\n } else {\n // Prepare container\n ytContainer = document.createElement(\"div\");\n ytContainer.setAttribute(\"data-popup-video\", \"youtube-container\");\n ytContainer.style.width = \"100%\";\n ytContainer.style.aspectRatio = \"16 / 9\";\n content.appendChild(ytContainer);\n\n try {\n await ensureYouTubeAPI();\n // Build the player\n ytPlayer = new (window as any).YT.Player(ytContainer, {\n width: \"100%\",\n height: \"100%\",\n videoId: id,\n playerVars: {\n autoplay: 1,\n controls: 1,\n rel: 0,\n modestbranding: 1,\n playsinline: 1,\n origin: window.location.origin,\n },\n events: {\n onReady: (ev: any) => {\n try {\n // Make sure sound is on\n ev.target.unMute?.();\n ev.target.setVolume?.(100);\n ev.target.playVideo?.();\n } catch { }\n },\n },\n });\n } catch (e) {\n console.error(\"Failed to initialize YouTube player:\", e);\n removeYouTube();\n openOk = false;\n }\n }\n } else {\n // HTML5 video fallback\n const videoEl = createVideoElement(linkMP4, linkWebm);\n if (!videoEl) {\n openOk = false;\n } else {\n content.appendChild(videoEl);\n }\n }\n\n if (!openOk) return;\n\n // Reset starting animation state on each open\n gsap.set([overlay, content], { opacity: 0 });\n gsap.set(content, { scale: 0.9 });\n\n // Show wrapper\n gsap.set(wrapper, { display: \"flex\" });\n\n // Animate overlay in\n gsap.to(overlay, {\n opacity: 1,\n duration: 0.3,\n ease: \"power2.out\",\n });\n\n // Animate content in with 0.2s delay\n gsap.to(content, {\n opacity: 1,\n scale: 1,\n duration: 0.35,\n delay: 0.3,\n ease: \"power2.out\",\n });\n\n console.log(\"Video modal opened.\");\n }\n\n function closeVideoModal(): void {\n if (!wrapper || !content || !overlay) {\n console.error(\"Modal elements missing. Cannot close modal.\");\n return;\n }\n\n // Reverse: fade/scale content down and fade overlay out\n const tl = gsap.timeline({\n defaults: { ease: \"power2.inOut\" },\n onComplete: () => {\n // Remove media after animation completes\n removeYouTube();\n removeInjectedVideo();\n\n gsap.set(wrapper, { display: \"none\" });\n console.log(\"Video modal closed.\");\n },\n });\n\n tl.to(content, { opacity: 0, scale: 0.9, duration: 0.25 }, 0).to(\n overlay,\n { opacity: 0, duration: 0.25 },\n 0\n );\n }\n\n // Bind triggers\n openTriggers.forEach((el) =>\n el.addEventListener(\"click\", () => {\n if (!wrapper) {\n console.error(\"Wrapper not found. Cannot open modal.\");\n return;\n }\n const mp4 = el.getAttribute(\"data-video-mp4\");\n const webm = el.getAttribute(\"data-video-webm\");\n const youtubeUrl = el.getAttribute(\"data-youtube-url\");\n // YouTube takes precedence when provided\n void openVideoModal(mp4, webm, youtubeUrl);\n })\n );\n\n closeTriggers.forEach((el) =>\n el.addEventListener(\"click\", () => {\n if (!wrapper) {\n console.error(\"Wrapper not found. Cannot close modal.\");\n return;\n }\n closeVideoModal();\n })\n );\n\n // Expose to window if you want to call manually\n (window as any).openVideoModal = openVideoModal;\n (window as any).closeVideoModal = closeVideoModal;\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../bin/live-reload.js", "../../src/global/geolocation/main.ts", "../../src/global/geolocation/geolocation-cached.ts", "../../src/global/animation/toggle-banner.ts", "../../src/utils/cookies.ts", "../../src/global/screen-type.ts", "../../src/navigation/country-detection/main.ts", "../../src/navigation/initialization.ts"],
|
|
4
|
-
"sourcesContent": ["// Only enable live reload when running on localhost\nif (\n window.location.hostname === \"localhost\" ||\n window.location.hostname === \"127.0.0.1\"\n) {\n new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener(\"change\", () =>\n location.reload()\n );\n} else {\n // console.log(\"Live reload disabled: not running on localhost\");\n}\n", "// Define the type for returned geolocation data\n// Remider for adding Fallback: ipinfo.io (HTTPS, requires token)\nexport type GeoData = {\n ip: string;\n country: string;\n region: string;\n city: string;\n latitude: number;\n longitude: number;\n isp: string;\n timezone: string;\n };\n \n // Exported function that can be reused anywhere\n export async function getGeolocation(): Promise<GeoData | null> {\n try {\n const response = await fetch(\"https://ipwho.is/\");\n if (!response.ok) {\n throw new Error(\"Failed to fetch geolocation\");\n }\n \n const data = await response.json();\n \n if (data.success === false) {\n console.error(\"Geolocation lookup failed:\", data.message);\n return null;\n }\n \n return {\n ip: data.ip,\n country: data.country,\n region: data.region,\n city: data.city,\n latitude: data.latitude,\n longitude: data.longitude,\n isp: data.connection?.isp || \"\",\n timezone: data.timezone?.id || \"\"\n };\n } catch (error) {\n console.error(\"Error fetching geolocation:\", error);\n return null;\n }\n }\n\n //used in /src/navigation/initialization.ts for displaying ip banner", "import { GeoData, getGeolocation } from \"./main\";\n\nconst GEO_CACHE_KEY = \"geo:data:v1\";\nconst GEO_COOKIE_KEY = \"geo_country\";\nconst GEO_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days\n\ntype Cached<T> = { data: T; expiresAt: number };\n\n// --- Cookie helpers ---\nfunction setCookie(name: string, value: string, maxAgeSec: number) {\n document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(\n value\n )}; Max-Age=${maxAgeSec}; Path=/; SameSite=Lax; Secure`;\n}\n\nfunction getCookie(name: string): string | null {\n const key = `${encodeURIComponent(name)}=`;\n const parts = document.cookie.split(\"; \");\n for (const p of parts) {\n if (p.startsWith(key)) return decodeURIComponent(p.slice(key.length));\n }\n return null;\n}\n\nfunction clearCookie(name: string) {\n document.cookie = `${encodeURIComponent(\n name\n )}=; Max-Age=0; Path=/; SameSite=Lax; Secure`;\n}\n\n// --- LocalStorage helpers ---\nfunction readCache<T>(key: string): T | null {\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as Cached<T>;\n if (!parsed?.expiresAt || Date.now() > parsed.expiresAt) {\n localStorage.removeItem(key);\n return null;\n }\n return parsed.data;\n } catch {\n localStorage.removeItem(key);\n return null;\n }\n}\n\nfunction writeCache<T>(key: string, data: T, ttlMs: number) {\n const payload: Cached<T> = { data, expiresAt: Date.now() + ttlMs };\n try {\n localStorage.setItem(key, JSON.stringify(payload));\n } catch {\n // ignore quota errors\n }\n}\n\n// --- Public API ---\nexport async function getGeolocationCached(options?: {\n forceRefresh?: boolean;\n}): Promise<GeoData | null> {\n if (typeof window === \"undefined\") return null;\n\n const forceRefresh = options?.forceRefresh ?? false;\n\n if (!forceRefresh) {\n const cached = readCache<GeoData>(GEO_CACHE_KEY);\n if (cached) {\n (window as any).__GEO = cached;\n if (!getCookie(GEO_COOKIE_KEY)) {\n setCookie(\n GEO_COOKIE_KEY,\n cached.country ?? \"\",\n Math.floor(GEO_TTL_MS / 1000)\n );\n }\n return cached;\n }\n }\n\n // \u2B07\uFE0F changed block starts here\n let geo: GeoData | null = null;\n try {\n geo = await getGeolocation();\n } catch (e) {\n console.warn(\"getGeolocation() failed; defaulting to India:\", e);\n }\n\n if (!geo) {\n // Fallback to India if the fetch failed or returned invalid data\n geo = { country: \"India\" } as GeoData;\n }\n\n writeCache(GEO_CACHE_KEY, geo, GEO_TTL_MS);\n setCookie(GEO_COOKIE_KEY, geo.country ?? \"\", Math.floor(GEO_TTL_MS / 1000));\n (window as any).__GEO = geo;\n return geo;\n // \u2B06\uFE0F changed block ends here\n}\n\nexport function getGeoCountryFromCookie(): string | null {\n return getCookie(GEO_COOKIE_KEY);\n}\n\nexport function clearGeolocationCache() {\n try {\n localStorage.removeItem(GEO_CACHE_KEY);\n } catch {}\n clearCookie(GEO_COOKIE_KEY);\n if (typeof window !== \"undefined\") {\n (window as any).__GEO = undefined;\n }\n}\n", "// toggleBanner.ts\n// Utility functions to open/close a banner using GSAP with optional target height.\n\nexport function openBanner(\n mainSelector: string,\n innerSelector: string,\n targetHeight: string | number = \"auto\" // default stays \"auto\"\n) {\n const w = (window as any) || {};\n const gsap = w.gsap as any;\n if (!gsap) {\n console.warn(\"GSAP not found on window. Did you include it globally?\");\n return;\n }\n\n const mainEl = document.querySelector<HTMLElement>(mainSelector);\n const innerEl = document.querySelector<HTMLElement>(innerSelector);\n\n if (!mainEl || !innerEl) {\n console.warn(\"openBanner: Element(s) not found for selectors:\", {\n mainSelector,\n innerSelector,\n });\n return;\n }\n\n // Ensure clean start\n gsap.set(mainEl, { height: 0, overflow: \"hidden\" });\n gsap.set(innerEl, { opacity: 0 });\n\n const tl = gsap.timeline();\n\n // Animate main from height: 0 -> targetHeight\n tl.to(mainEl, {\n height: targetHeight,\n duration: 0.5,\n ease: \"power2.out\",\n });\n\n // After 0.2s, fade inner to 1\n tl.to(\n innerEl,\n {\n opacity: 1,\n duration: 0.3,\n ease: \"power1.out\",\n },\n 0.2\n );\n\n return tl;\n}\n\nexport function closeBanner(\n mainSelector: string,\n innerSelector: string,\n targetHeight: string | number = 0 // default collapse fully\n) {\n const w = (window as any) || {};\n const gsap = w.gsap as any;\n if (!gsap) {\n console.warn(\"GSAP not found on window. Did you include it globally?\");\n return;\n }\n\n const mainEl = document.querySelector<HTMLElement>(mainSelector);\n const innerEl = document.querySelector<HTMLElement>(innerSelector);\n\n if (!mainEl || !innerEl) {\n console.warn(\"closeBanner: Element(s) not found for selectors:\", {\n mainSelector,\n innerSelector,\n });\n return;\n }\n\n gsap.set(mainEl, { overflow: \"hidden\" });\n\n const tl = gsap.timeline();\n\n // Fade inner out\n tl.to(innerEl, {\n opacity: 0,\n duration: 0.25,\n ease: \"power1.out\",\n });\n\n // Collapse height to targetHeight (default 0)\n tl.to(\n mainEl,\n {\n height: targetHeight,\n duration: 0.45,\n ease: \"power2.inOut\",\n },\n 0.2\n );\n\n return tl;\n}", "export function setCookie(name: string, value: string, hours: number) {\n const date = new Date();\n date.setTime(date.getTime() + hours * 60 * 60 * 1000);\n document.cookie = `${name}=${value}; expires=${date.toUTCString()}; path=/`;\n }\n \n export function getCookie(name: string): string | null {\n const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));\n return match ? match[2] : null;\n }", "// screen-type.ts\n// Utility to get the current screen type\n// Breakpoints:\n// - Desktop: 992px+\n// - Tablet: 768px\u2013991px\n// - Mobile Landscape: 480px\u2013767px\n// - Mobile Portrait: under 480px\n\nexport type ScreenType = \"desktop\" | \"tablet\" | \"mobileLandscape\" | \"mobilePortrait\";\n\nexport function getScreenType(): ScreenType {\n const width = window.innerWidth;\n\n if (width >= 992) {\n return \"desktop\";\n } else if (width >= 768) {\n return \"tablet\";\n } else if (width >= 480) {\n return \"mobileLandscape\";\n } else {\n return \"mobilePortrait\";\n }\n}", "// geo.ts\nimport { getGeoCountryFromCookie, getGeolocationCached } from \"src/global/geolocation/geolocation-cached\";\nimport { GeoData } from \"src/global/geolocation/main\";\n\n/** Your banner config */\ntype CountryConfig = {\n country: string; // canonical lowercase name\n countryCode: string; // ISO-2 lowercase code (e.g., \"in\")\n url: string; // leading-slash path (e.g., \"/in\")\n tagline: string; // banner text/html\n aliases?: string[]; // optional extra names to match against\n};\n\nexport const COUNTRY_CONFIG: CountryConfig[] = [\n {\n country: \"united arab emirates\",\n aliases: [\"uae\", \"u.a.e\", \"united arab emirates\"],\n countryCode: \"ae\",\n url: \"/ae\",\n tagline: \"You're in the UAE. Welcome!\"\n },\n {\n country: \"saudi arabia\",\n aliases: [\"saudi\", \"ksa\", \"kingdom of saudi arabia\"],\n countryCode: \"sa\",\n url: \"/sa\",\n tagline: \"Hello Saudi Arabia!\"\n },\n {\n country: \"south africa\",\n aliases: [\"rsa\"],\n countryCode: \"za\",\n url: \"/za\",\n tagline: \"Hi South Africa!\"\n },\n {\n country: \"malaysia\",\n countryCode: \"my\",\n url: \"/my\",\n tagline: \"Selamat datang, Malaysia!\"\n },\n {\n country: \"indonesia\",\n aliases: [\"idn\"],\n countryCode: \"id\",\n url: \"/id\",\n tagline: \"Halo Indonesia!\"\n },\n {\n country: \"philippines\",\n aliases: [\"phl\", \"the philippines\"],\n countryCode: \"ph\",\n url: \"/ph\",\n tagline: \"Kumusta, Philippines!\"\n },\n {\n country: \"india\",\n aliases: [\"bharat\"],\n countryCode: \"in\",\n url: \"/in\",\n tagline: \"This country is India. Hi some text\"\n },\n // \uD83D\uDC47 fallback\n {\n country: \"global\",\n aliases: [\"global\", \"rest of world\", \"others\"],\n countryCode: \"global\", // keep lowercase for consistency\n url: \"/global\",\n tagline: \"This is rest of world. Hi some text\"\n }\n];\n\n/** Utility: normalize strings for comparisons */\nfunction norm(s: string | null | undefined): string {\n return (s ?? \"\").trim().toLowerCase();\n}\n\n/** Utility: ensure URL starts with a single leading slash */\nfunction toPath(path: string): string {\n const p = path.trim();\n if (!p) return \"/\";\n return p.startsWith(\"/\") ? p : `/${p}`;\n}\n\n/** Determine user's country as a *string* (might be name or code depending on your geo source) */\nexport async function getUserCountry(): Promise<string | null> {\n if (typeof window === \"undefined\") return null;\n\n // 1) Cookie fast-path\n const cookieCountry = getGeoCountryFromCookie();\n if (cookieCountry) return norm(cookieCountry);\n\n // 2) Cached or network\n const geo: GeoData | null = await getGeolocationCached();\n return norm((geo as any)?.country);\n}\n\n/** Find matching config by country *name* or *ISO-2 code* with aliases */\nfunction findCountryConfig(input: string | null): CountryConfig | null {\n const v = norm(input);\n if (!v) return null;\n\n const byCode = COUNTRY_CONFIG.find(c => norm(c.countryCode) === v);\n if (byCode) return byCode;\n\n const byName = COUNTRY_CONFIG.find(c => norm(c.country) === v);\n if (byName) return byName;\n\n const byAlias = COUNTRY_CONFIG.find(c => (c.aliases ?? []).some(a => norm(a) === v));\n if (byAlias) return byAlias;\n\n return null;\n}\n\n/** Helper to fetch the global config */\nfunction getGlobalConfig(): CountryConfig {\n const g = COUNTRY_CONFIG.find(c => c.country === \"global\");\n if (!g) throw new Error(\"[geo-banner] Global config not found in COUNTRY_CONFIG\");\n return g;\n}\n\nfunction updateBannerLink(countryCode?: string | null): void {\n if (typeof window === \"undefined\") return;\n\n const code = norm(countryCode);\n const conf =\n COUNTRY_CONFIG.find(c => norm(c.countryCode) === code) ||\n getGlobalConfig();\n\n const linkEl = document.querySelector<HTMLAnchorElement>('[fynd-banner-field=\"link\"]');\n if (linkEl) {\n const base = window.location.origin;\n linkEl.href = `${base}${toPath(conf.url)}`;\n }\n}\n\nexport function setSelectValueSafely(selectEl: HTMLSelectElement, desired: string) {\n // 1) resolve config\n const conf =\n findCountryConfig(desired) ??\n COUNTRY_CONFIG.find(c => c.country === \"global\");\n if (!conf) {\n console.warn(\"[geo-banner] No matching config for\", desired);\n return false;\n }\n const desiredCode = conf.countryCode; // assume already normalized/lowercase\n\n // 2) find matching option (normalize both sides)\n const opts = Array.from(selectEl.options);\n const opt = opts.find(o => norm(o.value) === norm(desiredCode));\n if (!opt) {\n console.warn(\"[geo-banner] No matching <option> for\", desiredCode, \"on\", selectEl);\n return false;\n }\n\n // 3) update the <select> itself (more reliable than toggling option.selected)\n const prev = selectEl.value;\n selectEl.value = opt.value;\n\n // if some browsers/frameworks didn\u2019t adopt .value, force selectedIndex too\n if (selectEl.value !== opt.value) {\n selectEl.selectedIndex = opts.indexOf(opt);\n }\n\n // 4) (optional) keep options\u2019 selected flags in sync\n opts.forEach(o => (o.selected = o === opt));\n\n // 5) fire events frameworks listen to\n if (prev !== selectEl.value) {\n selectEl.dispatchEvent(new Event(\"input\", { bubbles: true }));\n selectEl.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n\n console.log(\"[geo-banner] Select updated \u2192\", conf.country, \"(\", conf.countryCode, \")\");\n return true;\n}\n\n/** Update the banner content for a given countryCode (lowercase ISO-2) with global fallback */\nexport function updateBannerContent(countryCode?: string | null): void {\n if (typeof window === \"undefined\") return;\n\n const code = norm(countryCode);\n const conf =\n COUNTRY_CONFIG.find(c => norm(c.countryCode) === code) ||\n getGlobalConfig();\n // 1) Set <select fynd-banner-field=\"geoswitch\"> value (robustly)\n const selectEl =\n document.querySelector<HTMLSelectElement>('#geoswitch-select') ||\n document.querySelector<HTMLSelectElement>('[fynd-banner-field=\"geoswitch\"]');\n\n if (selectEl) {\n console.log(`country code is ${conf.countryCode}`)\n setSelectValueSafely(selectEl, conf.countryCode);\n selectEl.value = conf.countryCode; // or \"global\", etc.\n\n selectEl.dispatchEvent(new Event(\"change\", { bubbles: true }));\n } else {\n console.warn('[geo-banner] Select not found: #geoswitch-select / [fynd-banner-field=\"geoswitch\"]');\n }\n\n // // 2) Update banner text (unchanged)\n // const textEl = document.querySelector<HTMLElement>('[fynd-banner-field=\"banner-text\"]');\n // if (textEl) textEl.innerHTML = conf.tagline;\n\n // 3) Update link href (unchanged)\n const linkEl = document.querySelector<HTMLAnchorElement>('[fynd-banner-field=\"link\"]');\n if (linkEl) {\n const base = window.location.origin;\n linkEl.href = `${base}${toPath(conf.url)}`;\n }\n}\n\n/**\n * Main entry: detect country and update banner if it matches one of the configured countries.\n * Always falls back to global if no match is found.\n */\nexport async function initCountryDetection(): Promise<CountryConfig> {\n if (typeof window === \"undefined\") return getGlobalConfig();\n\n if (document.readyState === \"loading\") {\n await new Promise<void>(resolve => {\n document.addEventListener(\"DOMContentLoaded\", () => resolve(), { once: true });\n });\n }\n\n const rawCountry = await getUserCountry();\n const match = findCountryConfig(rawCountry);\n const resolved = match ?? getGlobalConfig();\n\n // Debug visibility\n console.log(\"[geo-banner] rawCountry:\", rawCountry, \"\u2192 resolved:\", resolved.countryCode);\n\n // \u2705 Always update from the resolved config (guarantees global fallback)\n updateBannerContent(resolved.countryCode);\n\n // (If you also attached the select change listener, keep that here)\n const selectEl = document.querySelector<HTMLSelectElement>('[fynd-banner-field=\"geoswitch\"]');\n if (selectEl && !(selectEl as any).__geoHandlerAttached) {\n selectEl.addEventListener(\"change\", (e) => {\n const value = (e.target as HTMLSelectElement).value;\n updateBannerLink(value); // only updates href on change\n });\n (selectEl as any).__geoHandlerAttached = true;\n }\n\n return resolved;\n}", "import { getGeolocationCached } from \"src/global/geolocation/geolocation-cached\";\nimport { closeBanner, openBanner } from \"src/global/animation/toggle-banner\";\nimport { getCookie, setCookie } from \"$utils/cookies\";\nimport { getScreenType } from \"src/global/screen-type\";\nimport { initCountryDetection } from \"./country-detection/main\";\n\n/**\n * Banner rules by route (normalized, no trailing slash).\n * Modes:\n * - { mode: \"always\" }\n * - { mode: \"country\", countries: [...] } \u2192 open if geo.country matches (case-insensitive)\n * - { mode: \"notCountry\", countries: [...] } \u2192 open if geo.country does NOT match\n * - { mode: \"predicate\", test: (geo) => boolean }\n */\nconst bannerRouteRules: Record<\n string,\n | { mode: \"always\" }\n | { mode: \"country\"; countries: string[] }\n | { mode: \"notCountry\"; countries: string[] }\n | { mode: \"predicate\"; test: (geo?: any) => boolean }\n> = {\n \"/global\": { mode: \"country\", countries: [\"India\"] },\n \"/\": { mode: \"notCountry\", countries: [\"India\"] },\n};\n\n// Elements\nconst ipBannerMain = '[fynd-navigation=\"ip-banner\"]';\nconst ipBannerInner = '[fynd-navigation=\"ip-banner-inner\"]';\nconst closeIpBanner = '[fynd-navigation=\"ip-banner-close\"]';\n\nconst announcementBar = document.querySelector(\n '[fynd-navigation=\"announcement-bar\"]'\n);\nconst announcementList = document.querySelector(\n '[fynd-navigation=\"announcement-list\"]'\n);\n\n// Global navigation state\nconst navigationData = {\n ipbanner: {\n visibility: false,\n height: {\n desktop: \"56px\",\n tablet: \"60px\",\n mobileLandscape: \"120px\",\n mobilePortrait: \"120px\",\n },\n },\n announcementbar: {\n visibility: false,\n height: {\n desktop: \"40px\",\n tablet: \"40px\",\n mobileLandscape: \"40px\",\n mobilePortrait: \"46px\",\n },\n },\n default: {\n visibility: true,\n height: {\n desktop: \"70px\",\n tablet: \"64px\",\n mobileLandscape: \"40px\",\n mobilePortrait: \"64px\",\n },\n },\n};\n(window as any).navigationData = navigationData;\n\n// --- Utils -------------------------------------------------------------------\n\nfunction addPx(a: string | number, b: string | number): string {\n const toNumber = (val: string | number): number => {\n if (typeof val === \"number\") return val;\n const num = parseInt(val, 10);\n return isNaN(num) ? 0 : num;\n };\n return `${toNumber(a) + toNumber(b)}px`;\n}\n\nfunction subtractPx(a: string | number, b: string | number): string {\n const toNumber = (val: string | number): number => {\n if (typeof val === \"number\") return val;\n const num = parseInt(val, 10);\n return isNaN(num) ? 0 : num;\n };\n return `${toNumber(a) - toNumber(b)}px`;\n}\n\nconst normalizePath = (p: string) => {\n try {\n const urlPath = p.split(\"?\")[0].split(\"#\")[0];\n if (urlPath === \"/\") return \"/\";\n return urlPath.replace(/\\/+$/, \"\") || \"/\";\n } catch {\n return \"/\";\n }\n};\n\n// Longest-prefix match, so \"/india/offers\" matches \"/india\"\nfunction getMatchingRule(pathname: string) {\n const path = normalizePath(pathname);\n let bestKey = \"\";\n for (const key of Object.keys(bannerRouteRules)) {\n const normKey = normalizePath(key);\n if (path === normKey || path.startsWith(normKey + \"/\")) {\n if (normKey.length > bestKey.length) bestKey = normKey;\n }\n }\n return bestKey ? { key: bestKey, rule: bannerRouteRules[bestKey] } : null;\n}\n\nfunction shouldOpenBannerForPage(pathname: string, geo?: { country?: string }) {\n const match = getMatchingRule(pathname);\n if (!match) return false;\n\n const { rule } = match;\n const visitorCountry = (geo?.country || \"\").toLowerCase();\n\n switch (rule.mode) {\n case \"always\":\n return true;\n case \"country\":\n return rule.countries.some((c) => c.toLowerCase() === visitorCountry);\n case \"notCountry\":\n return !rule.countries.some((c) => c.toLowerCase() === visitorCountry);\n case \"predicate\":\n return !!rule.test?.(geo);\n default:\n return false;\n }\n}\n\n// --- Announcement Bar --------------------------------------------------------\n\nfunction initAnnouncementBar() {\n const swiperEl = document.querySelector<HTMLElement>(\n '[fynd-navigation=\"announcement-swiper\"]'\n );\n\n // Initialize swiper if present\n if (swiperEl && !(swiperEl as any).__swiperInstance) {\n try {\n const Swiper = (window as any).Swiper;\n const swiper = new Swiper(swiperEl, {\n slidesPerView: 1,\n spaceBetween: 0,\n effect: \"fade\",\n fadeEffect: { crossFade: true },\n autoplay: { delay: 3000, disableOnInteraction: false },\n loop: true,\n speed: 1000,\n allowTouchMove: false,\n on: {\n init: function (this: any): void {\n if (\n this.slides.length <= 1 &&\n this.autoplay &&\n typeof this.autoplay.stop === \"function\"\n ) {\n this.autoplay.stop();\n }\n },\n },\n });\n (swiperEl as any).__swiperInstance = swiper;\n } catch (err) {\n console.warn(\"Announcement Swiper init failed:\", err);\n }\n }\n\n // // Visibility & cleanup\n // if (announcementBar && announcementList && announcementList.children.length > 0) {\n // navigationData.announcementbar.visibility = true;\n // } else {\n // navigationData.announcementbar.visibility = false;\n // if (announcementBar && announcementBar.parentNode) {\n // if (swiperEl && (swiperEl as any).__swiperInstance) {\n // (swiperEl as any).__swiperInstance.destroy(true, true);\n // (swiperEl as any).__swiperInstance = undefined;\n // }\n // announcementBar.parentNode.removeChild(announcementBar);\n // }\n // }\n}\n\n// --- Desktop Dropdown Positioning -------------------------------------------\n\nfunction initDesktopDropdownMenu() {\n const selector = '[fynd-navigation=\"dropdown-container\"]';\n const el = document.querySelector<HTMLElement>(selector);\n if (!el) {\n console.warn(`initDesktopDropdownMenu: element not found: ${selector}`);\n return;\n }\n\n const screenType = getScreenType?.() ?? \"unknown\";\n\n // Not desktop \u2192 reset transform\n if (screenType !== \"desktop\") {\n el.style.transition = el.style.transition || \"transform 0.3s ease\";\n el.style.transform = \"translateY(0px)\";\n return;\n }\n\n // Compute total stacked height\n let total = navigationData.default.height?.[screenType];\n let subtractFlag = false;\n\n if (navigationData.announcementbar?.visibility) {\n const h = navigationData.announcementbar.height?.[screenType];\n total = addPx(total, h);\n total = subtractPx(total, \"46px\");\n subtractFlag = true;\n }\n\n if (navigationData.ipbanner?.visibility) {\n // Currently not offsetting desktop for IP banner\n const h = \"0px\";\n total = addPx(total, h);\n if (!subtractFlag) {\n total = subtractPx(total, \"46px\");\n }\n }\n\n // Offset dropdown under nav (minus header overlap 46px)\n el.style.transform = `translateY(${total})`;\n}\n\n// --- Dynamic Spacer ----------------------------------------------------------\n\nfunction initNavigationSpacer() {\n const spacer = document.querySelector<HTMLElement>(\n '[fynd-navigation=\"spacer\"][data-wf--navigation-spacer--variant=\"dynamic\"]'\n );\n\n if (!spacer) {\n console.warn(\"initNavigationSpacer: spacer element not found\");\n return;\n }\n\n const toPx = (v?: string | number): number => {\n if (typeof v === \"number\") return v;\n if (typeof v === \"string\") {\n const n = parseFloat(v);\n return Number.isFinite(n) ? n : 0;\n }\n return 0;\n };\n\n const screenType = getScreenType?.() ?? \"desktop\";\n let total = navigationData.default.height?.[screenType];\n\n if (navigationData.announcementbar?.visibility) {\n const h = navigationData.announcementbar.height?.[screenType];\n total = addPx(total, h);\n }\n\n if (navigationData.ipbanner?.visibility) {\n const h = toPx(navigationData.ipbanner.height?.[screenType]);\n total = addPx(total, h);\n }\n\n spacer.style.height = `${total}`;\n}\n\n// --- IP Banner ---------------------------------------------------------------\n\nasync function initIpBanner() {\n const ipClosed = getCookie(\"ipBannerClosed\") === \"true\";\n if (ipClosed) {\n navigationData.ipbanner.visibility = false;\n return;\n }\n\n const geo = await getGeolocationCached();\n const path = window.location.pathname || \"/\";\n const allowByRoute = shouldOpenBannerForPage(path, geo ?? undefined);\n\n const countryReady = await initCountryDetection();\n\n if (allowByRoute && countryReady) {\n openBanner(\n ipBannerMain,\n ipBannerInner,\n navigationData.ipbanner.height.desktop\n );\n navigationData.ipbanner.visibility = true;\n\n const closeBtn = document.querySelector<HTMLElement>(closeIpBanner);\n if (closeBtn) {\n closeBtn.addEventListener(\"click\", () => {\n closeBanner(ipBannerMain, ipBannerInner);\n setCookie(\"ipBannerClosed\", \"true\", 24);\n navigationData.ipbanner.visibility = false;\n initDesktopDropdownMenu();\n initNavigationSpacer();\n });\n }\n } else {\n navigationData.ipbanner.visibility = false;\n }\n}\n\n// --- Init --------------------------------------------------------------------\n\ndocument.addEventListener(\"DOMContentLoaded\", async () => {\n await initIpBanner();\n initAnnouncementBar();\n initDesktopDropdownMenu();\n initNavigationSpacer();\n});\n"],
|
|
4
|
+
"sourcesContent": ["// Only enable live reload when running on localhost\nif (\n window.location.hostname === \"localhost\" ||\n window.location.hostname === \"127.0.0.1\"\n) {\n new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener(\"change\", () =>\n location.reload()\n );\n} else {\n // console.log(\"Live reload disabled: not running on localhost\");\n}\n", "// Define the type for returned geolocation data\n// Remider for adding Fallback: ipinfo.io (HTTPS, requires token)\nexport type GeoData = {\n ip: string;\n country: string;\n region: string;\n city: string;\n latitude: number;\n longitude: number;\n isp: string;\n timezone: string;\n };\n \n // Exported function that can be reused anywhere\n export async function getGeolocation(): Promise<GeoData | null> {\n try {\n const response = await fetch(\"https://ipwho.is/\");\n if (!response.ok) {\n throw new Error(\"Failed to fetch geolocation\");\n }\n \n const data = await response.json();\n \n if (data.success === false) {\n console.error(\"Geolocation lookup failed:\", data.message);\n return null;\n }\n \n return {\n ip: data.ip,\n country: data.country,\n region: data.region,\n city: data.city,\n latitude: data.latitude,\n longitude: data.longitude,\n isp: data.connection?.isp || \"\",\n timezone: data.timezone?.id || \"\"\n };\n } catch (error) {\n console.error(\"Error fetching geolocation:\", error);\n return null;\n }\n }\n\n //used in /src/navigation/initialization.ts for displaying ip banner", "import { GeoData, getGeolocation } from \"./main\";\n\nconst GEO_CACHE_KEY = \"geo:data:v1\";\nconst GEO_COOKIE_KEY = \"geo_country\";\nconst GEO_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days\n\ntype Cached<T> = { data: T; expiresAt: number };\n\n// --- Cookie helpers ---\nfunction setCookie(name: string, value: string, maxAgeSec: number) {\n document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(\n value\n )}; Max-Age=${maxAgeSec}; Path=/; SameSite=Lax; Secure`;\n}\n\nfunction getCookie(name: string): string | null {\n const key = `${encodeURIComponent(name)}=`;\n const parts = document.cookie.split(\"; \");\n for (const p of parts) {\n if (p.startsWith(key)) return decodeURIComponent(p.slice(key.length));\n }\n return null;\n}\n\nfunction clearCookie(name: string) {\n document.cookie = `${encodeURIComponent(\n name\n )}=; Max-Age=0; Path=/; SameSite=Lax; Secure`;\n}\n\n// --- LocalStorage helpers ---\nfunction readCache<T>(key: string): T | null {\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as Cached<T>;\n if (!parsed?.expiresAt || Date.now() > parsed.expiresAt) {\n localStorage.removeItem(key);\n return null;\n }\n return parsed.data;\n } catch {\n localStorage.removeItem(key);\n return null;\n }\n}\n\nfunction writeCache<T>(key: string, data: T, ttlMs: number) {\n const payload: Cached<T> = { data, expiresAt: Date.now() + ttlMs };\n try {\n localStorage.setItem(key, JSON.stringify(payload));\n } catch {\n // ignore quota errors\n }\n}\n\n// --- Public API ---\nexport async function getGeolocationCached(options?: {\n forceRefresh?: boolean;\n}): Promise<GeoData | null> {\n if (typeof window === \"undefined\") return null;\n\n const forceRefresh = options?.forceRefresh ?? false;\n\n if (!forceRefresh) {\n const cached = readCache<GeoData>(GEO_CACHE_KEY);\n if (cached) {\n (window as any).__GEO = cached;\n if (!getCookie(GEO_COOKIE_KEY)) {\n setCookie(\n GEO_COOKIE_KEY,\n cached.country ?? \"\",\n Math.floor(GEO_TTL_MS / 1000)\n );\n }\n return cached;\n }\n }\n\n // \u2B07\uFE0F changed block starts here\n let geo: GeoData | null = null;\n try {\n geo = await getGeolocation();\n } catch (e) {\n console.warn(\"getGeolocation() failed; defaulting to India:\", e);\n }\n\n if (!geo) {\n // Fallback to India if the fetch failed or returned invalid data\n geo = { country: \"India\" } as GeoData;\n }\n\n writeCache(GEO_CACHE_KEY, geo, GEO_TTL_MS);\n setCookie(GEO_COOKIE_KEY, geo.country ?? \"\", Math.floor(GEO_TTL_MS / 1000));\n (window as any).__GEO = geo;\n return geo;\n // \u2B06\uFE0F changed block ends here\n}\n\nexport function getGeoCountryFromCookie(): string | null {\n return getCookie(GEO_COOKIE_KEY);\n}\n\nexport function clearGeolocationCache() {\n try {\n localStorage.removeItem(GEO_CACHE_KEY);\n } catch {}\n clearCookie(GEO_COOKIE_KEY);\n if (typeof window !== \"undefined\") {\n (window as any).__GEO = undefined;\n }\n}\n", "// toggleBanner.ts\n// Utility functions to open/close a banner using GSAP with optional target height.\n\nexport function openBanner(\n mainSelector: string,\n innerSelector: string,\n targetHeight: string | number = \"auto\" // default stays \"auto\"\n) {\n const w = (window as any) || {};\n const gsap = w.gsap as any;\n if (!gsap) {\n console.warn(\"GSAP not found on window. Did you include it globally?\");\n return;\n }\n\n const mainEl = document.querySelector<HTMLElement>(mainSelector);\n const innerEl = document.querySelector<HTMLElement>(innerSelector);\n\n if (!mainEl || !innerEl) {\n console.warn(\"openBanner: Element(s) not found for selectors:\", {\n mainSelector,\n innerSelector,\n });\n return;\n }\n\n // Ensure clean start\n gsap.set(mainEl, { height: 0, overflow: \"hidden\" });\n gsap.set(innerEl, { opacity: 0 });\n\n const tl = gsap.timeline();\n\n // Animate main from height: 0 -> targetHeight\n tl.to(mainEl, {\n height: targetHeight,\n duration: 0.5,\n ease: \"power2.out\",\n });\n\n // After 0.2s, fade inner to 1\n tl.to(\n innerEl,\n {\n opacity: 1,\n duration: 0.3,\n ease: \"power1.out\",\n },\n 0.2\n );\n\n return tl;\n}\n\nexport function closeBanner(\n mainSelector: string,\n innerSelector: string,\n targetHeight: string | number = 0 // default collapse fully\n) {\n const w = (window as any) || {};\n const gsap = w.gsap as any;\n if (!gsap) {\n console.warn(\"GSAP not found on window. Did you include it globally?\");\n return;\n }\n\n const mainEl = document.querySelector<HTMLElement>(mainSelector);\n const innerEl = document.querySelector<HTMLElement>(innerSelector);\n\n if (!mainEl || !innerEl) {\n console.warn(\"closeBanner: Element(s) not found for selectors:\", {\n mainSelector,\n innerSelector,\n });\n return;\n }\n\n gsap.set(mainEl, { overflow: \"hidden\" });\n\n const tl = gsap.timeline();\n\n // Fade inner out\n tl.to(innerEl, {\n opacity: 0,\n duration: 0.25,\n ease: \"power1.out\",\n });\n\n // Collapse height to targetHeight (default 0)\n tl.to(\n mainEl,\n {\n height: targetHeight,\n duration: 0.45,\n ease: \"power2.inOut\",\n },\n 0.2\n );\n\n return tl;\n}", "export function setCookie(name: string, value: string, hours: number) {\n const date = new Date();\n date.setTime(date.getTime() + hours * 60 * 60 * 1000);\n document.cookie = `${name}=${value}; expires=${date.toUTCString()}; path=/`;\n }\n \n export function getCookie(name: string): string | null {\n const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));\n return match ? match[2] : null;\n }", "// screen-type.ts\n// Utility to get the current screen type\n// Breakpoints:\n// - Desktop: 992px+\n// - Tablet: 768px\u2013991px\n// - Mobile Landscape: 480px\u2013767px\n// - Mobile Portrait: under 480px\n\nexport type ScreenType = \"desktop\" | \"tablet\" | \"mobileLandscape\" | \"mobilePortrait\";\n\nexport function getScreenType(): ScreenType {\n const width = window.innerWidth;\n\n if (width >= 992) {\n return \"desktop\";\n } else if (width >= 768) {\n return \"tablet\";\n } else if (width >= 480) {\n return \"mobileLandscape\";\n } else {\n return \"mobilePortrait\";\n }\n}", "// geo.ts\nimport { getGeoCountryFromCookie, getGeolocationCached } from \"src/global/geolocation/geolocation-cached\";\nimport { GeoData } from \"src/global/geolocation/main\";\n\n/** Your banner config */\ntype CountryConfig = {\n country: string; // canonical lowercase name\n countryCode: string; // ISO-2 lowercase code (e.g., \"in\")\n url: string; // leading-slash path (e.g., \"/in\")\n tagline: string; // banner text/html\n aliases?: string[]; // optional extra names to match against\n};\n\nexport const COUNTRY_CONFIG: CountryConfig[] = [\n {\n country: \"united arab emirates\",\n aliases: [\"uae\", \"u.a.e\", \"united arab emirates\"],\n countryCode: \"ae\",\n url: \"/ae\",\n tagline: \"You're in the UAE. Welcome!\"\n },\n {\n country: \"saudi arabia\",\n aliases: [\"saudi\", \"ksa\", \"kingdom of saudi arabia\"],\n countryCode: \"sa\",\n url: \"/sa\",\n tagline: \"Hello Saudi Arabia!\"\n },\n {\n country: \"south africa\",\n aliases: [\"rsa\"],\n countryCode: \"za\",\n url: \"/za\",\n tagline: \"Hi South Africa!\"\n },\n {\n country: \"malaysia\",\n countryCode: \"my\",\n url: \"/my\",\n tagline: \"Selamat datang, Malaysia!\"\n },\n {\n country: \"indonesia\",\n aliases: [\"idn\"],\n countryCode: \"id\",\n url: \"/id\",\n tagline: \"Halo Indonesia!\"\n },\n {\n country: \"philippines\",\n aliases: [\"phl\", \"the philippines\"],\n countryCode: \"ph\",\n url: \"/ph\",\n tagline: \"Kumusta, Philippines!\"\n },\n {\n country: \"india\",\n aliases: [\"bharat\"],\n countryCode: \"in\",\n url: \"/in\",\n tagline: \"This country is India. Hi some text\"\n },\n // \uD83D\uDC47 fallback\n {\n country: \"global\",\n aliases: [\"global\", \"rest of world\", \"others\"],\n countryCode: \"global\", // keep lowercase for consistency\n url: \"/global\",\n tagline: \"This is rest of world. Hi some text\"\n }\n];\n\n/** Utility: normalize strings for comparisons */\nfunction norm(s: string | null | undefined): string {\n return (s ?? \"\").trim().toLowerCase();\n}\n\n/** Utility: ensure URL starts with a single leading slash */\nfunction toPath(path: string): string {\n const p = path.trim();\n if (!p) return \"/\";\n return p.startsWith(\"/\") ? p : `/${p}`;\n}\n\n/** Determine user's country as a *string* (might be name or code depending on your geo source) */\nexport async function getUserCountry(): Promise<string | null> {\n if (typeof window === \"undefined\") return null;\n\n // 1) Cookie fast-path\n const cookieCountry = getGeoCountryFromCookie();\n if (cookieCountry) return norm(cookieCountry);\n\n // 2) Cached or network\n const geo: GeoData | null = await getGeolocationCached();\n return norm((geo as any)?.country);\n}\n\n/** Find matching config by country *name* or *ISO-2 code* with aliases */\nfunction findCountryConfig(input: string | null): CountryConfig | null {\n const v = norm(input);\n if (!v) return null;\n\n const byCode = COUNTRY_CONFIG.find(c => norm(c.countryCode) === v);\n if (byCode) return byCode;\n\n const byName = COUNTRY_CONFIG.find(c => norm(c.country) === v);\n if (byName) return byName;\n\n const byAlias = COUNTRY_CONFIG.find(c => (c.aliases ?? []).some(a => norm(a) === v));\n if (byAlias) return byAlias;\n\n return null;\n}\n\n/** Helper to fetch the global config */\nfunction getGlobalConfig(): CountryConfig {\n const g = COUNTRY_CONFIG.find(c => c.country === \"global\");\n if (!g) throw new Error(\"[geo-banner] Global config not found in COUNTRY_CONFIG\");\n return g;\n}\n\nfunction updateBannerLink(countryCode?: string | null): void {\n if (typeof window === \"undefined\") return;\n\n const code = norm(countryCode);\n const conf =\n COUNTRY_CONFIG.find(c => norm(c.countryCode) === code) ||\n getGlobalConfig();\n\n const linkEl = document.querySelector<HTMLAnchorElement>('[fynd-banner-field=\"link\"]');\n if (linkEl) {\n const base = window.location.origin;\n linkEl.href = `${base}${toPath(conf.url)}`;\n }\n}\n\nexport function setSelectValueSafely(selectEl: HTMLSelectElement, desired: string) {\n // 1) resolve config\n const conf =\n findCountryConfig(desired) ??\n COUNTRY_CONFIG.find(c => c.country === \"global\");\n if (!conf) {\n console.warn(\"[geo-banner] No matching config for\", desired);\n return false;\n }\n const desiredCode = conf.countryCode; // assume already normalized/lowercase\n\n // 2) find matching option (normalize both sides)\n const opts = Array.from(selectEl.options);\n const opt = opts.find(o => norm(o.value) === norm(desiredCode));\n if (!opt) {\n console.warn(\"[geo-banner] No matching <option> for\", desiredCode, \"on\", selectEl);\n return false;\n }\n\n // 3) update the <select> itself (more reliable than toggling option.selected)\n const prev = selectEl.value;\n selectEl.value = opt.value;\n\n // if some browsers/frameworks didn\u2019t adopt .value, force selectedIndex too\n if (selectEl.value !== opt.value) {\n selectEl.selectedIndex = opts.indexOf(opt);\n }\n\n // 4) (optional) keep options\u2019 selected flags in sync\n opts.forEach(o => (o.selected = o === opt));\n\n // 5) fire events frameworks listen to\n if (prev !== selectEl.value) {\n selectEl.dispatchEvent(new Event(\"input\", { bubbles: true }));\n selectEl.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n\n console.log(\"[geo-banner] Select updated \u2192\", conf.country, \"(\", conf.countryCode, \")\");\n return true;\n}\n\n/** Update the banner content for a given countryCode (lowercase ISO-2) with global fallback */\nexport function updateBannerContent(countryCode?: string | null): void {\n if (typeof window === \"undefined\") return;\n\n const code = norm(countryCode);\n const conf =\n COUNTRY_CONFIG.find(c => norm(c.countryCode) === code) ||\n getGlobalConfig();\n // 1) Set <select fynd-banner-field=\"geoswitch\"> value (robustly)\n const selectEl =\n document.querySelector<HTMLSelectElement>('#geoswitch-select') ||\n document.querySelector<HTMLSelectElement>('[fynd-banner-field=\"geoswitch\"]');\n\n if (selectEl) {\n console.log(`country code is ${conf.countryCode}`)\n setSelectValueSafely(selectEl, conf.countryCode);\n selectEl.value = conf.countryCode; // or \"global\", etc.\n\n selectEl.dispatchEvent(new Event(\"change\", { bubbles: true }));\n } else {\n console.warn('[geo-banner] Select not found: #geoswitch-select / [fynd-banner-field=\"geoswitch\"]');\n }\n\n // // 2) Update banner text (unchanged)\n // const textEl = document.querySelector<HTMLElement>('[fynd-banner-field=\"banner-text\"]');\n // if (textEl) textEl.innerHTML = conf.tagline;\n\n // 3) Update link href (unchanged)\n const linkEl = document.querySelector<HTMLAnchorElement>('[fynd-banner-field=\"link\"]');\n if (linkEl) {\n const base = window.location.origin;\n linkEl.href = `${base}${toPath(conf.url)}`;\n }\n}\n\n/**\n * Main entry: detect country and update banner if it matches one of the configured countries.\n * Always falls back to global if no match is found.\n */\nexport async function initCountryDetection(): Promise<CountryConfig> {\n if (typeof window === \"undefined\") return getGlobalConfig();\n\n if (document.readyState === \"loading\") {\n await new Promise<void>(resolve => {\n document.addEventListener(\"DOMContentLoaded\", () => resolve(), { once: true });\n });\n }\n\n const rawCountry = await getUserCountry();\n const match = findCountryConfig(rawCountry);\n const resolved = match ?? getGlobalConfig();\n\n // Debug visibility\n console.log(\"[geo-banner] rawCountry:\", rawCountry, \"\u2192 resolved:\", resolved.countryCode);\n\n // \u2705 Always update from the resolved config (guarantees global fallback)\n updateBannerContent(resolved.countryCode);\n\n // (If you also attached the select change listener, keep that here)\n const selectEl = document.querySelector<HTMLSelectElement>('[fynd-banner-field=\"geoswitch\"]');\n if (selectEl && !(selectEl as any).__geoHandlerAttached) {\n selectEl.addEventListener(\"change\", (e) => {\n const value = (e.target as HTMLSelectElement).value;\n updateBannerLink(value); // only updates href on change\n });\n (selectEl as any).__geoHandlerAttached = true;\n }\n\n return resolved;\n}", "import { getGeolocationCached } from \"src/global/geolocation/geolocation-cached\";\nimport { closeBanner, openBanner } from \"src/global/animation/toggle-banner\";\nimport { getCookie, setCookie } from \"$utils/cookies\";\nimport { getScreenType } from \"src/global/screen-type\";\nimport { initCountryDetection } from \"./country-detection/main\";\n\n/**\n * Banner rules by route (normalized, no trailing slash).\n * Modes:\n * - { mode: \"always\" }\n * - { mode: \"country\", countries: [...] } \u2192 open if geo.country matches (case-insensitive)\n * - { mode: \"notCountry\", countries: [...] } \u2192 open if geo.country does NOT match\n * - { mode: \"predicate\", test: (geo) => boolean }\n */\nconst bannerRouteRules: Record<\n string,\n | { mode: \"always\" }\n | { mode: \"country\"; countries: string[] }\n | { mode: \"notCountry\"; countries: string[] }\n | { mode: \"predicate\"; test: (geo?: any) => boolean }\n> = {\n \"/global\": { mode: \"country\", countries: [\"India\"] },\n \"/\": { mode: \"notCountry\", countries: [\"India\"] },\n};\n\n// Elements\nconst ipBannerMain = '[fynd-navigation=\"ip-banner\"]';\nconst ipBannerInner = '[fynd-navigation=\"ip-banner-inner\"]';\nconst closeIpBanner = '[fynd-navigation=\"ip-banner-close\"]';\n\nconst announcementBar = document.querySelector(\n '[fynd-navigation=\"announcement-bar\"]'\n);\nconst announcementList = document.querySelector(\n '[fynd-navigation=\"announcement-list\"]'\n);\n\n// Global navigation state\nconst navigationData = {\n ipbanner: {\n visibility: false,\n height: {\n desktop: \"56px\",\n tablet: \"60px\",\n mobileLandscape: \"120px\",\n mobilePortrait: \"120px\",\n },\n },\n announcementbar: {\n visibility: true,\n height: {\n desktop: \"40px\",\n tablet: \"40px\",\n mobileLandscape: \"40px\",\n mobilePortrait: \"46px\",\n },\n },\n default: {\n visibility: true,\n height: {\n desktop: \"70px\",\n tablet: \"64px\",\n mobileLandscape: \"40px\",\n mobilePortrait: \"64px\",\n },\n },\n};\n(window as any).navigationData = navigationData;\n\n// --- Utils -------------------------------------------------------------------\n\nfunction addPx(a: string | number, b: string | number): string {\n const toNumber = (val: string | number): number => {\n if (typeof val === \"number\") return val;\n const num = parseInt(val, 10);\n return isNaN(num) ? 0 : num;\n };\n return `${toNumber(a) + toNumber(b)}px`;\n}\n\nfunction subtractPx(a: string | number, b: string | number): string {\n const toNumber = (val: string | number): number => {\n if (typeof val === \"number\") return val;\n const num = parseInt(val, 10);\n return isNaN(num) ? 0 : num;\n };\n return `${toNumber(a) - toNumber(b)}px`;\n}\n\nconst normalizePath = (p: string) => {\n try {\n const urlPath = p.split(\"?\")[0].split(\"#\")[0];\n if (urlPath === \"/\") return \"/\";\n return urlPath.replace(/\\/+$/, \"\") || \"/\";\n } catch {\n return \"/\";\n }\n};\n\n// Longest-prefix match, so \"/india/offers\" matches \"/india\"\nfunction getMatchingRule(pathname: string) {\n const path = normalizePath(pathname);\n let bestKey = \"\";\n for (const key of Object.keys(bannerRouteRules)) {\n const normKey = normalizePath(key);\n if (path === normKey || path.startsWith(normKey + \"/\")) {\n if (normKey.length > bestKey.length) bestKey = normKey;\n }\n }\n return bestKey ? { key: bestKey, rule: bannerRouteRules[bestKey] } : null;\n}\n\nfunction shouldOpenBannerForPage(pathname: string, geo?: { country?: string }) {\n const match = getMatchingRule(pathname);\n if (!match) return false;\n\n const { rule } = match;\n const visitorCountry = (geo?.country || \"\").toLowerCase();\n\n switch (rule.mode) {\n case \"always\":\n return true;\n case \"country\":\n return rule.countries.some((c) => c.toLowerCase() === visitorCountry);\n case \"notCountry\":\n return !rule.countries.some((c) => c.toLowerCase() === visitorCountry);\n case \"predicate\":\n return !!rule.test?.(geo);\n default:\n return false;\n }\n}\n\n// --- Announcement Bar --------------------------------------------------------\n\nfunction initAnnouncementBar() {\n const swiperEl = document.querySelector<HTMLElement>(\n '[fynd-navigation=\"announcement-swiper\"]'\n );\n\n // Initialize swiper if present\n if (swiperEl && !(swiperEl as any).__swiperInstance) {\n try {\n const Swiper = (window as any).Swiper;\n const swiper = new Swiper(swiperEl, {\n slidesPerView: 1,\n spaceBetween: 0,\n effect: \"fade\",\n fadeEffect: { crossFade: true },\n autoplay: { delay: 3000, disableOnInteraction: false },\n loop: true,\n speed: 1000,\n allowTouchMove: false,\n on: {\n init: function (this: any): void {\n if (\n this.slides.length <= 1 &&\n this.autoplay &&\n typeof this.autoplay.stop === \"function\"\n ) {\n this.autoplay.stop();\n }\n },\n },\n });\n (swiperEl as any).__swiperInstance = swiper;\n } catch (err) {\n console.warn(\"Announcement Swiper init failed:\", err);\n }\n }\n\n // // Visibility & cleanup\n // if (announcementBar && announcementList && announcementList.children.length > 0) {\n // navigationData.announcementbar.visibility = true;\n // } else {\n // navigationData.announcementbar.visibility = false;\n // if (announcementBar && announcementBar.parentNode) {\n // if (swiperEl && (swiperEl as any).__swiperInstance) {\n // (swiperEl as any).__swiperInstance.destroy(true, true);\n // (swiperEl as any).__swiperInstance = undefined;\n // }\n // announcementBar.parentNode.removeChild(announcementBar);\n // }\n // }\n}\n\n// --- Desktop Dropdown Positioning -------------------------------------------\n\nfunction initDesktopDropdownMenu() {\n const selector = '[fynd-navigation=\"dropdown-container\"]';\n const el = document.querySelector<HTMLElement>(selector);\n if (!el) {\n console.warn(`initDesktopDropdownMenu: element not found: ${selector}`);\n return;\n }\n\n const screenType = getScreenType?.() ?? \"unknown\";\n\n // Not desktop \u2192 reset transform\n if (screenType !== \"desktop\") {\n el.style.transition = el.style.transition || \"transform 0.3s ease\";\n el.style.transform = \"translateY(0px)\";\n return;\n }\n\n // Compute total stacked height\n let total = navigationData.default.height?.[screenType];\n let subtractFlag = false;\n\n if (navigationData.announcementbar?.visibility) {\n const h = navigationData.announcementbar.height?.[screenType];\n total = addPx(total, h);\n total = subtractPx(total, \"46px\");\n subtractFlag = true;\n }\n\n if (navigationData.ipbanner?.visibility) {\n // Currently not offsetting desktop for IP banner\n const h = \"0px\";\n total = addPx(total, h);\n if (!subtractFlag) {\n total = subtractPx(total, \"46px\");\n }\n }\n\n // Offset dropdown under nav (minus header overlap 46px)\n el.style.transform = `translateY(${total})`;\n}\n\n// --- Dynamic Spacer ----------------------------------------------------------\n\nfunction initNavigationSpacer() {\n const spacer = document.querySelector<HTMLElement>(\n '[fynd-navigation=\"spacer\"][data-wf--navigation-spacer--variant=\"dynamic\"]'\n );\n\n if (!spacer) {\n console.warn(\"initNavigationSpacer: spacer element not found\");\n return;\n }\n\n const toPx = (v?: string | number): number => {\n if (typeof v === \"number\") return v;\n if (typeof v === \"string\") {\n const n = parseFloat(v);\n return Number.isFinite(n) ? n : 0;\n }\n return 0;\n };\n\n const screenType = getScreenType?.() ?? \"desktop\";\n let total = navigationData.default.height?.[screenType];\n\n if (navigationData.announcementbar?.visibility) {\n const h = navigationData.announcementbar.height?.[screenType];\n total = addPx(total, h);\n }\n\n if (navigationData.ipbanner?.visibility) {\n const h = toPx(navigationData.ipbanner.height?.[screenType]);\n total = addPx(total, h);\n }\n\n spacer.style.height = `${total}`;\n}\n\n// --- IP Banner ---------------------------------------------------------------\n\nasync function initIpBanner() {\n const ipClosed = getCookie(\"ipBannerClosed\") === \"true\";\n if (ipClosed) {\n navigationData.ipbanner.visibility = false;\n return;\n }\n\n const geo = await getGeolocationCached();\n const path = window.location.pathname || \"/\";\n const allowByRoute = shouldOpenBannerForPage(path, geo ?? undefined);\n\n const countryReady = await initCountryDetection();\n\n if (allowByRoute && countryReady) {\n openBanner(\n ipBannerMain,\n ipBannerInner,\n navigationData.ipbanner.height.desktop\n );\n navigationData.ipbanner.visibility = true;\n\n const closeBtn = document.querySelector<HTMLElement>(closeIpBanner);\n if (closeBtn) {\n closeBtn.addEventListener(\"click\", () => {\n closeBanner(ipBannerMain, ipBannerInner);\n setCookie(\"ipBannerClosed\", \"true\", 24);\n navigationData.ipbanner.visibility = false;\n initDesktopDropdownMenu();\n initNavigationSpacer();\n });\n }\n } else {\n navigationData.ipbanner.visibility = false;\n }\n}\n\n// --- Init --------------------------------------------------------------------\n\ndocument.addEventListener(\"DOMContentLoaded\", async () => {\n await initIpBanner();\n initAnnouncementBar();\n initDesktopDropdownMenu();\n initNavigationSpacer();\n});\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["setCookie", "getCookie", "getCookie", "setCookie"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../bin/live-reload.js", "../../src/tracking/custom-id.ts"],
|
|
4
|
-
"sourcesContent": ["// Only enable live reload when running on localhost\nif (\n window.location.hostname === \"localhost\" ||\n window.location.hostname === \"127.0.0.1\"\n) {\n new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener(\"change\", () =>\n location.reload()\n );\n} else {\n // console.log(\"Live reload disabled: not running on localhost\");\n}\n", "const COOKIE_RID = \"user-id\";\n\nfunction setCookie(name: string, value: string, days = 365): void {\n const expires = new Date(Date.now() + days * 864e5).toUTCString();\n const secure = location.protocol === \"https:\" ? \"; Secure\" : \"\";\n document.cookie = `${name}=${encodeURIComponent(value)}; Expires=${expires}; Path=/; SameSite=Lax${secure}`;\n}\n\nfunction getCookie(name: string): string | null {\n const match = document.cookie.match(new RegExp(\"(^| )\" + name + \"=([^;]+)\"));\n return match ? decodeURIComponent(match[2]) : null;\n}\n\nfunction getOrCreateStableRid(): string {\n let rid = getCookie(COOKIE_RID);\n if (rid) return rid;\n\n if (crypto && \"randomUUID\" in crypto) {\n rid = crypto.randomUUID();\n } else {\n rid = `rid_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;\n }\n\n setCookie(COOKIE_RID, rid, 365 * 5);\n console.log(\"Created new RID:\", rid);\n return rid;\n}\n\n(window as any).getRid = function (): string {\n return getOrCreateStableRid();\n};\n\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n const rid = getOrCreateStableRid();\n console.log(\"RID ready:\", rid);\n\n // --- 1. Add RID to console.fynd.com links ---\n const links = document.querySelectorAll<HTMLAnchorElement>(\n 'a[href*=\"console.fynd.com\"], a[href^=\"https://console.fynd.com/\"], a[href=\"https://console.fynd.com\"]'\n );\n\n links.forEach(link => {\n try {\n const url = new URL(link.href);\n url.searchParams.set(\"referrer_uuid\", rid);\n link.href = url.toString();\n } catch (err) {\n console.warn(\"Invalid URL in link:\", link.href);\n }\n });\n\n // --- 2. Fill RID into input#UUID if it exists ---\n const uuidInput = document.getElementById(\"UUID\") as HTMLInputElement | null;\n if (uuidInput) {\n uuidInput.value = rid;\n console.log(\"Filled UUID input with RID:\", rid);\n }\n});"],
|
|
5
|
-
"mappings": ";;;AACA,MACE,OAAO,SAAS,aAAa,eAC7B,OAAO,SAAS,aAAa,aAC7B;AACA,QAAI,YAAY,GAAG,uBAAY,UAAU,EAAE;AAAA,MAAiB;AAAA,MAAU,MACpE,SAAS,OAAO;AAAA,IAClB;AAAA,EACF,OAAO;AAAA,EAEP;;;ACVA,MAAM,aAAa;AAEnB,WAAS,UAAU,MAAc,OAAe,OAAO,KAAW;AAC9D,UAAM,UAAU,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,EAAE,YAAY;AAChE,UAAM,SAAS,SAAS,aAAa,WAAW,aAAa;AAC7D,aAAS,SAAS,GAAG,IAAI,IAAI,mBAAmB,KAAK,CAAC,aAAa,OAAO,yBAAyB,MAAM;AAAA,EAC7G;AAEA,WAAS,UAAU,MAA6B;AAC5C,UAAM,QAAQ,SAAS,OAAO,MAAM,IAAI,OAAO,UAAU,OAAO,UAAU,CAAC;AAC3E,WAAO,QAAQ,mBAAmB,MAAM,CAAC,CAAC,IAAI;AAAA,EAClD;AAEA,WAAS,uBAA+B;AACpC,QAAI,MAAM,UAAU,UAAU;AAC9B,QAAI,IAAK,QAAO;AAEhB,QAAI,UAAU,gBAAgB,QAAQ;AAClC,YAAM,OAAO,WAAW;AAAA,IAC5B,OAAO;AACH,YAAM,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,IACtE;AAEA,cAAU,YAAY,KAAK,MAAM,CAAC;AAClC,YAAQ,IAAI,oBAAoB,GAAG;AACnC,WAAO;AAAA,EACX;AAEA,EAAC,OAAe,SAAS,WAAoB;AACzC,WAAO,qBAAqB;AAAA,EAChC;AAEA,WAAS,iBAAiB,oBAAoB,MAAM;AAChD,UAAM,MAAM,qBAAqB;
|
|
4
|
+
"sourcesContent": ["// Only enable live reload when running on localhost\nif (\n window.location.hostname === \"localhost\" ||\n window.location.hostname === \"127.0.0.1\"\n) {\n new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener(\"change\", () =>\n location.reload()\n );\n} else {\n // console.log(\"Live reload disabled: not running on localhost\");\n}\n", "const COOKIE_RID = \"user-id\";\n\nfunction setCookie(name: string, value: string, days = 365): void {\n const expires = new Date(Date.now() + days * 864e5).toUTCString();\n const secure = location.protocol === \"https:\" ? \"; Secure\" : \"\";\n document.cookie = `${name}=${encodeURIComponent(value)}; Expires=${expires}; Path=/; SameSite=Lax${secure}`;\n}\n\nfunction getCookie(name: string): string | null {\n const match = document.cookie.match(new RegExp(\"(^| )\" + name + \"=([^;]+)\"));\n return match ? decodeURIComponent(match[2]) : null;\n}\n\nfunction getOrCreateStableRid(): string {\n let rid = getCookie(COOKIE_RID);\n if (rid) return rid;\n\n if (crypto && \"randomUUID\" in crypto) {\n rid = crypto.randomUUID();\n } else {\n rid = `rid_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;\n }\n\n setCookie(COOKIE_RID, rid, 365 * 5);\n console.log(\"Created new RID:\", rid);\n return rid;\n}\n\n(window as any).getRid = function (): string {\n return getOrCreateStableRid();\n};\n\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n const rid = getOrCreateStableRid();\n // console.log(\"RID ready:\", rid);\n\n // --- 1. Add RID to console.fynd.com links ---\n const links = document.querySelectorAll<HTMLAnchorElement>(\n 'a[href*=\"console.fynd.com\"], a[href^=\"https://console.fynd.com/\"], a[href=\"https://console.fynd.com\"]'\n );\n\n links.forEach(link => {\n try {\n const url = new URL(link.href);\n url.searchParams.set(\"referrer_uuid\", rid);\n link.href = url.toString();\n } catch (err) {\n console.warn(\"Invalid URL in link:\", link.href);\n }\n });\n\n // --- 2. Fill RID into input#UUID if it exists ---\n const uuidInput = document.getElementById(\"UUID\") as HTMLInputElement | null;\n if (uuidInput) {\n uuidInput.value = rid;\n // console.log(\"Filled UUID input with RID:\", rid);\n }\n});"],
|
|
5
|
+
"mappings": ";;;AACA,MACE,OAAO,SAAS,aAAa,eAC7B,OAAO,SAAS,aAAa,aAC7B;AACA,QAAI,YAAY,GAAG,uBAAY,UAAU,EAAE;AAAA,MAAiB;AAAA,MAAU,MACpE,SAAS,OAAO;AAAA,IAClB;AAAA,EACF,OAAO;AAAA,EAEP;;;ACVA,MAAM,aAAa;AAEnB,WAAS,UAAU,MAAc,OAAe,OAAO,KAAW;AAC9D,UAAM,UAAU,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,EAAE,YAAY;AAChE,UAAM,SAAS,SAAS,aAAa,WAAW,aAAa;AAC7D,aAAS,SAAS,GAAG,IAAI,IAAI,mBAAmB,KAAK,CAAC,aAAa,OAAO,yBAAyB,MAAM;AAAA,EAC7G;AAEA,WAAS,UAAU,MAA6B;AAC5C,UAAM,QAAQ,SAAS,OAAO,MAAM,IAAI,OAAO,UAAU,OAAO,UAAU,CAAC;AAC3E,WAAO,QAAQ,mBAAmB,MAAM,CAAC,CAAC,IAAI;AAAA,EAClD;AAEA,WAAS,uBAA+B;AACpC,QAAI,MAAM,UAAU,UAAU;AAC9B,QAAI,IAAK,QAAO;AAEhB,QAAI,UAAU,gBAAgB,QAAQ;AAClC,YAAM,OAAO,WAAW;AAAA,IAC5B,OAAO;AACH,YAAM,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,IACtE;AAEA,cAAU,YAAY,KAAK,MAAM,CAAC;AAClC,YAAQ,IAAI,oBAAoB,GAAG;AACnC,WAAO;AAAA,EACX;AAEA,EAAC,OAAe,SAAS,WAAoB;AACzC,WAAO,qBAAqB;AAAA,EAChC;AAEA,WAAS,iBAAiB,oBAAoB,MAAM;AAChD,UAAM,MAAM,qBAAqB;AAIjC,UAAM,QAAQ,SAAS;AAAA,MACnB;AAAA,IACJ;AAEA,UAAM,QAAQ,UAAQ;AAClB,UAAI;AACA,cAAM,MAAM,IAAI,IAAI,KAAK,IAAI;AAC7B,YAAI,aAAa,IAAI,iBAAiB,GAAG;AACzC,aAAK,OAAO,IAAI,SAAS;AAAA,MAC7B,SAAS,KAAK;AACV,gBAAQ,KAAK,wBAAwB,KAAK,IAAI;AAAA,MAClD;AAAA,IACJ,CAAC;AAGD,UAAM,YAAY,SAAS,eAAe,MAAM;AAChD,QAAI,WAAW;AACX,gBAAU,QAAQ;AAAA,IAEtB;AAAA,EACJ,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED