@oddsmith/ui 1.0.3 → 1.0.5

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.
@@ -46,7 +46,7 @@
46
46
  "hero": {
47
47
  "bannerAsset": {
48
48
  "uuid": "banner-1",
49
- "createdTs": "2026-06-22T09:00:06.011Z",
49
+ "createdTs": "2026-06-23T18:02:55.151Z",
50
50
  "name": "midnight-millions-banner",
51
51
  "label": "Midnight Millions",
52
52
  "comment": "",
@@ -57,7 +57,7 @@
57
57
  },
58
58
  "title": "Midnight Millions",
59
59
  "description": "Climb the board before the timer hits zero.",
60
- "endTs": "2026-06-25T09:00:06.012Z",
60
+ "endTs": "2026-06-27T08:02:55.152Z",
61
61
  "status": "active",
62
62
  "prizePoolValue": 124500,
63
63
  "prizePoolCurrency": "USD"
@@ -2,5 +2,5 @@
2
2
  "version": 1,
3
3
  "component": "os-leaderboard-casino",
4
4
  "tier": "free",
5
- "generatedAt": "2026-06-22T09:00:06.012Z"
5
+ "generatedAt": "2026-06-23T18:02:55.152Z"
6
6
  }
@@ -83,7 +83,7 @@
83
83
  "hero": {
84
84
  "bannerAsset": {
85
85
  "uuid": "banner-1",
86
- "createdTs": "2026-06-22T09:00:06.011Z",
86
+ "createdTs": "2026-06-23T18:02:55.151Z",
87
87
  "name": "midnight-millions-banner",
88
88
  "label": "Midnight Millions",
89
89
  "comment": "",
@@ -94,7 +94,7 @@
94
94
  },
95
95
  "title": "Midnight Millions",
96
96
  "description": "Climb the board before the timer hits zero.",
97
- "endTs": "2026-06-25T09:00:06.012Z",
97
+ "endTs": "2026-06-27T08:02:55.152Z",
98
98
  "status": "active",
99
99
  "prizePoolValue": 124500,
100
100
  "prizePoolCurrency": "USD"
@@ -1,4 +1,4 @@
1
- const e = { config: { appearance: "glam", themeId: "glam-default", labels: { back: "Return", live: "Live", cta: "Enter the Leaderboard" }, enabled: ["marquee", "events", "hero", "prize", "stats", "games", "climb", "table", "footer", "legals"], mainOrder: ["prize", "stats", "games", "climb", "table"], themeVars: { "--os-casino-font-display": "'Sora', system-ui, sans-serif", "--os-casino-font-body": "'Inter', system-ui, sans-serif", "--os-casino-font-mono": "ui-monospace, 'JetBrains Mono', monospace", "--os-casino-bg": "#181622", "--os-casino-bg-2": "#181622" } }, sections: { marquee: { items: [{ id: "mq-1", gameId: "slot-machine", text: "krakenbet won $4,200 on Mega Fortune", amount: 4200, currency: "USD", vip: !0 }, { id: "mq-2", gameId: "roulette", text: "marisol_v won $1,800 on Lightning Roulette", amount: 1800, currency: "USD" }, { id: "mq-3", gameId: "cards", text: "mr_midnight won $9,600 on VIP Baccarat", amount: 9600, currency: "USD", vip: !0 }], speedSec: 32 }, events: { events: [{ id: "event-1", title: "Double points weekend", subtitle: "All slots count 2× toward the board", accent: "gold" }, { id: "event-2", title: "High roller boost", subtitle: "Tables over $500 qualify for bonus tiers", accent: "violet" }] }, hero: { bannerAsset: { uuid: "banner-1", createdTs: "2026-06-22T09:00:06.011Z", name: "midnight-millions-banner", label: "Midnight Millions", comment: "", url: "", tags: [], type: "GAME", sportType: "casino" }, title: "Midnight Millions", description: "Climb the board before the timer hits zero.", endTs: "2026-06-25T09:00:06.012Z", status: "active", prizePoolValue: 124500, prizePoolCurrency: "USD" }, prize: { prizePackage: { uuid: "prize-package-1", name: "Midnight Millions", prizes: [{ uuid: "prize-1", label: { values: [{ value: "Grand Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Grand Jackpot" }, value: 5e4, currency: "USD", rankFrom: 1, rankTo: 1 }, { uuid: "prize-2", label: { values: [{ value: "Major Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Major Jackpot" }, value: 25e3, currency: "USD", rankFrom: 2, rankTo: 2 }, { uuid: "prize-3", label: { values: [{ value: "Mini Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Mini Jackpot" }, value: 1e4, currency: "USD", rankFrom: 3, rankTo: 3 }, { uuid: "prize-4", label: { values: [{ value: "Casino Credits", language: "en" }], labelType: "ON_DEMAND", enValue: "Casino Credits" }, value: 1e3, currency: "USD", rankFrom: 4, rankTo: 4 }, { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, { uuid: "prize-6", label: { values: [{ value: "Mystery Bonus Drop", language: "en" }], labelType: "ON_DEMAND", enValue: "Mystery Bonus Drop" }, value: 100, currency: "USD", rankFrom: 11, rankTo: 200 }] }, allocationStrategy: "BEST_PRIZE" }, stats: { totalParticipants: 12842, totalPrizes: 6, biggestWin: 9600, biggestWinCurrency: "USD" }, games: { games: [{ id: "chips", title: "Golden Chips", boost: "2×" }, { id: "cards", title: "VIP Baccarat", boost: "1.5×" }, { id: "slot-machine", title: "Mega Fortune", boost: "2×" }, { id: "roulette", title: "Lightning Roulette", boost: "1.5×" }, { id: "dice", title: "Crystal Dice", boost: "1.2×" }, { id: "gates-of-olympus", title: "Gates of Olympus", boost: "3×" }] }, climb: { username: "deep_cut", rank: 17, points: 28460, nextTierRank: 10, nextTierLabel: "Free Spins ×25", pointsToNextTier: 1240, progress: 0.62, trend: 3 }, table: { mode: "preview", topPlayers: [{ username: "krakenbet", rank: 1, points: 184200, totalBet: 14200, prize: { uuid: "prize-1", label: { values: [{ value: "Grand Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Grand Jackpot" }, value: 5e4, currency: "USD", rankFrom: 1, rankTo: 1 }, splitCount: 1, you: !1, vip: !0, previousRank: 3, winRate: 68, gamesPlayed: 182 }, { username: "marisol_v", rank: 2, points: 129718, totalBet: 12800, prize: { uuid: "prize-2", label: { values: [{ value: "Major Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Major Jackpot" }, value: 25e3, currency: "USD", rankFrom: 2, rankTo: 2 }, splitCount: 1, you: !1, previousRank: 4, winRate: 64, gamesPlayed: 168 }, { username: "mr_midnight", rank: 3, points: 100109, totalBet: 11500, prize: { uuid: "prize-3", label: { values: [{ value: "Mini Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Mini Jackpot" }, value: 1e4, currency: "USD", rankFrom: 3, rankTo: 3 }, splitCount: 1, you: !1, vip: !0, previousRank: 2, winRate: 61, gamesPlayed: 155 }, { username: "piotr_k", rank: 4, points: 81504, totalBet: 10200, prize: { uuid: "prize-4", label: { values: [{ value: "Casino Credits", language: "en" }], labelType: "ON_DEMAND", enValue: "Casino Credits" }, value: 1e3, currency: "USD", rankFrom: 4, rankTo: 4 }, splitCount: 1, you: !1, vip: !0, previousRank: 1, winRate: 58, gamesPlayed: 144 }, { username: "bl4ze77", rank: 5, points: 68731, totalBet: 9100, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, previousRank: 6, winRate: 56, gamesPlayed: 138 }, { username: "ghostchip", rank: 6, points: 59419, totalBet: 8200, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, previousRank: 5, winRate: 54, gamesPlayed: 127 }, { username: "LunaX", rank: 7, points: 52330, totalBet: 7400, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, vip: !0, previousRank: 10, winRate: 51, gamesPlayed: 119 }, { username: "soyuz3", rank: 8, points: 46751, totalBet: 6600, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, previousRank: 7, winRate: 49, gamesPlayed: 113 }, { username: "NovaBet", rank: 9, points: 42248, totalBet: 5800, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, previousRank: 9, winRate: 47, gamesPlayed: 106 }, { username: "tundra_rex", rank: 10, points: 38536, totalBet: 5e3, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, previousRank: 8, winRate: 44, gamesPlayed: 98 }], currentUser: { username: "deep_cut", rank: 17, points: 28460, totalBet: 3200, prize: { uuid: "prize-6", label: { values: [{ value: "Mystery Bonus Drop", language: "en" }], labelType: "ON_DEMAND", enValue: "Mystery Bonus Drop" }, value: 100, currency: "USD", rankFrom: 11, rankTo: 200 }, splitCount: 1, you: !0, previousRank: 20, winRate: 48, gamesPlayed: 31 }, ctaLabel: "Enter the Leaderboard" }, footer: { text: "Unused powered by oddsmith.io" }, legals: { links: [{ type: "internal", label: "Rules" }, { type: "internal", label: "FAQ" }, { type: "external", label: "Terms & Conditions", href: "https://www.google.com" }] } } }, a = {
1
+ const e = { config: { appearance: "glam", themeId: "glam-default", labels: { back: "Return", live: "Live", cta: "Enter the Leaderboard" }, enabled: ["marquee", "events", "hero", "prize", "stats", "games", "climb", "table", "footer", "legals"], mainOrder: ["prize", "stats", "games", "climb", "table"], themeVars: { "--os-casino-font-display": "'Sora', system-ui, sans-serif", "--os-casino-font-body": "'Inter', system-ui, sans-serif", "--os-casino-font-mono": "ui-monospace, 'JetBrains Mono', monospace", "--os-casino-bg": "#181622", "--os-casino-bg-2": "#181622" } }, sections: { marquee: { items: [{ id: "mq-1", gameId: "slot-machine", text: "krakenbet won $4,200 on Mega Fortune", amount: 4200, currency: "USD", vip: !0 }, { id: "mq-2", gameId: "roulette", text: "marisol_v won $1,800 on Lightning Roulette", amount: 1800, currency: "USD" }, { id: "mq-3", gameId: "cards", text: "mr_midnight won $9,600 on VIP Baccarat", amount: 9600, currency: "USD", vip: !0 }], speedSec: 32 }, events: { events: [{ id: "event-1", title: "Double points weekend", subtitle: "All slots count 2× toward the board", accent: "gold" }, { id: "event-2", title: "High roller boost", subtitle: "Tables over $500 qualify for bonus tiers", accent: "violet" }] }, hero: { bannerAsset: { uuid: "banner-1", createdTs: "2026-06-23T18:02:55.151Z", name: "midnight-millions-banner", label: "Midnight Millions", comment: "", url: "", tags: [], type: "GAME", sportType: "casino" }, title: "Midnight Millions", description: "Climb the board before the timer hits zero.", endTs: "2026-06-27T08:02:55.152Z", status: "active", prizePoolValue: 124500, prizePoolCurrency: "USD" }, prize: { prizePackage: { uuid: "prize-package-1", name: "Midnight Millions", prizes: [{ uuid: "prize-1", label: { values: [{ value: "Grand Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Grand Jackpot" }, value: 5e4, currency: "USD", rankFrom: 1, rankTo: 1 }, { uuid: "prize-2", label: { values: [{ value: "Major Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Major Jackpot" }, value: 25e3, currency: "USD", rankFrom: 2, rankTo: 2 }, { uuid: "prize-3", label: { values: [{ value: "Mini Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Mini Jackpot" }, value: 1e4, currency: "USD", rankFrom: 3, rankTo: 3 }, { uuid: "prize-4", label: { values: [{ value: "Casino Credits", language: "en" }], labelType: "ON_DEMAND", enValue: "Casino Credits" }, value: 1e3, currency: "USD", rankFrom: 4, rankTo: 4 }, { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, { uuid: "prize-6", label: { values: [{ value: "Mystery Bonus Drop", language: "en" }], labelType: "ON_DEMAND", enValue: "Mystery Bonus Drop" }, value: 100, currency: "USD", rankFrom: 11, rankTo: 200 }] }, allocationStrategy: "BEST_PRIZE" }, stats: { totalParticipants: 12842, totalPrizes: 6, biggestWin: 9600, biggestWinCurrency: "USD" }, games: { games: [{ id: "chips", title: "Golden Chips", boost: "2×" }, { id: "cards", title: "VIP Baccarat", boost: "1.5×" }, { id: "slot-machine", title: "Mega Fortune", boost: "2×" }, { id: "roulette", title: "Lightning Roulette", boost: "1.5×" }, { id: "dice", title: "Crystal Dice", boost: "1.2×" }, { id: "gates-of-olympus", title: "Gates of Olympus", boost: "3×" }] }, climb: { username: "deep_cut", rank: 17, points: 28460, nextTierRank: 10, nextTierLabel: "Free Spins ×25", pointsToNextTier: 1240, progress: 0.62, trend: 3 }, table: { mode: "preview", topPlayers: [{ username: "krakenbet", rank: 1, points: 184200, totalBet: 14200, prize: { uuid: "prize-1", label: { values: [{ value: "Grand Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Grand Jackpot" }, value: 5e4, currency: "USD", rankFrom: 1, rankTo: 1 }, splitCount: 1, you: !1, vip: !0, previousRank: 3, winRate: 68, gamesPlayed: 182 }, { username: "marisol_v", rank: 2, points: 129718, totalBet: 12800, prize: { uuid: "prize-2", label: { values: [{ value: "Major Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Major Jackpot" }, value: 25e3, currency: "USD", rankFrom: 2, rankTo: 2 }, splitCount: 1, you: !1, previousRank: 4, winRate: 64, gamesPlayed: 168 }, { username: "mr_midnight", rank: 3, points: 100109, totalBet: 11500, prize: { uuid: "prize-3", label: { values: [{ value: "Mini Jackpot", language: "en" }], labelType: "ON_DEMAND", enValue: "Mini Jackpot" }, value: 1e4, currency: "USD", rankFrom: 3, rankTo: 3 }, splitCount: 1, you: !1, vip: !0, previousRank: 2, winRate: 61, gamesPlayed: 155 }, { username: "piotr_k", rank: 4, points: 81504, totalBet: 10200, prize: { uuid: "prize-4", label: { values: [{ value: "Casino Credits", language: "en" }], labelType: "ON_DEMAND", enValue: "Casino Credits" }, value: 1e3, currency: "USD", rankFrom: 4, rankTo: 4 }, splitCount: 1, you: !1, vip: !0, previousRank: 1, winRate: 58, gamesPlayed: 144 }, { username: "bl4ze77", rank: 5, points: 68731, totalBet: 9100, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, previousRank: 6, winRate: 56, gamesPlayed: 138 }, { username: "ghostchip", rank: 6, points: 59419, totalBet: 8200, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, previousRank: 5, winRate: 54, gamesPlayed: 127 }, { username: "LunaX", rank: 7, points: 52330, totalBet: 7400, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, vip: !0, previousRank: 10, winRate: 51, gamesPlayed: 119 }, { username: "soyuz3", rank: 8, points: 46751, totalBet: 6600, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, previousRank: 7, winRate: 49, gamesPlayed: 113 }, { username: "NovaBet", rank: 9, points: 42248, totalBet: 5800, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, previousRank: 9, winRate: 47, gamesPlayed: 106 }, { username: "tundra_rex", rank: 10, points: 38536, totalBet: 5e3, prize: { uuid: "prize-5", label: { values: [{ value: "Free Spins ×25", language: "en" }], labelType: "ON_DEMAND", enValue: "Free Spins ×25" }, value: 250, currency: "USD", rankFrom: 5, rankTo: 10 }, splitCount: 1, you: !1, previousRank: 8, winRate: 44, gamesPlayed: 98 }], currentUser: { username: "deep_cut", rank: 17, points: 28460, totalBet: 3200, prize: { uuid: "prize-6", label: { values: [{ value: "Mystery Bonus Drop", language: "en" }], labelType: "ON_DEMAND", enValue: "Mystery Bonus Drop" }, value: 100, currency: "USD", rankFrom: 11, rankTo: 200 }, splitCount: 1, you: !0, previousRank: 20, winRate: 48, gamesPlayed: 31 }, ctaLabel: "Enter the Leaderboard" }, footer: { text: "Unused powered by oddsmith.io" }, legals: { links: [{ type: "internal", label: "Rules" }, { type: "internal", label: "FAQ" }, { type: "external", label: "Terms & Conditions", href: "https://www.google.com" }] } } }, a = {
2
2
  golden: e
3
3
  };
4
4
  export {
@@ -1,11 +1,12 @@
1
- import { getBundleDefaultPresetId as u, getOsLeaderboardCasinoPreset as a, resolvePresetState as f, getBundleLabels as b, getThemeVars as g, getTheme as p, resolveAssetsBundle as m } from "./assets-context.js";
2
- import { LEADERBOARD_CASINO_PRESET_CATALOG as z } from "./assets-context.js";
1
+ import { getBundleDefaultPresetId as a, getOsLeaderboardCasinoPreset as f, resolvePresetState as b, getBundleLabels as h, getThemeVars as g, getTheme as p, resolveAssetsBundle as m } from "./assets-context.js";
2
+ import { LEADERBOARD_CASINO_PRESET_CATALOG as U } from "./assets-context.js";
3
3
  import { resolveBackgroundVars as P } from "../theme/background.js";
4
- function h(e, n, r, s) {
5
- const o = e.branding?.themeId;
6
- return !o || p(o, s).appearance !== n ? r : o;
4
+ import { refreshPresetHeroCountdown as C } from "../utils/demo-countdown.js";
5
+ function k(e, n, r, t) {
6
+ const s = e.branding?.themeId;
7
+ return !s || p(s, t).appearance !== n ? r : s;
7
8
  }
8
- function d(e) {
9
+ function c(e) {
9
10
  return {
10
11
  username: e.username,
11
12
  rank: e.rank,
@@ -16,7 +17,7 @@ function d(e) {
16
17
  you: e.isCurrentUser ?? !1
17
18
  };
18
19
  }
19
- function c(e) {
20
+ function u(e) {
20
21
  const n = e.winnings ?? e.points ?? 0;
21
22
  return {
22
23
  id: e.id ?? `player-${e.rank}`,
@@ -31,7 +32,7 @@ function c(e) {
31
32
  badges: []
32
33
  };
33
34
  }
34
- function k(e, n) {
35
+ function v(e, n) {
35
36
  n && (e.sections.hero && (e.sections.hero = {
36
37
  ...e.sections.hero,
37
38
  ...n.title != null ? { title: n.title } : {},
@@ -48,56 +49,67 @@ function k(e, n) {
48
49
  text: n.footerText
49
50
  }));
50
51
  }
51
- function C(e, n) {
52
+ function w(e, n) {
52
53
  if (!n?.length || !e.sections.table) return;
53
- const r = [...n].sort((o, t) => o.rank - t.rank), s = r.find((o) => o.isCurrentUser) ?? r.find((o) => o.username.toLowerCase() === "you");
54
+ const r = [...n].sort((s, i) => s.rank - i.rank), t = r.find((s) => s.isCurrentUser) ?? r.find((s) => s.username.toLowerCase() === "you");
54
55
  if (e.config.appearance === "glam" && e.sections.table.mode === "preview") {
55
56
  e.sections.table = {
56
57
  ...e.sections.table,
57
- topPlayers: r.slice(0, 10).map(d),
58
- currentUser: s ? d(s) : e.sections.table.currentUser
58
+ topPlayers: r.slice(0, 10).map(c),
59
+ currentUser: t ? c(t) : e.sections.table.currentUser
59
60
  };
60
61
  return;
61
62
  }
62
63
  if (e.sections.table.mode === "ledger") {
63
- const t = r.map(c).slice(0, 8), i = s && !t.some((l) => l.id === (s.id ?? `player-${s.rank}`)) ? c(s) : void 0;
64
+ const i = r.map(u).slice(0, 8), o = t && !i.some((l) => l.id === (t.id ?? `player-${t.rank}`)) ? u(t) : void 0;
64
65
  e.sections.table = {
65
66
  ...e.sections.table,
66
- players: t,
67
- currentUser: i
67
+ players: i,
68
+ currentUser: o
68
69
  };
69
70
  }
70
71
  }
71
- function v(e, n) {
72
- const r = m(n), s = e.preset ?? u(r), o = a(s, r);
73
- if (!o)
72
+ function T(e, n) {
73
+ const r = m(n), t = e.preset ?? a(r), s = f(t, r);
74
+ if (!s)
74
75
  throw new Error(
75
- `Unknown leaderboard preset "${s}". Check assets catalog.`
76
+ `Unknown leaderboard preset "${t}". Check assets catalog.`
76
77
  );
77
- const t = h(
78
+ const i = k(
78
79
  e,
79
- o.appearance,
80
- o.themeId,
80
+ s.appearance,
81
+ s.themeId,
81
82
  r
82
- ), i = f(s, r);
83
- i.config.themeId = t, i.config.labels = {
84
- ...b(r),
85
- ...o.config.labels,
83
+ ), o = b(t, r);
84
+ o.config.themeId = i, o.config.labels = {
85
+ ...h(r),
86
+ ...s.config.labels,
86
87
  ...e.branding?.labels
87
88
  };
88
89
  const l = e.branding?.background ? P(e.branding.background) : null;
89
- return i.config.themeVars = {
90
- ...g(t, r),
90
+ if (o.config.themeVars = {
91
+ ...g(i, r),
91
92
  ...l ?? {},
92
93
  ...e.branding?.themeVars
93
- }, k(i, e.campaign), C(i, e.players), i;
94
+ }, v(o, e.campaign), w(o, e.players), o.sections.hero) {
95
+ const d = C(
96
+ o.sections.hero.endTs,
97
+ o.sections.hero.status,
98
+ e.campaign?.endAt
99
+ );
100
+ d !== o.sections.hero.endTs && (o.sections.hero = {
101
+ ...o.sections.hero,
102
+ endTs: d
103
+ });
104
+ }
105
+ return o;
94
106
  }
95
- function A(e, n, r) {
96
- r !== void 0 && (e.assets = r), e.input = n, e.uuid = n.campaign?.uuid ?? "", e.finished = n.campaign?.finished ?? !1, e.state = v(n, e.assets);
107
+ function z(e, n, r) {
108
+ r !== void 0 && (e.assets = r), e.input = n, e.uuid = n.campaign?.uuid ?? "", e.finished = n.campaign?.finished ?? !1, e.state = T(n, e.assets);
97
109
  }
98
110
  export {
99
- z as LEADERBOARD_CASINO_PRESET_CATALOG,
100
- A as applyLeaderboardCasinoInput,
101
- v as resolveLeaderboardCasinoInput
111
+ U as LEADERBOARD_CASINO_PRESET_CATALOG,
112
+ z as applyLeaderboardCasinoInput,
113
+ T as resolveLeaderboardCasinoInput
102
114
  };
103
115
  //# sourceMappingURL=resolve-input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-input.js","sources":["../../../../src/components/os-leaderboard-casino/integration/resolve-input.ts"],"sourcesContent":["import type { Player } from '../types/ledger.js';\nimport type { UserRank } from '@os-leaderboard-casino/types/data.js';\nimport type { LeaderboardCasinoAssetsBundle } from '../types/assets.js';\nimport type {\n LeaderboardCasinoCampaign,\n LeaderboardCasinoInput,\n LeaderboardCasinoPlayer,\n} from '../types/input.js';\nimport type { OsLeaderboardCasinoState } from '../types/state.js';\nimport {\n getBundleLabels,\n getBundleDefaultPresetId,\n getOsLeaderboardCasinoPreset,\n resolveAssetsBundle,\n resolvePresetState,\n getTheme,\n getThemeVars,\n type OsLeaderboardCasinoThemeId,\n LEADERBOARD_CASINO_PRESET_CATALOG,\n} from './assets-context.js';\nimport { resolveBackgroundVars } from '@os-leaderboard-casino/theme/background.js';\n\nexport { LEADERBOARD_CASINO_PRESET_CATALOG };\n\nfunction resolveThemeId(\n input: LeaderboardCasinoInput,\n appearance: OsLeaderboardCasinoState['config']['appearance'],\n fallback: string,\n bundle: LeaderboardCasinoAssetsBundle,\n): OsLeaderboardCasinoThemeId {\n const requested = input.branding?.themeId;\n if (!requested) return fallback as OsLeaderboardCasinoThemeId;\n const theme = getTheme(requested as OsLeaderboardCasinoThemeId, bundle);\n if (theme.appearance !== appearance)\n return fallback as OsLeaderboardCasinoThemeId;\n return requested as OsLeaderboardCasinoThemeId;\n}\n\nfunction toPreviewPlayer(player: LeaderboardCasinoPlayer): UserRank {\n return {\n username: player.username,\n rank: player.rank,\n points: player.points ?? player.winnings ?? 0,\n totalBet: player.winnings,\n prize: null,\n splitCount: 1,\n you: player.isCurrentUser ?? false,\n };\n}\n\nfunction toLedgerPlayer(player: LeaderboardCasinoPlayer): Player {\n const winnings = player.winnings ?? player.points ?? 0;\n return {\n id: player.id ?? `player-${player.rank}`,\n username: player.username,\n rank: player.rank,\n totalWinnings: winnings,\n points: player.points ?? winnings,\n winRate: 52,\n gamesPlayed: 120,\n streak: 2,\n level: 12,\n badges: [],\n };\n}\n\nfunction applyCampaign(\n state: OsLeaderboardCasinoState,\n campaign: LeaderboardCasinoCampaign | undefined,\n): void {\n if (!campaign) return;\n\n if (state.sections.hero) {\n state.sections.hero = {\n ...state.sections.hero,\n ...(campaign.title != null ? { title: campaign.title } : {}),\n ...(campaign.description != null\n ? { description: campaign.description }\n : {}),\n ...(campaign.endAt != null ? { endTs: campaign.endAt } : {}),\n ...(campaign.prizePool?.value != null\n ? { prizePoolValue: campaign.prizePool.value }\n : {}),\n ...(campaign.prizePool?.currency != null\n ? { prizePoolCurrency: campaign.prizePool.currency }\n : {}),\n ...(campaign.finished != null\n ? { status: campaign.finished ? 'completed' : 'active' }\n : {}),\n };\n }\n\n if (state.sections.stats && campaign.participantCount != null) {\n state.sections.stats = {\n ...state.sections.stats,\n totalParticipants: campaign.participantCount,\n };\n }\n\n if (state.sections.footer && campaign.footerText != null) {\n state.sections.footer = {\n ...state.sections.footer,\n text: campaign.footerText,\n };\n }\n}\n\nfunction applyPlayers(\n state: OsLeaderboardCasinoState,\n players: LeaderboardCasinoPlayer[] | undefined,\n): void {\n if (!players?.length || !state.sections.table) return;\n\n const sorted = [...players].sort((a, b) => a.rank - b.rank);\n const current =\n sorted.find((p) => p.isCurrentUser) ??\n sorted.find((p) => p.username.toLowerCase() === 'you');\n\n if (\n state.config.appearance === 'glam' &&\n state.sections.table.mode === 'preview'\n ) {\n state.sections.table = {\n ...state.sections.table,\n topPlayers: sorted.slice(0, 10).map(toPreviewPlayer),\n currentUser: current\n ? toPreviewPlayer(current)\n : state.sections.table.currentUser,\n };\n return;\n }\n\n if (state.sections.table.mode === 'ledger') {\n const ledger = sorted.map(toLedgerPlayer);\n const top = ledger.slice(0, 8);\n const pinned =\n current &&\n !top.some((p) => p.id === (current.id ?? `player-${current.rank}`))\n ? toLedgerPlayer(current)\n : undefined;\n\n state.sections.table = {\n ...state.sections.table,\n players: top,\n currentUser: pinned,\n };\n }\n}\n\n/**\n * Resolve integration input into render state using the provided assets bundle.\n * Falls back to bundled `assets/fallback/fallback.json` when `assets` is omitted.\n */\nexport function resolveLeaderboardCasinoInput(\n input: LeaderboardCasinoInput,\n assets?: LeaderboardCasinoAssetsBundle | null,\n): OsLeaderboardCasinoState {\n const bundle = resolveAssetsBundle(assets);\n const presetId = input.preset ?? getBundleDefaultPresetId(bundle);\n const preset = getOsLeaderboardCasinoPreset(presetId, bundle);\n if (!preset) {\n throw new Error(\n `Unknown leaderboard preset \"${presetId}\". Check assets catalog.`,\n );\n }\n\n const themeId = resolveThemeId(\n input,\n preset.appearance,\n preset.themeId,\n bundle,\n );\n const state = resolvePresetState(presetId, bundle);\n\n state.config.themeId = themeId;\n state.config.labels = {\n ...getBundleLabels(bundle),\n ...preset.config.labels,\n ...input.branding?.labels,\n };\n\n const backgroundVars = input.branding?.background\n ? resolveBackgroundVars(input.branding.background)\n : null;\n\n state.config.themeVars = {\n ...getThemeVars(themeId, bundle),\n ...(backgroundVars ?? {}),\n ...input.branding?.themeVars,\n };\n\n applyCampaign(state, input.campaign);\n applyPlayers(state, input.players);\n\n return state;\n}\n\nexport type LeaderboardCasinoHost = HTMLElement & {\n state: OsLeaderboardCasinoState;\n uuid?: string;\n finished?: boolean;\n input?: LeaderboardCasinoInput | null;\n assets?: LeaderboardCasinoAssetsBundle | null;\n assetsBaseUrl?: string;\n};\n\n/** Apply input (+ optional assets bundle) to a mounted element. */\nexport function applyLeaderboardCasinoInput(\n host: LeaderboardCasinoHost,\n input: LeaderboardCasinoInput,\n assets?: LeaderboardCasinoAssetsBundle | null,\n): void {\n if (assets !== undefined) {\n host.assets = assets;\n }\n host.input = input;\n host.uuid = input.campaign?.uuid ?? '';\n host.finished = input.campaign?.finished ?? false;\n host.state = resolveLeaderboardCasinoInput(input, host.assets);\n}\n"],"names":["resolveThemeId","input","appearance","fallback","bundle","requested","getTheme","toPreviewPlayer","player","toLedgerPlayer","winnings","applyCampaign","state","campaign","applyPlayers","players","sorted","a","b","current","p","top","pinned","resolveLeaderboardCasinoInput","assets","resolveAssetsBundle","presetId","getBundleDefaultPresetId","preset","getOsLeaderboardCasinoPreset","themeId","resolvePresetState","getBundleLabels","backgroundVars","resolveBackgroundVars","getThemeVars","applyLeaderboardCasinoInput","host"],"mappings":"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"}
1
+ {"version":3,"file":"resolve-input.js","sources":["../../../../src/components/os-leaderboard-casino/integration/resolve-input.ts"],"sourcesContent":["import type { Player } from '../types/ledger.js';\nimport type { UserRank } from '@os-leaderboard-casino/types/data.js';\nimport type { LeaderboardCasinoAssetsBundle } from '../types/assets.js';\nimport type {\n LeaderboardCasinoCampaign,\n LeaderboardCasinoInput,\n LeaderboardCasinoPlayer,\n} from '../types/input.js';\nimport type { OsLeaderboardCasinoState } from '../types/state.js';\nimport {\n getBundleLabels,\n getBundleDefaultPresetId,\n getOsLeaderboardCasinoPreset,\n resolveAssetsBundle,\n resolvePresetState,\n getTheme,\n getThemeVars,\n type OsLeaderboardCasinoThemeId,\n LEADERBOARD_CASINO_PRESET_CATALOG,\n} from './assets-context.js';\nimport { resolveBackgroundVars } from '@os-leaderboard-casino/theme/background.js';\nimport { refreshPresetHeroCountdown } from '@os-leaderboard-casino/utils/demo-countdown.js';\n\nexport { LEADERBOARD_CASINO_PRESET_CATALOG };\n\nfunction resolveThemeId(\n input: LeaderboardCasinoInput,\n appearance: OsLeaderboardCasinoState['config']['appearance'],\n fallback: string,\n bundle: LeaderboardCasinoAssetsBundle,\n): OsLeaderboardCasinoThemeId {\n const requested = input.branding?.themeId;\n if (!requested) return fallback as OsLeaderboardCasinoThemeId;\n const theme = getTheme(requested as OsLeaderboardCasinoThemeId, bundle);\n if (theme.appearance !== appearance)\n return fallback as OsLeaderboardCasinoThemeId;\n return requested as OsLeaderboardCasinoThemeId;\n}\n\nfunction toPreviewPlayer(player: LeaderboardCasinoPlayer): UserRank {\n return {\n username: player.username,\n rank: player.rank,\n points: player.points ?? player.winnings ?? 0,\n totalBet: player.winnings,\n prize: null,\n splitCount: 1,\n you: player.isCurrentUser ?? false,\n };\n}\n\nfunction toLedgerPlayer(player: LeaderboardCasinoPlayer): Player {\n const winnings = player.winnings ?? player.points ?? 0;\n return {\n id: player.id ?? `player-${player.rank}`,\n username: player.username,\n rank: player.rank,\n totalWinnings: winnings,\n points: player.points ?? winnings,\n winRate: 52,\n gamesPlayed: 120,\n streak: 2,\n level: 12,\n badges: [],\n };\n}\n\nfunction applyCampaign(\n state: OsLeaderboardCasinoState,\n campaign: LeaderboardCasinoCampaign | undefined,\n): void {\n if (!campaign) return;\n\n if (state.sections.hero) {\n state.sections.hero = {\n ...state.sections.hero,\n ...(campaign.title != null ? { title: campaign.title } : {}),\n ...(campaign.description != null\n ? { description: campaign.description }\n : {}),\n ...(campaign.endAt != null ? { endTs: campaign.endAt } : {}),\n ...(campaign.prizePool?.value != null\n ? { prizePoolValue: campaign.prizePool.value }\n : {}),\n ...(campaign.prizePool?.currency != null\n ? { prizePoolCurrency: campaign.prizePool.currency }\n : {}),\n ...(campaign.finished != null\n ? { status: campaign.finished ? 'completed' : 'active' }\n : {}),\n };\n }\n\n if (state.sections.stats && campaign.participantCount != null) {\n state.sections.stats = {\n ...state.sections.stats,\n totalParticipants: campaign.participantCount,\n };\n }\n\n if (state.sections.footer && campaign.footerText != null) {\n state.sections.footer = {\n ...state.sections.footer,\n text: campaign.footerText,\n };\n }\n}\n\nfunction applyPlayers(\n state: OsLeaderboardCasinoState,\n players: LeaderboardCasinoPlayer[] | undefined,\n): void {\n if (!players?.length || !state.sections.table) return;\n\n const sorted = [...players].sort((a, b) => a.rank - b.rank);\n const current =\n sorted.find((p) => p.isCurrentUser) ??\n sorted.find((p) => p.username.toLowerCase() === 'you');\n\n if (\n state.config.appearance === 'glam' &&\n state.sections.table.mode === 'preview'\n ) {\n state.sections.table = {\n ...state.sections.table,\n topPlayers: sorted.slice(0, 10).map(toPreviewPlayer),\n currentUser: current\n ? toPreviewPlayer(current)\n : state.sections.table.currentUser,\n };\n return;\n }\n\n if (state.sections.table.mode === 'ledger') {\n const ledger = sorted.map(toLedgerPlayer);\n const top = ledger.slice(0, 8);\n const pinned =\n current &&\n !top.some((p) => p.id === (current.id ?? `player-${current.rank}`))\n ? toLedgerPlayer(current)\n : undefined;\n\n state.sections.table = {\n ...state.sections.table,\n players: top,\n currentUser: pinned,\n };\n }\n}\n\n/**\n * Resolve integration input into render state using the provided assets bundle.\n * Falls back to bundled `assets/fallback/fallback.json` when `assets` is omitted.\n */\nexport function resolveLeaderboardCasinoInput(\n input: LeaderboardCasinoInput,\n assets?: LeaderboardCasinoAssetsBundle | null,\n): OsLeaderboardCasinoState {\n const bundle = resolveAssetsBundle(assets);\n const presetId = input.preset ?? getBundleDefaultPresetId(bundle);\n const preset = getOsLeaderboardCasinoPreset(presetId, bundle);\n if (!preset) {\n throw new Error(\n `Unknown leaderboard preset \"${presetId}\". Check assets catalog.`,\n );\n }\n\n const themeId = resolveThemeId(\n input,\n preset.appearance,\n preset.themeId,\n bundle,\n );\n const state = resolvePresetState(presetId, bundle);\n\n state.config.themeId = themeId;\n state.config.labels = {\n ...getBundleLabels(bundle),\n ...preset.config.labels,\n ...input.branding?.labels,\n };\n\n const backgroundVars = input.branding?.background\n ? resolveBackgroundVars(input.branding.background)\n : null;\n\n state.config.themeVars = {\n ...getThemeVars(themeId, bundle),\n ...(backgroundVars ?? {}),\n ...input.branding?.themeVars,\n };\n\n applyCampaign(state, input.campaign);\n applyPlayers(state, input.players);\n\n if (state.sections.hero) {\n const refreshedEndTs = refreshPresetHeroCountdown(\n state.sections.hero.endTs,\n state.sections.hero.status,\n input.campaign?.endAt,\n );\n if (refreshedEndTs !== state.sections.hero.endTs) {\n state.sections.hero = {\n ...state.sections.hero,\n endTs: refreshedEndTs,\n };\n }\n }\n\n return state;\n}\n\nexport type LeaderboardCasinoHost = HTMLElement & {\n state: OsLeaderboardCasinoState;\n uuid?: string;\n finished?: boolean;\n input?: LeaderboardCasinoInput | null;\n assets?: LeaderboardCasinoAssetsBundle | null;\n assetsBaseUrl?: string;\n};\n\n/** Apply input (+ optional assets bundle) to a mounted element. */\nexport function applyLeaderboardCasinoInput(\n host: LeaderboardCasinoHost,\n input: LeaderboardCasinoInput,\n assets?: LeaderboardCasinoAssetsBundle | null,\n): void {\n if (assets !== undefined) {\n host.assets = assets;\n }\n host.input = input;\n host.uuid = input.campaign?.uuid ?? '';\n host.finished = input.campaign?.finished ?? false;\n host.state = resolveLeaderboardCasinoInput(input, host.assets);\n}\n"],"names":["resolveThemeId","input","appearance","fallback","bundle","requested","getTheme","toPreviewPlayer","player","toLedgerPlayer","winnings","applyCampaign","state","campaign","applyPlayers","players","sorted","a","b","current","p","top","pinned","resolveLeaderboardCasinoInput","assets","resolveAssetsBundle","presetId","getBundleDefaultPresetId","preset","getOsLeaderboardCasinoPreset","themeId","resolvePresetState","getBundleLabels","backgroundVars","resolveBackgroundVars","getThemeVars","refreshedEndTs","refreshPresetHeroCountdown","applyLeaderboardCasinoInput","host"],"mappings":";;;;AAyBA,SAASA,EACPC,GACAC,GACAC,GACAC,GAC4B;AAC5B,QAAMC,IAAYJ,EAAM,UAAU;AAGlC,SAFI,CAACI,KACSC,EAASD,GAAyCD,CAAM,EAC5D,eAAeF,IAChBC,IACFE;AACT;AAEA,SAASE,EAAgBC,GAA2C;AAClE,SAAO;AAAA,IACL,UAAUA,EAAO;AAAA,IACjB,MAAMA,EAAO;AAAA,IACb,QAAQA,EAAO,UAAUA,EAAO,YAAY;AAAA,IAC5C,UAAUA,EAAO;AAAA,IACjB,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,KAAKA,EAAO,iBAAiB;AAAA,EAAA;AAEjC;AAEA,SAASC,EAAeD,GAAyC;AAC/D,QAAME,IAAWF,EAAO,YAAYA,EAAO,UAAU;AACrD,SAAO;AAAA,IACL,IAAIA,EAAO,MAAM,UAAUA,EAAO,IAAI;AAAA,IACtC,UAAUA,EAAO;AAAA,IACjB,MAAMA,EAAO;AAAA,IACb,eAAeE;AAAA,IACf,QAAQF,EAAO,UAAUE;AAAA,IACzB,SAAS;AAAA,IACT,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ,CAAA;AAAA,EAAC;AAEb;AAEA,SAASC,EACPC,GACAC,GACM;AACN,EAAKA,MAEDD,EAAM,SAAS,SACjBA,EAAM,SAAS,OAAO;AAAA,IACpB,GAAGA,EAAM,SAAS;AAAA,IAClB,GAAIC,EAAS,SAAS,OAAO,EAAE,OAAOA,EAAS,MAAA,IAAU,CAAA;AAAA,IACzD,GAAIA,EAAS,eAAe,OACxB,EAAE,aAAaA,EAAS,YAAA,IACxB,CAAA;AAAA,IACJ,GAAIA,EAAS,SAAS,OAAO,EAAE,OAAOA,EAAS,MAAA,IAAU,CAAA;AAAA,IACzD,GAAIA,EAAS,WAAW,SAAS,OAC7B,EAAE,gBAAgBA,EAAS,UAAU,MAAA,IACrC,CAAA;AAAA,IACJ,GAAIA,EAAS,WAAW,YAAY,OAChC,EAAE,mBAAmBA,EAAS,UAAU,SAAA,IACxC,CAAA;AAAA,IACJ,GAAIA,EAAS,YAAY,OACrB,EAAE,QAAQA,EAAS,WAAW,cAAc,aAC5C,CAAA;AAAA,EAAC,IAILD,EAAM,SAAS,SAASC,EAAS,oBAAoB,SACvDD,EAAM,SAAS,QAAQ;AAAA,IACrB,GAAGA,EAAM,SAAS;AAAA,IAClB,mBAAmBC,EAAS;AAAA,EAAA,IAI5BD,EAAM,SAAS,UAAUC,EAAS,cAAc,SAClDD,EAAM,SAAS,SAAS;AAAA,IACtB,GAAGA,EAAM,SAAS;AAAA,IAClB,MAAMC,EAAS;AAAA,EAAA;AAGrB;AAEA,SAASC,EACPF,GACAG,GACM;AACN,MAAI,CAACA,GAAS,UAAU,CAACH,EAAM,SAAS,MAAO;AAE/C,QAAMI,IAAS,CAAC,GAAGD,CAAO,EAAE,KAAK,CAACE,GAAGC,MAAMD,EAAE,OAAOC,EAAE,IAAI,GACpDC,IACJH,EAAO,KAAK,CAACI,MAAMA,EAAE,aAAa,KAClCJ,EAAO,KAAK,CAACI,MAAMA,EAAE,SAAS,YAAA,MAAkB,KAAK;AAEvD,MACER,EAAM,OAAO,eAAe,UAC5BA,EAAM,SAAS,MAAM,SAAS,WAC9B;AACA,IAAAA,EAAM,SAAS,QAAQ;AAAA,MACrB,GAAGA,EAAM,SAAS;AAAA,MAClB,YAAYI,EAAO,MAAM,GAAG,EAAE,EAAE,IAAIT,CAAe;AAAA,MACnD,aAAaY,IACTZ,EAAgBY,CAAO,IACvBP,EAAM,SAAS,MAAM;AAAA,IAAA;AAE3B;AAAA,EACF;AAEA,MAAIA,EAAM,SAAS,MAAM,SAAS,UAAU;AAE1C,UAAMS,IADSL,EAAO,IAAIP,CAAc,EACrB,MAAM,GAAG,CAAC,GACvBa,IACJH,KACA,CAACE,EAAI,KAAK,CAACD,MAAMA,EAAE,QAAQD,EAAQ,MAAM,UAAUA,EAAQ,IAAI,GAAG,IAC9DV,EAAeU,CAAO,IACtB;AAEN,IAAAP,EAAM,SAAS,QAAQ;AAAA,MACrB,GAAGA,EAAM,SAAS;AAAA,MAClB,SAASS;AAAA,MACT,aAAaC;AAAA,IAAA;AAAA,EAEjB;AACF;AAMO,SAASC,EACdtB,GACAuB,GAC0B;AAC1B,QAAMpB,IAASqB,EAAoBD,CAAM,GACnCE,IAAWzB,EAAM,UAAU0B,EAAyBvB,CAAM,GAC1DwB,IAASC,EAA6BH,GAAUtB,CAAM;AAC5D,MAAI,CAACwB;AACH,UAAM,IAAI;AAAA,MACR,+BAA+BF,CAAQ;AAAA,IAAA;AAI3C,QAAMI,IAAU9B;AAAA,IACdC;AAAA,IACA2B,EAAO;AAAA,IACPA,EAAO;AAAA,IACPxB;AAAA,EAAA,GAEIQ,IAAQmB,EAAmBL,GAAUtB,CAAM;AAEjD,EAAAQ,EAAM,OAAO,UAAUkB,GACvBlB,EAAM,OAAO,SAAS;AAAA,IACpB,GAAGoB,EAAgB5B,CAAM;AAAA,IACzB,GAAGwB,EAAO,OAAO;AAAA,IACjB,GAAG3B,EAAM,UAAU;AAAA,EAAA;AAGrB,QAAMgC,IAAiBhC,EAAM,UAAU,aACnCiC,EAAsBjC,EAAM,SAAS,UAAU,IAC/C;AAWJ,MATAW,EAAM,OAAO,YAAY;AAAA,IACvB,GAAGuB,EAAaL,GAAS1B,CAAM;AAAA,IAC/B,GAAI6B,KAAkB,CAAA;AAAA,IACtB,GAAGhC,EAAM,UAAU;AAAA,EAAA,GAGrBU,EAAcC,GAAOX,EAAM,QAAQ,GACnCa,EAAaF,GAAOX,EAAM,OAAO,GAE7BW,EAAM,SAAS,MAAM;AACvB,UAAMwB,IAAiBC;AAAA,MACrBzB,EAAM,SAAS,KAAK;AAAA,MACpBA,EAAM,SAAS,KAAK;AAAA,MACpBX,EAAM,UAAU;AAAA,IAAA;AAElB,IAAImC,MAAmBxB,EAAM,SAAS,KAAK,UACzCA,EAAM,SAAS,OAAO;AAAA,MACpB,GAAGA,EAAM,SAAS;AAAA,MAClB,OAAOwB;AAAA,IAAA;AAAA,EAGb;AAEA,SAAOxB;AACT;AAYO,SAAS0B,EACdC,GACAtC,GACAuB,GACM;AACN,EAAIA,MAAW,WACbe,EAAK,SAASf,IAEhBe,EAAK,QAAQtC,GACbsC,EAAK,OAAOtC,EAAM,UAAU,QAAQ,IACpCsC,EAAK,WAAWtC,EAAM,UAAU,YAAY,IAC5CsC,EAAK,QAAQhB,EAA8BtB,GAAOsC,EAAK,MAAM;AAC/D;"}
@@ -7,6 +7,8 @@ export declare class OsLeaderboardCasinoHero extends LitElement implements HeroS
7
7
  static styles: import('lit').CSSResult[];
8
8
  section: OsLeaderboardCasinoHeroSection;
9
9
  private now;
10
+ /** Rolled forward once per mount when preset endTs is stale (demo/marketing). */
11
+ private sessionEndTs;
10
12
  /** Animated odometer value shown for `prizePoolValue`. */
11
13
  private poolDisplay;
12
14
  poolBump: boolean;
@@ -32,6 +34,8 @@ export declare class OsLeaderboardCasinoHero extends LitElement implements HeroS
32
34
  private animatePool;
33
35
  private formatPool;
34
36
  private get isFinished();
37
+ private get countdownEndTs();
38
+ private syncSessionEndTs;
35
39
  renderCountdown(): typeof nothing | import('lit').TemplateResult<1>;
36
40
  render(): import('lit').TemplateResult | typeof nothing;
37
41
  }
@@ -1,39 +1,40 @@
1
1
  import "../../../../shared/vendor/lit-reactive-element-reactive-element.js";
2
2
  import { nothing as u, html as p } from "../../../../shared/vendor/lit-html-lit-html.js";
3
- import { LitElement as f } from "../../../../shared/vendor/lit-element-lit-element.js";
4
- import { property as d } from "../../../../shared/vendor/lit-reactive-element-property.js";
3
+ import { LitElement as m } from "../../../../shared/vendor/lit-element-lit-element.js";
4
+ import { property as f } from "../../../../shared/vendor/lit-reactive-element-property.js";
5
5
  import { state as c } from "../../../../shared/vendor/lit-reactive-element-state.js";
6
- import { Component as b } from "../../../../shared/lib/lit/component.js";
6
+ import { Component as T } from "../../../../shared/lib/lit/component.js";
7
7
  import { scss as y } from "../../../../shared/lib/lit/scss.js";
8
8
  import { OS_LEADERBOARD_CASINO_HERO as w } from "../../constants/tags.js";
9
- import { osLeaderboardCasinoTheme as D } from "../../theme/styles.js";
9
+ import { osLeaderboardCasinoTheme as b } from "../../theme/styles.js";
10
10
  import "../../../../shared/vendor/lit-html-unsafe-svg.js";
11
+ import { isCountdownExpired as E, demoCountdownEndIso as D } from "../../utils/demo-countdown.js";
11
12
  import g from "./hero-section.html.js";
12
- import T from "./hero-section.scss.js";
13
- var v = Object.defineProperty, A = Object.getOwnPropertyDescriptor, l = (t, e, s, i) => {
14
- for (var o = i > 1 ? void 0 : i ? A(e, s) : e, a = t.length - 1, r; a >= 0; a--)
15
- (r = t[a]) && (o = (i ? r(e, s, o) : r(o)) || o);
16
- return i && o && v(e, s, o), o;
13
+ import v from "./hero-section.scss.js";
14
+ var A = Object.defineProperty, C = Object.getOwnPropertyDescriptor, a = (s, t, e, n) => {
15
+ for (var o = n > 1 ? void 0 : n ? C(t, e) : t, l = s.length - 1, r; l >= 0; l--)
16
+ (r = s[l]) && (o = (n ? r(t, e, o) : r(o)) || o);
17
+ return n && o && A(t, e, o), o;
17
18
  };
18
- function h(t, e = Date.now()) {
19
- const s = Math.floor((new Date(t).getTime() - e) / 1e3);
20
- return !Number.isFinite(s) || s <= 0 ? { expired: !0, days: 0, hours: 0, minutes: 0, seconds: 0 } : {
19
+ function h(s, t = Date.now()) {
20
+ const e = Math.floor((new Date(s).getTime() - t) / 1e3);
21
+ return !Number.isFinite(e) || e <= 0 ? { expired: !0, days: 0, hours: 0, minutes: 0, seconds: 0 } : {
21
22
  expired: !1,
22
- days: Math.floor(s / 86400),
23
- hours: Math.floor(s % 86400 / 3600),
24
- minutes: Math.floor(s % 3600 / 60),
25
- seconds: s % 60
23
+ days: Math.floor(e / 86400),
24
+ hours: Math.floor(e % 86400 / 3600),
25
+ minutes: Math.floor(e % 3600 / 60),
26
+ seconds: e % 60
26
27
  };
27
28
  }
28
- const P = {
29
+ const S = {
29
30
  upcoming: "Upcoming",
30
31
  active: "Live",
31
32
  completed: "Finished",
32
33
  cancelled: "Cancelled"
33
34
  };
34
- let n = class extends f {
35
+ let i = class extends m {
35
36
  constructor() {
36
- super(...arguments), this.now = Date.now(), this.poolDisplay = null, this.poolBump = !1;
37
+ super(...arguments), this.now = Date.now(), this.sessionEndTs = null, this.poolDisplay = null, this.poolBump = !1;
37
38
  }
38
39
  get showBanner() {
39
40
  return !!this.section?.bannerAsset?.url;
@@ -51,8 +52,8 @@ let n = class extends f {
51
52
  return this.section?.status;
52
53
  }
53
54
  get statusLabel() {
54
- const t = this.section?.status;
55
- return t ? P[t] : "";
55
+ const s = this.section?.status;
56
+ return s ? S[s] : "";
56
57
  }
57
58
  get showActiveDot() {
58
59
  return this.section?.status === "active";
@@ -73,67 +74,92 @@ let n = class extends f {
73
74
  return this.poolDisplay != null;
74
75
  }
75
76
  connectedCallback() {
76
- super.connectedCallback(), this.timer = setInterval(() => {
77
- this.now = Date.now();
77
+ super.connectedCallback(), this.syncSessionEndTs(), this.timer = setInterval(() => {
78
+ this.now = Date.now(), this.syncSessionEndTs();
78
79
  }, 1e3);
79
80
  }
80
81
  disconnectedCallback() {
81
82
  super.disconnectedCallback(), this.timer && clearInterval(this.timer), this.poolRaf && cancelAnimationFrame(this.poolRaf), this.bumpTimer && clearTimeout(this.bumpTimer);
82
83
  }
83
- willUpdate(t) {
84
- if (!t.has("section")) return;
85
- const e = this.section?.prizePoolValue;
86
- if (e == null) {
84
+ willUpdate(s) {
85
+ if (s.has("section") && (this.sessionEndTs = null, this.syncSessionEndTs()), !s.has("section")) return;
86
+ const t = this.section?.prizePoolValue;
87
+ if (t == null) {
87
88
  this.poolDisplay = null;
88
89
  return;
89
90
  }
90
91
  if (this.poolDisplay == null) {
91
- this.poolDisplay = e;
92
+ this.poolDisplay = t;
92
93
  return;
93
94
  }
94
- e !== this.poolDisplay && this.animatePool(e);
95
+ t !== this.poolDisplay && this.animatePool(t);
95
96
  }
96
97
  /** Rolling count-up from the current display value to `target`. */
97
- animatePool(t) {
98
+ animatePool(s) {
98
99
  this.poolRaf && cancelAnimationFrame(this.poolRaf);
99
- const e = this.poolDisplay ?? t, s = 1100, i = performance.now(), o = (a) => {
100
- const r = Math.min(1, (a - i) / s), m = 1 - Math.pow(1 - r, 3);
101
- this.poolDisplay = Math.round(e + (t - e) * m), r < 1 && (this.poolRaf = requestAnimationFrame(o));
100
+ const t = this.poolDisplay ?? s, e = 1100, n = performance.now(), o = (l) => {
101
+ const r = Math.min(1, (l - n) / e), d = 1 - Math.pow(1 - r, 3);
102
+ this.poolDisplay = Math.round(t + (s - t) * d), r < 1 && (this.poolRaf = requestAnimationFrame(o));
102
103
  };
103
- this.poolRaf = requestAnimationFrame(o), t > e && (this.poolBump = !0, this.bumpTimer && clearTimeout(this.bumpTimer), this.bumpTimer = setTimeout(() => {
104
+ this.poolRaf = requestAnimationFrame(o), s > t && (this.poolBump = !0, this.bumpTimer && clearTimeout(this.bumpTimer), this.bumpTimer = setTimeout(() => {
104
105
  this.poolBump = !1;
105
106
  }, 650));
106
107
  }
107
- formatPool(t) {
108
+ formatPool(s) {
108
109
  try {
109
110
  return new Intl.NumberFormat("en-US", {
110
111
  style: "currency",
111
112
  currency: this.section?.prizePoolCurrency ?? "USD",
112
113
  maximumFractionDigits: 0
113
- }).format(t);
114
+ }).format(s);
114
115
  } catch {
115
- return t.toLocaleString();
116
+ return s.toLocaleString();
116
117
  }
117
118
  }
118
119
  get isFinished() {
119
- const t = this.section?.status;
120
- return t === "completed" || t === "cancelled" ? !0 : this.section?.endTs ? h(this.section.endTs, this.now).expired : !1;
120
+ const s = this.section?.status;
121
+ if (s === "completed" || s === "cancelled") return !0;
122
+ const t = this.countdownEndTs;
123
+ return t ? h(t, this.now).expired : !1;
124
+ }
125
+ get countdownEndTs() {
126
+ const s = this.section?.status;
127
+ return s === "completed" || s === "cancelled" ? this.section?.endTs : this.sessionEndTs ?? this.section?.endTs;
128
+ }
129
+ syncSessionEndTs() {
130
+ const s = this.section?.endTs, t = this.section?.status;
131
+ if (!s) {
132
+ this.sessionEndTs = null;
133
+ return;
134
+ }
135
+ if (t === "completed" || t === "cancelled") {
136
+ this.sessionEndTs = s;
137
+ return;
138
+ }
139
+ const e = this.sessionEndTs ?? s;
140
+ if (!E(e, this.now)) {
141
+ this.sessionEndTs || (this.sessionEndTs = s);
142
+ return;
143
+ }
144
+ this.sessionEndTs = D(this.now);
121
145
  }
122
146
  renderCountdown() {
123
- const t = this.section?.endTs;
124
- if (!t) return u;
147
+ const s = this.countdownEndTs;
148
+ if (!s) return u;
125
149
  if (this.isFinished)
126
150
  return p`<span class="ended">🏁 Contest finished</span>`;
127
- const e = h(t, this.now), s = (i, o) => p`<div class="cell">
128
- <b>${String(i).padStart(2, "0")}</b><span>${o}</span>
151
+ const t = h(s, this.now), e = (n, o) => p`<div class="cell">
152
+ <b>${String(n).padStart(2, "0")}</b><span>${o}</span>
129
153
  </div>`;
130
154
  return p`
131
155
  <div class="countdown">
132
156
  <span class="label">Ends in</span>
133
- ${s(e.days, "days")}<span class="sep">:</span>
134
- ${s(e.hours, "hours")}<span class="sep">:</span>
135
- ${s(e.minutes, "min")}<span class="sep">:</span>
136
- ${s(e.seconds, "sec")}
157
+ <div class="countdown-track">
158
+ ${e(t.days, "days")}<span class="sep">:</span>
159
+ ${e(t.hours, "hours")}<span class="sep">:</span>
160
+ ${e(t.minutes, "min")}<span class="sep">:</span>
161
+ ${e(t.seconds, "sec")}
162
+ </div>
137
163
  </div>
138
164
  `;
139
165
  }
@@ -141,23 +167,26 @@ let n = class extends f {
141
167
  return this.section ? g(this) : u;
142
168
  }
143
169
  };
144
- n.styles = [D, y(T)];
145
- l([
146
- d({ attribute: !1 })
147
- ], n.prototype, "section", 2);
148
- l([
170
+ i.styles = [b, y(v)];
171
+ a([
172
+ f({ attribute: !1 })
173
+ ], i.prototype, "section", 2);
174
+ a([
175
+ c()
176
+ ], i.prototype, "now", 2);
177
+ a([
149
178
  c()
150
- ], n.prototype, "now", 2);
151
- l([
179
+ ], i.prototype, "sessionEndTs", 2);
180
+ a([
152
181
  c()
153
- ], n.prototype, "poolDisplay", 2);
154
- l([
182
+ ], i.prototype, "poolDisplay", 2);
183
+ a([
155
184
  c()
156
- ], n.prototype, "poolBump", 2);
157
- n = l([
158
- b({ selector: w })
159
- ], n);
185
+ ], i.prototype, "poolBump", 2);
186
+ i = a([
187
+ T({ selector: w })
188
+ ], i);
160
189
  export {
161
- n as OsLeaderboardCasinoHero
190
+ i as OsLeaderboardCasinoHero
162
191
  };
163
192
  //# sourceMappingURL=hero-section.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hero-section.js","sources":["../../../../../src/components/os-leaderboard-casino/sections/hero-section/hero-section.ts"],"sourcesContent":["import { LitElement, html, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { Component } from '@oddsmith/lib/lit/component.js';\nimport { scss } from '@oddsmith/lib/lit/scss.js';\nimport { OS_LEADERBOARD_CASINO_HERO } from '@os-leaderboard-casino/constants/tags.js';\nimport { osLeaderboardCasinoTheme } from '@os-leaderboard-casino/theme/index.js';\nimport type { LeaderboardStatus } from '@os-leaderboard-casino/types/data.js';\nimport type { OsLeaderboardCasinoHeroSection } from '@os-leaderboard-casino/types/sections.js';\nimport type { HeroSectionHost } from './hero-section.host.js';\nimport renderTemplate from './hero-section.html?lit-html';\nimport styles from './hero-section.scss?inline';\n\ninterface CountdownParts {\n expired: boolean;\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n}\n\nfunction countdownTo(endTs: string, now = Date.now()): CountdownParts {\n const remaining = Math.floor((new Date(endTs).getTime() - now) / 1000);\n if (!Number.isFinite(remaining) || remaining <= 0) {\n return { expired: true, days: 0, hours: 0, minutes: 0, seconds: 0 };\n }\n return {\n expired: false,\n days: Math.floor(remaining / 86400),\n hours: Math.floor((remaining % 86400) / 3600),\n minutes: Math.floor((remaining % 3600) / 60),\n seconds: remaining % 60,\n };\n}\n\nconst STATUS_LABELS: Record<LeaderboardStatus, string> = {\n upcoming: 'Upcoming',\n active: 'Live',\n completed: 'Finished',\n cancelled: 'Cancelled',\n};\n\n/** Glam hero — golden ring, shimmer title, prize-pool headline, glowing countdown. */\n@Component({ selector: OS_LEADERBOARD_CASINO_HERO })\nexport class OsLeaderboardCasinoHero\n extends LitElement\n implements HeroSectionHost\n{\n static styles = [osLeaderboardCasinoTheme, scss(styles)];\n\n @property({ attribute: false })\n section!: OsLeaderboardCasinoHeroSection;\n\n @state()\n private now = Date.now();\n\n /** Animated odometer value shown for `prizePoolValue`. */\n @state()\n private poolDisplay: number | null = null;\n\n @state()\n poolBump = false;\n\n private timer?: ReturnType<typeof setInterval>;\n private poolRaf?: number;\n private bumpTimer?: ReturnType<typeof setTimeout>;\n\n get showBanner(): boolean {\n return Boolean(this.section?.bannerAsset?.url);\n }\n\n get bannerUrl(): string {\n return this.section?.bannerAsset?.url ?? '';\n }\n\n get bannerAlt(): string {\n return this.section?.bannerAsset?.label || '';\n }\n\n get showStatus(): boolean {\n return Boolean(this.section?.status);\n }\n\n get status(): LeaderboardStatus | undefined {\n return this.section?.status;\n }\n\n get statusLabel(): string {\n const status = this.section?.status;\n return status ? STATUS_LABELS[status] : '';\n }\n\n get showActiveDot(): boolean {\n return this.section?.status === 'active';\n }\n\n get showDescription(): boolean {\n return Boolean(this.section?.description);\n }\n\n get showPool(): boolean {\n return this.poolDisplay != null || Boolean(this.section?.prizePool);\n }\n\n get poolValueLabel(): string {\n if (this.poolDisplay != null) return this.formatPool(this.poolDisplay);\n return this.section?.prizePool ?? '';\n }\n\n get poolLabel(): string {\n return this.section?.prizePoolLabel ?? 'Total prize pool';\n }\n\n get showRising(): boolean {\n return this.poolDisplay != null;\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n this.timer = setInterval(() => {\n this.now = Date.now();\n }, 1000);\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n if (this.timer) clearInterval(this.timer);\n if (this.poolRaf) cancelAnimationFrame(this.poolRaf);\n if (this.bumpTimer) clearTimeout(this.bumpTimer);\n }\n\n willUpdate(changed: Map<string, unknown>) {\n if (!changed.has('section')) return;\n const target = this.section?.prizePoolValue;\n if (target == null) {\n this.poolDisplay = null;\n return;\n }\n if (this.poolDisplay == null) {\n this.poolDisplay = target;\n return;\n }\n if (target !== this.poolDisplay) this.animatePool(target);\n }\n\n /** Rolling count-up from the current display value to `target`. */\n private animatePool(target: number) {\n if (this.poolRaf) cancelAnimationFrame(this.poolRaf);\n const from = this.poolDisplay ?? target;\n const duration = 1100;\n const start = performance.now();\n const tick = (t: number) => {\n const p = Math.min(1, (t - start) / duration);\n const eased = 1 - Math.pow(1 - p, 3);\n this.poolDisplay = Math.round(from + (target - from) * eased);\n if (p < 1) this.poolRaf = requestAnimationFrame(tick);\n };\n this.poolRaf = requestAnimationFrame(tick);\n\n if (target > from) {\n this.poolBump = true;\n if (this.bumpTimer) clearTimeout(this.bumpTimer);\n this.bumpTimer = setTimeout(() => {\n this.poolBump = false;\n }, 650);\n }\n }\n\n private formatPool(value: number): string {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: this.section?.prizePoolCurrency ?? 'USD',\n maximumFractionDigits: 0,\n }).format(value);\n } catch {\n return value.toLocaleString();\n }\n }\n\n private get isFinished(): boolean {\n const status = this.section?.status;\n if (status === 'completed' || status === 'cancelled') return true;\n if (!this.section?.endTs) return false;\n return countdownTo(this.section.endTs, this.now).expired;\n }\n\n renderCountdown() {\n const endTs = this.section?.endTs;\n if (!endTs) return nothing;\n\n if (this.isFinished) {\n return html`<span class=\"ended\">🏁 Contest finished</span>`;\n }\n\n const c = countdownTo(endTs, this.now);\n const cell = (v: number, label: string) =>\n html`<div class=\"cell\">\n <b>${String(v).padStart(2, '0')}</b><span>${label}</span>\n </div>`;\n\n return html`\n <div class=\"countdown\">\n <span class=\"label\">Ends in</span>\n ${cell(c.days, 'days')}<span class=\"sep\">:</span>\n ${cell(c.hours, 'hours')}<span class=\"sep\">:</span>\n ${cell(c.minutes, 'min')}<span class=\"sep\">:</span>\n ${cell(c.seconds, 'sec')}\n </div>\n `;\n }\n\n render() {\n if (!this.section) return nothing;\n return renderTemplate(this);\n }\n}\n"],"names":["countdownTo","endTs","now","remaining","STATUS_LABELS","OsLeaderboardCasinoHero","LitElement","status","changed","target","from","duration","start","tick","t","p","eased","value","nothing","html","c","cell","v","label","renderTemplate","osLeaderboardCasinoTheme","scss","styles","__decorateClass","property","state","Component","OS_LEADERBOARD_CASINO_HERO"],"mappings":"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"}
1
+ {"version":3,"file":"hero-section.js","sources":["../../../../../src/components/os-leaderboard-casino/sections/hero-section/hero-section.ts"],"sourcesContent":["import { LitElement, html, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { Component } from '@oddsmith/lib/lit/component.js';\nimport { scss } from '@oddsmith/lib/lit/scss.js';\nimport { OS_LEADERBOARD_CASINO_HERO } from '@os-leaderboard-casino/constants/tags.js';\nimport { osLeaderboardCasinoTheme } from '@os-leaderboard-casino/theme/index.js';\nimport type { LeaderboardStatus } from '@os-leaderboard-casino/types/data.js';\nimport type { OsLeaderboardCasinoHeroSection } from '@os-leaderboard-casino/types/sections.js';\nimport {\n demoCountdownEndIso,\n isCountdownExpired,\n} from '@os-leaderboard-casino/utils/demo-countdown.js';\nimport type { HeroSectionHost } from './hero-section.host.js';\nimport renderTemplate from './hero-section.html?lit-html';\nimport styles from './hero-section.scss?inline';\n\ninterface CountdownParts {\n expired: boolean;\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n}\n\nfunction countdownTo(endTs: string, now = Date.now()): CountdownParts {\n const remaining = Math.floor((new Date(endTs).getTime() - now) / 1000);\n if (!Number.isFinite(remaining) || remaining <= 0) {\n return { expired: true, days: 0, hours: 0, minutes: 0, seconds: 0 };\n }\n return {\n expired: false,\n days: Math.floor(remaining / 86400),\n hours: Math.floor((remaining % 86400) / 3600),\n minutes: Math.floor((remaining % 3600) / 60),\n seconds: remaining % 60,\n };\n}\n\nconst STATUS_LABELS: Record<LeaderboardStatus, string> = {\n upcoming: 'Upcoming',\n active: 'Live',\n completed: 'Finished',\n cancelled: 'Cancelled',\n};\n\n/** Glam hero — golden ring, shimmer title, prize-pool headline, glowing countdown. */\n@Component({ selector: OS_LEADERBOARD_CASINO_HERO })\nexport class OsLeaderboardCasinoHero\n extends LitElement\n implements HeroSectionHost\n{\n static styles = [osLeaderboardCasinoTheme, scss(styles)];\n\n @property({ attribute: false })\n section!: OsLeaderboardCasinoHeroSection;\n\n @state()\n private now = Date.now();\n\n /** Rolled forward once per mount when preset endTs is stale (demo/marketing). */\n @state()\n private sessionEndTs: string | null = null;\n\n /** Animated odometer value shown for `prizePoolValue`. */\n @state()\n private poolDisplay: number | null = null;\n\n @state()\n poolBump = false;\n\n private timer?: ReturnType<typeof setInterval>;\n private poolRaf?: number;\n private bumpTimer?: ReturnType<typeof setTimeout>;\n\n get showBanner(): boolean {\n return Boolean(this.section?.bannerAsset?.url);\n }\n\n get bannerUrl(): string {\n return this.section?.bannerAsset?.url ?? '';\n }\n\n get bannerAlt(): string {\n return this.section?.bannerAsset?.label || '';\n }\n\n get showStatus(): boolean {\n return Boolean(this.section?.status);\n }\n\n get status(): LeaderboardStatus | undefined {\n return this.section?.status;\n }\n\n get statusLabel(): string {\n const status = this.section?.status;\n return status ? STATUS_LABELS[status] : '';\n }\n\n get showActiveDot(): boolean {\n return this.section?.status === 'active';\n }\n\n get showDescription(): boolean {\n return Boolean(this.section?.description);\n }\n\n get showPool(): boolean {\n return this.poolDisplay != null || Boolean(this.section?.prizePool);\n }\n\n get poolValueLabel(): string {\n if (this.poolDisplay != null) return this.formatPool(this.poolDisplay);\n return this.section?.prizePool ?? '';\n }\n\n get poolLabel(): string {\n return this.section?.prizePoolLabel ?? 'Total prize pool';\n }\n\n get showRising(): boolean {\n return this.poolDisplay != null;\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n this.syncSessionEndTs();\n this.timer = setInterval(() => {\n this.now = Date.now();\n this.syncSessionEndTs();\n }, 1000);\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n if (this.timer) clearInterval(this.timer);\n if (this.poolRaf) cancelAnimationFrame(this.poolRaf);\n if (this.bumpTimer) clearTimeout(this.bumpTimer);\n }\n\n willUpdate(changed: Map<string, unknown>) {\n if (changed.has('section')) {\n this.sessionEndTs = null;\n this.syncSessionEndTs();\n }\n\n if (!changed.has('section')) return;\n const target = this.section?.prizePoolValue;\n if (target == null) {\n this.poolDisplay = null;\n return;\n }\n if (this.poolDisplay == null) {\n this.poolDisplay = target;\n return;\n }\n if (target !== this.poolDisplay) this.animatePool(target);\n }\n\n /** Rolling count-up from the current display value to `target`. */\n private animatePool(target: number) {\n if (this.poolRaf) cancelAnimationFrame(this.poolRaf);\n const from = this.poolDisplay ?? target;\n const duration = 1100;\n const start = performance.now();\n const tick = (t: number) => {\n const p = Math.min(1, (t - start) / duration);\n const eased = 1 - Math.pow(1 - p, 3);\n this.poolDisplay = Math.round(from + (target - from) * eased);\n if (p < 1) this.poolRaf = requestAnimationFrame(tick);\n };\n this.poolRaf = requestAnimationFrame(tick);\n\n if (target > from) {\n this.poolBump = true;\n if (this.bumpTimer) clearTimeout(this.bumpTimer);\n this.bumpTimer = setTimeout(() => {\n this.poolBump = false;\n }, 650);\n }\n }\n\n private formatPool(value: number): string {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: this.section?.prizePoolCurrency ?? 'USD',\n maximumFractionDigits: 0,\n }).format(value);\n } catch {\n return value.toLocaleString();\n }\n }\n\n private get isFinished(): boolean {\n const status = this.section?.status;\n if (status === 'completed' || status === 'cancelled') return true;\n const endTs = this.countdownEndTs;\n if (!endTs) return false;\n return countdownTo(endTs, this.now).expired;\n }\n\n private get countdownEndTs(): string | undefined {\n const status = this.section?.status;\n if (status === 'completed' || status === 'cancelled') {\n return this.section?.endTs;\n }\n\n return this.sessionEndTs ?? this.section?.endTs;\n }\n\n private syncSessionEndTs(): void {\n const endTs = this.section?.endTs;\n const status = this.section?.status;\n\n if (!endTs) {\n this.sessionEndTs = null;\n return;\n }\n\n if (status === 'completed' || status === 'cancelled') {\n this.sessionEndTs = endTs;\n return;\n }\n\n const activeEndTs = this.sessionEndTs ?? endTs;\n if (!isCountdownExpired(activeEndTs, this.now)) {\n if (!this.sessionEndTs) this.sessionEndTs = endTs;\n return;\n }\n\n this.sessionEndTs = demoCountdownEndIso(this.now);\n }\n\n renderCountdown() {\n const endTs = this.countdownEndTs;\n if (!endTs) return nothing;\n\n if (this.isFinished) {\n return html`<span class=\"ended\">🏁 Contest finished</span>`;\n }\n\n const c = countdownTo(endTs, this.now);\n const cell = (v: number, label: string) =>\n html`<div class=\"cell\">\n <b>${String(v).padStart(2, '0')}</b><span>${label}</span>\n </div>`;\n\n return html`\n <div class=\"countdown\">\n <span class=\"label\">Ends in</span>\n <div class=\"countdown-track\">\n ${cell(c.days, 'days')}<span class=\"sep\">:</span>\n ${cell(c.hours, 'hours')}<span class=\"sep\">:</span>\n ${cell(c.minutes, 'min')}<span class=\"sep\">:</span>\n ${cell(c.seconds, 'sec')}\n </div>\n </div>\n `;\n }\n\n render() {\n if (!this.section) return nothing;\n return renderTemplate(this);\n }\n}\n"],"names":["countdownTo","endTs","now","remaining","STATUS_LABELS","OsLeaderboardCasinoHero","LitElement","status","changed","target","from","duration","start","tick","t","p","eased","value","activeEndTs","isCountdownExpired","demoCountdownEndIso","nothing","html","c","cell","v","label","renderTemplate","osLeaderboardCasinoTheme","scss","styles","__decorateClass","property","state","Component","OS_LEADERBOARD_CASINO_HERO"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- const e = ':host{display:block;width:100%}.hero{position:relative;overflow:hidden;border-radius:var(--radius-sm);border:1px solid var(--panel-border);background:radial-gradient(90% 130% at 50% -20%,color-mix(in srgb,var(--violet) 22%,transparent),transparent 55%),radial-gradient(70% 110% at 12% 110%,color-mix(in srgb,var(--gold) 16%,transparent),transparent 58%),radial-gradient(65% 100% at 88% 108%,color-mix(in srgb,var(--gold) 12%,transparent),transparent 62%),var(--panel-bg);box-shadow:var(--panel-shadow);text-align:center;padding:clamp(26px,5vw,44px) clamp(18px,4vw,36px) clamp(22px,4vw,34px)}.hero:before{content:"";position:absolute;top:120%;left:50%;width:150%;aspect-ratio:1;transform:translate(-50%,-50%);transform-origin:50% 50%;background:conic-gradient(from 0deg,transparent 0deg,transparent 45deg,color-mix(in srgb,var(--gold) 24%,transparent) 55deg,color-mix(in srgb,var(--gold) 20%,transparent) 58deg,transparent 67deg,transparent 198deg,color-mix(in srgb,var(--violet) 22%,transparent) 208deg,color-mix(in srgb,var(--violet) 16%,transparent) 211deg,transparent 220deg,transparent 360deg);filter:blur(28px);opacity:.92;animation:halo 16s linear infinite;pointer-events:none;z-index:0}@keyframes halo{to{transform:translate(-50%,-50%) rotate(360deg)}}@media(max-width:640px){.hero:before{top:100%;width:215%}}.banner-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.22;z-index:0}.inner{position:relative;z-index:1}.status{display:inline-flex;align-items:center;gap:7px;font-size:10.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;padding:6px 14px;border-radius:999px;background:var(--panel-bg);border:1px solid var(--panel-border);color:var(--text-dim)}.status.active{color:var(--green);border-color:color-mix(in srgb,var(--green) 45%,transparent)}.status.active .dot{width:7px;height:7px;border-radius:50%;background:var(--green);animation:pulse 1.6s ease-in-out infinite}.status.completed{color:var(--gold);border-color:var(--hairline-gold)}.status.cancelled{color:var(--red)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.35}}h2{margin:16px 0 0;font-family:var(--font-display);font-size:clamp(26px,5.4vw,40px);font-weight:800;letter-spacing:-.02em;line-height:1.12;background:var(--gold-gradient);background-size:200% auto;background-position:0% center;-webkit-background-clip:text;background-clip:text;color:transparent;animation:shimmer 5.5s linear infinite;text-wrap:balance}@keyframes shimmer{0%{background-position:0% center}to{background-position:200% center}}.description{margin:12px auto 0;font-size:13.5px;line-height:1.6;color:var(--text-dim);max-width:52ch}.pool{margin-top:22px;display:inline-flex;flex-direction:column;align-items:center;gap:4px;padding:14px 34px;border-radius:16px;background:var(--panel-bg);border:1px solid var(--panel-border);box-shadow:var(--panel-shadow)}.pool .label{font-size:10px;font-weight:800;letter-spacing:.2em;text-transform:uppercase;color:var(--text-faint)}.pool .value{font-family:var(--font-mono);font-size:clamp(28px,5vw,38px);font-weight:800;color:var(--gold-strong);text-shadow:0 0 26px var(--gold-glow);line-height:1.1;font-variant-numeric:tabular-nums;transition:text-shadow .3s ease}.pool .value.bump{animation:pool-bump .6s ease}@keyframes pool-bump{0%{transform:scale(1)}35%{transform:scale(1.06);text-shadow:0 0 42px var(--gold-glow),0 0 12px var(--gold-strong)}to{transform:scale(1)}}.pool .rising{display:inline-flex;align-items:center;gap:4px;margin-top:2px;font-size:9.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--green)}.pool .rising i{width:5px;height:5px;border-radius:50%;background:var(--green);animation:pulse 1.6s ease-in-out infinite}.countdown{display:flex;align-items:center;justify-content:center;gap:8px;margin-top:22px;flex-wrap:wrap}.countdown .label{width:100%;font-size:10px;font-weight:800;letter-spacing:.2em;text-transform:uppercase;color:var(--text-faint);margin-bottom:2px}.cell{min-width:60px;text-align:center;background:var(--panel-bg);border:1px solid var(--panel-border);border-radius:var(--radius-sm);padding:9px 10px 8px}.cell b{display:block;font-family:var(--font-mono);font-size:21px;font-weight:800;color:var(--text);line-height:1.1}.cell span{display:block;margin-top:3px;font-size:9px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--text-faint)}.sep{font-family:var(--font-mono);font-size:18px;font-weight:800;color:var(--gold);opacity:.7}@media(max-width:480px){.cell{min-width:48px;padding:8px 6px 7px}.cell b{font-size:18px}.countdown{gap:5px}.sep{font-size:15px}}.ended{display:inline-flex;align-items:center;gap:8px;margin-top:22px;padding:10px 20px;border-radius:var(--radius-sm);background:var(--gold-soft);border:1px solid var(--hairline-gold);color:var(--gold);font-weight:700;font-size:14px}';
1
+ const e = ':host{display:block;width:100%}.hero{position:relative;overflow:hidden;border-radius:var(--radius-sm);border:1px solid var(--panel-border);background:radial-gradient(90% 130% at 50% -20%,color-mix(in srgb,var(--violet) 22%,transparent),transparent 55%),radial-gradient(70% 110% at 12% 110%,color-mix(in srgb,var(--gold) 16%,transparent),transparent 58%),radial-gradient(65% 100% at 88% 108%,color-mix(in srgb,var(--gold) 12%,transparent),transparent 62%),var(--panel-bg);box-shadow:var(--panel-shadow);text-align:center;padding:clamp(26px,5vw,44px) clamp(18px,4vw,36px) clamp(22px,4vw,34px)}.hero:before{content:"";position:absolute;top:120%;left:50%;width:150%;aspect-ratio:1;transform:translate(-50%,-50%);transform-origin:50% 50%;background:conic-gradient(from 0deg,transparent 0deg,transparent 45deg,color-mix(in srgb,var(--gold) 24%,transparent) 55deg,color-mix(in srgb,var(--gold) 20%,transparent) 58deg,transparent 67deg,transparent 198deg,color-mix(in srgb,var(--violet) 22%,transparent) 208deg,color-mix(in srgb,var(--violet) 16%,transparent) 211deg,transparent 220deg,transparent 360deg);filter:blur(28px);opacity:.92;animation:halo 16s linear infinite;pointer-events:none;z-index:0}@keyframes halo{to{transform:translate(-50%,-50%) rotate(360deg)}}@media(max-width:640px){.hero:before{top:100%;width:215%}}.banner-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.22;z-index:0}.inner{position:relative;z-index:1}.status{display:inline-flex;align-items:center;gap:7px;font-size:10.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;padding:6px 14px;border-radius:999px;background:var(--panel-bg);border:1px solid var(--panel-border);color:var(--text-dim)}.status.active{color:var(--green);border-color:color-mix(in srgb,var(--green) 45%,transparent)}.status.active .dot{width:7px;height:7px;border-radius:50%;background:var(--green);animation:pulse 1.6s ease-in-out infinite}.status.completed{color:var(--gold);border-color:var(--hairline-gold)}.status.cancelled{color:var(--red)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.35}}h2{margin:16px 0 0;font-family:var(--font-display);font-size:clamp(26px,5.4vw,40px);font-weight:800;letter-spacing:-.02em;line-height:1.12;background:var(--gold-gradient);background-size:200% auto;background-position:0% center;-webkit-background-clip:text;background-clip:text;color:transparent;animation:shimmer 5.5s linear infinite;text-wrap:balance}@keyframes shimmer{0%{background-position:0% center}to{background-position:200% center}}.description{margin:12px auto 0;font-size:13.5px;line-height:1.6;color:var(--text-dim);max-width:52ch}.pool{margin-top:22px;display:inline-flex;flex-direction:column;align-items:center;gap:4px;padding:14px 34px;border-radius:16px;background:var(--panel-bg);border:1px solid var(--panel-border);box-shadow:var(--panel-shadow)}.pool .label{font-size:10px;font-weight:800;letter-spacing:.2em;text-transform:uppercase;color:var(--text-faint)}.pool .value{font-family:var(--font-mono);font-size:clamp(28px,5vw,38px);font-weight:800;color:var(--gold-strong);text-shadow:0 0 26px var(--gold-glow);line-height:1.1;font-variant-numeric:tabular-nums;transition:text-shadow .3s ease}.pool .value.bump{animation:pool-bump .6s ease}@keyframes pool-bump{0%{transform:scale(1)}35%{transform:scale(1.06);text-shadow:0 0 42px var(--gold-glow),0 0 12px var(--gold-strong)}to{transform:scale(1)}}.pool .rising{display:inline-flex;align-items:center;gap:4px;margin-top:2px;font-size:9.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--green)}.pool .rising i{width:5px;height:5px;border-radius:50%;background:var(--green);animation:pulse 1.6s ease-in-out infinite}.countdown{--countdown-cell-size: 60px;--countdown-digit-size: 21px;--countdown-unit-size: 9px;--countdown-sep-size: 18px;--countdown-track-gap: 6px;display:flex;flex-direction:column;align-items:center;gap:8px;margin-top:22px}.countdown .label{font-size:10px;font-weight:800;letter-spacing:.2em;text-transform:uppercase;color:var(--text-faint)}.countdown-track{display:inline-grid;grid-template-columns:var(--countdown-cell-size) auto var(--countdown-cell-size) auto var(--countdown-cell-size) auto var(--countdown-cell-size);column-gap:var(--countdown-track-gap);align-items:center;justify-items:center;max-width:100%}.countdown-track>.cell{width:var(--countdown-cell-size);height:var(--countdown-cell-size);min-width:var(--countdown-cell-size);max-width:var(--countdown-cell-size);min-height:var(--countdown-cell-size);max-height:var(--countdown-cell-size);box-sizing:border-box;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;background:var(--panel-bg);border:1px solid var(--panel-border);border-radius:var(--radius-sm);padding:0;overflow:hidden;grid-column:span 1}.countdown-track>.cell b{display:block;width:100%;font-family:var(--font-mono);font-size:var(--countdown-digit-size);font-weight:800;color:var(--text);line-height:1}.countdown-track>.cell span{display:block;width:100%;margin-top:3px;font-size:var(--countdown-unit-size);font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-faint);line-height:1;white-space:nowrap}.countdown-track>.sep{flex:none;text-align:center;font-family:var(--font-mono);font-size:var(--countdown-sep-size);font-weight:800;color:var(--gold);opacity:.7;line-height:1}@media(max-width:545px){.countdown{--countdown-cell-size: 52px;--countdown-digit-size: 18px;--countdown-unit-size: 8px;--countdown-sep-size: 15px}}@media(max-width:420px){.countdown{--countdown-cell-size: 44px;--countdown-digit-size: 14px;--countdown-unit-size: 7px;--countdown-sep-size: 11px}.countdown .label{font-size:9px;letter-spacing:.16em}}.ended{display:inline-flex;align-items:center;gap:8px;margin-top:22px;padding:10px 20px;border-radius:var(--radius-sm);background:var(--gold-soft);border:1px solid var(--hairline-gold);color:var(--gold);font-weight:700;font-size:14px}';
2
2
  export {
3
3
  e as default
4
4
  };
@@ -1,4 +1,4 @@
1
- const o = '@charset "UTF-8";:host{display:block;width:100%}.strategy{font-size:9.5px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;padding:4px 10px;border-radius:999px;background:var(--violet-soft);border:1px solid color-mix(in srgb,var(--violet) 40%,transparent);color:#c9adff}.podium{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;align-items:end}.slot{position:relative;overflow:hidden;border-radius:var(--radius-sm);padding:16px 12px 14px;text-align:center;border:1px solid var(--panel-border);background:var(--panel-bg);box-shadow:var(--panel-shadow);transition:transform var(--transition-fast),box-shadow var(--transition-fast)}.slot:hover{transform:translateY(-3px)}.slot.first{order:2;padding-top:22px;padding-bottom:20px;border-color:var(--panel-border);background:radial-gradient(120% 90% at 50% -10%,color-mix(in srgb,var(--gold) 18%,transparent),transparent 60%),var(--panel-bg);box-shadow:var(--panel-shadow)}.slot.second{order:1;border-color:var(--panel-border);background:var(--panel-bg)}.slot.third{order:3;border-color:var(--panel-border);background:var(--panel-bg)}.coin{display:flex;justify-content:center;min-height:52px}.slot.first .coin{min-height:68px}.place{margin-top:7px;font-size:9px;font-weight:800;letter-spacing:.16em;text-transform:uppercase;color:var(--text-faint)}.slot.first .place{color:var(--gold)}.slot.second .place{color:var(--silver)}.slot.third .place{color:var(--bronze)}.slot .name{margin-top:5px;font-size:12px;font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.slot .value{margin-top:6px;font-family:var(--font-mono);font-size:16px;font-weight:800;color:var(--gold-strong)}.slot.first .value{font-size:20px;text-shadow:0 0 18px var(--gold-glow)}.list{display:flex;flex-direction:column;gap:7px;margin-top:10px}.tier{display:flex;align-items:center;gap:12px;width:100%;text-align:left;font-family:var(--font-body);padding:11px 14px;background:var(--panel-bg);border:1px solid var(--panel-border);border-radius:var(--radius-sm);box-shadow:var(--panel-shadow);transition:border-color var(--transition-fast)}.tier:hover{border-color:var(--hairline-gold)}.tier .icon{flex:none;display:grid;place-items:center;line-height:0}.tier .icon svg{width:28px;height:28px}.tier .info{flex:1;min-width:0}.tier .name{font-size:13px;font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tier .range{margin-top:1px;font-size:11px;color:var(--text-dim)}.tier .value{flex:none;font-family:var(--font-mono);font-size:13.5px;font-weight:700;color:var(--gold)}@media(max-width:480px){.slot .value{font-size:13.5px}.slot.first .value{font-size:16px}}';
1
+ const o = '@charset "UTF-8";:host{display:block;width:100%}.strategy{font-size:9.5px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;padding:4px 10px;border-radius:999px;background:var(--violet-soft);border:1px solid color-mix(in srgb,var(--violet) 40%,transparent);color:#c9adff}.podium{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;align-items:end}.slot{position:relative;overflow:hidden;border-radius:var(--radius-sm);padding:16px 12px 14px;text-align:center;border:1px solid var(--panel-border);background:var(--panel-bg);box-shadow:var(--panel-shadow);transition:transform var(--transition-fast),box-shadow var(--transition-fast)}.slot:hover{transform:translateY(-3px)}.slot.first{order:2;padding-top:22px;padding-bottom:20px;border-color:var(--panel-border);background:radial-gradient(120% 90% at 50% -10%,color-mix(in srgb,var(--gold) 18%,transparent),transparent 60%),var(--panel-bg);box-shadow:var(--panel-shadow)}.slot.second{order:1;border-color:var(--panel-border);background:var(--panel-bg)}.slot.third{order:3;border-color:var(--panel-border);background:var(--panel-bg)}.coin{display:flex;justify-content:center;min-height:52px}.slot.first .coin{min-height:68px}.place{margin-top:7px;font-size:9px;font-weight:800;letter-spacing:.16em;text-transform:uppercase;color:var(--text-faint)}.slot.first .place{color:var(--gold)}.slot.second .place{color:var(--silver)}.slot.third .place{color:var(--bronze)}.slot .name{margin-top:5px;font-size:12px;font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.slot .value{margin-top:6px;font-family:var(--font-mono);font-size:16px;font-weight:800;color:var(--gold-strong)}.slot.first .value{font-size:20px;text-shadow:0 0 18px var(--gold-glow)}.list{display:flex;flex-direction:column;gap:7px;margin-top:10px}.tier{display:flex;align-items:center;gap:12px;width:100%;text-align:left;font-family:var(--font-body);padding:11px 14px;background:var(--panel-bg);border:1px solid var(--panel-border);border-radius:var(--radius-sm);box-shadow:var(--panel-shadow);transition:border-color var(--transition-fast)}.tier:hover{border-color:var(--hairline-gold)}.tier .icon{flex:none;display:grid;place-items:center;line-height:0}.tier .icon svg{width:28px;height:28px}.tier .info{flex:1;min-width:0}.tier .name{font-size:13px;font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tier .range{margin-top:1px;font-size:11px;color:var(--text-dim)}.tier .value{flex:none;font-family:var(--font-mono);font-size:13.5px;font-weight:700;color:var(--gold)}@media(max-width:480px){.slot .value{font-size:13.5px}.slot.first .value{font-size:16px}}@media(max-width:420px){.podium{gap:8px}.slot{padding:14px 8px 12px}.slot.first{padding-top:18px;padding-bottom:16px}.slot .name{font-size:11px;letter-spacing:-.01em}}';
2
2
  export {
3
3
  o as default
4
4
  };
@@ -0,0 +1,7 @@
1
+ /** Default glam demo countdown — ~3d 14h (matches producer preset pattern). */
2
+ export declare const DEMO_COUNTDOWN_MS: number;
3
+ export declare function demoCountdownEndIso(now?: number): string;
4
+ export declare function countdownRemainingMs(endTs: string, now?: number): number;
5
+ export declare function isCountdownExpired(endTs: string, now?: number): boolean;
6
+ /** Refresh preset/demo hero end when the host did not supply campaign.endAt. */
7
+ export declare function refreshPresetHeroCountdown(endTs: string | undefined, status: string | undefined, campaignEndAt: string | undefined, now?: number): string | undefined;
@@ -0,0 +1,22 @@
1
+ const u = 3096e5;
2
+ function r(n = Date.now()) {
3
+ return new Date(n + 3096e5).toISOString();
4
+ }
5
+ function i(n, e = Date.now()) {
6
+ return new Date(n).getTime() - e;
7
+ }
8
+ function c(n, e = Date.now()) {
9
+ const t = i(n, e);
10
+ return !Number.isFinite(t) || t <= 0;
11
+ }
12
+ function w(n, e, t, o = Date.now()) {
13
+ return t != null || !n || e === "completed" || e === "cancelled" ? n : r(o);
14
+ }
15
+ export {
16
+ u as DEMO_COUNTDOWN_MS,
17
+ i as countdownRemainingMs,
18
+ r as demoCountdownEndIso,
19
+ c as isCountdownExpired,
20
+ w as refreshPresetHeroCountdown
21
+ };
22
+ //# sourceMappingURL=demo-countdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demo-countdown.js","sources":["../../../../src/components/os-leaderboard-casino/utils/demo-countdown.ts"],"sourcesContent":["/** Default glam demo countdown — ~3d 14h (matches producer preset pattern). */\nexport const DEMO_COUNTDOWN_MS =\n 3 * 24 * 60 * 60 * 1000 + 14 * 60 * 60 * 1000;\n\nexport function demoCountdownEndIso(now = Date.now()): string {\n return new Date(now + DEMO_COUNTDOWN_MS).toISOString();\n}\n\nexport function countdownRemainingMs(\n endTs: string,\n now = Date.now(),\n): number {\n return new Date(endTs).getTime() - now;\n}\n\nexport function isCountdownExpired(endTs: string, now = Date.now()): boolean {\n const remaining = countdownRemainingMs(endTs, now);\n return !Number.isFinite(remaining) || remaining <= 0;\n}\n\n/** Refresh preset/demo hero end when the host did not supply campaign.endAt. */\nexport function refreshPresetHeroCountdown(\n endTs: string | undefined,\n status: string | undefined,\n campaignEndAt: string | undefined,\n now = Date.now(),\n): string | undefined {\n if (campaignEndAt != null) return endTs;\n if (!endTs) return endTs;\n if (status === 'completed' || status === 'cancelled') return endTs;\n return demoCountdownEndIso(now);\n}\n"],"names":["DEMO_COUNTDOWN_MS","demoCountdownEndIso","now","countdownRemainingMs","endTs","isCountdownExpired","remaining","refreshPresetHeroCountdown","status","campaignEndAt"],"mappings":"AACO,MAAMA,IACX;AAEK,SAASC,EAAoBC,IAAM,KAAK,OAAe;AAC5D,SAAO,IAAI,KAAKA,IAAM,MAAiB,EAAE,YAAA;AAC3C;AAEO,SAASC,EACdC,GACAF,IAAM,KAAK,OACH;AACR,SAAO,IAAI,KAAKE,CAAK,EAAE,YAAYF;AACrC;AAEO,SAASG,EAAmBD,GAAeF,IAAM,KAAK,OAAgB;AAC3E,QAAMI,IAAYH,EAAqBC,GAAOF,CAAG;AACjD,SAAO,CAAC,OAAO,SAASI,CAAS,KAAKA,KAAa;AACrD;AAGO,SAASC,EACdH,GACAI,GACAC,GACAP,IAAM,KAAK,OACS;AAGpB,SAFIO,KAAiB,QACjB,CAACL,KACDI,MAAW,eAAeA,MAAW,cAAoBJ,IACtDH,EAAoBC,CAAG;AAChC;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oddsmith/ui",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Brandable casino leaderboard web component",
5
5
  "keywords": [
6
6
  "casino",