@open-slot-ui/pixi 0.11.1 → 0.12.1
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-Z7X5JH7H.js → chunk-FN6UJ3WO.js} +16 -6
- package/dist/chunk-FN6UJ3WO.js.map +1 -0
- package/dist/index.cjs +368 -267
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -31
- package/dist/index.d.ts +8 -31
- package/dist/index.js +359 -267
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-Z7X5JH7H.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1336,6 +1336,7 @@ var ValueDisplayView = class extends ControlView {
|
|
|
1336
1336
|
super.dispose();
|
|
1337
1337
|
}
|
|
1338
1338
|
};
|
|
1339
|
+
var TAP_SLOP = 24;
|
|
1339
1340
|
var GLYPH_SVG = {
|
|
1340
1341
|
speaker: '<svg viewBox="0 0 22.5 22.5" xmlns="http://www.w3.org/2000/svg"><path d="M13.6745 5.01252C13.9316 4.84399 14.2647 4.8292 14.5397 4.97456C14.8146 5.1199 14.9868 5.40142 14.9872 5.706L15.0007 16.8107C15.0011 17.1153 14.8296 17.3934 14.555 17.5333C14.2804 17.6731 13.9472 17.6517 13.6897 17.4781L10.4454 15.2905L8.61605 15.2722C6.76074 15.2537 5.25495 13.7655 5.25266 11.9484L5.25073 10.3739C5.2486 8.55679 6.75081 7.09863 8.6061 7.11714L10.4355 7.13539L13.6745 5.01252Z" fill="none" stroke="black" stroke-width="1.5" stroke-linejoin="round"/><path d="M16.1933 9.375C16.6252 10.4652 16.6015 11.654 16.1257 12.75" fill="none" stroke="black" stroke-width="3" stroke-linecap="round"/></svg>',
|
|
1341
1342
|
"speaker-mute": '<svg viewBox="0 0 22.5 22.5" xmlns="http://www.w3.org/2000/svg"><path d="M13.6745 5.01252C13.9316 4.84399 14.2647 4.8292 14.5397 4.97456C14.8146 5.1199 14.9868 5.40142 14.9872 5.706L15.0007 16.8107C15.0011 17.1153 14.8296 17.3934 14.555 17.5333C14.2804 17.6731 13.9472 17.6517 13.6897 17.4781L10.4454 15.2905L8.61605 15.2722C6.76074 15.2537 5.25495 13.7655 5.25266 11.9484L5.25073 10.3739C5.2486 8.55679 6.75081 7.09863 8.6061 7.11714L10.4355 7.13539L13.6745 5.01252Z" fill="none" stroke="black" stroke-width="1.5" stroke-linejoin="round"/><path d="M15.5 8.5L19.5 13.5M19.5 8.5L15.5 13.5" fill="none" stroke="black" stroke-width="1.8" stroke-linecap="round"/></svg>',
|
|
@@ -1433,17 +1434,26 @@ var ButtonView = class extends ControlView {
|
|
|
1433
1434
|
this.sprite.scale.set(1);
|
|
1434
1435
|
this.sprite.scale.set(this.iconTarget / this.sprite.height);
|
|
1435
1436
|
}
|
|
1436
|
-
|
|
1437
|
-
|
|
1437
|
+
/** Screen position of the current press, for the tap-slop check on release. */
|
|
1438
|
+
downPt = null;
|
|
1439
|
+
onDown = (e) => {
|
|
1440
|
+
if (!this.btn.interactable) return;
|
|
1441
|
+
this.btn.setState("pressed");
|
|
1442
|
+
this.downPt = { x: e.global.x, y: e.global.y };
|
|
1438
1443
|
};
|
|
1439
1444
|
onUp = () => {
|
|
1440
1445
|
if (this.btn.current === "pressed") {
|
|
1441
1446
|
this.btn.setState("idle");
|
|
1442
1447
|
this.btn.activate();
|
|
1443
1448
|
}
|
|
1449
|
+
this.downPt = null;
|
|
1444
1450
|
};
|
|
1445
|
-
onUpOutside = () => {
|
|
1446
|
-
|
|
1451
|
+
onUpOutside = (e) => {
|
|
1452
|
+
const p = this.downPt;
|
|
1453
|
+
this.downPt = null;
|
|
1454
|
+
if (this.btn.current !== "pressed") return;
|
|
1455
|
+
this.btn.setState("idle");
|
|
1456
|
+
if (p && Math.hypot(e.global.x - p.x, e.global.y - p.y) <= TAP_SLOP) this.btn.activate();
|
|
1447
1457
|
};
|
|
1448
1458
|
updateHit() {
|
|
1449
1459
|
if (this.sprite) {
|
|
@@ -4145,67 +4155,10 @@ function mountInfoMenu(app, ui) {
|
|
|
4145
4155
|
};
|
|
4146
4156
|
}
|
|
4147
4157
|
|
|
4148
|
-
// src/confirmModal.ts
|
|
4149
|
-
var esc2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4150
|
-
function showConfirm(ui, opts) {
|
|
4151
|
-
return new Promise((resolve) => {
|
|
4152
|
-
const host2 = document.createElement("div");
|
|
4153
|
-
host2.className = "osc-confirm";
|
|
4154
|
-
host2.style.setProperty("--font", ui.theme.type.family);
|
|
4155
|
-
const title = ui.t(opts.title ?? "Buy Feature");
|
|
4156
|
-
const yes = ui.t(opts.confirmLabel ?? "openui.confirm");
|
|
4157
|
-
const no = ui.t(opts.cancelLabel ?? "openui.cancel");
|
|
4158
|
-
host2.innerHTML = `
|
|
4159
|
-
<div class="osc-confirm-backdrop" data-no></div>
|
|
4160
|
-
<div class="osc-confirm-card" role="dialog" aria-modal="true">
|
|
4161
|
-
${title ? `<h3 class="osc-confirm-title">${esc2(title)}</h3>` : ""}
|
|
4162
|
-
<p class="osc-confirm-msg">${esc2(opts.message)}</p>
|
|
4163
|
-
<div class="osc-confirm-row">
|
|
4164
|
-
<button class="osc-confirm-btn osc-confirm-no" data-no>${esc2(no)}</button>
|
|
4165
|
-
<button class="osc-confirm-btn osc-confirm-yes" data-yes>${esc2(yes)}</button>
|
|
4166
|
-
</div>
|
|
4167
|
-
</div>`;
|
|
4168
|
-
const style = document.createElement("style");
|
|
4169
|
-
style.textContent = CONFIRM_CSS;
|
|
4170
|
-
host2.appendChild(style);
|
|
4171
|
-
document.body.appendChild(host2);
|
|
4172
|
-
let settled = false;
|
|
4173
|
-
const close = (val) => {
|
|
4174
|
-
if (settled) return;
|
|
4175
|
-
settled = true;
|
|
4176
|
-
window.removeEventListener("keydown", onKey);
|
|
4177
|
-
host2.remove();
|
|
4178
|
-
resolve(val);
|
|
4179
|
-
};
|
|
4180
|
-
const onKey = (e) => {
|
|
4181
|
-
if (e.key === "Escape") close(false);
|
|
4182
|
-
else if (e.key === "Enter") close(true);
|
|
4183
|
-
};
|
|
4184
|
-
host2.querySelectorAll("[data-no]").forEach((b) => b.addEventListener("click", () => close(false)));
|
|
4185
|
-
host2.querySelector("[data-yes]")?.addEventListener("click", () => close(true));
|
|
4186
|
-
window.addEventListener("keydown", onKey);
|
|
4187
|
-
});
|
|
4188
|
-
}
|
|
4189
|
-
var CONFIRM_CSS = `
|
|
4190
|
-
.osc-confirm { position: fixed; inset: 0; z-index: 12000; display: grid; place-items: center; font-family: var(--font); }
|
|
4191
|
-
.osc-confirm *, .osc-confirm *::before, .osc-confirm *::after { box-sizing: border-box; }
|
|
4192
|
-
.osc-confirm-backdrop { position: absolute; inset: 0; background: rgba(8,6,4,.6); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
|
|
4193
|
-
.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; }
|
|
4194
|
-
.osc-confirm-title { margin: 0 0 12px; font-size: 22px; font-weight: 800; letter-spacing: .3px; }
|
|
4195
|
-
.osc-confirm-msg { margin: 0 0 22px; font-size: 19px; font-weight: 700; line-height: 1.4; }
|
|
4196
|
-
.osc-confirm-row { display: flex; gap: 14px; }
|
|
4197
|
-
.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; }
|
|
4198
|
-
.osc-confirm-btn:active { transform: scale(.96); }
|
|
4199
|
-
.osc-confirm-no { background: #ffffff; color: #181b20; }
|
|
4200
|
-
.osc-confirm-no:hover { background: #eef1f6; }
|
|
4201
|
-
.osc-confirm-yes { background: #d99000; color: #1a1200; }
|
|
4202
|
-
.osc-confirm-yes:hover { filter: brightness(1.05); }
|
|
4203
|
-
`;
|
|
4204
|
-
|
|
4205
4158
|
// src/mountHud.ts
|
|
4206
4159
|
function showReplayModal(ui, info, buttonKey, onSelect) {
|
|
4207
4160
|
const cur = info.currency ?? ui.balance.currency.get();
|
|
4208
|
-
const
|
|
4161
|
+
const money = (n) => core.formatAmountPrecise(n, cur);
|
|
4209
4162
|
ui.showNotice(
|
|
4210
4163
|
[
|
|
4211
4164
|
{ kind: "heading", id: "openui-replay-h", text: "openui.replay.title" },
|
|
@@ -4213,10 +4166,10 @@ function showReplayModal(ui, info, buttonKey, onSelect) {
|
|
|
4213
4166
|
kind: "stat-grid",
|
|
4214
4167
|
id: "openui-replay-g",
|
|
4215
4168
|
items: [
|
|
4216
|
-
{ label: "openui.replay.baseBet", value:
|
|
4169
|
+
{ label: "openui.replay.baseBet", value: money(info.baseBet) },
|
|
4217
4170
|
{ label: "openui.replay.costMultiplier", value: `${info.costMultiplier}\xD7` },
|
|
4218
4171
|
{ label: "openui.replay.payoutMultiplier", value: `${info.payoutMultiplier}\xD7` },
|
|
4219
|
-
{ label: "openui.replay.amount", value:
|
|
4172
|
+
{ label: "openui.replay.amount", value: money(info.amount) }
|
|
4220
4173
|
]
|
|
4221
4174
|
}
|
|
4222
4175
|
],
|
|
@@ -4230,7 +4183,7 @@ function showReplayModal(ui, info, buttonKey, onSelect) {
|
|
|
4230
4183
|
function mountHud(app, spec = {}, opts = {}) {
|
|
4231
4184
|
const { hooks, infoMenu, ...pixiOpts } = opts;
|
|
4232
4185
|
const ui = core.createUI(spec, hooks);
|
|
4233
|
-
const useInfoMenu = infoMenu
|
|
4186
|
+
const useInfoMenu = infoMenu === true && pixiOpts.menu !== false;
|
|
4234
4187
|
const locales = spec.locale ? Array.from(/* @__PURE__ */ new Set([spec.locale.locale, ...Object.keys(spec.locale.messages)])) : [];
|
|
4235
4188
|
const menu = pixiOpts.menu === false || useInfoMenu ? false : core.composeMenu(spec.menu, { locales, localeSelectId: spec.localeSelectId, rulesFallback: spec.rules });
|
|
4236
4189
|
if (menu && spec.game && (spec.game.name || spec.game.version)) {
|
|
@@ -4239,6 +4192,21 @@ function mountHud(app, spec = {}, opts = {}) {
|
|
|
4239
4192
|
const pixi = new OpenUIPixi(ui, { ...pixiOpts, menu });
|
|
4240
4193
|
pixi.mount(app);
|
|
4241
4194
|
const disposeInfoMenu = useInfoMenu ? mountInfoMenu(app, ui) : void 0;
|
|
4195
|
+
const canvas = app.canvas;
|
|
4196
|
+
const cancelToUp = (e) => {
|
|
4197
|
+
canvas?.dispatchEvent(new PointerEvent("pointerup", {
|
|
4198
|
+
pointerId: e.pointerId,
|
|
4199
|
+
pointerType: e.pointerType,
|
|
4200
|
+
isPrimary: e.isPrimary,
|
|
4201
|
+
clientX: e.clientX,
|
|
4202
|
+
clientY: e.clientY,
|
|
4203
|
+
pressure: 0,
|
|
4204
|
+
bubbles: true,
|
|
4205
|
+
cancelable: true,
|
|
4206
|
+
composed: true
|
|
4207
|
+
}));
|
|
4208
|
+
};
|
|
4209
|
+
canvas?.addEventListener("pointercancel", cancelToUp, true);
|
|
4242
4210
|
const extra = [];
|
|
4243
4211
|
if (spec.panels?.length) {
|
|
4244
4212
|
for (const ps of spec.panels) {
|
|
@@ -4259,6 +4227,7 @@ function mountHud(app, spec = {}, opts = {}) {
|
|
|
4259
4227
|
});
|
|
4260
4228
|
const teardown = () => {
|
|
4261
4229
|
offRelayout();
|
|
4230
|
+
canvas?.removeEventListener("pointercancel", cancelToUp, true);
|
|
4262
4231
|
disposeInfoMenu?.();
|
|
4263
4232
|
for (const v of extra) v.dispose();
|
|
4264
4233
|
extra.length = 0;
|
|
@@ -4321,14 +4290,19 @@ function mountHud(app, spec = {}, opts = {}) {
|
|
|
4321
4290
|
return;
|
|
4322
4291
|
}
|
|
4323
4292
|
const message = o.message ?? (o.name ? ui.t("openui.buyFeature.confirm", { name: ui.t(o.name), price: o.price ?? "" }) : ui.t("openui.buyFeature.message"));
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4293
|
+
ui.showNotice(
|
|
4294
|
+
[
|
|
4295
|
+
{ kind: "heading", id: "buy-confirm-title", text: o.title ?? "openui.buyFeature.title" },
|
|
4296
|
+
{ kind: "text", id: "buy-confirm-body", text: message }
|
|
4297
|
+
],
|
|
4298
|
+
[
|
|
4299
|
+
{ label: o.cancelLabel ?? "openui.cancel", variant: "secondary" },
|
|
4300
|
+
{ label: o.confirmLabel ?? "openui.confirm", variant: "primary", onSelect: () => {
|
|
4301
|
+
ui.hideNotice();
|
|
4302
|
+
o.onConfirm();
|
|
4303
|
+
} }
|
|
4304
|
+
]
|
|
4305
|
+
);
|
|
4332
4306
|
},
|
|
4333
4307
|
showControls: () => pixi.setControlsVisible(true),
|
|
4334
4308
|
hideControls: () => pixi.setControlsVisible(false),
|
|
@@ -4342,208 +4316,332 @@ function mountHud(app, spec = {}, opts = {}) {
|
|
|
4342
4316
|
dispose: teardown
|
|
4343
4317
|
};
|
|
4344
4318
|
}
|
|
4345
|
-
|
|
4346
|
-
|
|
4319
|
+
var LIGHT3 = {
|
|
4320
|
+
surface: "#ffffff",
|
|
4321
|
+
surfaceAlt: "#eef1f6",
|
|
4322
|
+
text: "#181b20",
|
|
4323
|
+
textDim: "#5b6472",
|
|
4324
|
+
border: "#000000",
|
|
4325
|
+
accent: "#d99000",
|
|
4326
|
+
accentText: "#1a1200",
|
|
4327
|
+
scrim: "#080604"
|
|
4328
|
+
};
|
|
4329
|
+
var CARD_W = 200;
|
|
4330
|
+
var IMG_H = 120;
|
|
4331
|
+
var STRIP_H = 8;
|
|
4332
|
+
var CARD_H = 214;
|
|
4333
|
+
var ACT_GAP = 12;
|
|
4334
|
+
var ACT_H = 50;
|
|
4335
|
+
var CELL_H = CARD_H + ACT_GAP + ACT_H;
|
|
4336
|
+
var GAP3 = 18;
|
|
4337
|
+
var STEP_R = 27;
|
|
4338
|
+
var BET_W = 220;
|
|
4339
|
+
var BET_H = 60;
|
|
4340
|
+
var TITLE_H = 40;
|
|
4341
|
+
var ROW_GAP2 = 22;
|
|
4342
|
+
var TAP_SLOP2 = 24;
|
|
4343
|
+
var texCache = /* @__PURE__ */ new Map();
|
|
4344
|
+
function loadTex(url) {
|
|
4345
|
+
let p = texCache.get(url);
|
|
4346
|
+
if (!p) {
|
|
4347
|
+
p = pixi_js.Assets.load(url).catch(() => pixi_js.Texture.EMPTY);
|
|
4348
|
+
texCache.set(url, p);
|
|
4349
|
+
}
|
|
4350
|
+
return p;
|
|
4347
4351
|
}
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
const
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
"--surface": "#ffffff",
|
|
4364
|
-
"--surface-alt": "#eef1f6",
|
|
4365
|
-
"--text": "#181b20",
|
|
4366
|
-
"--text-dim": "#5b6472",
|
|
4367
|
-
"--font": ui.theme.type.family
|
|
4368
|
-
};
|
|
4369
|
-
for (const [k, v] of Object.entries(vars)) host2.style.setProperty(k, v);
|
|
4370
|
-
host2.innerHTML = `
|
|
4371
|
-
<div class="bfm-backdrop" data-close></div>
|
|
4372
|
-
<button class="bfm-x" data-close aria-label="Close">\u2715</button>
|
|
4373
|
-
<div class="bfm-panel" role="dialog" aria-modal="true">
|
|
4374
|
-
<div class="bfm-fit" id="bfm-fit">
|
|
4375
|
-
<h2 class="bfm-title" data-t="Buy Feature">${esc3(tr("Buy Feature"))}</h2>
|
|
4376
|
-
<div class="bfm-bet">
|
|
4377
|
-
<button class="bfm-step" id="bfm-minus" aria-label="Decrease">\u2212</button>
|
|
4378
|
-
<div class="bfm-betbox"><span class="bfm-betlabel" data-t="Bet">${esc3(tr("Bet"))}</span><b id="bfm-betval">\u2014</b></div>
|
|
4379
|
-
<button class="bfm-step" id="bfm-plus" aria-label="Increase">+</button>
|
|
4380
|
-
</div>
|
|
4381
|
-
<div class="bfm-cards" id="bfm-cards"></div>
|
|
4382
|
-
</div>
|
|
4383
|
-
</div>`;
|
|
4384
|
-
const style = document.createElement("style");
|
|
4385
|
-
style.textContent = BFM_CSS;
|
|
4386
|
-
host2.appendChild(style);
|
|
4387
|
-
document.body.appendChild(host2);
|
|
4388
|
-
const $ = (sel) => host2.querySelector(sel);
|
|
4389
|
-
const panel = $(".bfm-panel");
|
|
4390
|
-
const fitEl = $("#bfm-fit");
|
|
4391
|
-
const cardsEl = $("#bfm-cards");
|
|
4392
|
-
const betValEl = $("#bfm-betval");
|
|
4393
|
-
const askConfirm = (name, price, onYes) => {
|
|
4394
|
-
const message = ui.t("openui.buyFeature.confirm", { name: ui.t(name), price });
|
|
4395
|
-
void showConfirm(ui, { title: "Buy Feature", message }).then((ok) => {
|
|
4396
|
-
if (ok) onYes();
|
|
4397
|
-
});
|
|
4398
|
-
};
|
|
4399
|
-
const layout = () => {
|
|
4400
|
-
const vw = window.innerWidth;
|
|
4401
|
-
const vh = window.innerHeight;
|
|
4402
|
-
const cols = vw >= 720 && (vw >= 900 || vh <= 540) ? Math.min(4, list.length) : Math.min(2, list.length);
|
|
4403
|
-
cardsEl.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
|
|
4404
|
-
const fitW = Math.min(vw * 0.96, cols >= 4 ? 1180 : cols === 1 ? 380 : 760);
|
|
4405
|
-
fitEl.style.width = `${fitW}px`;
|
|
4406
|
-
fitEl.style.transform = "none";
|
|
4407
|
-
const natH = fitEl.offsetHeight;
|
|
4408
|
-
const s = Math.min(1, vh * 0.95 / natH);
|
|
4409
|
-
fitEl.style.transform = `translateX(-50%) scale(${s})`;
|
|
4410
|
-
panel.style.width = `${Math.ceil(fitW * s)}px`;
|
|
4411
|
-
panel.style.height = `${Math.ceil(natH * s)}px`;
|
|
4352
|
+
function wireTap(node, hit, onTap) {
|
|
4353
|
+
node.eventMode = "static";
|
|
4354
|
+
node.cursor = "pointer";
|
|
4355
|
+
node.hitArea = hit;
|
|
4356
|
+
let down = null;
|
|
4357
|
+
node.on("pointerdown", (e) => {
|
|
4358
|
+
down = { x: e.global.x, y: e.global.y };
|
|
4359
|
+
node.alpha = 0.82;
|
|
4360
|
+
});
|
|
4361
|
+
const end = (e, inside) => {
|
|
4362
|
+
node.alpha = 1;
|
|
4363
|
+
const p = down;
|
|
4364
|
+
down = null;
|
|
4365
|
+
if (!p) return;
|
|
4366
|
+
if (inside || Math.hypot(e.global.x - p.x, e.global.y - p.y) <= TAP_SLOP2) onTap();
|
|
4412
4367
|
};
|
|
4413
|
-
|
|
4414
|
-
|
|
4368
|
+
node.on("pointerup", (e) => end(e, true));
|
|
4369
|
+
node.on("pointerupoutside", (e) => end(e, false));
|
|
4370
|
+
}
|
|
4371
|
+
var FeatureCard = class extends pixi_js.Container {
|
|
4372
|
+
priceText;
|
|
4373
|
+
actionBg = new pixi_js.Graphics();
|
|
4374
|
+
actionLabel;
|
|
4375
|
+
action = new pixi_js.Container();
|
|
4376
|
+
constructor(spec, ui, onAction) {
|
|
4377
|
+
super();
|
|
4378
|
+
const fam = ui.theme.type.family;
|
|
4379
|
+
const fill = new pixi_js.Graphics().roundRect(0, 0, CARD_W, CARD_H, 14).fill({ color: LIGHT3.surface });
|
|
4380
|
+
const clip = new pixi_js.Container();
|
|
4381
|
+
const clipMask = new pixi_js.Graphics().roundRect(0, 0, CARD_W, CARD_H, 14).fill({ color: 16777215 });
|
|
4382
|
+
clip.mask = clipMask;
|
|
4383
|
+
const placeholder = new pixi_js.Graphics().rect(0, 0, CARD_W, IMG_H).fill({ color: LIGHT3.surfaceAlt });
|
|
4384
|
+
clip.addChild(placeholder);
|
|
4385
|
+
if (spec.image) {
|
|
4386
|
+
void loadTex(spec.image).then((tex) => {
|
|
4387
|
+
if (this.destroyed || tex === pixi_js.Texture.EMPTY) return;
|
|
4388
|
+
const sp = new pixi_js.Sprite(tex);
|
|
4389
|
+
const s = Math.max(CARD_W / tex.width, IMG_H / tex.height);
|
|
4390
|
+
sp.scale.set(s);
|
|
4391
|
+
sp.x = (CARD_W - tex.width * s) / 2;
|
|
4392
|
+
sp.y = (IMG_H - tex.height * s) / 2;
|
|
4393
|
+
clip.addChildAt(sp, 1);
|
|
4394
|
+
});
|
|
4395
|
+
}
|
|
4396
|
+
const strip = new pixi_js.Graphics().rect(0, IMG_H, CARD_W, STRIP_H).fill({ color: LIGHT3.accent });
|
|
4397
|
+
const name = new pixi_js.Text({ text: ui.t(spec.name), style: { fontFamily: fam, fontSize: 16, fontWeight: "600", fill: LIGHT3.text } });
|
|
4398
|
+
name.anchor.set(0.5, 0);
|
|
4399
|
+
name.position.set(CARD_W / 2, IMG_H + STRIP_H + 12);
|
|
4400
|
+
this.priceText = new pixi_js.Text({ text: "", style: { fontFamily: fam, fontSize: 22, fontWeight: "800", fill: LIGHT3.text } });
|
|
4401
|
+
this.priceText.anchor.set(0.5, 0);
|
|
4402
|
+
this.priceText.position.set(CARD_W / 2, IMG_H + STRIP_H + 36);
|
|
4403
|
+
clip.addChild(strip, name, this.priceText);
|
|
4404
|
+
const stroke = new pixi_js.Graphics().roundRect(0, 0, CARD_W, CARD_H, 14).stroke({ width: 4, color: LIGHT3.border });
|
|
4405
|
+
this.addChild(fill, clip, clipMask, stroke);
|
|
4406
|
+
this.actionLabel = new pixi_js.Text({ text: "", style: { fontFamily: fam, fontSize: 15, fontWeight: "800", fill: LIGHT3.text, letterSpacing: 0.5 } });
|
|
4407
|
+
this.actionLabel.anchor.set(0.5);
|
|
4408
|
+
this.actionLabel.position.set(CARD_W / 2, CARD_H + ACT_GAP + ACT_H / 2);
|
|
4409
|
+
this.action.addChild(this.actionBg, this.actionLabel);
|
|
4410
|
+
wireTap(this.action, new pixi_js.Rectangle(0, CARD_H + ACT_GAP, CARD_W, ACT_H), onAction);
|
|
4411
|
+
this.addChild(this.action);
|
|
4412
|
+
}
|
|
4413
|
+
/** Update price + action label/state for the current bet + boost state. */
|
|
4414
|
+
update(price, label, active, blocked) {
|
|
4415
|
+
this.priceText.text = price;
|
|
4416
|
+
this.actionLabel.text = label;
|
|
4417
|
+
this.actionLabel.style.fill = active ? LIGHT3.accentText : LIGHT3.text;
|
|
4418
|
+
this.actionBg.clear().roundRect(0, CARD_H + ACT_GAP, CARD_W, ACT_H, 12).fill({ color: active ? LIGHT3.accent : LIGHT3.surface }).stroke({ width: 4, color: LIGHT3.border });
|
|
4419
|
+
this.action.eventMode = blocked ? "none" : "static";
|
|
4420
|
+
this.action.alpha = blocked ? 0.38 : 1;
|
|
4421
|
+
}
|
|
4422
|
+
};
|
|
4423
|
+
var BuyFeatureModalView = class extends pixi_js.Container {
|
|
4424
|
+
constructor(hud, features, opts) {
|
|
4425
|
+
super();
|
|
4426
|
+
this.hud = hud;
|
|
4427
|
+
this.opts = opts;
|
|
4428
|
+
const ui = hud.ui;
|
|
4429
|
+
const fam = ui.theme.type.family;
|
|
4430
|
+
this.list = features.slice(0, 4);
|
|
4431
|
+
this.zIndex = 125;
|
|
4432
|
+
this.visible = false;
|
|
4433
|
+
this.eventMode = "none";
|
|
4434
|
+
ui.declareFacts({ modes: this.list.map((f) => ({ id: f.id, name: f.name, kind: f.variant, cost: f.cost })) });
|
|
4435
|
+
this.backdrop.eventMode = "static";
|
|
4436
|
+
this.backdrop.on("pointertap", () => this.close());
|
|
4437
|
+
this.title = new pixi_js.Text({ text: ui.t("Buy Feature"), style: { fontFamily: fam, fontSize: 30, fontWeight: "800", fill: "#ffffff", letterSpacing: 1 } });
|
|
4438
|
+
this.title.anchor.set(0.5, 0);
|
|
4439
|
+
const minus = this.stepButton("\u2212", () => ui.betStepper.dec());
|
|
4440
|
+
const plus = this.stepButton("+", () => ui.betStepper.inc());
|
|
4441
|
+
const betBox = new pixi_js.Container();
|
|
4442
|
+
const betBg = new pixi_js.Graphics().roundRect(-BET_W / 2, -BET_H / 2, BET_W, BET_H, 12).fill({ color: LIGHT3.surface }).stroke({ width: 3, color: LIGHT3.border });
|
|
4443
|
+
const betLabel = new pixi_js.Text({ text: ui.t("Bet"), style: { fontFamily: fam, fontSize: 12, fontWeight: "700", fill: LIGHT3.textDim, letterSpacing: 1 } });
|
|
4444
|
+
betLabel.anchor.set(0.5, 0);
|
|
4445
|
+
betLabel.position.set(0, -BET_H / 2 + 8);
|
|
4446
|
+
this.betValue = new pixi_js.Text({ text: "", style: { fontFamily: fam, fontSize: 24, fontWeight: "800", fill: LIGHT3.text } });
|
|
4447
|
+
this.betValue.anchor.set(0.5, 1);
|
|
4448
|
+
this.betValue.position.set(0, BET_H / 2 - 8);
|
|
4449
|
+
betBox.addChild(betBg, betLabel, this.betValue);
|
|
4450
|
+
const betRow = new pixi_js.Container();
|
|
4451
|
+
minus.position.set(STEP_R, 0);
|
|
4452
|
+
betBox.position.set(STEP_R * 2 + 16 + BET_W / 2, 0);
|
|
4453
|
+
plus.position.set(STEP_R * 2 + 16 + BET_W + 16 + STEP_R, 0);
|
|
4454
|
+
betRow.addChild(minus, betBox, plus);
|
|
4455
|
+
this.betRow = betRow;
|
|
4456
|
+
for (const spec of this.list) {
|
|
4457
|
+
const card = new FeatureCard(spec, ui, () => this.onAction(spec.id, spec.variant));
|
|
4458
|
+
this.cards.push(card);
|
|
4459
|
+
this.cardsRow.addChild(card);
|
|
4460
|
+
}
|
|
4461
|
+
this.content.addChild(this.title, betRow, this.cardsRow);
|
|
4462
|
+
const cbg = new pixi_js.Graphics().circle(0, 0, 23).fill({ color: LIGHT3.scrim, alpha: 0.85 });
|
|
4463
|
+
const cx = new pixi_js.Graphics().moveTo(-7, -7).lineTo(7, 7).moveTo(7, -7).lineTo(-7, 7).stroke({ width: 3, color: "#ffffff", cap: "round" });
|
|
4464
|
+
this.closeBtn.addChild(cbg, cx);
|
|
4465
|
+
wireTap(this.closeBtn, new pixi_js.Rectangle(-23, -23, 46, 46), () => this.close());
|
|
4466
|
+
this.addChild(this.backdrop, this.content, this.closeBtn);
|
|
4467
|
+
this.disposers.push(
|
|
4468
|
+
ui.bet.value.subscribe(() => this.refresh()),
|
|
4469
|
+
ui.locale.subscribe(() => {
|
|
4470
|
+
this.title.text = ui.t("Buy Feature");
|
|
4471
|
+
betLabel.text = ui.t("Bet");
|
|
4472
|
+
this.refresh();
|
|
4473
|
+
this.relayout();
|
|
4474
|
+
})
|
|
4475
|
+
);
|
|
4476
|
+
}
|
|
4477
|
+
hud;
|
|
4478
|
+
opts;
|
|
4479
|
+
backdrop = new pixi_js.Graphics();
|
|
4480
|
+
content = new pixi_js.Container();
|
|
4481
|
+
closeBtn = new pixi_js.Container();
|
|
4482
|
+
title;
|
|
4483
|
+
betValue;
|
|
4484
|
+
cardsRow = new pixi_js.Container();
|
|
4485
|
+
cards = [];
|
|
4486
|
+
list;
|
|
4487
|
+
boosts = /* @__PURE__ */ new Set();
|
|
4488
|
+
disposers = [];
|
|
4489
|
+
screen;
|
|
4490
|
+
betRow;
|
|
4491
|
+
stepButton(glyph, onTap) {
|
|
4492
|
+
const c = new pixi_js.Container();
|
|
4493
|
+
const fam = this.hud.ui.theme.type.family;
|
|
4494
|
+
const bg = new pixi_js.Graphics().circle(0, 0, STEP_R).fill({ color: LIGHT3.surface }).stroke({ width: 3, color: LIGHT3.border });
|
|
4495
|
+
const t = new pixi_js.Text({ text: glyph, style: { fontFamily: fam, fontSize: 28, fontWeight: "800", fill: LIGHT3.text } });
|
|
4496
|
+
t.anchor.set(0.5);
|
|
4497
|
+
t.position.set(0, -1);
|
|
4498
|
+
c.addChild(bg, t);
|
|
4499
|
+
wireTap(c, new pixi_js.Rectangle(-STEP_R, -STEP_R, STEP_R * 2, STEP_R * 2), onTap);
|
|
4500
|
+
return c;
|
|
4501
|
+
}
|
|
4502
|
+
/** Price + action state per current bet + boosts. */
|
|
4503
|
+
refresh() {
|
|
4504
|
+
const ui = this.hud.ui;
|
|
4505
|
+
const bet = this.opts.getBet ? this.opts.getBet() : ui.bet.get();
|
|
4415
4506
|
const cur = ui.bet.currency.get();
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4507
|
+
const money = (n) => core.formatAmountPrecise(n, cur);
|
|
4508
|
+
this.betValue.text = money(bet);
|
|
4509
|
+
const blocksBuy = this.opts.activationBlocksBuy ?? false;
|
|
4510
|
+
this.list.forEach((f, i) => {
|
|
4511
|
+
const active = this.boosts.has(f.id);
|
|
4419
4512
|
const perSpin = (f.variant === "buy" ? f.cost : 1 + f.cost) * bet;
|
|
4420
|
-
const
|
|
4421
|
-
const
|
|
4422
|
-
|
|
4423
|
-
const img = f.image ? ` style="background-image:url('${f.image}')"` : "";
|
|
4424
|
-
return `
|
|
4425
|
-
<div class="bfm-cell">
|
|
4426
|
-
<div class="bfm-card">
|
|
4427
|
-
<div class="bfm-cardimg"${img}></div>
|
|
4428
|
-
<div class="bfm-strip"></div>
|
|
4429
|
-
<div class="bfm-cardbody">
|
|
4430
|
-
<span class="bfm-name">${esc3(tr(f.name))}</span>
|
|
4431
|
-
<b class="bfm-price">${esc3(price)}</b>
|
|
4432
|
-
</div>
|
|
4433
|
-
</div>
|
|
4434
|
-
<button class="${cls}" data-id="${f.id}" data-variant="${f.variant}"${buyBlocked ? " disabled" : ""}>${esc3(label)}</button>
|
|
4435
|
-
</div>`;
|
|
4436
|
-
}).join("");
|
|
4437
|
-
betValEl.textContent = money(bet, cur);
|
|
4438
|
-
cardsEl.querySelectorAll(".bfm-action").forEach((b) => {
|
|
4439
|
-
b.addEventListener("click", () => onAction(b.dataset.id, b.dataset.variant));
|
|
4513
|
+
const label = f.variant === "buy" ? ui.t("Buy") : active ? ui.t("Activated") : ui.t("Activate");
|
|
4514
|
+
const blocked = f.variant === "buy" && blocksBuy && this.boosts.size > 0;
|
|
4515
|
+
this.cards[i].update(money(perSpin), label, active, blocked);
|
|
4440
4516
|
});
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
const f = list.find((x) => x.id === id);
|
|
4445
|
-
const bet = opts.getBet ? opts.getBet() : ui.bet.get();
|
|
4517
|
+
}
|
|
4518
|
+
onAction(id, variant) {
|
|
4519
|
+
const ui = this.hud.ui;
|
|
4520
|
+
const f = this.list.find((x) => x.id === id);
|
|
4521
|
+
const bet = this.opts.getBet ? this.opts.getBet() : ui.bet.get();
|
|
4446
4522
|
const cur = ui.bet.currency.get();
|
|
4523
|
+
const money = (n) => core.formatAmountPrecise(n, cur);
|
|
4524
|
+
const activation = this.opts.activation ?? "multi";
|
|
4525
|
+
const blocksBuy = this.opts.activationBlocksBuy ?? false;
|
|
4447
4526
|
if (variant === "boost") {
|
|
4448
|
-
const wasActive = boosts.has(id);
|
|
4527
|
+
const wasActive = this.boosts.has(id);
|
|
4449
4528
|
const commit = () => {
|
|
4450
|
-
if (activation === "single") boosts.clear();
|
|
4451
|
-
if (wasActive) boosts.delete(id);
|
|
4452
|
-
else boosts.add(id);
|
|
4529
|
+
if (activation === "single") this.boosts.clear();
|
|
4530
|
+
if (wasActive) this.boosts.delete(id);
|
|
4531
|
+
else this.boosts.add(id);
|
|
4453
4532
|
ui.bus.emit("cardActivated", { id });
|
|
4454
|
-
|
|
4455
|
-
opts.onActivate?.([...boosts], id, boosts.has(id));
|
|
4533
|
+
this.refresh();
|
|
4534
|
+
this.opts.onActivate?.([...this.boosts], id, this.boosts.has(id));
|
|
4456
4535
|
};
|
|
4457
4536
|
if (wasActive) {
|
|
4458
4537
|
commit();
|
|
4459
4538
|
return;
|
|
4460
4539
|
}
|
|
4461
4540
|
const total = 1 + (f?.cost ?? 0);
|
|
4462
|
-
askConfirm(f?.name ?? id, money(total * bet
|
|
4541
|
+
this.askConfirm(f?.name ?? id, money(total * bet), commit);
|
|
4463
4542
|
} else {
|
|
4464
|
-
if (blocksBuy && boosts.size > 0) return;
|
|
4543
|
+
if (blocksBuy && this.boosts.size > 0) return;
|
|
4465
4544
|
const cost = (f?.cost ?? 0) * bet;
|
|
4466
|
-
askConfirm(f?.name ?? id, money(cost
|
|
4545
|
+
this.askConfirm(f?.name ?? id, money(cost), () => {
|
|
4467
4546
|
ui.bus.emit("cardActivated", { id });
|
|
4468
|
-
close();
|
|
4469
|
-
opts.onBuy?.(id, cost);
|
|
4547
|
+
this.close();
|
|
4548
|
+
this.opts.onBuy?.(id, cost);
|
|
4470
4549
|
});
|
|
4471
4550
|
}
|
|
4472
|
-
}
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4551
|
+
}
|
|
4552
|
+
/** The ONE universal confirm — the in-canvas Pixi notice (DialogView, zIndex 130), so it
|
|
4553
|
+
* layers over this modal. Message + labels come from the library's i18n (social-aware). */
|
|
4554
|
+
askConfirm(name, price, onYes) {
|
|
4555
|
+
const ui = this.hud.ui;
|
|
4556
|
+
const message = ui.t("openui.buyFeature.confirm", { name: ui.t(name), price });
|
|
4557
|
+
ui.showNotice(
|
|
4558
|
+
[
|
|
4559
|
+
{ kind: "heading", id: "bfm-confirm-h", text: "Buy Feature" },
|
|
4560
|
+
{ kind: "text", id: "bfm-confirm-b", text: message }
|
|
4561
|
+
],
|
|
4562
|
+
[
|
|
4563
|
+
{ label: "openui.cancel", variant: "secondary" },
|
|
4564
|
+
{ label: "openui.confirm", variant: "primary", onSelect: () => {
|
|
4565
|
+
ui.hideNotice();
|
|
4566
|
+
onYes();
|
|
4567
|
+
} }
|
|
4568
|
+
]
|
|
4569
|
+
);
|
|
4570
|
+
}
|
|
4571
|
+
layout(screen) {
|
|
4572
|
+
this.screen = screen;
|
|
4573
|
+
if (this.visible) this.relayout();
|
|
4574
|
+
}
|
|
4575
|
+
relayout() {
|
|
4576
|
+
const s = this.screen;
|
|
4577
|
+
if (!s) return;
|
|
4578
|
+
const W = s.width;
|
|
4579
|
+
const H = s.height;
|
|
4580
|
+
this.backdrop.clear().rect(0, 0, W, H).fill({ color: LIGHT3.scrim, alpha: 0.55 });
|
|
4581
|
+
this.backdrop.hitArea = new pixi_js.Rectangle(0, 0, W, H);
|
|
4582
|
+
const n = this.list.length;
|
|
4583
|
+
const cols = W >= 720 && (W >= 900 || H <= 540) ? Math.min(4, n) : Math.min(2, n);
|
|
4584
|
+
const rows = Math.ceil(n / cols);
|
|
4585
|
+
this.cards.forEach((card, i) => {
|
|
4586
|
+
const r = Math.floor(i / cols);
|
|
4587
|
+
const c = i % cols;
|
|
4588
|
+
card.position.set(c * (CARD_W + GAP3), r * (CELL_H + GAP3));
|
|
4589
|
+
});
|
|
4590
|
+
const gridW = cols * CARD_W + (cols - 1) * GAP3;
|
|
4591
|
+
const gridH = rows * CELL_H + (rows - 1) * GAP3;
|
|
4592
|
+
const betW = 4 * STEP_R + BET_W + 32;
|
|
4593
|
+
const contentW = Math.max(gridW, betW, 340);
|
|
4594
|
+
this.title.position.set(contentW / 2, 0);
|
|
4595
|
+
this.betRow.position.set((contentW - betW) / 2, TITLE_H + ROW_GAP2 + STEP_R);
|
|
4596
|
+
this.cardsRow.position.set((contentW - gridW) / 2, TITLE_H + ROW_GAP2 + BET_H + ROW_GAP2);
|
|
4597
|
+
const contentH = TITLE_H + ROW_GAP2 + BET_H + ROW_GAP2 + gridH;
|
|
4598
|
+
const scale = Math.min(1, W * 0.94 / contentW, H * 0.92 / contentH);
|
|
4599
|
+
this.content.scale.set(scale);
|
|
4600
|
+
this.content.position.set((W - contentW * scale) / 2, (H - contentH * scale) / 2);
|
|
4601
|
+
this.closeBtn.position.set(W - 34, 34);
|
|
4602
|
+
}
|
|
4603
|
+
open() {
|
|
4604
|
+
if (this.visible) return;
|
|
4605
|
+
this.hud.ui.lock();
|
|
4606
|
+
this.visible = true;
|
|
4607
|
+
this.eventMode = "static";
|
|
4608
|
+
this.refresh();
|
|
4609
|
+
this.relayout();
|
|
4610
|
+
}
|
|
4611
|
+
close() {
|
|
4612
|
+
if (!this.visible) return;
|
|
4613
|
+
this.visible = false;
|
|
4614
|
+
this.eventMode = "none";
|
|
4615
|
+
this.hud.ui.unlock();
|
|
4616
|
+
}
|
|
4617
|
+
get isOpen() {
|
|
4618
|
+
return this.visible;
|
|
4619
|
+
}
|
|
4620
|
+
dispose() {
|
|
4621
|
+
if (this.visible) this.hud.ui.unlock();
|
|
4622
|
+
for (const d of this.disposers.splice(0)) d();
|
|
4623
|
+
if (!this.destroyed) this.destroy({ children: true });
|
|
4624
|
+
}
|
|
4625
|
+
};
|
|
4626
|
+
function mountBuyFeatureModal(_app, hud, features, opts = {}) {
|
|
4627
|
+
const ui = hud.ui;
|
|
4628
|
+
const view = new BuyFeatureModalView(hud, features, opts);
|
|
4629
|
+
hud.pixi.root.addChild(view);
|
|
4630
|
+
view.layout(ui.screen.get());
|
|
4631
|
+
const offScreen = ui.screen.subscribe(() => view.layout(ui.screen.get()));
|
|
4632
|
+
const offOpen = ui.on("buttonActivated", ({ id }) => {
|
|
4633
|
+
if (id === "bonus") view.open();
|
|
4634
|
+
});
|
|
4502
4635
|
return () => {
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
host2.remove();
|
|
4636
|
+
offScreen();
|
|
4637
|
+
offOpen();
|
|
4638
|
+
view.dispose();
|
|
4507
4639
|
};
|
|
4508
4640
|
}
|
|
4509
|
-
var BFM_CSS = `
|
|
4510
|
-
.bfm-root { position: fixed; inset: 0; z-index: 11000; display: grid; place-items: center; font-family: var(--font); opacity: 0; pointer-events: none; transition: opacity .18s ease; }
|
|
4511
|
-
.bfm-root.open { opacity: 1; pointer-events: auto; }
|
|
4512
|
-
.bfm-backdrop { position: absolute; inset: 0; background: rgba(8,6,4,0); backdrop-filter: blur(0px) saturate(1); -webkit-backdrop-filter: blur(0px) saturate(1); transition: background .4s ease, backdrop-filter .4s ease, -webkit-backdrop-filter .4s ease; }
|
|
4513
|
-
.bfm-root.open .bfm-backdrop { background: rgba(8,6,4,.5); backdrop-filter: blur(10px) saturate(1.1); -webkit-backdrop-filter: blur(10px) saturate(1.1); }
|
|
4514
|
-
.bfm-x { position: absolute; top: 18px; right: 22px; width: 46px; height: 46px; border-radius: 999px; border: 0; background: rgba(18,14,10,.82); color: #fff; font-size: 18px; cursor: pointer; display: grid; place-items: center; box-shadow: 0 6px 18px rgba(0,0,0,.45); z-index: 2; transition: transform .12s, background .12s; }
|
|
4515
|
-
.bfm-x:hover { transform: scale(1.08); background: rgba(18,14,10,.95); }
|
|
4516
|
-
.bfm-root *, .bfm-root *::before, .bfm-root *::after { box-sizing: border-box; }
|
|
4517
|
-
.bfm-panel { position: relative; transform: translateY(8px) scale(.985); transition: transform .18s ease; }
|
|
4518
|
-
.bfm-root.open .bfm-panel { transform: none; }
|
|
4519
|
-
.bfm-fit { position: absolute; top: 0; left: 50%; transform: translateX(-50%); transform-origin: top center; }
|
|
4520
|
-
.bfm-title { margin: 0 0 14px; text-align: center; color: #fff; font-size: 30px; font-weight: 800; letter-spacing: 1px; text-shadow: 0 2px 12px rgba(0,0,0,.6); }
|
|
4521
|
-
.bfm-bet { display: flex; align-items: center; justify-content: center; gap: 16px; margin: 0 0 24px; }
|
|
4522
|
-
.bfm-betbox { min-width: 200px; padding: 10px 22px; border-radius: 12px; background: var(--surface); border: 3px solid #000; display: flex; flex-direction: column; align-items: center; line-height: 1.1; }
|
|
4523
|
-
.bfm-betlabel { font-size: 12px; font-weight: 700; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; }
|
|
4524
|
-
.bfm-betbox b { font-size: 24px; color: var(--text); }
|
|
4525
|
-
.bfm-step { flex: none; width: 54px; height: 54px; border-radius: 999px; border: 3px solid #000; background: var(--surface); color: var(--text); font-size: 28px; font-weight: 800; cursor: pointer; display: grid; place-items: center; line-height: 1; transition: transform .1s, background .12s; box-shadow: 0 4px 12px rgba(0,0,0,.3); }
|
|
4526
|
-
.bfm-step:hover { background: var(--surface-alt); }
|
|
4527
|
-
.bfm-step:active { transform: scale(.92); }
|
|
4528
|
-
.bfm-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; align-items: start; }
|
|
4529
|
-
.bfm-cell { display: flex; flex-direction: column; min-width: 0; }
|
|
4530
|
-
.bfm-card { background: var(--surface); border: 4px solid #000; border-radius: 14px; overflow: hidden; box-shadow: 0 14px 34px rgba(0,0,0,.45); }
|
|
4531
|
-
.bfm-cardimg { width: 100%; aspect-ratio: 16 / 10; background-size: cover; background-position: center; background-color: var(--surface-alt); background-image: linear-gradient(135deg, #e7ebf2, #cfd6e2); }
|
|
4532
|
-
.bfm-strip { height: 8px; background: linear-gradient(90deg, #f0a500, #ffd166, #f0a500); }
|
|
4533
|
-
.bfm-cardbody { padding: 12px 14px 16px; text-align: center; }
|
|
4534
|
-
.bfm-name { display: block; font-size: 15px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
4535
|
-
.bfm-price { display: block; margin-top: 2px; font-size: 22px; font-weight: 800; color: var(--text); }
|
|
4536
|
-
.bfm-action { display: block; width: 100%; margin-top: 12px; padding: 14px 10px; border-radius: 12px; border: 4px solid #000; background: var(--surface); color: var(--text); font-size: 15px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase; cursor: pointer; transition: transform .1s, background .12s, color .12s; box-shadow: 0 5px 14px rgba(0,0,0,.35); white-space: nowrap; }
|
|
4537
|
-
.bfm-action:hover { background: var(--surface-alt); }
|
|
4538
|
-
.bfm-action:active { transform: scale(.96); }
|
|
4539
|
-
.bfm-action.is-active { background: var(--accent); color: var(--accent-text); border-color: #000; }
|
|
4540
|
-
.bfm-action.is-blocked, .bfm-action:disabled { opacity: .38; cursor: not-allowed; box-shadow: none; }
|
|
4541
|
-
.bfm-action.is-blocked:hover, .bfm-action:disabled:hover { background: var(--surface); }
|
|
4542
|
-
`;
|
|
4543
4641
|
|
|
4544
4642
|
// src/bootError.ts
|
|
4545
4643
|
var host = null;
|
|
4546
|
-
var
|
|
4644
|
+
var esc2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4547
4645
|
function showBootError(opts = {}) {
|
|
4548
4646
|
const title = opts.title ?? "Connection lost";
|
|
4549
4647
|
const message = opts.message ?? "The game could not reach the game server. Please reload to reconnect and continue.";
|
|
@@ -4555,27 +4653,31 @@ function showBootError(opts = {}) {
|
|
|
4555
4653
|
host.innerHTML = `
|
|
4556
4654
|
<div class="openui-be-card">
|
|
4557
4655
|
<div class="openui-be-icon" aria-hidden="true">
|
|
4558
|
-
<svg viewBox="0 0 48 48" width="
|
|
4656
|
+
<svg viewBox="0 0 48 48" width="46" height="46"><path d="M24 5 4 41h40L24 5Z" fill="none" stroke="#000" stroke-width="4" stroke-linejoin="round"/><rect x="22" y="19" width="4" height="12" rx="2" fill="#000"/><circle cx="24" cy="35.5" r="2.5" fill="#000"/></svg>
|
|
4559
4657
|
</div>
|
|
4560
|
-
<h1 class="openui-be-title">${
|
|
4561
|
-
<p class="openui-be-msg">${
|
|
4562
|
-
${opts.detail ? `<p class="openui-be-detail">${
|
|
4563
|
-
${showReload ? `<button class="openui-be-reload" type="button">${
|
|
4658
|
+
<h1 class="openui-be-title">${esc2(title)}</h1>
|
|
4659
|
+
<p class="openui-be-msg">${esc2(message)}</p>
|
|
4660
|
+
${opts.detail ? `<p class="openui-be-detail">${esc2(opts.detail)}</p>` : ""}
|
|
4661
|
+
${showReload ? `<button class="openui-be-reload" type="button">${esc2(opts.reloadLabel ?? "Reload")}</button>` : ""}
|
|
4564
4662
|
</div>
|
|
4565
4663
|
<style>
|
|
4664
|
+
/* MONOCHROME by design \u2014 a neutral black-and-white system card, no theme accent. */
|
|
4566
4665
|
.openui-boot-error { position: fixed; inset: 0; z-index: 2147483000; display: grid; place-items: center;
|
|
4567
|
-
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; color: #
|
|
4568
|
-
background: rgba(
|
|
4569
|
-
.openui-be-card { width: min(90%, 440px); text-align: center; padding:
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
.openui-be-
|
|
4573
|
-
|
|
4574
|
-
.openui-be-
|
|
4575
|
-
.openui-be-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
.openui-be-reload
|
|
4666
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; color: #181b20;
|
|
4667
|
+
background: rgba(8,8,8,.62); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
|
|
4668
|
+
.openui-be-card { width: min(90%, 440px); text-align: center; padding: 40px 36px 32px;
|
|
4669
|
+
display: flex; flex-direction: column; align-items: center; gap: 14px;
|
|
4670
|
+
background: #fff; border: 4px solid #000; border-radius: 24px; box-shadow: 0 24px 60px rgba(0,0,0,.55); }
|
|
4671
|
+
.openui-be-icon { display: grid; place-items: center; width: 72px; height: 72px; border-radius: 999px;
|
|
4672
|
+
border: 4px solid #000; line-height: 0; }
|
|
4673
|
+
.openui-be-title { margin: 0; font-size: 26px; font-weight: 800; color: #000; letter-spacing: .01em; }
|
|
4674
|
+
.openui-be-msg { margin: 0; font-size: 16px; line-height: 1.5; font-weight: 600; color: #3a3f47; max-width: 34ch; }
|
|
4675
|
+
.openui-be-detail { margin: 0; font-size: 12px; line-height: 1.4; color: #8a9099; word-break: break-word;
|
|
4676
|
+
font-family: ui-monospace, "SF Mono", Menlo, monospace; max-width: 40ch; }
|
|
4677
|
+
.openui-be-reload { appearance: none; cursor: pointer; margin-top: 8px; padding: 14px 42px; border-radius: 999px;
|
|
4678
|
+
border: 4px solid #000; background: #000; color: #fff; font-weight: 800; font-size: 16px; letter-spacing: .03em;
|
|
4679
|
+
transition: transform .1s ease, background .12s ease; }
|
|
4680
|
+
.openui-be-reload:hover { background: #1c1c1c; }
|
|
4579
4681
|
.openui-be-reload:active { transform: scale(.96); }
|
|
4580
4682
|
</style>`;
|
|
4581
4683
|
if (showReload) {
|
|
@@ -4644,7 +4746,6 @@ exports.mountBuyFeatureModal = mountBuyFeatureModal;
|
|
|
4644
4746
|
exports.mountHud = mountHud;
|
|
4645
4747
|
exports.mountInfoMenu = mountInfoMenu;
|
|
4646
4748
|
exports.showBootError = showBootError;
|
|
4647
|
-
exports.showConfirm = showConfirm;
|
|
4648
4749
|
exports.svgSpinSkin = svgSpinSkin;
|
|
4649
4750
|
//# sourceMappingURL=index.cjs.map
|
|
4650
4751
|
//# sourceMappingURL=index.cjs.map
|