@open-slot-ui/pixi 0.8.2 → 0.9.0
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.
- package/dist/art.js +1 -1
- package/dist/{chunk-PYXZIGXG.js → chunk-Z7X5JH7H.js} +7 -4
- package/dist/chunk-Z7X5JH7H.js.map +1 -0
- package/dist/index.cjs +170 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +169 -83
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-PYXZIGXG.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -762,6 +762,31 @@ interface BuyFeatureOptions {
|
|
|
762
762
|
/** Mount the buy-feature modal. Returns a leak-free teardown. */
|
|
763
763
|
declare function mountBuyFeatureModal(_app: Application, hud: BootedHud, features: FeatureSpec[], opts?: BuyFeatureOptions): () => void;
|
|
764
764
|
|
|
765
|
+
/** Minimal HUD surface the confirm needs — the translator + theme font. */
|
|
766
|
+
interface ConfirmUI {
|
|
767
|
+
t(key: string, params?: Record<string, string | number>): string;
|
|
768
|
+
theme: {
|
|
769
|
+
type: {
|
|
770
|
+
family: string;
|
|
771
|
+
};
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
interface ConfirmOptions {
|
|
775
|
+
/** Heading (already resolved text, or an i18n key). Default `Buy Feature`. */
|
|
776
|
+
title?: string;
|
|
777
|
+
/** Body message (already resolved). */
|
|
778
|
+
message: string;
|
|
779
|
+
/** Confirm button label (resolved text or i18n key). Default `openui.confirm`. */
|
|
780
|
+
confirmLabel?: string;
|
|
781
|
+
/** Cancel button label. Default `openui.cancel`. */
|
|
782
|
+
cancelLabel?: string;
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Show the universal confirm dialog. Resolves `true` on Confirm, `false` on Cancel / backdrop
|
|
786
|
+
* / Escape. Self-mounting + self-cleaning; layers above everything (z-index above the buy modal).
|
|
787
|
+
*/
|
|
788
|
+
declare function showConfirm(ui: ConfirmUI, opts: ConfirmOptions): Promise<boolean>;
|
|
789
|
+
|
|
765
790
|
interface BootErrorOptions {
|
|
766
791
|
title?: string;
|
|
767
792
|
message?: string;
|
|
@@ -844,4 +869,4 @@ declare class Tweener {
|
|
|
844
869
|
/** Treat touch devices as non-desktop so we don't fire phantom hover states. */
|
|
845
870
|
declare function isDesktop(): boolean;
|
|
846
871
|
|
|
847
|
-
export { AutoplayDrawerView, AutoplayView, type AutoplayViewOptions, type BootErrorOptions, type BootedHud, type ButtonGlyph, ButtonView, type ButtonViewOptions, type BuyFeatureOptions, ControlView, ControlViewFactory, DialogView, type DialogViewOptions, type FeatureSpec, type HudOptions, type InfoContentBuilder, MenuView, type MenuViewOptions, OpenUIPixi, OpenUIPixiOptions, type PanelBodyOptions, PanelBodyView, PanelView, type PanelViewOptions, type PopoverArt, type PopoverParts, PopoverView, ReadoutView, type ReadoutViewOptions, type ReplayInfo, SelectView, type SelectViewOptions, SliderView, SpinSkin, SpinSkinFactory, SpinView, type SpinViewOptions, StepperView, type SvgSpinTextures, TextCellRenderer, type TextCellRendererOptions, ToggleView, type ToggleViewOptions, TurboView, type TurboViewOptions, Tweener, ValueDisplayView, defaultSpinSkin, drawSpin, hideBootError, isDesktop, mountBuyFeatureModal, mountHud, mountInfoMenu, showBootError, svgSpinSkin };
|
|
872
|
+
export { AutoplayDrawerView, AutoplayView, type AutoplayViewOptions, type BootErrorOptions, type BootedHud, type ButtonGlyph, ButtonView, type ButtonViewOptions, type BuyFeatureOptions, type ConfirmOptions, ControlView, ControlViewFactory, DialogView, type DialogViewOptions, type FeatureSpec, type HudOptions, type InfoContentBuilder, MenuView, type MenuViewOptions, OpenUIPixi, OpenUIPixiOptions, type PanelBodyOptions, PanelBodyView, PanelView, type PanelViewOptions, type PopoverArt, type PopoverParts, PopoverView, ReadoutView, type ReadoutViewOptions, type ReplayInfo, SelectView, type SelectViewOptions, SliderView, SpinSkin, SpinSkinFactory, SpinView, type SpinViewOptions, StepperView, type SvgSpinTextures, TextCellRenderer, type TextCellRendererOptions, ToggleView, type ToggleViewOptions, TurboView, type TurboViewOptions, Tweener, ValueDisplayView, defaultSpinSkin, drawSpin, hideBootError, isDesktop, mountBuyFeatureModal, mountHud, mountInfoMenu, showBootError, showConfirm, svgSpinSkin };
|
package/dist/index.d.ts
CHANGED
|
@@ -762,6 +762,31 @@ interface BuyFeatureOptions {
|
|
|
762
762
|
/** Mount the buy-feature modal. Returns a leak-free teardown. */
|
|
763
763
|
declare function mountBuyFeatureModal(_app: Application, hud: BootedHud, features: FeatureSpec[], opts?: BuyFeatureOptions): () => void;
|
|
764
764
|
|
|
765
|
+
/** Minimal HUD surface the confirm needs — the translator + theme font. */
|
|
766
|
+
interface ConfirmUI {
|
|
767
|
+
t(key: string, params?: Record<string, string | number>): string;
|
|
768
|
+
theme: {
|
|
769
|
+
type: {
|
|
770
|
+
family: string;
|
|
771
|
+
};
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
interface ConfirmOptions {
|
|
775
|
+
/** Heading (already resolved text, or an i18n key). Default `Buy Feature`. */
|
|
776
|
+
title?: string;
|
|
777
|
+
/** Body message (already resolved). */
|
|
778
|
+
message: string;
|
|
779
|
+
/** Confirm button label (resolved text or i18n key). Default `openui.confirm`. */
|
|
780
|
+
confirmLabel?: string;
|
|
781
|
+
/** Cancel button label. Default `openui.cancel`. */
|
|
782
|
+
cancelLabel?: string;
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Show the universal confirm dialog. Resolves `true` on Confirm, `false` on Cancel / backdrop
|
|
786
|
+
* / Escape. Self-mounting + self-cleaning; layers above everything (z-index above the buy modal).
|
|
787
|
+
*/
|
|
788
|
+
declare function showConfirm(ui: ConfirmUI, opts: ConfirmOptions): Promise<boolean>;
|
|
789
|
+
|
|
765
790
|
interface BootErrorOptions {
|
|
766
791
|
title?: string;
|
|
767
792
|
message?: string;
|
|
@@ -844,4 +869,4 @@ declare class Tweener {
|
|
|
844
869
|
/** Treat touch devices as non-desktop so we don't fire phantom hover states. */
|
|
845
870
|
declare function isDesktop(): boolean;
|
|
846
871
|
|
|
847
|
-
export { AutoplayDrawerView, AutoplayView, type AutoplayViewOptions, type BootErrorOptions, type BootedHud, type ButtonGlyph, ButtonView, type ButtonViewOptions, type BuyFeatureOptions, ControlView, ControlViewFactory, DialogView, type DialogViewOptions, type FeatureSpec, type HudOptions, type InfoContentBuilder, MenuView, type MenuViewOptions, OpenUIPixi, OpenUIPixiOptions, type PanelBodyOptions, PanelBodyView, PanelView, type PanelViewOptions, type PopoverArt, type PopoverParts, PopoverView, ReadoutView, type ReadoutViewOptions, type ReplayInfo, SelectView, type SelectViewOptions, SliderView, SpinSkin, SpinSkinFactory, SpinView, type SpinViewOptions, StepperView, type SvgSpinTextures, TextCellRenderer, type TextCellRendererOptions, ToggleView, type ToggleViewOptions, TurboView, type TurboViewOptions, Tweener, ValueDisplayView, defaultSpinSkin, drawSpin, hideBootError, isDesktop, mountBuyFeatureModal, mountHud, mountInfoMenu, showBootError, svgSpinSkin };
|
|
872
|
+
export { AutoplayDrawerView, AutoplayView, type AutoplayViewOptions, type BootErrorOptions, type BootedHud, type ButtonGlyph, ButtonView, type ButtonViewOptions, type BuyFeatureOptions, type ConfirmOptions, ControlView, ControlViewFactory, DialogView, type DialogViewOptions, type FeatureSpec, type HudOptions, type InfoContentBuilder, MenuView, type MenuViewOptions, OpenUIPixi, OpenUIPixiOptions, type PanelBodyOptions, PanelBodyView, PanelView, type PanelViewOptions, type PopoverArt, type PopoverParts, PopoverView, ReadoutView, type ReadoutViewOptions, type ReplayInfo, SelectView, type SelectViewOptions, SliderView, SpinSkin, SpinSkinFactory, SpinView, type SpinViewOptions, StepperView, type SvgSpinTextures, TextCellRenderer, type TextCellRendererOptions, ToggleView, type ToggleViewOptions, TurboView, type TurboViewOptions, Tweener, ValueDisplayView, defaultSpinSkin, drawSpin, hideBootError, isDesktop, mountBuyFeatureModal, mountHud, mountInfoMenu, showBootError, showConfirm, svgSpinSkin };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ControlView, ButtonView, SliderView, buildBlockColumn, OpenUIPixi } from './chunk-
|
|
2
|
-
export { AutoplayDrawerView, AutoplayView, ButtonView, ControlView, DialogView, MenuView, OpenUIPixi, ReadoutView, SelectView, SliderView, SpinView, StepperView, TextCellRenderer, ToggleView, TurboView, Tweener, ValueDisplayView, buildBlockColumn, defaultSpinSkin, drawSpin, isDesktop, svgSpinSkin } from './chunk-
|
|
1
|
+
import { ControlView, ButtonView, SliderView, buildBlockColumn, OpenUIPixi } from './chunk-Z7X5JH7H.js';
|
|
2
|
+
export { AutoplayDrawerView, AutoplayView, ButtonView, ControlView, DialogView, MenuView, OpenUIPixi, ReadoutView, SelectView, SliderView, SpinView, StepperView, TextCellRenderer, ToggleView, TurboView, Tweener, ValueDisplayView, buildBlockColumn, defaultSpinSkin, drawSpin, isDesktop, svgSpinSkin } from './chunk-Z7X5JH7H.js';
|
|
3
3
|
import { Text, Graphics, Container, Rectangle } from 'pixi.js';
|
|
4
|
-
import { LOCALE_LABELS, createUI, composeMenu, buildPanel,
|
|
4
|
+
import { LOCALE_LABELS, createUI, composeMenu, buildPanel, modeStatsItems, formatAmountPrecise, factsVars, auditRules } from '@open-slot-ui/core';
|
|
5
5
|
|
|
6
6
|
var RISE = 26;
|
|
7
7
|
var STAGGER = 38;
|
|
@@ -280,7 +280,11 @@ var PanelBodyView = class extends ControlView {
|
|
|
280
280
|
};
|
|
281
281
|
var esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
282
282
|
var rich = (s) => esc(s).replace(/\*\*(.+?)\*\*/g, "<b>$1</b>");
|
|
283
|
-
function
|
|
283
|
+
function statGridHtml(items, tr) {
|
|
284
|
+
const rows = items.map((it) => `<div><dt>${esc(tr(it.label))}</dt><dd>${esc(tr(it.value))}</dd></div>`).join("");
|
|
285
|
+
return `<dl class="ohm-stats">${rows}</dl>`;
|
|
286
|
+
}
|
|
287
|
+
function renderBlocks(blocks, tr, facts) {
|
|
284
288
|
const out = [];
|
|
285
289
|
for (const b of blocks) {
|
|
286
290
|
switch (b.kind) {
|
|
@@ -322,9 +326,16 @@ function renderBlocks(blocks, tr) {
|
|
|
322
326
|
out.push(`<table class="ohm-table">${head}<tbody>${body}</tbody></table>`);
|
|
323
327
|
break;
|
|
324
328
|
}
|
|
325
|
-
case "stat-grid":
|
|
326
|
-
|
|
327
|
-
|
|
329
|
+
case "stat-grid":
|
|
330
|
+
out.push(statGridHtml(b.items, tr));
|
|
331
|
+
break;
|
|
332
|
+
// The AUTO per-mode RTP / Max-win grid — rendered straight from the declared
|
|
333
|
+
// game facts (+ any host extras), so the table can never drift from the config.
|
|
334
|
+
// `modeStatsItems` localizes the label PARTS itself ("Max win" · the mode name),
|
|
335
|
+
// so the grid renderer gets identity-tr — no double translation.
|
|
336
|
+
case "mode-stats": {
|
|
337
|
+
const extras = (b.extras ?? []).map((e) => ({ label: tr(e.label), value: tr(e.value) }));
|
|
338
|
+
out.push(statGridHtml([...modeStatsItems(facts, tr), ...extras], (s) => s));
|
|
328
339
|
break;
|
|
329
340
|
}
|
|
330
341
|
case "steps": {
|
|
@@ -394,8 +405,30 @@ function mountInfoMenu(app, ui) {
|
|
|
394
405
|
const soundMode = menu.sound ?? "sliders";
|
|
395
406
|
const volRow = (id, label, hint, val) => `<div class="ohm-setting"><label class="ohm-row"><span>${esc(tr(label))}</span><input class="ohm-slider" data-vol="${id}" type="range" min="0" max="1" step="0.01" value="${val}"></label><div class="ohm-hint">${esc(tr(hint))}</div></div>`;
|
|
396
407
|
const soundSliders = soundMode === "master" ? volRow("master", "Volume", "Adjust the overall game volume.", ui.sfxSlider.value.get()) : soundMode === "sliders" ? volRow("music", "Music", "Adjust the background music volume.", ui.musicSlider.value.get()) + volRow("sfx", "Effects", "Adjust the sound-effects volume.", ui.sfxSlider.value.get()) : "";
|
|
397
|
-
const
|
|
398
|
-
|
|
408
|
+
const rulesTr = () => {
|
|
409
|
+
const vars2 = factsVars(ui.facts.get(), { "game.name": ui.gameInfo.name ?? "", "game.version": ui.gameInfo.version ?? "" });
|
|
410
|
+
return (s) => ui.t(s, vars2);
|
|
411
|
+
};
|
|
412
|
+
const auditCardHtml = (trr) => {
|
|
413
|
+
if (!menu.rules?.length) return "";
|
|
414
|
+
const issues = auditRules(ui.facts.get(), menu.rules, { resolve: trr });
|
|
415
|
+
if (!issues.length) return "";
|
|
416
|
+
const req = issues.filter((i) => i.level === "required");
|
|
417
|
+
const rec = issues.filter((i) => i.level === "recommended");
|
|
418
|
+
const list = (items) => `<ul>${items.map((i) => `<li>${esc(tr(i.message))}</li>`).join("")}</ul>`;
|
|
419
|
+
return `<div class="ohm-audit" role="alert">
|
|
420
|
+
<div class="ohm-audit-title">\u26A0 ${esc(tr("openui.rulesAudit.title"))}</div>
|
|
421
|
+
${req.length ? `<div class="ohm-audit-sub">${esc(tr("openui.rulesAudit.required"))}</div>${list(req)}` : ""}
|
|
422
|
+
${rec.length ? `<div class="ohm-audit-sub ohm-audit-sub--rec">${esc(tr("openui.rulesAudit.recommended"))}</div><div class="ohm-audit-rec">${list(rec)}</div>` : ""}
|
|
423
|
+
</div>`;
|
|
424
|
+
};
|
|
425
|
+
const rulesInnerHtml = () => {
|
|
426
|
+
if (!menu.rules) return "";
|
|
427
|
+
const trr = rulesTr();
|
|
428
|
+
return auditCardHtml(trr) + renderBlocks(menu.rules, trr, ui.facts.get());
|
|
429
|
+
};
|
|
430
|
+
const paytableHtml = menu.paytable ? renderBlocks(menu.paytable, tr, ui.facts.get()) : "";
|
|
431
|
+
const rulesHtml = rulesInnerHtml();
|
|
399
432
|
const banner = menu.banner ? `<img class="ohm-logo" alt="" src="${menu.banner.src}"${menu.banner.width ? ` width="${menu.banner.width}"` : ""}${menu.banner.height ? ` height="${menu.banner.height}"` : ""}>` : ui.gameInfo.name ? `<h1 class="ohm-logo-text">${esc(ui.gameInfo.name)}</h1>` : "";
|
|
400
433
|
host2.innerHTML = `
|
|
401
434
|
<div class="ohm-backdrop" data-close></div>
|
|
@@ -467,19 +500,40 @@ function mountInfoMenu(app, ui) {
|
|
|
467
500
|
else if (el instanceof HTMLSelectElement) el.addEventListener("change", () => ui.bus.emit("optionSelected", { id, value: el.value, index: el.selectedIndex }));
|
|
468
501
|
});
|
|
469
502
|
host2.querySelectorAll("[data-close]").forEach((b) => b.addEventListener("click", () => ui.settingsPanel.closePanel()));
|
|
503
|
+
const refreshRules = () => {
|
|
504
|
+
const rulesEl = host2.querySelector("#ohm-rules");
|
|
505
|
+
if (rulesEl && menu.rules) rulesEl.innerHTML = rulesInnerHtml();
|
|
506
|
+
};
|
|
470
507
|
disposers.push(
|
|
471
508
|
ui.locale.subscribe(() => {
|
|
472
509
|
const body = host2.querySelector(".ohm-body");
|
|
473
510
|
if (body) {
|
|
474
|
-
|
|
475
|
-
if (rulesEl && menu.rules) rulesEl.innerHTML = renderBlocks(menu.rules, tr);
|
|
511
|
+
refreshRules();
|
|
476
512
|
if (lang) lang.value = ui.locale.get();
|
|
477
513
|
}
|
|
514
|
+
}),
|
|
515
|
+
ui.facts.subscribe(refreshRules)
|
|
516
|
+
);
|
|
517
|
+
let menuLocked = false;
|
|
518
|
+
disposers.push(
|
|
519
|
+
ui.settingsPanel.state.subscribe(() => {
|
|
520
|
+
const isOpen = ui.settingsPanel.isOpen;
|
|
521
|
+
host2.classList.toggle("open", isOpen);
|
|
522
|
+
if (isOpen && !menuLocked) {
|
|
523
|
+
ui.lock();
|
|
524
|
+
menuLocked = true;
|
|
525
|
+
} else if (!isOpen && menuLocked) {
|
|
526
|
+
ui.unlock();
|
|
527
|
+
menuLocked = false;
|
|
528
|
+
}
|
|
478
529
|
})
|
|
479
530
|
);
|
|
480
|
-
disposers.push(ui.settingsPanel.state.subscribe(() => host2.classList.toggle("open", ui.settingsPanel.isOpen)));
|
|
481
531
|
return () => {
|
|
482
532
|
for (const d of disposers.splice(0)) d();
|
|
533
|
+
if (menuLocked) {
|
|
534
|
+
ui.unlock();
|
|
535
|
+
menuLocked = false;
|
|
536
|
+
}
|
|
483
537
|
host2.remove();
|
|
484
538
|
};
|
|
485
539
|
}
|
|
@@ -533,6 +587,13 @@ var OHM_CSS = `
|
|
|
533
587
|
.ohm-stats { margin: 12px 0; display: grid; grid-template-columns: 1fr 1fr; gap: 0 28px; }
|
|
534
588
|
.ohm-stats > div { display: flex; justify-content: space-between; padding: 9px 0; border-bottom: 1px solid color-mix(in srgb, var(--text-dim) 20%, transparent); }
|
|
535
589
|
.ohm-stats dt { color: var(--text-dim); margin: 0; } .ohm-stats dd { margin: 0; font-weight: 700; }
|
|
590
|
+
.ohm-audit { margin: 12px 0 18px; padding: 14px 16px; border-radius: 12px; border: 2px solid #d03131; background: color-mix(in srgb, #d03131 8%, transparent); }
|
|
591
|
+
.ohm-audit-title { font-weight: 900; letter-spacing: .5px; color: #b31d1d; }
|
|
592
|
+
.ohm-audit-sub { margin-top: 8px; font-size: 13px; font-weight: 800; color: #b31d1d; }
|
|
593
|
+
.ohm-audit-sub--rec { color: #b07d09; }
|
|
594
|
+
.ohm-audit ul { margin: 6px 0 0; padding-left: 20px; color: var(--text); font-size: 13.5px; line-height: 1.55; }
|
|
595
|
+
.ohm-audit li { margin: 3px 0; }
|
|
596
|
+
.ohm-audit-rec ul { color: var(--text-dim); }
|
|
536
597
|
.ohm-callout { margin: 16px 0 4px; padding: 14px 16px; border-radius: 12px; border-left: 4px solid var(--accent); background: color-mix(in srgb, var(--accent) 9%, transparent); }
|
|
537
598
|
.ohm-callout b { color: var(--accent); } .ohm-callout p { margin: 4px 0 0; color: var(--text); }
|
|
538
599
|
.ohm-callout--warning { border-left-color: #e0a106; background: color-mix(in srgb, #e0a106 10%, transparent); }
|
|
@@ -562,10 +623,67 @@ var OHM_CSS = `
|
|
|
562
623
|
.ohm-group { margin: 8px 0; }
|
|
563
624
|
`;
|
|
564
625
|
|
|
626
|
+
// src/confirmModal.ts
|
|
627
|
+
var esc2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
628
|
+
function showConfirm(ui, opts) {
|
|
629
|
+
return new Promise((resolve) => {
|
|
630
|
+
const host2 = document.createElement("div");
|
|
631
|
+
host2.className = "osc-confirm";
|
|
632
|
+
host2.style.setProperty("--font", ui.theme.type.family);
|
|
633
|
+
const title = ui.t(opts.title ?? "Buy Feature");
|
|
634
|
+
const yes = ui.t(opts.confirmLabel ?? "openui.confirm");
|
|
635
|
+
const no = ui.t(opts.cancelLabel ?? "openui.cancel");
|
|
636
|
+
host2.innerHTML = `
|
|
637
|
+
<div class="osc-confirm-backdrop" data-no></div>
|
|
638
|
+
<div class="osc-confirm-card" role="dialog" aria-modal="true">
|
|
639
|
+
${title ? `<h3 class="osc-confirm-title">${esc2(title)}</h3>` : ""}
|
|
640
|
+
<p class="osc-confirm-msg">${esc2(opts.message)}</p>
|
|
641
|
+
<div class="osc-confirm-row">
|
|
642
|
+
<button class="osc-confirm-btn osc-confirm-no" data-no>${esc2(no)}</button>
|
|
643
|
+
<button class="osc-confirm-btn osc-confirm-yes" data-yes>${esc2(yes)}</button>
|
|
644
|
+
</div>
|
|
645
|
+
</div>`;
|
|
646
|
+
const style = document.createElement("style");
|
|
647
|
+
style.textContent = CONFIRM_CSS;
|
|
648
|
+
host2.appendChild(style);
|
|
649
|
+
document.body.appendChild(host2);
|
|
650
|
+
let settled = false;
|
|
651
|
+
const close = (val) => {
|
|
652
|
+
if (settled) return;
|
|
653
|
+
settled = true;
|
|
654
|
+
window.removeEventListener("keydown", onKey);
|
|
655
|
+
host2.remove();
|
|
656
|
+
resolve(val);
|
|
657
|
+
};
|
|
658
|
+
const onKey = (e) => {
|
|
659
|
+
if (e.key === "Escape") close(false);
|
|
660
|
+
else if (e.key === "Enter") close(true);
|
|
661
|
+
};
|
|
662
|
+
host2.querySelectorAll("[data-no]").forEach((b) => b.addEventListener("click", () => close(false)));
|
|
663
|
+
host2.querySelector("[data-yes]")?.addEventListener("click", () => close(true));
|
|
664
|
+
window.addEventListener("keydown", onKey);
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
var CONFIRM_CSS = `
|
|
668
|
+
.osc-confirm { position: fixed; inset: 0; z-index: 12000; display: grid; place-items: center; font-family: var(--font); }
|
|
669
|
+
.osc-confirm *, .osc-confirm *::before, .osc-confirm *::after { box-sizing: border-box; }
|
|
670
|
+
.osc-confirm-backdrop { position: absolute; inset: 0; background: rgba(8,6,4,.6); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
|
|
671
|
+
.osc-confirm-card { position: relative; width: min(90vw, 420px); background: #ffffff; color: #181b20; border: 3px solid #000; border-radius: 14px; padding: 24px; box-shadow: 0 24px 60px rgba(0,0,0,.55); text-align: center; }
|
|
672
|
+
.osc-confirm-title { margin: 0 0 12px; font-size: 22px; font-weight: 800; letter-spacing: .3px; }
|
|
673
|
+
.osc-confirm-msg { margin: 0 0 22px; font-size: 19px; font-weight: 700; line-height: 1.4; }
|
|
674
|
+
.osc-confirm-row { display: flex; gap: 14px; }
|
|
675
|
+
.osc-confirm-btn { flex: 1; padding: 14px 10px; border-radius: 12px; border: 3px solid #000; font-size: 15px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase; cursor: pointer; transition: transform .1s, background .12s; }
|
|
676
|
+
.osc-confirm-btn:active { transform: scale(.96); }
|
|
677
|
+
.osc-confirm-no { background: #ffffff; color: #181b20; }
|
|
678
|
+
.osc-confirm-no:hover { background: #eef1f6; }
|
|
679
|
+
.osc-confirm-yes { background: #d99000; color: #1a1200; }
|
|
680
|
+
.osc-confirm-yes:hover { filter: brightness(1.05); }
|
|
681
|
+
`;
|
|
682
|
+
|
|
565
683
|
// src/mountHud.ts
|
|
566
684
|
function showReplayModal(ui, info, buttonKey, onSelect) {
|
|
567
685
|
const cur = info.currency ?? ui.balance.currency.get();
|
|
568
|
-
const money2 = (n) =>
|
|
686
|
+
const money2 = (n) => formatAmountPrecise(n, cur);
|
|
569
687
|
ui.showNotice(
|
|
570
688
|
[
|
|
571
689
|
{ kind: "heading", id: "openui-replay-h", text: "openui.replay.title" },
|
|
@@ -680,17 +798,15 @@ function mountHud(app, spec = {}, opts = {}) {
|
|
|
680
798
|
o.onConfirm();
|
|
681
799
|
return;
|
|
682
800
|
}
|
|
683
|
-
const message = o.message ?? (o.name ? ui.t("openui.buyFeature.confirm", { name: ui.t(o.name), price: o.price ?? "" }) : "openui.buyFeature.message");
|
|
684
|
-
ui
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
]
|
|
693
|
-
);
|
|
801
|
+
const message = o.message ?? (o.name ? ui.t("openui.buyFeature.confirm", { name: ui.t(o.name), price: o.price ?? "" }) : ui.t("openui.buyFeature.message"));
|
|
802
|
+
void showConfirm(ui, {
|
|
803
|
+
title: o.title ?? "openui.buyFeature.title",
|
|
804
|
+
message,
|
|
805
|
+
confirmLabel: o.confirmLabel,
|
|
806
|
+
cancelLabel: o.cancelLabel
|
|
807
|
+
}).then((ok) => {
|
|
808
|
+
if (ok) o.onConfirm();
|
|
809
|
+
});
|
|
694
810
|
},
|
|
695
811
|
showControls: () => pixi.setControlsVisible(true),
|
|
696
812
|
hideControls: () => pixi.setControlsVisible(false),
|
|
@@ -705,13 +821,14 @@ function mountHud(app, spec = {}, opts = {}) {
|
|
|
705
821
|
};
|
|
706
822
|
}
|
|
707
823
|
function money(amount, cur) {
|
|
708
|
-
return
|
|
824
|
+
return formatAmountPrecise(amount, cur);
|
|
709
825
|
}
|
|
710
|
-
var
|
|
826
|
+
var esc3 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
711
827
|
function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
712
828
|
const ui = hud.ui;
|
|
713
829
|
const tr = (k) => ui.t(k);
|
|
714
830
|
const list = features.slice(0, 4);
|
|
831
|
+
ui.declareFacts({ modes: list.map((f) => ({ id: f.id, name: f.name, kind: f.variant, cost: f.cost })) });
|
|
715
832
|
const boosts = /* @__PURE__ */ new Set();
|
|
716
833
|
const activation = opts.activation ?? "multi";
|
|
717
834
|
const blocksBuy = opts.activationBlocksBuy ?? false;
|
|
@@ -733,23 +850,14 @@ function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
|
733
850
|
<button class="bfm-x" data-close aria-label="Close">\u2715</button>
|
|
734
851
|
<div class="bfm-panel" role="dialog" aria-modal="true">
|
|
735
852
|
<div class="bfm-fit" id="bfm-fit">
|
|
736
|
-
<h2 class="bfm-title" data-t="Buy Feature">${
|
|
853
|
+
<h2 class="bfm-title" data-t="Buy Feature">${esc3(tr("Buy Feature"))}</h2>
|
|
737
854
|
<div class="bfm-bet">
|
|
738
855
|
<button class="bfm-step" id="bfm-minus" aria-label="Decrease">\u2212</button>
|
|
739
|
-
<div class="bfm-betbox"><span class="bfm-betlabel" data-t="Bet">${
|
|
856
|
+
<div class="bfm-betbox"><span class="bfm-betlabel" data-t="Bet">${esc3(tr("Bet"))}</span><b id="bfm-betval">\u2014</b></div>
|
|
740
857
|
<button class="bfm-step" id="bfm-plus" aria-label="Increase">+</button>
|
|
741
858
|
</div>
|
|
742
859
|
<div class="bfm-cards" id="bfm-cards"></div>
|
|
743
860
|
</div>
|
|
744
|
-
</div>
|
|
745
|
-
<div class="bfm-confirm" id="bfm-confirm">
|
|
746
|
-
<div class="bfm-confirm-card">
|
|
747
|
-
<p class="bfm-confirm-msg" id="bfm-confirm-msg"></p>
|
|
748
|
-
<div class="bfm-confirm-row">
|
|
749
|
-
<button class="bfm-confirm-btn bfm-confirm-no" id="bfm-confirm-no" data-t="openui.cancel">${esc2(tr("openui.cancel"))}</button>
|
|
750
|
-
<button class="bfm-confirm-btn bfm-confirm-yes" id="bfm-confirm-yes" data-t="openui.confirm">${esc2(tr("openui.confirm"))}</button>
|
|
751
|
-
</div>
|
|
752
|
-
</div>
|
|
753
861
|
</div>`;
|
|
754
862
|
const style = document.createElement("style");
|
|
755
863
|
style.textContent = BFM_CSS;
|
|
@@ -760,29 +868,11 @@ function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
|
760
868
|
const fitEl = $("#bfm-fit");
|
|
761
869
|
const cardsEl = $("#bfm-cards");
|
|
762
870
|
const betValEl = $("#bfm-betval");
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
const hideConfirm = () => {
|
|
769
|
-
confirmEl.classList.remove("show");
|
|
770
|
-
pendingConfirm = null;
|
|
771
|
-
};
|
|
772
|
-
confirmNo.addEventListener("click", hideConfirm);
|
|
773
|
-
confirmYes.addEventListener("click", () => {
|
|
774
|
-
const fn = pendingConfirm;
|
|
775
|
-
hideConfirm();
|
|
776
|
-
fn?.();
|
|
777
|
-
});
|
|
778
|
-
const askConfirm = (totalCost, name, price, onYes) => {
|
|
779
|
-
if (!hud.shouldConfirmBuy(totalCost)) {
|
|
780
|
-
onYes();
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
confirmMsg.textContent = ui.t("openui.buyFeature.confirm", { name: ui.t(name), price });
|
|
784
|
-
pendingConfirm = onYes;
|
|
785
|
-
confirmEl.classList.add("show");
|
|
871
|
+
const askConfirm = (name, price, onYes) => {
|
|
872
|
+
const message = ui.t("openui.buyFeature.confirm", { name: ui.t(name), price });
|
|
873
|
+
void showConfirm(ui, { title: "Buy Feature", message }).then((ok) => {
|
|
874
|
+
if (ok) onYes();
|
|
875
|
+
});
|
|
786
876
|
};
|
|
787
877
|
const layout = () => {
|
|
788
878
|
const vw = window.innerWidth;
|
|
@@ -814,11 +904,11 @@ function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
|
814
904
|
<div class="bfm-cardimg"${img}></div>
|
|
815
905
|
<div class="bfm-strip"></div>
|
|
816
906
|
<div class="bfm-cardbody">
|
|
817
|
-
<span class="bfm-name">${
|
|
818
|
-
<b class="bfm-price">${
|
|
907
|
+
<span class="bfm-name">${esc3(tr(f.name))}</span>
|
|
908
|
+
<b class="bfm-price">${esc3(price)}</b>
|
|
819
909
|
</div>
|
|
820
910
|
</div>
|
|
821
|
-
<button class="${cls}" data-id="${f.id}" data-variant="${f.variant}"${buyBlocked ? " disabled" : ""}>${
|
|
911
|
+
<button class="${cls}" data-id="${f.id}" data-variant="${f.variant}"${buyBlocked ? " disabled" : ""}>${esc3(label)}</button>
|
|
822
912
|
</div>`;
|
|
823
913
|
}).join("");
|
|
824
914
|
betValEl.textContent = money(bet, cur);
|
|
@@ -846,11 +936,11 @@ function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
|
846
936
|
return;
|
|
847
937
|
}
|
|
848
938
|
const total = 1 + (f?.cost ?? 0);
|
|
849
|
-
askConfirm(
|
|
939
|
+
askConfirm(f?.name ?? id, money(total * bet, cur), commit);
|
|
850
940
|
} else {
|
|
851
941
|
if (blocksBuy && boosts.size > 0) return;
|
|
852
942
|
const cost = (f?.cost ?? 0) * bet;
|
|
853
|
-
askConfirm(f?.
|
|
943
|
+
askConfirm(f?.name ?? id, money(cost, cur), () => {
|
|
854
944
|
ui.bus.emit("cardActivated", { id });
|
|
855
945
|
close();
|
|
856
946
|
opts.onBuy?.(id, cost);
|
|
@@ -861,10 +951,16 @@ function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
|
861
951
|
$("#bfm-plus").addEventListener("click", () => ui.betStepper.inc());
|
|
862
952
|
disposers.push(ui.bet.value.subscribe(() => renderCards()));
|
|
863
953
|
const open = () => {
|
|
954
|
+
if (host2.classList.contains("open")) return;
|
|
864
955
|
renderCards();
|
|
865
956
|
host2.classList.add("open");
|
|
957
|
+
ui.lock();
|
|
958
|
+
};
|
|
959
|
+
const close = () => {
|
|
960
|
+
if (!host2.classList.contains("open")) return;
|
|
961
|
+
host2.classList.remove("open");
|
|
962
|
+
ui.unlock();
|
|
866
963
|
};
|
|
867
|
-
const close = () => host2.classList.remove("open");
|
|
868
964
|
host2.querySelectorAll("[data-close]").forEach((b) => b.addEventListener("click", close));
|
|
869
965
|
disposers.push(ui.on("buttonActivated", ({ id }) => {
|
|
870
966
|
if (id === "bonus") open();
|
|
@@ -882,6 +978,7 @@ function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
|
882
978
|
renderCards();
|
|
883
979
|
return () => {
|
|
884
980
|
window.removeEventListener("resize", onResize);
|
|
981
|
+
if (host2.classList.contains("open")) ui.unlock();
|
|
885
982
|
for (const d of disposers.splice(0)) d();
|
|
886
983
|
host2.remove();
|
|
887
984
|
};
|
|
@@ -919,22 +1016,11 @@ var BFM_CSS = `
|
|
|
919
1016
|
.bfm-action.is-active { background: var(--accent); color: var(--accent-text); border-color: #000; }
|
|
920
1017
|
.bfm-action.is-blocked, .bfm-action:disabled { opacity: .38; cursor: not-allowed; box-shadow: none; }
|
|
921
1018
|
.bfm-action.is-blocked:hover, .bfm-action:disabled:hover { background: var(--surface); }
|
|
922
|
-
.bfm-confirm { position: absolute; inset: 0; z-index: 5; display: grid; place-items: center; opacity: 0; pointer-events: none; transition: opacity .16s ease; }
|
|
923
|
-
.bfm-confirm.show { opacity: 1; pointer-events: auto; }
|
|
924
|
-
.bfm-confirm::before { content: ""; position: absolute; inset: 0; background: rgba(8,6,4,.6); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
|
|
925
|
-
.bfm-confirm-card { position: relative; width: min(90%, 420px); background: var(--surface); color: var(--text); border: 3px solid #000; border-radius: 14px; padding: 26px 24px 22px; box-shadow: 0 24px 60px rgba(0,0,0,.55); text-align: center; }
|
|
926
|
-
.bfm-confirm-msg { margin: 0 0 22px; font-size: 19px; font-weight: 700; line-height: 1.4; color: var(--text); }
|
|
927
|
-
.bfm-confirm-row { display: flex; gap: 14px; }
|
|
928
|
-
.bfm-confirm-btn { flex: 1; padding: 14px 10px; border-radius: 12px; border: 3px solid #000; font-size: 15px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase; cursor: pointer; transition: transform .1s, background .12s; }
|
|
929
|
-
.bfm-confirm-btn:active { transform: scale(.96); }
|
|
930
|
-
.bfm-confirm-no { background: var(--surface); color: var(--text); }
|
|
931
|
-
.bfm-confirm-no:hover { background: var(--surface-alt); }
|
|
932
|
-
.bfm-confirm-yes { background: var(--accent); color: var(--accent-text); }
|
|
933
1019
|
`;
|
|
934
1020
|
|
|
935
1021
|
// src/bootError.ts
|
|
936
1022
|
var host = null;
|
|
937
|
-
var
|
|
1023
|
+
var esc4 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
938
1024
|
function showBootError(opts = {}) {
|
|
939
1025
|
const title = opts.title ?? "Connection lost";
|
|
940
1026
|
const message = opts.message ?? "The game could not reach the game server. Please reload to reconnect and continue.";
|
|
@@ -948,10 +1034,10 @@ function showBootError(opts = {}) {
|
|
|
948
1034
|
<div class="openui-be-icon" aria-hidden="true">
|
|
949
1035
|
<svg viewBox="0 0 48 48" width="48" height="48"><path d="M24 4 3 42h42L24 4Z" fill="none" stroke="#ffc935" stroke-width="3" stroke-linejoin="round"/><rect x="22" y="18" width="4" height="12" rx="2" fill="#ffc935"/><circle cx="24" cy="35" r="2.4" fill="#ffc935"/></svg>
|
|
950
1036
|
</div>
|
|
951
|
-
<h1 class="openui-be-title">${
|
|
952
|
-
<p class="openui-be-msg">${
|
|
953
|
-
${opts.detail ? `<p class="openui-be-detail">${
|
|
954
|
-
${showReload ? `<button class="openui-be-reload" type="button">${
|
|
1037
|
+
<h1 class="openui-be-title">${esc4(title)}</h1>
|
|
1038
|
+
<p class="openui-be-msg">${esc4(message)}</p>
|
|
1039
|
+
${opts.detail ? `<p class="openui-be-detail">${esc4(opts.detail)}</p>` : ""}
|
|
1040
|
+
${showReload ? `<button class="openui-be-reload" type="button">${esc4(opts.reloadLabel ?? "Reload")}</button>` : ""}
|
|
955
1041
|
</div>
|
|
956
1042
|
<style>
|
|
957
1043
|
.openui-boot-error { position: fixed; inset: 0; z-index: 2147483000; display: grid; place-items: center;
|
|
@@ -979,6 +1065,6 @@ function hideBootError() {
|
|
|
979
1065
|
host = null;
|
|
980
1066
|
}
|
|
981
1067
|
|
|
982
|
-
export { PanelBodyView, PanelView, PopoverView, hideBootError, mountBuyFeatureModal, mountHud, mountInfoMenu, showBootError };
|
|
1068
|
+
export { PanelBodyView, PanelView, PopoverView, hideBootError, mountBuyFeatureModal, mountHud, mountInfoMenu, showBootError, showConfirm };
|
|
983
1069
|
//# sourceMappingURL=index.js.map
|
|
984
1070
|
//# sourceMappingURL=index.js.map
|