@open-slot-ui/pixi 0.0.1 → 0.1.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/index.cjs +205 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -9
- package/dist/index.d.ts +28 -9
- package/dist/index.js +205 -99
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -181,6 +181,16 @@ var SpinView = class extends ControlView {
|
|
|
181
181
|
this.fsFace.addChild(ring, this.fsCount, this.fsLabel);
|
|
182
182
|
this.fsFace.visible = false;
|
|
183
183
|
this.art.addChild(this.fsFace);
|
|
184
|
+
const stopRing = new Graphics().circle(0, 0, 96).fill({ color: 16777215 }).stroke({ width: 7, color: 657930 });
|
|
185
|
+
this.stopLabel = new Text({ text: ui.t("openui.stop") === "openui.stop" ? "STOP" : ui.t("openui.stop"), style: { fontFamily: ui.theme.type.family, fontSize: 26, fill: 657930, fontWeight: "900", letterSpacing: 3 } });
|
|
186
|
+
this.stopLabel.anchor.set(0.5);
|
|
187
|
+
this.stopLabel.y = -38;
|
|
188
|
+
this.stopCount = new Text({ text: "0", style: { fontFamily: ui.theme.type.family, fontSize: 64, fill: 657930, fontWeight: "900" } });
|
|
189
|
+
this.stopCount.anchor.set(0.5);
|
|
190
|
+
this.stopCount.y = 16;
|
|
191
|
+
this.stopFace.addChild(stopRing, this.stopLabel, this.stopCount);
|
|
192
|
+
this.stopFace.visible = false;
|
|
193
|
+
this.art.addChild(this.stopFace);
|
|
184
194
|
this.addChild(this.art);
|
|
185
195
|
this.hitArea = new Circle(0, 0, 118);
|
|
186
196
|
this.eventMode = "static";
|
|
@@ -199,13 +209,19 @@ var SpinView = class extends ControlView {
|
|
|
199
209
|
this.spin.allowSlamStop.subscribe(() => this.updateInteractive()),
|
|
200
210
|
this.spin.onTransition((t) => this.play(t)),
|
|
201
211
|
// free-spins face: switch between the normal skin and the "N FS" counter
|
|
202
|
-
this.spin.freeSpins.subscribe(() => this.
|
|
212
|
+
this.spin.freeSpins.subscribe(() => this.updateFaces()),
|
|
213
|
+
// autoplay: while active the spin button becomes the STOP-count button
|
|
214
|
+
this.ui.autoplay.state.subscribe(() => {
|
|
215
|
+
this.updateFaces();
|
|
216
|
+
this.updateInteractive();
|
|
217
|
+
}),
|
|
218
|
+
this.ui.autoplay.count.subscribe(() => this.updateFaces()),
|
|
203
219
|
this.ui.locale.subscribe(() => {
|
|
204
220
|
if (!this.destroyed) this.fsLabel.text = this.ui.t("openui.freeSpins");
|
|
205
221
|
})
|
|
206
222
|
);
|
|
207
223
|
this.skin.update(this.spin.current);
|
|
208
|
-
this.
|
|
224
|
+
this.updateFaces();
|
|
209
225
|
this.updateInteractive();
|
|
210
226
|
}
|
|
211
227
|
spin;
|
|
@@ -219,13 +235,25 @@ var SpinView = class extends ControlView {
|
|
|
219
235
|
fsFace = new Container();
|
|
220
236
|
fsCount;
|
|
221
237
|
fsLabel;
|
|
222
|
-
/**
|
|
223
|
-
|
|
238
|
+
/** Autoplay STOP face — a "STOP" label over the remaining count (or ∞); shown while
|
|
239
|
+
* autoplay is active. Tapping the spin button then STOPS autoplay. */
|
|
240
|
+
stopFace = new Container();
|
|
241
|
+
stopCount;
|
|
242
|
+
stopLabel;
|
|
243
|
+
/** Pick the spin face: autoplay STOP-count (top priority) → free-spins counter →
|
|
244
|
+
* the normal skin. */
|
|
245
|
+
updateFaces() {
|
|
246
|
+
const auto = this.ui.autoplay.isActive;
|
|
224
247
|
const n = this.spin.freeSpins.get();
|
|
225
|
-
const fs = n > 0;
|
|
226
|
-
|
|
248
|
+
const fs = n > 0 && !auto;
|
|
249
|
+
if (auto) {
|
|
250
|
+
const c = this.ui.autoplay.count.get();
|
|
251
|
+
this.stopCount.text = c === Infinity ? "\u221E" : String(c);
|
|
252
|
+
}
|
|
253
|
+
if (fs) this.fsCount.text = String(n);
|
|
254
|
+
this.stopFace.visible = auto;
|
|
227
255
|
this.fsFace.visible = fs;
|
|
228
|
-
this.skin.view.visible = !fs;
|
|
256
|
+
this.skin.view.visible = !auto && !fs;
|
|
229
257
|
}
|
|
230
258
|
onOver = () => {
|
|
231
259
|
if (isDesktop() && this.spin.current === "idle") this.spin.setState("hover");
|
|
@@ -253,6 +281,10 @@ var SpinView = class extends ControlView {
|
|
|
253
281
|
onUp = () => {
|
|
254
282
|
if (this.holding) return this.endHold();
|
|
255
283
|
this.clearHoldTimer();
|
|
284
|
+
if (this.ui.autoplay.isActive) {
|
|
285
|
+
this.ui.autoplay.stop();
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
256
288
|
if (this.spin.current === "pressed") {
|
|
257
289
|
this.spin.setState("idle");
|
|
258
290
|
this.spin.activate();
|
|
@@ -281,7 +313,7 @@ var SpinView = class extends ControlView {
|
|
|
281
313
|
if (this.spin.current === "pressed") this.spin.setState("idle");
|
|
282
314
|
}
|
|
283
315
|
updateInteractive() {
|
|
284
|
-
const ok = this.spin.interactable;
|
|
316
|
+
const ok = this.spin.interactable || this.ui.autoplay.isActive;
|
|
285
317
|
this.eventMode = ok ? "static" : "none";
|
|
286
318
|
this.cursor = ok ? "pointer" : "default";
|
|
287
319
|
const inSpin = this.spin.current === "spinning" || this.spin.current === "auto" || this.spin.current === "stop";
|
|
@@ -1138,9 +1170,9 @@ var TextCellRenderer = class {
|
|
|
1138
1170
|
};
|
|
1139
1171
|
|
|
1140
1172
|
// src/views/ValueDisplayView.ts
|
|
1141
|
-
var DIGIT_W =
|
|
1142
|
-
var DIGIT_H =
|
|
1143
|
-
var FONT_SIZE =
|
|
1173
|
+
var DIGIT_W = 39;
|
|
1174
|
+
var DIGIT_H = 68;
|
|
1175
|
+
var FONT_SIZE = 48;
|
|
1144
1176
|
var FIT_BUDGET_COLS = 9;
|
|
1145
1177
|
var ValueDisplayView = class extends ControlView {
|
|
1146
1178
|
constructor(vd, ui, ticker, fitGsap) {
|
|
@@ -1174,6 +1206,7 @@ var ValueDisplayView = class extends ControlView {
|
|
|
1174
1206
|
fitGsap;
|
|
1175
1207
|
counter;
|
|
1176
1208
|
caption;
|
|
1209
|
+
captionPill;
|
|
1177
1210
|
side() {
|
|
1178
1211
|
const a = this.vd.layout.anchor;
|
|
1179
1212
|
return a.includes("left") ? "left" : a.includes("right") ? "right" : "center";
|
|
@@ -1183,13 +1216,20 @@ var ValueDisplayView = class extends ControlView {
|
|
|
1183
1216
|
const side = this.side();
|
|
1184
1217
|
if (this.vd.label) {
|
|
1185
1218
|
this.caption = new Text({
|
|
1186
|
-
|
|
1187
|
-
|
|
1219
|
+
// Figma: the label is NOT uppercased — "Баланс" / "Ставка" as authored.
|
|
1220
|
+
text: this.ui.t(this.vd.label),
|
|
1221
|
+
style: { fontFamily: theme.type.family, fontSize: 28, fill: 16777215, fontWeight: "900", letterSpacing: 0 }
|
|
1188
1222
|
});
|
|
1189
|
-
this.caption.
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1223
|
+
this.caption.anchor.set(0.5, 0.5);
|
|
1224
|
+
const padX = 24;
|
|
1225
|
+
const padY = 8;
|
|
1226
|
+
const pillW = Math.ceil(this.caption.width) + padX * 2;
|
|
1227
|
+
const pillH = Math.ceil(this.caption.height) + padY * 2;
|
|
1228
|
+
const pillX = side === "left" ? 0 : side === "right" ? -pillW : -pillW / 2;
|
|
1229
|
+
const pillY = -DIGIT_H / 2 - pillH - 14;
|
|
1230
|
+
this.captionPill = new Graphics().roundRect(pillX, pillY, pillW, pillH, 12).fill({ color: 0 });
|
|
1231
|
+
this.caption.position.set(pillX + pillW / 2, pillY + pillH / 2);
|
|
1232
|
+
this.addChild(this.captionPill, this.caption);
|
|
1193
1233
|
}
|
|
1194
1234
|
const cur = this.vd.currency.get();
|
|
1195
1235
|
this.buildCounter(displayDigits(this.vd.get(), this.vd.digits, cur.decimals), this.vd.minorUnits);
|
|
@@ -1201,7 +1241,16 @@ var ValueDisplayView = class extends ControlView {
|
|
|
1201
1241
|
const cur = this.vd.currency.get();
|
|
1202
1242
|
const side = this.side();
|
|
1203
1243
|
const renderer = new TextCellRenderer({
|
|
1204
|
-
|
|
1244
|
+
// Figma "default" readout: Montserrat Black, white, with a bold BLACK OUTLINE
|
|
1245
|
+
// plus a soft drop shadow (0px 4px, 25% black) under it.
|
|
1246
|
+
style: {
|
|
1247
|
+
fontFamily: theme.type.family,
|
|
1248
|
+
fontSize: FONT_SIZE,
|
|
1249
|
+
fill: 16777215,
|
|
1250
|
+
fontWeight: "900",
|
|
1251
|
+
stroke: { color: 0, width: 8, join: "round" },
|
|
1252
|
+
dropShadow: { color: 0, alpha: 0.25, blur: 2, distance: 4, angle: Math.PI / 2 }
|
|
1253
|
+
},
|
|
1205
1254
|
digitWidth: DIGIT_W,
|
|
1206
1255
|
digitHeight: DIGIT_H
|
|
1207
1256
|
// no fillerChar → rolling cells show real digits (crisp, no blur, no blank flicker)
|
|
@@ -1246,8 +1295,10 @@ var ValueDisplayView = class extends ControlView {
|
|
|
1246
1295
|
rebuild() {
|
|
1247
1296
|
this.counter?.destroy();
|
|
1248
1297
|
this.caption?.destroy();
|
|
1298
|
+
this.captionPill?.destroy();
|
|
1249
1299
|
this.counter = void 0;
|
|
1250
1300
|
this.caption = void 0;
|
|
1301
|
+
this.captionPill = void 0;
|
|
1251
1302
|
this.removeChildren();
|
|
1252
1303
|
this.build();
|
|
1253
1304
|
}
|
|
@@ -1256,6 +1307,12 @@ var ValueDisplayView = class extends ControlView {
|
|
|
1256
1307
|
super.dispose();
|
|
1257
1308
|
}
|
|
1258
1309
|
};
|
|
1310
|
+
var GLYPH_SVG = {
|
|
1311
|
+
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>',
|
|
1312
|
+
"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>',
|
|
1313
|
+
fullscreen: '<svg viewBox="0 0 22.5 22.5" xmlns="http://www.w3.org/2000/svg"><path d="M7.875 18H7.5C5.84315 18 4.5 16.6569 4.5 15V14.25M7.875 4.5H7.5C5.84315 4.5 4.5 5.84315 4.5 7.5V8.25M14.25 4.5H15C16.6569 4.5 18 5.84315 18 7.5V8.25M14.25 18H15C16.6569 18 18 16.6569 18 15V14.25" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
1314
|
+
"fullscreen-exit": '<svg viewBox="0 0 22.5 22.5" xmlns="http://www.w3.org/2000/svg"><path d="M4.5 8.25H5.25C6.9 8.25 8.25 6.9 8.25 5.25V4.5M14.25 4.5V5.25C14.25 6.9 15.6 8.25 17.25 8.25H18M18 14.25H17.25C15.6 14.25 14.25 15.6 14.25 17.25V18M8.25 18V17.25C8.25 15.6 6.9 14.25 5.25 14.25H4.5" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>'
|
|
1315
|
+
};
|
|
1259
1316
|
var ButtonView = class extends ControlView {
|
|
1260
1317
|
constructor(btn, ui, ticker, opts = {}) {
|
|
1261
1318
|
super(btn, ui);
|
|
@@ -1267,6 +1324,7 @@ var ButtonView = class extends ControlView {
|
|
|
1267
1324
|
this.glyph = opts.glyph ?? "none";
|
|
1268
1325
|
this.iconTarget = opts.iconTarget ?? 84;
|
|
1269
1326
|
this.mono = opts.mono ?? false;
|
|
1327
|
+
this.dark = opts.dark ?? false;
|
|
1270
1328
|
this.addChild(this.art);
|
|
1271
1329
|
if (opts.iconTexture) {
|
|
1272
1330
|
this.sprite = new Sprite(opts.iconTexture);
|
|
@@ -1274,7 +1332,7 @@ var ButtonView = class extends ControlView {
|
|
|
1274
1332
|
this.fitSprite();
|
|
1275
1333
|
this.art.addChild(this.sprite);
|
|
1276
1334
|
} else {
|
|
1277
|
-
this.art.addChild(this.bg);
|
|
1335
|
+
this.art.addChild(this.bg, this.glyphG);
|
|
1278
1336
|
if (btn.label) {
|
|
1279
1337
|
this.labelText = new Text({
|
|
1280
1338
|
text: ui.t(btn.label),
|
|
@@ -1286,8 +1344,6 @@ var ButtonView = class extends ControlView {
|
|
|
1286
1344
|
}
|
|
1287
1345
|
this.eventMode = "static";
|
|
1288
1346
|
this.cursor = "pointer";
|
|
1289
|
-
this.on("pointerover", this.onOver);
|
|
1290
|
-
this.on("pointerout", this.onOut);
|
|
1291
1347
|
this.on("pointerdown", this.onDown);
|
|
1292
1348
|
this.on("pointerup", this.onUp);
|
|
1293
1349
|
this.on("pointerupoutside", this.onUpOutside);
|
|
@@ -1297,6 +1353,12 @@ var ButtonView = class extends ControlView {
|
|
|
1297
1353
|
this.updateInteractive();
|
|
1298
1354
|
}),
|
|
1299
1355
|
this.btn.onTransition((t) => this.play(t)),
|
|
1356
|
+
// The host input lock gates `interactable` without a state change, so react to
|
|
1357
|
+
// it directly: a locked/disabled button dims to a semi-transparent state.
|
|
1358
|
+
this.ui.locked.subscribe(() => {
|
|
1359
|
+
this.redraw();
|
|
1360
|
+
this.updateInteractive();
|
|
1361
|
+
}),
|
|
1300
1362
|
this.ui.locale.subscribe(() => {
|
|
1301
1363
|
if (this.destroyed) return;
|
|
1302
1364
|
if (this.labelText && this.btn.label) {
|
|
@@ -1312,6 +1374,7 @@ var ButtonView = class extends ControlView {
|
|
|
1312
1374
|
btn;
|
|
1313
1375
|
art = new Container();
|
|
1314
1376
|
bg = new Graphics();
|
|
1377
|
+
glyphG = new Graphics();
|
|
1315
1378
|
sprite;
|
|
1316
1379
|
labelText;
|
|
1317
1380
|
tween;
|
|
@@ -1321,6 +1384,7 @@ var ButtonView = class extends ControlView {
|
|
|
1321
1384
|
glyph;
|
|
1322
1385
|
iconTarget;
|
|
1323
1386
|
mono;
|
|
1387
|
+
dark;
|
|
1324
1388
|
/** Swap the displayed art (e.g. ☰ → ✕). */
|
|
1325
1389
|
setIconTexture(tex) {
|
|
1326
1390
|
if (!this.sprite) return;
|
|
@@ -1340,12 +1404,6 @@ var ButtonView = class extends ControlView {
|
|
|
1340
1404
|
this.sprite.scale.set(1);
|
|
1341
1405
|
this.sprite.scale.set(this.iconTarget / this.sprite.height);
|
|
1342
1406
|
}
|
|
1343
|
-
onOver = () => {
|
|
1344
|
-
if (isDesktop() && this.btn.current === "idle") this.btn.setState("hover");
|
|
1345
|
-
};
|
|
1346
|
-
onOut = () => {
|
|
1347
|
-
if (this.btn.current === "hover") this.btn.setState("idle");
|
|
1348
|
-
};
|
|
1349
1407
|
onDown = () => {
|
|
1350
1408
|
if (this.btn.interactable) this.btn.setState("pressed");
|
|
1351
1409
|
};
|
|
@@ -1374,6 +1432,7 @@ var ButtonView = class extends ControlView {
|
|
|
1374
1432
|
const ok = this.btn.interactable;
|
|
1375
1433
|
this.eventMode = ok ? "static" : "none";
|
|
1376
1434
|
this.cursor = ok ? "pointer" : "default";
|
|
1435
|
+
this.alpha = ok ? 1 : 0.4;
|
|
1377
1436
|
}
|
|
1378
1437
|
redraw() {
|
|
1379
1438
|
if (this.sprite) {
|
|
@@ -1384,31 +1443,37 @@ var ButtonView = class extends ControlView {
|
|
|
1384
1443
|
const g = this.bg;
|
|
1385
1444
|
g.clear();
|
|
1386
1445
|
const disabled = this.btn.current === "disabled";
|
|
1387
|
-
const fillC = this.mono ? "#ffffff" : t.color.surface;
|
|
1446
|
+
const fillC = this.dark ? "#0a0a0a" : this.mono ? "#ffffff" : t.color.surface;
|
|
1388
1447
|
const lineC = this.mono ? "#0a0a0a" : t.color.accent;
|
|
1389
|
-
const ink = this.mono ? disabled ? "#9aa0a6" : "#0a0a0a" : disabled ? t.color.textDim : t.color.text;
|
|
1448
|
+
const ink = this.dark ? "#ffffff" : this.mono ? disabled ? "#9aa0a6" : "#0a0a0a" : disabled ? t.color.textDim : t.color.text;
|
|
1449
|
+
this.glyphG.clear();
|
|
1450
|
+
this.glyphG.visible = false;
|
|
1390
1451
|
if (this.shape === "circle") {
|
|
1391
1452
|
const r = this.radius;
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1453
|
+
if (this.mono) {
|
|
1454
|
+
g.circle(0, r * 0.16, r).fill({ color: 0, alpha: disabled ? 0.08 : 0.18 });
|
|
1455
|
+
g.circle(0, 0, r).fill({ color: "#ffffff", alpha: disabled ? 0.6 : 1 });
|
|
1456
|
+
g.circle(0, 0, r * 0.925).stroke({ width: r * 0.15, color: "#0a0a0a", alpha: disabled ? 0.5 : 1 });
|
|
1457
|
+
} else if (this.dark) {
|
|
1458
|
+
g.circle(0, r * 0.16, r).fill({ color: 0, alpha: 0.18 });
|
|
1459
|
+
g.circle(0, 0, r).fill({ color: "#0a0a0a" });
|
|
1460
|
+
} else {
|
|
1461
|
+
g.circle(0, 0, r).fill({ color: fillC }).circle(0, 0, r).stroke({ width: 4, color: lineC });
|
|
1462
|
+
}
|
|
1463
|
+
const svg = GLYPH_SVG[this.glyph];
|
|
1464
|
+
if (svg) {
|
|
1465
|
+
const s = r / 15;
|
|
1466
|
+
this.glyphG.svg(svg);
|
|
1467
|
+
this.glyphG.scale.set(s);
|
|
1468
|
+
this.glyphG.position.set(-11.25 * s, -11.25 * s);
|
|
1469
|
+
this.glyphG.alpha = disabled ? 0.5 : 1;
|
|
1470
|
+
this.glyphG.visible = true;
|
|
1471
|
+
} else if (this.glyph === "menu") {
|
|
1472
|
+
const barW = this.dark ? 6 : 4;
|
|
1473
|
+
const spread = this.dark ? 9 : 8;
|
|
1474
|
+
for (const dy of [-spread, 0, spread]) g.moveTo(-14, dy).lineTo(14, dy).stroke({ width: barW, color: ink, cap: "round" });
|
|
1396
1475
|
} else if (this.glyph === "close") {
|
|
1397
1476
|
g.moveTo(-10, -10).lineTo(10, 10).moveTo(10, -10).lineTo(-10, 10).stroke({ width: 4, color: ink });
|
|
1398
|
-
} else if (this.glyph === "speaker" || this.glyph === "speaker-mute") {
|
|
1399
|
-
g.poly([-12, -4, -6, -4, 1, -11, 1, 11, -6, 4, -12, 4]).fill({ color: ink });
|
|
1400
|
-
if (this.glyph === "speaker") {
|
|
1401
|
-
g.moveTo(6, -6).lineTo(11, 0).lineTo(6, 6).stroke({ width: 2.5, color: ink });
|
|
1402
|
-
g.moveTo(11, -9).lineTo(17, 0).lineTo(11, 9).stroke({ width: 2.5, color: ink });
|
|
1403
|
-
} else {
|
|
1404
|
-
g.moveTo(7, -6).lineTo(17, 6).moveTo(17, -6).lineTo(7, 6).stroke({ width: 2.5, color: ink });
|
|
1405
|
-
}
|
|
1406
|
-
} else if (this.glyph === "fullscreen") {
|
|
1407
|
-
const a = 13, b = 6;
|
|
1408
|
-
g.moveTo(-a, -a + b).lineTo(-a, -a).lineTo(-a + b, -a).moveTo(a - b, -a).lineTo(a, -a).lineTo(a, -a + b).moveTo(-a, a - b).lineTo(-a, a).lineTo(-a + b, a).moveTo(a - b, a).lineTo(a, a).lineTo(a, a - b).stroke({ width: 3, color: ink });
|
|
1409
|
-
} else if (this.glyph === "fullscreen-exit") {
|
|
1410
|
-
const c = 4, d = 12;
|
|
1411
|
-
g.moveTo(-d, -c).lineTo(-c, -c).lineTo(-c, -d).moveTo(d, -c).lineTo(c, -c).lineTo(c, -d).moveTo(-d, c).lineTo(-c, c).lineTo(-c, d).moveTo(d, c).lineTo(c, c).lineTo(c, d).stroke({ width: 3, color: ink });
|
|
1412
1477
|
}
|
|
1413
1478
|
} else {
|
|
1414
1479
|
const w = this.labelText ? this.labelText.width + 48 : 120;
|
|
@@ -1653,24 +1718,30 @@ var AutoplayView = class extends ControlView {
|
|
|
1653
1718
|
}
|
|
1654
1719
|
drawButton() {
|
|
1655
1720
|
const st = this.auto.current;
|
|
1656
|
-
this.countText.visible =
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1721
|
+
this.countText.visible = false;
|
|
1722
|
+
const th = this.ui.theme;
|
|
1723
|
+
const r = this.sprite ? this.target / 2 : this.radius;
|
|
1724
|
+
const active = st === "active";
|
|
1725
|
+
this.eventMode = active ? "none" : "static";
|
|
1726
|
+
this.cursor = active ? "default" : "pointer";
|
|
1727
|
+
if (active) {
|
|
1728
|
+
this.bg.clear().circle(0, 0, r).fill({ color: th.color.accent }).stroke({ width: 4, color: th.color.accentText });
|
|
1729
|
+
if (this.sprite) {
|
|
1730
|
+
this.sprite.visible = true;
|
|
1731
|
+
this.sprite.tint = th.color.accentText;
|
|
1732
|
+
this.sprite.alpha = 0.55;
|
|
1733
|
+
}
|
|
1663
1734
|
return;
|
|
1664
1735
|
}
|
|
1665
1736
|
if (this.sprite) {
|
|
1666
1737
|
this.sprite.visible = true;
|
|
1738
|
+
this.sprite.tint = 16777215;
|
|
1667
1739
|
this.bg.clear();
|
|
1668
1740
|
const tex = this.idleTex ?? this.activeTex;
|
|
1669
1741
|
if (tex) this.sprite.texture = tex;
|
|
1670
1742
|
this.fit();
|
|
1671
1743
|
this.sprite.alpha = st === "disabled" ? 0.5 : 1;
|
|
1672
1744
|
} else {
|
|
1673
|
-
const th = this.ui.theme;
|
|
1674
1745
|
this.bg.clear();
|
|
1675
1746
|
this.bg.circle(0, 0, this.radius).fill({ color: th.color.surface }).stroke({ width: 4, color: th.color.accent });
|
|
1676
1747
|
}
|
|
@@ -1841,8 +1912,8 @@ var AutoplayDrawerView = class extends Container {
|
|
|
1841
1912
|
this.startBtn.position.set(W / 2, startY);
|
|
1842
1913
|
this.startBtn.hitArea = new Rectangle(-startW / 2, -startH / 2, startW, startH);
|
|
1843
1914
|
this.sheetH = startY + startH / 2 + 20 * k;
|
|
1844
|
-
this.sheetBg.clear().rect(
|
|
1845
|
-
this.handle.clear().
|
|
1915
|
+
this.sheetBg.clear().rect(-1, 0, W + 2, this.sheetH + 40 + 600).fill({ color: DARK });
|
|
1916
|
+
this.handle.clear().roundRect(W / 2 - 30 * k, 13 * k, 60 * k, 5 * k, 2.5 * k).fill({ color: DIM });
|
|
1846
1917
|
return this.sheetH + 40;
|
|
1847
1918
|
}
|
|
1848
1919
|
drawGroup(g) {
|
|
@@ -2906,7 +2977,27 @@ var ReadoutView = class extends ControlView {
|
|
|
2906
2977
|
this.ticker = ticker;
|
|
2907
2978
|
const t = ui.theme;
|
|
2908
2979
|
const inline = opts.inline ?? false;
|
|
2909
|
-
|
|
2980
|
+
this.prefix = opts.prefix ?? false;
|
|
2981
|
+
const fill = opts.fill ?? (opts.mono ? "#ffffff" : t.color.text);
|
|
2982
|
+
if (this.prefix) {
|
|
2983
|
+
this.valueText = new Text({ text: "", style: { fontFamily: t.type.family, fontSize: 12, fill: opts.fill ?? "#ffffff", fontWeight: "400" } });
|
|
2984
|
+
this.valueText.alpha = opts.fill ? 1 : 0.5;
|
|
2985
|
+
this.valueText.anchor.set(0, 0);
|
|
2986
|
+
this.addChild(this.valueText);
|
|
2987
|
+
this.disposers.push(
|
|
2988
|
+
this.ro.value.subscribe(() => this.render()),
|
|
2989
|
+
this.ui.locale.subscribe(() => {
|
|
2990
|
+
if (!this.destroyed) this.render();
|
|
2991
|
+
})
|
|
2992
|
+
);
|
|
2993
|
+
if (this.ro.currency) this.disposers.push(this.ro.currency.subscribe(() => this.render()));
|
|
2994
|
+
if (this.ro.kind === "duration") {
|
|
2995
|
+
this.tick = (tk) => this.ro.tick(tk.deltaMS / 1e3);
|
|
2996
|
+
this.ticker.add(this.tick);
|
|
2997
|
+
}
|
|
2998
|
+
this.render();
|
|
2999
|
+
return;
|
|
3000
|
+
}
|
|
2910
3001
|
if (ro.label) {
|
|
2911
3002
|
this.caption = new Text({
|
|
2912
3003
|
text: ui.t(ro.label).toUpperCase(),
|
|
@@ -2949,6 +3040,7 @@ var ReadoutView = class extends ControlView {
|
|
|
2949
3040
|
caption;
|
|
2950
3041
|
valueText;
|
|
2951
3042
|
tick;
|
|
3043
|
+
prefix;
|
|
2952
3044
|
render() {
|
|
2953
3045
|
const v = this.ro.value.get();
|
|
2954
3046
|
let text;
|
|
@@ -2965,7 +3057,7 @@ var ReadoutView = class extends ControlView {
|
|
|
2965
3057
|
default:
|
|
2966
3058
|
text = String(v);
|
|
2967
3059
|
}
|
|
2968
|
-
this.valueText.text = text;
|
|
3060
|
+
this.valueText.text = this.prefix && this.ro.label ? `${this.ui.t(this.ro.label)}: ${text}` : text;
|
|
2969
3061
|
}
|
|
2970
3062
|
dispose() {
|
|
2971
3063
|
if (this.tick) this.ticker.remove(this.tick);
|
|
@@ -2973,9 +3065,18 @@ var ReadoutView = class extends ControlView {
|
|
|
2973
3065
|
}
|
|
2974
3066
|
};
|
|
2975
3067
|
var INSET2 = 24;
|
|
2976
|
-
var BTN_H =
|
|
2977
|
-
var BTN_GAP =
|
|
3068
|
+
var BTN_H = 52;
|
|
3069
|
+
var BTN_GAP = 14;
|
|
2978
3070
|
var ROW_GAP = 16;
|
|
3071
|
+
var LIGHT = {
|
|
3072
|
+
surface: "#ffffff",
|
|
3073
|
+
surfaceAlt: "#eef1f6",
|
|
3074
|
+
text: "#181b20",
|
|
3075
|
+
textDim: "#5b6472",
|
|
3076
|
+
border: "#000000",
|
|
3077
|
+
primary: "#0a0a0a",
|
|
3078
|
+
primaryText: "#ffffff"
|
|
3079
|
+
};
|
|
2979
3080
|
var DialogView = class extends ControlView {
|
|
2980
3081
|
constructor(panel, blocks, actions, ui, ticker, opts = {}) {
|
|
2981
3082
|
super(panel, ui);
|
|
@@ -2986,6 +3087,8 @@ var DialogView = class extends ControlView {
|
|
|
2986
3087
|
this.opts = opts;
|
|
2987
3088
|
this.zIndex = 130;
|
|
2988
3089
|
this.maxWidth = opts.maxWidth ?? 520;
|
|
3090
|
+
const lightTheme = { ...ui.theme, color: { ...ui.theme.color, surface: LIGHT.surface, surfaceAlt: LIGHT.surfaceAlt, text: LIGHT.text, textDim: LIGHT.textDim } };
|
|
3091
|
+
this.lightUi = new Proxy(ui, { get: (t, p) => p === "theme" ? lightTheme : Reflect.get(t, p) });
|
|
2989
3092
|
this.backdrop.eventMode = "static";
|
|
2990
3093
|
this.backdrop.on("pointertap", () => {
|
|
2991
3094
|
if (!this.ui.noticeBlocking.get()) this.panel.closePanel();
|
|
@@ -3025,11 +3128,13 @@ var DialogView = class extends ControlView {
|
|
|
3025
3128
|
childViews = [];
|
|
3026
3129
|
screen;
|
|
3027
3130
|
maxWidth;
|
|
3131
|
+
/** `ui` proxy with a light theme — so the shared block renderer draws dark-on-white
|
|
3132
|
+
* content inside the white modal card (Figma "default" dialog look). */
|
|
3133
|
+
lightUi;
|
|
3028
3134
|
buildClose() {
|
|
3029
|
-
const
|
|
3030
|
-
const
|
|
3031
|
-
const
|
|
3032
|
-
const x = new Graphics().moveTo(-6, -6).lineTo(6, 6).moveTo(6, -6).lineTo(-6, 6).stroke({ width: 3, color: t.color.text });
|
|
3135
|
+
const r = 22;
|
|
3136
|
+
const bg = new Graphics().circle(0, 0, r).fill({ color: LIGHT.primary });
|
|
3137
|
+
const x = new Graphics().moveTo(-7, -7).lineTo(7, 7).moveTo(7, -7).lineTo(-7, 7).stroke({ width: 3, color: "#ffffff", cap: "round" });
|
|
3033
3138
|
this.closeBtn.addChild(bg, x);
|
|
3034
3139
|
this.closeBtn.eventMode = "static";
|
|
3035
3140
|
this.closeBtn.cursor = "pointer";
|
|
@@ -3048,13 +3153,12 @@ var DialogView = class extends ControlView {
|
|
|
3048
3153
|
if (!this.panel.isOpen) return;
|
|
3049
3154
|
const W = s.width;
|
|
3050
3155
|
const H = s.height;
|
|
3051
|
-
const t = this.ui.theme;
|
|
3052
3156
|
for (const v of this.childViews) v.dispose();
|
|
3053
3157
|
this.childViews.length = 0;
|
|
3054
3158
|
for (const ch of this.content.removeChildren()) ch.destroy();
|
|
3055
3159
|
const cardW = Math.min(W - 48, this.maxWidth);
|
|
3056
3160
|
const innerW = cardW - INSET2 * 2;
|
|
3057
|
-
const col = buildBlockColumn(this.blocks.get(), [], this.
|
|
3161
|
+
const col = buildBlockColumn(this.blocks.get(), [], this.lightUi, this.ticker, innerW, { controlSkins: this.opts.controlSkins });
|
|
3058
3162
|
this.childViews = col.views;
|
|
3059
3163
|
const kids = col.content.removeChildren();
|
|
3060
3164
|
if (kids.length) this.content.addChild(...kids);
|
|
@@ -3064,15 +3168,15 @@ var DialogView = class extends ControlView {
|
|
|
3064
3168
|
const cardH = Math.min(H - 48, wantH);
|
|
3065
3169
|
const cx = (W - cardW) / 2;
|
|
3066
3170
|
const cy = (H - cardH) / 2;
|
|
3067
|
-
this.backdrop.clear().rect(0, 0, W, H).fill({ color: 0, alpha: 0.
|
|
3171
|
+
this.backdrop.clear().rect(0, 0, W, H).fill({ color: 0, alpha: 0.5 });
|
|
3068
3172
|
this.backdrop.hitArea = new Rectangle(0, 0, W, H);
|
|
3069
|
-
this.card.clear().roundRect(cx, cy, cardW, cardH,
|
|
3173
|
+
this.card.clear().roundRect(cx, cy, cardW, cardH, 14).fill({ color: LIGHT.surface }).stroke({ width: 2.5, color: LIGHT.border });
|
|
3070
3174
|
const bodyH = cardH - (buttonsH ? ROW_GAP + buttonsH + INSET2 : INSET2);
|
|
3071
3175
|
this.content.x = cx + cardW / 2;
|
|
3072
3176
|
this.content.y = cy;
|
|
3073
3177
|
this.maskG.clear().rect(cx, cy, cardW, Math.max(0, bodyH)).fill({ color: 16777215 });
|
|
3074
3178
|
this.buttons.position.set(cx + cardW / 2, cy + cardH - INSET2 / 2 - buttonsH / 2);
|
|
3075
|
-
this.closeBtn.position.set(cx + cardW -
|
|
3179
|
+
this.closeBtn.position.set(cx + cardW - 8, cy + 8);
|
|
3076
3180
|
}
|
|
3077
3181
|
/** Build the footer buttons from `noticeActions` into a centered row (shrunk to
|
|
3078
3182
|
* fit if needed). Returns the row height (0 when there are no actions). */
|
|
@@ -3105,7 +3209,7 @@ var DialogView = class extends ControlView {
|
|
|
3105
3209
|
const bg = new Graphics();
|
|
3106
3210
|
const label = new Text({
|
|
3107
3211
|
text: this.ui.t(action.label),
|
|
3108
|
-
style: { fontFamily: t.type.family, fontSize: 18, fontWeight: "800", fill: variant === "primary" ?
|
|
3212
|
+
style: { fontFamily: t.type.family, fontSize: 18, fontWeight: "800", fill: variant === "primary" ? LIGHT.primaryText : LIGHT.text, letterSpacing: 0.5 }
|
|
3109
3213
|
});
|
|
3110
3214
|
label.anchor.set(0.5);
|
|
3111
3215
|
node.addChild(bg, label);
|
|
@@ -3122,12 +3226,11 @@ var DialogView = class extends ControlView {
|
|
|
3122
3226
|
return { node, bg, width, variant };
|
|
3123
3227
|
}
|
|
3124
3228
|
drawButton(bg, variant, width) {
|
|
3125
|
-
const t = this.ui.theme;
|
|
3126
3229
|
bg.clear();
|
|
3127
3230
|
if (variant === "primary") {
|
|
3128
|
-
bg.roundRect(-width / 2, -BTN_H / 2, width, BTN_H, BTN_H / 2).fill({ color:
|
|
3231
|
+
bg.roundRect(-width / 2, -BTN_H / 2, width, BTN_H, BTN_H / 2).fill({ color: LIGHT.primary });
|
|
3129
3232
|
} else {
|
|
3130
|
-
bg.roundRect(-width / 2, -BTN_H / 2, width, BTN_H, BTN_H / 2).fill({ color:
|
|
3233
|
+
bg.roundRect(-width / 2, -BTN_H / 2, width, BTN_H, BTN_H / 2).fill({ color: LIGHT.surface }).stroke({ width: 2.5, color: LIGHT.border });
|
|
3131
3234
|
}
|
|
3132
3235
|
}
|
|
3133
3236
|
applyOpen(open) {
|
|
@@ -3261,8 +3364,8 @@ var OpenUIPixi = class {
|
|
|
3261
3364
|
glyph: "menu",
|
|
3262
3365
|
iconTexture: ic.settingsIdle,
|
|
3263
3366
|
iconTarget: 88,
|
|
3264
|
-
|
|
3265
|
-
//
|
|
3367
|
+
dark: true
|
|
3368
|
+
// Figma ☰: solid black circle, white bars, no ring
|
|
3266
3369
|
});
|
|
3267
3370
|
settingsView.zIndex = 5;
|
|
3268
3371
|
const menuView = this.opts.menu === false ? void 0 : this.buildMenu(ticker);
|
|
@@ -3270,7 +3373,7 @@ var OpenUIPixi = class {
|
|
|
3270
3373
|
offTexture: ic.turboOff,
|
|
3271
3374
|
onTexture: ic.turboOn,
|
|
3272
3375
|
modeTextures: ic.turboModes,
|
|
3273
|
-
target:
|
|
3376
|
+
target: 79
|
|
3274
3377
|
});
|
|
3275
3378
|
const spinOff = this.ui.spin.layout.offset ?? [0, 0];
|
|
3276
3379
|
const autoOff = this.ui.autoplay.layout.offset ?? [0, 0];
|
|
@@ -3278,23 +3381,24 @@ var OpenUIPixi = class {
|
|
|
3278
3381
|
const autoplayView = new AutoplayView(this.ui.autoplay, this.ui, ticker, {
|
|
3279
3382
|
idleTexture: ic.autoIdle,
|
|
3280
3383
|
activeTexture: ic.autoActive,
|
|
3281
|
-
target:
|
|
3384
|
+
target: 73,
|
|
3282
3385
|
picker,
|
|
3283
3386
|
arcCenter: { x: spinOff[0] - autoOff[0], y: spinOff[1] - autoOff[1] },
|
|
3284
3387
|
arcStepDeg: 22
|
|
3285
3388
|
});
|
|
3286
3389
|
autoplayView.zIndex = 20;
|
|
3287
|
-
const bonusView = new ButtonView(this.ui.bonusButton, this.ui, ticker, { shape: "circle", radius:
|
|
3390
|
+
const bonusView = new ButtonView(this.ui.bonusButton, this.ui, ticker, { shape: "circle", radius: 60, iconTexture: ic.bonus, iconTarget: 130 });
|
|
3288
3391
|
const betPlusView = new ButtonView(this.ui.betPlus, this.ui, ticker, { shape: "circle", radius: 30, iconTexture: ic.betPlus, iconTarget: 64 });
|
|
3289
3392
|
const betMinusView = new ButtonView(this.ui.betMinus, this.ui, ticker, { shape: "circle", radius: 30, iconTexture: ic.betMinus, iconTarget: 64 });
|
|
3290
|
-
const muteView = new ButtonView(this.ui.muteButton, this.ui, ticker, { shape: "circle", radius:
|
|
3291
|
-
const fullscreenView = new ButtonView(this.ui.fullscreenButton, this.ui, ticker, { shape: "circle", radius:
|
|
3393
|
+
const muteView = new ButtonView(this.ui.muteButton, this.ui, ticker, { shape: "circle", radius: 30, glyph: "speaker", iconTarget: 60, mono: true });
|
|
3394
|
+
const fullscreenView = new ButtonView(this.ui.fullscreenButton, this.ui, ticker, { shape: "circle", radius: 30, glyph: "fullscreen", iconTarget: 60, mono: true });
|
|
3292
3395
|
muteView.zIndex = 65;
|
|
3293
3396
|
fullscreenView.zIndex = 65;
|
|
3294
3397
|
const statusBarSide = this.opts.statusBar;
|
|
3295
|
-
const
|
|
3296
|
-
const
|
|
3297
|
-
const
|
|
3398
|
+
const roOpts = { prefix: true, fill: this.opts.readoutColor };
|
|
3399
|
+
const rtpView = statusBarSide ? void 0 : new ReadoutView(this.ui.rtp, this.ui, ticker, roOpts);
|
|
3400
|
+
const netView = statusBarSide ? void 0 : new ReadoutView(this.ui.netPosition, this.ui, ticker, roOpts);
|
|
3401
|
+
const timerView = statusBarSide ? void 0 : new ReadoutView(this.ui.sessionTimer, this.ui, ticker, roOpts);
|
|
3298
3402
|
const entries = [
|
|
3299
3403
|
[this.ui.spin.id, spinView],
|
|
3300
3404
|
[this.ui.balance.id, balanceView],
|
|
@@ -3375,6 +3479,23 @@ var OpenUIPixi = class {
|
|
|
3375
3479
|
const bar = new StatusBarView([this.ui.netPosition, this.ui.rtp, this.ui.sessionTimer], this.ui, ticker, statusBarSide);
|
|
3376
3480
|
this.root.addChild(bar);
|
|
3377
3481
|
this.overlays.push(bar);
|
|
3482
|
+
} else {
|
|
3483
|
+
const vignette = new Graphics();
|
|
3484
|
+
vignette.zIndex = -1;
|
|
3485
|
+
this.root.addChild(vignette);
|
|
3486
|
+
this.overlays.push({
|
|
3487
|
+
applyLayout: (s) => {
|
|
3488
|
+
const r = 200 * s.scale;
|
|
3489
|
+
vignette.clear();
|
|
3490
|
+
for (let i = 0; i < 14; i++) {
|
|
3491
|
+
const t = i / 14;
|
|
3492
|
+
vignette.circle(0, 0, r * (1 - t)).fill({ color: 0, alpha: 0.5 / 14 });
|
|
3493
|
+
}
|
|
3494
|
+
},
|
|
3495
|
+
dispose: () => {
|
|
3496
|
+
if (!vignette.destroyed) vignette.destroy();
|
|
3497
|
+
}
|
|
3498
|
+
});
|
|
3378
3499
|
}
|
|
3379
3500
|
const replayBadge = new Container();
|
|
3380
3501
|
const replayBg = new Graphics();
|
|
@@ -3404,21 +3525,6 @@ var OpenUIPixi = class {
|
|
|
3404
3525
|
if (!replayBadge.destroyed) replayText.text = this.ui.t("openui.replay").toUpperCase();
|
|
3405
3526
|
})
|
|
3406
3527
|
);
|
|
3407
|
-
if (ic.settingsIdle && ic.settingsActive) {
|
|
3408
|
-
const idle = ic.settingsIdle;
|
|
3409
|
-
const active = ic.settingsActive;
|
|
3410
|
-
this.disposers.push(
|
|
3411
|
-
this.ui.settingsPanel.state.subscribe(() => {
|
|
3412
|
-
settingsView.setIconTexture(this.ui.settingsPanel.isOpen ? active : idle);
|
|
3413
|
-
})
|
|
3414
|
-
);
|
|
3415
|
-
} else {
|
|
3416
|
-
this.disposers.push(
|
|
3417
|
-
this.ui.settingsPanel.state.subscribe(() => {
|
|
3418
|
-
settingsView.setGlyph(this.ui.settingsPanel.isOpen ? "close" : "menu");
|
|
3419
|
-
})
|
|
3420
|
-
);
|
|
3421
|
-
}
|
|
3422
3528
|
const applyLayout = () => {
|
|
3423
3529
|
const screen = this.ui.screen.get();
|
|
3424
3530
|
const barH = statusBarSide ? StatusBarView.heightFor(screen) : 0;
|