@playruo/embed 1.3.0 → 1.3.2
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/README.md +9 -0
- package/dist/index.cjs +1354 -371
- package/dist/index.d.cts +22 -2
- package/dist/index.d.ts +22 -2
- package/dist/index.js +1354 -371
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -74,15 +74,18 @@ var PlayruoEmbed = ({
|
|
|
74
74
|
onReady,
|
|
75
75
|
onStateChange,
|
|
76
76
|
onDemoCompleted,
|
|
77
|
+
onEvent,
|
|
77
78
|
onPurchaseRequest,
|
|
78
79
|
onError,
|
|
80
|
+
forwardEventsToParent = true,
|
|
79
81
|
renderState,
|
|
80
82
|
iframeRef: externalIframeRef
|
|
81
83
|
}) => {
|
|
82
84
|
const internalIframeRef = (0, import_react.useRef)(null);
|
|
83
85
|
const iframeRef = externalIframeRef || internalIframeRef;
|
|
84
86
|
const wasEmbedFullscreenRef = (0, import_react.useRef)(false);
|
|
85
|
-
const
|
|
87
|
+
const hasNotifiedCompletionRef = (0, import_react.useRef)(false);
|
|
88
|
+
const suppressNextFullscreenExitCleanupRef = (0, import_react.useRef)(false);
|
|
86
89
|
const [isIframeLoaded, setIsIframeLoaded] = (0, import_react.useState)(false);
|
|
87
90
|
const [hasPlayedOnce, setHasPlayedOnce] = (0, import_react.useState)(false);
|
|
88
91
|
const [showGameIframe, setShowGameIframe] = (0, import_react.useState)(false);
|
|
@@ -152,6 +155,149 @@ var PlayruoEmbed = ({
|
|
|
152
155
|
console.warn("[PlayruoEmbed] Failed to release Escape key lock:", error);
|
|
153
156
|
}
|
|
154
157
|
}, [getKeyboardApi]);
|
|
158
|
+
const getFullscreenElement = (0, import_react.useCallback)(() => {
|
|
159
|
+
const doc = document;
|
|
160
|
+
return doc.fullscreenElement || doc.webkitFullscreenElement || doc.mozFullScreenElement || doc.msFullscreenElement || null;
|
|
161
|
+
}, []);
|
|
162
|
+
const notifyDemoCompletedOnce = (0, import_react.useCallback)(
|
|
163
|
+
(payload) => {
|
|
164
|
+
if (hasNotifiedCompletionRef.current) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
hasNotifiedCompletionRef.current = true;
|
|
168
|
+
onDemoCompleted?.(
|
|
169
|
+
payload ?? {
|
|
170
|
+
reason: "Demo session ended",
|
|
171
|
+
storeUrl
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
},
|
|
175
|
+
[onDemoCompleted, storeUrl]
|
|
176
|
+
);
|
|
177
|
+
const postExitFullscreenToIframe = (0, import_react.useCallback)(() => {
|
|
178
|
+
const iframe = iframeRef.current;
|
|
179
|
+
if (!iframe) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
iframe.contentWindow?.postMessage({
|
|
184
|
+
type: "playruo",
|
|
185
|
+
action: "exitFullscreen",
|
|
186
|
+
fromEmbed: true,
|
|
187
|
+
isFullscreen: false,
|
|
188
|
+
parentWillHandleFullscreen: true
|
|
189
|
+
}, "*");
|
|
190
|
+
} catch {
|
|
191
|
+
console.error("[PlayruoEmbed] Failed to exit fullscreen");
|
|
192
|
+
}
|
|
193
|
+
}, [iframeRef]);
|
|
194
|
+
const postExitFullscreenAckToIframe = (0, import_react.useCallback)(() => {
|
|
195
|
+
const iframe = iframeRef.current;
|
|
196
|
+
if (!iframe) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
iframe.contentWindow?.postMessage({ type: "ACK_EXIT_FULLSCREEN" }, "*");
|
|
201
|
+
} catch {
|
|
202
|
+
console.error("[PlayruoEmbed] Failed to acknowledge fullscreen exit");
|
|
203
|
+
}
|
|
204
|
+
}, [iframeRef]);
|
|
205
|
+
const exitEmbedFullscreen = (0, import_react.useCallback)(
|
|
206
|
+
async ({
|
|
207
|
+
reason = "cleanup",
|
|
208
|
+
suppressFullscreenExitCleanup = true
|
|
209
|
+
} = {}) => {
|
|
210
|
+
const fullscreenElement = getFullscreenElement();
|
|
211
|
+
const doc = document;
|
|
212
|
+
const exitFullscreen = doc.exitFullscreen?.bind(doc) ?? doc.webkitExitFullscreen?.bind(doc) ?? doc.mozCancelFullScreen?.bind(doc) ?? doc.msExitFullscreen?.bind(doc);
|
|
213
|
+
const shouldAttemptExit = Boolean(fullscreenElement || wasEmbedFullscreenRef.current);
|
|
214
|
+
if (!shouldAttemptExit || !exitFullscreen) {
|
|
215
|
+
console.log("[PlayruoEmbed] Parent fullscreen exit skipped", {
|
|
216
|
+
hasFullscreenElement: Boolean(fullscreenElement),
|
|
217
|
+
hasExitFullscreen: Boolean(exitFullscreen),
|
|
218
|
+
reason,
|
|
219
|
+
wasEmbedFullscreen: wasEmbedFullscreenRef.current
|
|
220
|
+
});
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
console.log("[PlayruoEmbed] Parent fullscreen exit requested", {
|
|
224
|
+
fullscreenElement: fullscreenElement?.tagName,
|
|
225
|
+
reason,
|
|
226
|
+
wasEmbedFullscreen: wasEmbedFullscreenRef.current
|
|
227
|
+
});
|
|
228
|
+
const shouldSuppressFullscreenExitCleanup = Boolean(
|
|
229
|
+
suppressFullscreenExitCleanup && fullscreenElement
|
|
230
|
+
);
|
|
231
|
+
if (shouldSuppressFullscreenExitCleanup) {
|
|
232
|
+
suppressNextFullscreenExitCleanupRef.current = true;
|
|
233
|
+
wasEmbedFullscreenRef.current = false;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
await exitFullscreen();
|
|
237
|
+
if (shouldSuppressFullscreenExitCleanup) {
|
|
238
|
+
window.setTimeout(() => {
|
|
239
|
+
suppressNextFullscreenExitCleanupRef.current = false;
|
|
240
|
+
}, 1e3);
|
|
241
|
+
}
|
|
242
|
+
return true;
|
|
243
|
+
} catch (error) {
|
|
244
|
+
if (shouldSuppressFullscreenExitCleanup) {
|
|
245
|
+
suppressNextFullscreenExitCleanupRef.current = false;
|
|
246
|
+
wasEmbedFullscreenRef.current = Boolean(getFullscreenElement());
|
|
247
|
+
}
|
|
248
|
+
console.warn("[PlayruoEmbed] Failed to leave fullscreen:", error);
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
[getFullscreenElement]
|
|
253
|
+
);
|
|
254
|
+
const cleanupEmbedSession = (0, import_react.useCallback)(
|
|
255
|
+
({
|
|
256
|
+
payload,
|
|
257
|
+
notifyCompletion = true,
|
|
258
|
+
requestFullscreenExit = true,
|
|
259
|
+
notifyIframe = false,
|
|
260
|
+
markPlayed = true
|
|
261
|
+
} = {}) => {
|
|
262
|
+
setShowGameIframe(false);
|
|
263
|
+
if (markPlayed) {
|
|
264
|
+
setHasPlayedOnce(true);
|
|
265
|
+
}
|
|
266
|
+
releaseEscapeKeyLock();
|
|
267
|
+
if (notifyIframe) {
|
|
268
|
+
postExitFullscreenToIframe();
|
|
269
|
+
}
|
|
270
|
+
if (requestFullscreenExit) {
|
|
271
|
+
void exitEmbedFullscreen();
|
|
272
|
+
}
|
|
273
|
+
if (notifyCompletion) {
|
|
274
|
+
notifyDemoCompletedOnce(payload);
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
[
|
|
278
|
+
exitEmbedFullscreen,
|
|
279
|
+
notifyDemoCompletedOnce,
|
|
280
|
+
postExitFullscreenToIframe,
|
|
281
|
+
releaseEscapeKeyLock
|
|
282
|
+
]
|
|
283
|
+
);
|
|
284
|
+
const markStreamActive = (0, import_react.useCallback)(() => {
|
|
285
|
+
hasNotifiedCompletionRef.current = false;
|
|
286
|
+
setShowGameIframe(true);
|
|
287
|
+
}, []);
|
|
288
|
+
const forwardEventToParent = (0, import_react.useCallback)(
|
|
289
|
+
(message) => {
|
|
290
|
+
if (!forwardEventsToParent || typeof window === "undefined" || window.parent === window) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
try {
|
|
294
|
+
window.parent.postMessage(message, "*");
|
|
295
|
+
} catch (error) {
|
|
296
|
+
console.warn("[PlayruoEmbed] Failed to forward event to parent:", error);
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
[forwardEventsToParent]
|
|
300
|
+
);
|
|
155
301
|
const lockEscapeKey = (0, import_react.useCallback)(async () => {
|
|
156
302
|
const keyboard = getKeyboardApi();
|
|
157
303
|
if (!keyboard?.lock) {
|
|
@@ -164,55 +310,8 @@ var PlayruoEmbed = ({
|
|
|
164
310
|
console.warn("[PlayruoEmbed] Failed to lock Escape key:", error);
|
|
165
311
|
}
|
|
166
312
|
}, [getKeyboardApi]);
|
|
167
|
-
const getPointerLockElement = (0, import_react.useCallback)(() => {
|
|
168
|
-
const doc = document;
|
|
169
|
-
return doc.pointerLockElement || doc.mozPointerLockElement || doc.webkitPointerLockElement || null;
|
|
170
|
-
}, []);
|
|
171
|
-
const releasePointerLock = (0, import_react.useCallback)(() => {
|
|
172
|
-
const doc = document;
|
|
173
|
-
const exitPointerLock = doc.exitPointerLock?.bind(doc) || doc.mozExitPointerLock?.bind(doc) || doc.webkitExitPointerLock?.bind(doc);
|
|
174
|
-
try {
|
|
175
|
-
exitPointerLock?.();
|
|
176
|
-
wasEmbedPointerLockedRef.current = false;
|
|
177
|
-
} catch (error) {
|
|
178
|
-
console.warn("[PlayruoEmbed] Failed to release pointer lock:", error);
|
|
179
|
-
}
|
|
180
|
-
}, []);
|
|
181
313
|
const requestImmersiveMode = (0, import_react.useCallback)(
|
|
182
314
|
async (iframe) => {
|
|
183
|
-
const pointerTarget = iframe;
|
|
184
|
-
if (pointerTarget.requestPointerLock) {
|
|
185
|
-
try {
|
|
186
|
-
const pointerLockResult = pointerTarget.requestPointerLock({ unadjustedMovement: true });
|
|
187
|
-
if (pointerLockResult && typeof pointerLockResult.then === "function") {
|
|
188
|
-
void pointerLockResult.then(() => {
|
|
189
|
-
wasEmbedPointerLockedRef.current = true;
|
|
190
|
-
console.log("[PlayruoEmbed] Pointer locked on iframe");
|
|
191
|
-
}).catch(async (error) => {
|
|
192
|
-
if (error instanceof DOMException && error.name === "NotSupportedError") {
|
|
193
|
-
try {
|
|
194
|
-
const fallbackResult = pointerTarget.requestPointerLock?.();
|
|
195
|
-
if (fallbackResult && typeof fallbackResult.then === "function") {
|
|
196
|
-
await fallbackResult;
|
|
197
|
-
}
|
|
198
|
-
wasEmbedPointerLockedRef.current = true;
|
|
199
|
-
console.log("[PlayruoEmbed] Pointer locked on iframe without raw input");
|
|
200
|
-
return;
|
|
201
|
-
} catch (fallbackError) {
|
|
202
|
-
console.warn("[PlayruoEmbed] Failed to lock pointer without raw input:", fallbackError);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
console.warn("[PlayruoEmbed] Failed to lock pointer:", error);
|
|
207
|
-
});
|
|
208
|
-
} else {
|
|
209
|
-
wasEmbedPointerLockedRef.current = true;
|
|
210
|
-
console.log("[PlayruoEmbed] Pointer lock requested on iframe");
|
|
211
|
-
}
|
|
212
|
-
} catch (error) {
|
|
213
|
-
console.warn("[PlayruoEmbed] Failed to request pointer lock:", error);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
315
|
const fullscreenPromise = iframe.requestFullscreen();
|
|
217
316
|
try {
|
|
218
317
|
await fullscreenPromise;
|
|
@@ -220,11 +319,10 @@ var PlayruoEmbed = ({
|
|
|
220
319
|
console.log("[PlayruoEmbed] Fullscreen granted");
|
|
221
320
|
} catch (error) {
|
|
222
321
|
releaseEscapeKeyLock();
|
|
223
|
-
releasePointerLock();
|
|
224
322
|
throw error;
|
|
225
323
|
}
|
|
226
324
|
},
|
|
227
|
-
[releaseEscapeKeyLock
|
|
325
|
+
[releaseEscapeKeyLock]
|
|
228
326
|
);
|
|
229
327
|
const handleTryNow = (0, import_react.useCallback)(async () => {
|
|
230
328
|
if (!isCompatible) {
|
|
@@ -236,6 +334,7 @@ var PlayruoEmbed = ({
|
|
|
236
334
|
console.warn("[PlayruoEmbed] Iframe not ready");
|
|
237
335
|
return;
|
|
238
336
|
}
|
|
337
|
+
hasNotifiedCompletionRef.current = false;
|
|
239
338
|
setShowGameIframe(true);
|
|
240
339
|
try {
|
|
241
340
|
try {
|
|
@@ -259,6 +358,7 @@ var PlayruoEmbed = ({
|
|
|
259
358
|
setHasPlayedOnce(true);
|
|
260
359
|
} catch (error) {
|
|
261
360
|
console.error("[PlayruoEmbed] Failed to start game:", error);
|
|
361
|
+
setShowGameIframe(false);
|
|
262
362
|
setErrorMessage("Failed to start game");
|
|
263
363
|
onError?.("Failed to start game");
|
|
264
364
|
}
|
|
@@ -282,7 +382,8 @@ var PlayruoEmbed = ({
|
|
|
282
382
|
}, [isReady, onReady]);
|
|
283
383
|
(0, import_react.useEffect)(() => {
|
|
284
384
|
const handleGameMessage = (event) => {
|
|
285
|
-
const
|
|
385
|
+
const message = event.data || {};
|
|
386
|
+
const { type, data } = message;
|
|
286
387
|
const iframe = iframeRef.current;
|
|
287
388
|
if (!iframe || event.source !== iframe.contentWindow) {
|
|
288
389
|
return;
|
|
@@ -303,8 +404,7 @@ var PlayruoEmbed = ({
|
|
|
303
404
|
onPurchaseRequest?.(data);
|
|
304
405
|
} else if (type === "playruo_demo_completed" && data) {
|
|
305
406
|
console.log("\u{1F537} [Embed] playruo_demo_completed received:", data);
|
|
306
|
-
|
|
307
|
-
onDemoCompleted?.(data);
|
|
407
|
+
cleanupEmbedSession({ payload: data });
|
|
308
408
|
} else if (type === "playruo_error") {
|
|
309
409
|
const errorMessage2 = typeof data === "string" ? data : data?.message || "Unknown error";
|
|
310
410
|
console.log("\u{1F537} [Embed] playruo_error received:", errorMessage2);
|
|
@@ -325,25 +425,65 @@ var PlayruoEmbed = ({
|
|
|
325
425
|
onError?.(errorMessage2);
|
|
326
426
|
} else if (type === "playruo_session_over" && data) {
|
|
327
427
|
console.log("\u{1F537} [Embed] playruo_session_over received:", data);
|
|
328
|
-
|
|
428
|
+
void exitEmbedFullscreen({ reason: "playruo_session_over" });
|
|
329
429
|
setIframeState(data);
|
|
330
430
|
onStateChange?.(data);
|
|
431
|
+
cleanupEmbedSession({ requestFullscreenExit: false });
|
|
331
432
|
} else if (type === "playruo_stream_start") {
|
|
332
433
|
console.log("\u{1F537} [Embed] playruo_stream_start received");
|
|
434
|
+
markStreamActive();
|
|
435
|
+
} else if (type === "playruo_stream_stop") {
|
|
436
|
+
console.log("\u{1F537} [Embed] playruo_stream_stop received");
|
|
437
|
+
void exitEmbedFullscreen({ reason: "playruo_stream_stop" });
|
|
438
|
+
cleanupEmbedSession({
|
|
439
|
+
markPlayed: false,
|
|
440
|
+
notifyCompletion: false,
|
|
441
|
+
requestFullscreenExit: false
|
|
442
|
+
});
|
|
443
|
+
} else if (type === "REQUEST_EXIT_FULLSCREEN") {
|
|
444
|
+
console.log("\u{1F537} [Embed] REQUEST_EXIT_FULLSCREEN received");
|
|
445
|
+
void exitEmbedFullscreen({
|
|
446
|
+
reason: "REQUEST_EXIT_FULLSCREEN",
|
|
447
|
+
suppressFullscreenExitCleanup: false
|
|
448
|
+
}).finally(postExitFullscreenAckToIframe);
|
|
449
|
+
} else if (type === "playruo_event" && data && typeof data === "object") {
|
|
450
|
+
console.log("\u{1F537} [Embed] playruo_event received:", data);
|
|
451
|
+
const eventPayload = data;
|
|
452
|
+
onEvent?.(eventPayload);
|
|
453
|
+
forwardEventToParent({ type: "playruo_event", data: eventPayload });
|
|
454
|
+
} else if (type === "playruo" && message.action === "event" && message.payload && typeof message.payload === "object") {
|
|
455
|
+
console.log("\u{1F537} [Embed] legacy playruo event received:", message.payload);
|
|
456
|
+
const eventPayload = message.payload;
|
|
457
|
+
onEvent?.(eventPayload);
|
|
458
|
+
forwardEventToParent({ type: "playruo_event", data: eventPayload });
|
|
333
459
|
}
|
|
334
460
|
if (type === "error" || type === "closeForBuy" || type === "goToStore") {
|
|
335
461
|
console.log("\u{1F537} [Embed] Legacy message received:", type);
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
462
|
+
cleanupEmbedSession({
|
|
463
|
+
payload: {
|
|
464
|
+
reason: "Demo session ended",
|
|
465
|
+
storeUrl
|
|
466
|
+
}
|
|
467
|
+
});
|
|
342
468
|
}
|
|
343
469
|
};
|
|
344
470
|
window.addEventListener("message", handleGameMessage);
|
|
345
471
|
return () => window.removeEventListener("message", handleGameMessage);
|
|
346
|
-
}, [
|
|
472
|
+
}, [
|
|
473
|
+
cleanupEmbedSession,
|
|
474
|
+
exitEmbedFullscreen,
|
|
475
|
+
forwardEventToParent,
|
|
476
|
+
hasPlayedOnce,
|
|
477
|
+
iframeRef,
|
|
478
|
+
markStreamActive,
|
|
479
|
+
onEvent,
|
|
480
|
+
onError,
|
|
481
|
+
onPurchaseRequest,
|
|
482
|
+
onReady,
|
|
483
|
+
onStateChange,
|
|
484
|
+
postExitFullscreenAckToIframe,
|
|
485
|
+
storeUrl
|
|
486
|
+
]);
|
|
347
487
|
const generateUUID = () => {
|
|
348
488
|
if (self.crypto.randomUUID) return self.crypto.randomUUID();
|
|
349
489
|
const bytes = new Uint8Array(16);
|
|
@@ -390,9 +530,8 @@ var PlayruoEmbed = ({
|
|
|
390
530
|
}, [iframeRef]);
|
|
391
531
|
(0, import_react.useEffect)(() => {
|
|
392
532
|
const handleFullscreenChange = () => {
|
|
393
|
-
const doc = document;
|
|
394
533
|
const iframe = iframeRef.current;
|
|
395
|
-
const fullscreenElement =
|
|
534
|
+
const fullscreenElement = getFullscreenElement();
|
|
396
535
|
const isEmbedFullscreen = Boolean(iframe && fullscreenElement === iframe);
|
|
397
536
|
if (isEmbedFullscreen) {
|
|
398
537
|
wasEmbedFullscreenRef.current = true;
|
|
@@ -409,30 +548,15 @@ var PlayruoEmbed = ({
|
|
|
409
548
|
return;
|
|
410
549
|
}
|
|
411
550
|
releaseEscapeKeyLock();
|
|
551
|
+
if (suppressNextFullscreenExitCleanupRef.current) {
|
|
552
|
+
suppressNextFullscreenExitCleanupRef.current = false;
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
412
555
|
if (wasEmbedFullscreenRef.current) {
|
|
413
556
|
wasEmbedFullscreenRef.current = false;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
if (iframe) {
|
|
419
|
-
try {
|
|
420
|
-
iframe.contentWindow?.postMessage({
|
|
421
|
-
type: "playruo",
|
|
422
|
-
action: "exitFullscreen",
|
|
423
|
-
fromEmbed: true,
|
|
424
|
-
isFullscreen: false,
|
|
425
|
-
parentWillHandleFullscreen: true
|
|
426
|
-
}, "*");
|
|
427
|
-
} catch {
|
|
428
|
-
console.error("[PlayruoEmbed] Failed to exit fullscreen");
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
setShowGameIframe(false);
|
|
432
|
-
setHasPlayedOnce(true);
|
|
433
|
-
onDemoCompleted?.({
|
|
434
|
-
reason: "Demo session ended",
|
|
435
|
-
storeUrl
|
|
557
|
+
cleanupEmbedSession({
|
|
558
|
+
notifyIframe: true,
|
|
559
|
+
requestFullscreenExit: false
|
|
436
560
|
});
|
|
437
561
|
}
|
|
438
562
|
};
|
|
@@ -446,33 +570,18 @@ var PlayruoEmbed = ({
|
|
|
446
570
|
document.removeEventListener("mozfullscreenchange", handleFullscreenChange);
|
|
447
571
|
document.removeEventListener("MSFullscreenChange", handleFullscreenChange);
|
|
448
572
|
};
|
|
449
|
-
}, [
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
wasEmbedPointerLockedRef.current = false;
|
|
457
|
-
console.warn("[PlayruoEmbed] Pointer lock request was rejected");
|
|
458
|
-
};
|
|
459
|
-
document.addEventListener("pointerlockchange", handlePointerLockChange);
|
|
460
|
-
document.addEventListener("pointerlockerror", handlePointerLockError);
|
|
461
|
-
return () => {
|
|
462
|
-
document.removeEventListener("pointerlockchange", handlePointerLockChange);
|
|
463
|
-
document.removeEventListener("pointerlockerror", handlePointerLockError);
|
|
464
|
-
};
|
|
465
|
-
}, [getPointerLockElement, iframeRef]);
|
|
573
|
+
}, [
|
|
574
|
+
cleanupEmbedSession,
|
|
575
|
+
getFullscreenElement,
|
|
576
|
+
iframeRef,
|
|
577
|
+
lockEscapeKey,
|
|
578
|
+
releaseEscapeKeyLock
|
|
579
|
+
]);
|
|
466
580
|
(0, import_react.useEffect)(() => {
|
|
467
581
|
return () => {
|
|
468
582
|
releaseEscapeKeyLock();
|
|
469
|
-
const iframe = iframeRef.current;
|
|
470
|
-
const isEmbedPointerLocked = Boolean(iframe && getPointerLockElement() === iframe);
|
|
471
|
-
if (wasEmbedPointerLockedRef.current || isEmbedPointerLocked) {
|
|
472
|
-
releasePointerLock();
|
|
473
|
-
}
|
|
474
583
|
};
|
|
475
|
-
}, [
|
|
584
|
+
}, [releaseEscapeKeyLock]);
|
|
476
585
|
(0, import_react.useEffect)(() => {
|
|
477
586
|
const logCrossOriginStatus = () => {
|
|
478
587
|
const isIsolated = self.crossOriginIsolated;
|
|
@@ -552,6 +661,8 @@ var PlayruoEmbed = ({
|
|
|
552
661
|
}
|
|
553
662
|
}, [isReady]);
|
|
554
663
|
const isAvailable = Boolean(isReady && isCompatible && hasIframeConfirmed);
|
|
664
|
+
const shouldDisplayGameIframe = showGameIframe;
|
|
665
|
+
const shouldShowIframeMisuseMessage = Boolean(showIframe && !showGameIframe);
|
|
555
666
|
const renderContent = () => {
|
|
556
667
|
if (!renderState) return null;
|
|
557
668
|
const canTryNow = Boolean(
|
|
@@ -581,6 +692,26 @@ var PlayruoEmbed = ({
|
|
|
581
692
|
};
|
|
582
693
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className, children: [
|
|
583
694
|
renderContent(),
|
|
695
|
+
isCompatible && shouldShowIframeMisuseMessage && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
696
|
+
"div",
|
|
697
|
+
{
|
|
698
|
+
role: "status",
|
|
699
|
+
style: {
|
|
700
|
+
alignItems: "center",
|
|
701
|
+
background: "#000",
|
|
702
|
+
color: "#fff",
|
|
703
|
+
display: "flex",
|
|
704
|
+
fontFamily: "system-ui, sans-serif",
|
|
705
|
+
fontSize: 14,
|
|
706
|
+
height: "100%",
|
|
707
|
+
justifyContent: "center",
|
|
708
|
+
padding: 24,
|
|
709
|
+
textAlign: "center",
|
|
710
|
+
width: "100%"
|
|
711
|
+
},
|
|
712
|
+
children: "This iframe is only meant to be displayed through PlayruoEmbed during an active stream."
|
|
713
|
+
}
|
|
714
|
+
),
|
|
584
715
|
isCompatible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
585
716
|
"iframe",
|
|
586
717
|
{
|
|
@@ -593,9 +724,9 @@ var PlayruoEmbed = ({
|
|
|
593
724
|
title: "Playruo",
|
|
594
725
|
referrerPolicy: "strict-origin-when-cross-origin",
|
|
595
726
|
style: {
|
|
596
|
-
//
|
|
597
|
-
opacity:
|
|
598
|
-
pointerEvents:
|
|
727
|
+
// The iframe stays mounted for readiness checks, visible only during launch/play, and hidden after terminal events.
|
|
728
|
+
opacity: shouldDisplayGameIframe ? 1 : 0,
|
|
729
|
+
pointerEvents: shouldDisplayGameIframe ? "auto" : "none",
|
|
599
730
|
width: "100%",
|
|
600
731
|
height: "100%",
|
|
601
732
|
border: 0
|
|
@@ -622,36 +753,61 @@ var PlayruoEmbed = ({
|
|
|
622
753
|
// src/react/embed-tester.tsx
|
|
623
754
|
var import_react2 = __toESM(require("react"), 1);
|
|
624
755
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
756
|
+
var createInitialEmbedState = () => ({
|
|
757
|
+
buyNow: { available: false, status: "Not ready" },
|
|
758
|
+
hasPlayedOnce: false,
|
|
759
|
+
isReady: false,
|
|
760
|
+
tryNow: { available: false, status: "Not ready" }
|
|
761
|
+
});
|
|
762
|
+
var createInitialDiagnostics = () => ({
|
|
763
|
+
chromiumBrowser: false,
|
|
764
|
+
crossOriginIsolation: false,
|
|
765
|
+
desktopBrowser: false,
|
|
766
|
+
fullscreenSupported: false,
|
|
767
|
+
gamepadSupported: false,
|
|
768
|
+
iframeAllowsFullscreen: false,
|
|
769
|
+
iframeAllowsGamepad: false,
|
|
770
|
+
iframeAllowsPointerLock: false,
|
|
771
|
+
keyboardLockSupported: false,
|
|
772
|
+
localStorageSupported: false,
|
|
773
|
+
pointerLockSupported: false,
|
|
774
|
+
secureContext: false,
|
|
775
|
+
sharedArrayBufferSupported: false,
|
|
776
|
+
topLevelContext: false,
|
|
777
|
+
webAssemblySupported: false,
|
|
778
|
+
webgl2Supported: false
|
|
779
|
+
});
|
|
625
780
|
var EmbedTester = (props = {}) => {
|
|
626
|
-
const [
|
|
627
|
-
const [
|
|
781
|
+
const [operationDraft, setOperationDraft] = (0, import_react2.useState)(props.operation ?? "iframe");
|
|
782
|
+
const [storeUrlDraft, setStoreUrlDraft] = (0, import_react2.useState)(
|
|
783
|
+
props.storeUrl ?? "https://store.steampowered.com/app/123456"
|
|
784
|
+
);
|
|
785
|
+
const [appliedOperation, setAppliedOperation] = (0, import_react2.useState)(props.operation ?? "iframe");
|
|
786
|
+
const [appliedStoreUrl, setAppliedStoreUrl] = (0, import_react2.useState)(
|
|
628
787
|
props.storeUrl ?? "https://store.steampowered.com/app/123456"
|
|
629
788
|
);
|
|
630
789
|
const [key, setKey] = (0, import_react2.useState)(0);
|
|
631
790
|
const [hasUserClicked, setHasUserClicked] = (0, import_react2.useState)(false);
|
|
632
791
|
const [showIframe, setShowIframe] = (0, import_react2.useState)(false);
|
|
633
|
-
const [embedState, setEmbedState] = (0, import_react2.useState)(
|
|
634
|
-
buyNow: { available: false, status: "Not ready" },
|
|
635
|
-
hasPlayedOnce: false,
|
|
636
|
-
isReady: false,
|
|
637
|
-
tryNow: { available: false, status: "Not ready" }
|
|
638
|
-
});
|
|
792
|
+
const [embedState, setEmbedState] = (0, import_react2.useState)(createInitialEmbedState);
|
|
639
793
|
const [eventLog, setEventLog] = (0, import_react2.useState)([]);
|
|
640
|
-
const [diagnostics, setDiagnostics] = (0, import_react2.useState)(
|
|
641
|
-
crossOriginIsolation: false,
|
|
642
|
-
gamepadSupported: false,
|
|
643
|
-
fullscreenSupported: false,
|
|
644
|
-
keyboardLockSupported: false
|
|
645
|
-
});
|
|
794
|
+
const [diagnostics, setDiagnostics] = (0, import_react2.useState)(createInitialDiagnostics);
|
|
646
795
|
const displayHost = props.baseUrl ? new URL(props.baseUrl).host : "playruo.live";
|
|
647
796
|
const enableConsoleLog = props.enableConsoleLog ?? false;
|
|
648
797
|
const hasReadyBeenCalled = (0, import_react2.useRef)(false);
|
|
798
|
+
const nextEventIdRef = (0, import_react2.useRef)(0);
|
|
649
799
|
const previousStateRef = (0, import_react2.useRef)("");
|
|
650
800
|
const iframeRef = (0, import_react2.useRef)(null);
|
|
801
|
+
const isOperationPending = operationDraft !== appliedOperation;
|
|
802
|
+
const isStoreUrlPending = storeUrlDraft !== appliedStoreUrl;
|
|
803
|
+
const hasPendingConfigChanges = isOperationPending || isStoreUrlPending;
|
|
804
|
+
const pendingChangeCount = Number(isOperationPending) + Number(isStoreUrlPending);
|
|
651
805
|
const addEvent = (0, import_react2.useCallback)(
|
|
652
806
|
(message) => {
|
|
653
807
|
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
654
|
-
|
|
808
|
+
const id = nextEventIdRef.current;
|
|
809
|
+
nextEventIdRef.current += 1;
|
|
810
|
+
setEventLog((prev) => [...prev.slice(-10), { id, message, timestamp }]);
|
|
655
811
|
if (enableConsoleLog) {
|
|
656
812
|
console.log(`[EmbedTester] ${timestamp}: ${message}`);
|
|
657
813
|
}
|
|
@@ -659,18 +815,48 @@ var EmbedTester = (props = {}) => {
|
|
|
659
815
|
[enableConsoleLog]
|
|
660
816
|
);
|
|
661
817
|
const runDiagnostics = (0, import_react2.useCallback)(() => {
|
|
818
|
+
const userAgent = navigator.userAgent || navigator.vendor || window.opera || "";
|
|
819
|
+
const isMobileDevice = /android|iPad|iPhone|iPod/i.test(userAgent);
|
|
820
|
+
const hasChrome = !!window.chrome;
|
|
821
|
+
const isChromium = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
|
|
822
|
+
const iframeAllow = iframeRef.current?.getAttribute("allow") ?? "";
|
|
823
|
+
const iframeSandbox = iframeRef.current?.getAttribute("sandbox") ?? "";
|
|
824
|
+
const canvas = document.createElement("canvas");
|
|
825
|
+
let localStorageSupported = false;
|
|
826
|
+
try {
|
|
827
|
+
const storageKey = "__playruo_embed_tester__";
|
|
828
|
+
window.localStorage.setItem(storageKey, "1");
|
|
829
|
+
window.localStorage.removeItem(storageKey);
|
|
830
|
+
localStorageSupported = true;
|
|
831
|
+
} catch {
|
|
832
|
+
localStorageSupported = false;
|
|
833
|
+
}
|
|
662
834
|
const newDiagnostics = {
|
|
835
|
+
chromiumBrowser: hasChrome || isChromium,
|
|
663
836
|
crossOriginIsolation: !!(window.crossOriginIsolated || window.crossOriginIsolated),
|
|
664
|
-
|
|
837
|
+
desktopBrowser: !isMobileDevice,
|
|
665
838
|
fullscreenSupported: !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled),
|
|
666
|
-
|
|
839
|
+
gamepadSupported: "getGamepads" in navigator,
|
|
840
|
+
iframeAllowsFullscreen: iframeAllow.includes("fullscreen"),
|
|
841
|
+
iframeAllowsGamepad: iframeAllow.includes("gamepad"),
|
|
842
|
+
iframeAllowsPointerLock: iframeSandbox.includes("allow-pointer-lock"),
|
|
843
|
+
keyboardLockSupported: "keyboard" in navigator && "lock" in navigator.keyboard,
|
|
844
|
+
localStorageSupported,
|
|
845
|
+
pointerLockSupported: "requestPointerLock" in HTMLIFrameElement.prototype || "requestPointerLock" in HTMLElement.prototype || "pointerLockElement" in document,
|
|
846
|
+
secureContext: window.isSecureContext,
|
|
847
|
+
sharedArrayBufferSupported: typeof SharedArrayBuffer !== "undefined",
|
|
848
|
+
topLevelContext: window.self === window.top,
|
|
849
|
+
webAssemblySupported: typeof WebAssembly !== "undefined",
|
|
850
|
+
webgl2Supported: !!canvas.getContext("webgl2")
|
|
667
851
|
};
|
|
668
852
|
setDiagnostics(newDiagnostics);
|
|
669
|
-
addEvent(
|
|
670
|
-
|
|
853
|
+
addEvent(
|
|
854
|
+
`\u{1F50D} Diagnostics updated - Browser: ${newDiagnostics.desktopBrowser && newDiagnostics.chromiumBrowser}, COI: ${newDiagnostics.crossOriginIsolation}, Fullscreen: ${newDiagnostics.fullscreenSupported}`
|
|
855
|
+
);
|
|
856
|
+
}, [addEvent, iframeRef]);
|
|
671
857
|
import_react2.default.useEffect(() => {
|
|
672
858
|
runDiagnostics();
|
|
673
|
-
}, [runDiagnostics]);
|
|
859
|
+
}, [key, runDiagnostics]);
|
|
674
860
|
const handleReady = (0, import_react2.useCallback)(() => {
|
|
675
861
|
if (!hasReadyBeenCalled.current) {
|
|
676
862
|
hasReadyBeenCalled.current = true;
|
|
@@ -699,284 +885,1081 @@ var EmbedTester = (props = {}) => {
|
|
|
699
885
|
console.error("Embed error:", error);
|
|
700
886
|
}
|
|
701
887
|
}, [addEvent, enableConsoleLog]);
|
|
888
|
+
const handleEvent = (0, import_react2.useCallback)((data) => {
|
|
889
|
+
const eventName = typeof data.event === "string" ? data.event : typeof data.name === "string" ? data.name : "unknown";
|
|
890
|
+
addEvent(`Event received: ${eventName}`);
|
|
891
|
+
if (enableConsoleLog) {
|
|
892
|
+
console.log("Embed event:", data);
|
|
893
|
+
}
|
|
894
|
+
}, [addEvent, enableConsoleLog]);
|
|
702
895
|
const handlePurchaseRequest = (0, import_react2.useCallback)((data) => {
|
|
703
896
|
addEvent(`\u{1F4B3} Explicit purchase request from Buy Now button`);
|
|
704
897
|
addEvent(`Opening store: ${data.storeUrl}`);
|
|
705
898
|
window.open(data.storeUrl, "_blank");
|
|
706
899
|
}, [addEvent]);
|
|
707
|
-
const
|
|
900
|
+
const resetEmbedSession = (0, import_react2.useCallback)((message) => {
|
|
901
|
+
setEmbedState(createInitialEmbedState());
|
|
708
902
|
setKey((prev) => prev + 1);
|
|
709
903
|
setHasUserClicked(false);
|
|
710
904
|
setShowIframe(false);
|
|
711
905
|
hasReadyBeenCalled.current = false;
|
|
712
906
|
previousStateRef.current = "";
|
|
713
|
-
addEvent(
|
|
907
|
+
addEvent(message);
|
|
714
908
|
}, [addEvent]);
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
909
|
+
const handleApply = (0, import_react2.useCallback)(() => {
|
|
910
|
+
if (!hasPendingConfigChanges) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
setAppliedOperation(operationDraft);
|
|
914
|
+
setAppliedStoreUrl(storeUrlDraft);
|
|
915
|
+
resetEmbedSession("Applied updated embed settings");
|
|
916
|
+
}, [hasPendingConfigChanges, operationDraft, resetEmbedSession, storeUrlDraft]);
|
|
917
|
+
const handleRestartSession = (0, import_react2.useCallback)(() => {
|
|
918
|
+
resetEmbedSession("Embed restarted with applied settings");
|
|
919
|
+
}, [resetEmbedSession]);
|
|
920
|
+
const handleResetDrafts = (0, import_react2.useCallback)(() => {
|
|
921
|
+
setOperationDraft(appliedOperation);
|
|
922
|
+
setStoreUrlDraft(appliedStoreUrl);
|
|
923
|
+
addEvent("Reverted draft changes to the applied configuration");
|
|
924
|
+
}, [addEvent, appliedOperation, appliedStoreUrl]);
|
|
925
|
+
const panelStyle = {
|
|
926
|
+
position: "relative",
|
|
927
|
+
border: "1px solid rgba(148, 163, 184, 0.18)",
|
|
928
|
+
borderRadius: "24px",
|
|
929
|
+
padding: "20px",
|
|
930
|
+
background: "linear-gradient(180deg, rgba(15, 23, 42, 0.88) 0%, rgba(7, 12, 24, 0.96) 100%)",
|
|
931
|
+
boxShadow: "0 24px 80px rgba(0, 0, 0, 0.35)",
|
|
932
|
+
backdropFilter: "blur(18px)"
|
|
933
|
+
};
|
|
934
|
+
const sectionTitleStyle = {
|
|
935
|
+
margin: 0,
|
|
936
|
+
fontSize: "18px",
|
|
937
|
+
fontWeight: 600,
|
|
938
|
+
color: "#f8fafc"
|
|
725
939
|
};
|
|
940
|
+
const labelStyle = {
|
|
941
|
+
display: "flex",
|
|
942
|
+
alignItems: "center",
|
|
943
|
+
justifyContent: "space-between",
|
|
944
|
+
gap: "12px",
|
|
945
|
+
marginBottom: "8px",
|
|
946
|
+
fontSize: "13px",
|
|
947
|
+
fontWeight: 600,
|
|
948
|
+
color: "#dbe7ff"
|
|
949
|
+
};
|
|
950
|
+
const buildIndicatorStyle = (pending) => ({
|
|
951
|
+
display: "inline-flex",
|
|
952
|
+
alignItems: "center",
|
|
953
|
+
gap: "8px",
|
|
954
|
+
padding: "4px 10px",
|
|
955
|
+
borderRadius: "999px",
|
|
956
|
+
border: pending ? "1px solid rgba(251, 191, 36, 0.28)" : "1px solid rgba(74, 222, 128, 0.22)",
|
|
957
|
+
backgroundColor: pending ? "rgba(245, 158, 11, 0.12)" : "rgba(34, 197, 94, 0.12)",
|
|
958
|
+
color: pending ? "#fbbf24" : "#86efac",
|
|
959
|
+
fontSize: "11px",
|
|
960
|
+
fontWeight: 700,
|
|
961
|
+
letterSpacing: "0.08em",
|
|
962
|
+
textTransform: "uppercase"
|
|
963
|
+
});
|
|
964
|
+
const buildIndicatorDotStyle = (pending) => ({
|
|
965
|
+
width: "8px",
|
|
966
|
+
height: "8px",
|
|
967
|
+
borderRadius: "999px",
|
|
968
|
+
backgroundColor: pending ? "#f59e0b" : "#22c55e",
|
|
969
|
+
boxShadow: pending ? "0 0 0 4px rgba(245, 158, 11, 0.12)" : "0 0 0 4px rgba(34, 197, 94, 0.12)"
|
|
970
|
+
});
|
|
971
|
+
const buildInputShellStyle = (pending) => ({
|
|
972
|
+
display: "flex",
|
|
973
|
+
alignItems: "center",
|
|
974
|
+
gap: "12px",
|
|
975
|
+
border: pending ? "1px solid rgba(245, 158, 11, 0.35)" : "1px solid rgba(148, 163, 184, 0.18)",
|
|
976
|
+
borderRadius: "16px",
|
|
977
|
+
padding: "0 14px",
|
|
978
|
+
background: pending ? "rgba(35, 23, 8, 0.72)" : "rgba(15, 23, 42, 0.7)",
|
|
979
|
+
boxShadow: pending ? "0 0 0 1px rgba(245, 158, 11, 0.08)" : "none"
|
|
980
|
+
});
|
|
726
981
|
const inputStyle = {
|
|
727
982
|
width: "100%",
|
|
728
|
-
padding: "
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
fontSize: "14px"
|
|
983
|
+
padding: "14px 0",
|
|
984
|
+
border: "none",
|
|
985
|
+
outline: "none",
|
|
986
|
+
backgroundColor: "transparent",
|
|
987
|
+
color: "#f8fafc",
|
|
988
|
+
fontSize: "15px"
|
|
735
989
|
};
|
|
736
|
-
const
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
backgroundColor: "#1a1a1a"
|
|
990
|
+
const helperTextStyle = {
|
|
991
|
+
margin: "8px 0 0 0",
|
|
992
|
+
color: "#94a3b8",
|
|
993
|
+
fontSize: "12px",
|
|
994
|
+
lineHeight: 1.5
|
|
742
995
|
};
|
|
743
|
-
const
|
|
996
|
+
const codeStyle = {
|
|
744
997
|
display: "inline-block",
|
|
745
|
-
padding: "
|
|
746
|
-
|
|
747
|
-
|
|
998
|
+
padding: "2px 8px",
|
|
999
|
+
borderRadius: "999px",
|
|
1000
|
+
backgroundColor: "rgba(148, 163, 184, 0.12)",
|
|
1001
|
+
color: "#e2e8f0",
|
|
1002
|
+
fontSize: "12px",
|
|
1003
|
+
fontFamily: '"SF Mono", "Roboto Mono", monospace',
|
|
1004
|
+
wordBreak: "break-all"
|
|
1005
|
+
};
|
|
1006
|
+
const buildButtonStyle = (variant, disabled = false) => {
|
|
1007
|
+
const palette = {
|
|
1008
|
+
ghost: {
|
|
1009
|
+
background: "rgba(15, 23, 42, 0.5)",
|
|
1010
|
+
border: "1px solid rgba(148, 163, 184, 0.18)",
|
|
1011
|
+
color: "#dbe7ff"
|
|
1012
|
+
},
|
|
1013
|
+
primary: {
|
|
1014
|
+
background: "linear-gradient(135deg, #38bdf8 0%, #2563eb 100%)",
|
|
1015
|
+
border: "1px solid rgba(125, 211, 252, 0.32)",
|
|
1016
|
+
color: "#eff6ff"
|
|
1017
|
+
},
|
|
1018
|
+
secondary: {
|
|
1019
|
+
background: "linear-gradient(135deg, rgba(30, 41, 59, 0.92) 0%, rgba(15, 23, 42, 0.98) 100%)",
|
|
1020
|
+
border: "1px solid rgba(148, 163, 184, 0.18)",
|
|
1021
|
+
color: "#e2e8f0"
|
|
1022
|
+
}
|
|
1023
|
+
}[variant];
|
|
1024
|
+
return {
|
|
1025
|
+
display: "inline-flex",
|
|
1026
|
+
alignItems: "center",
|
|
1027
|
+
justifyContent: "center",
|
|
1028
|
+
gap: "10px",
|
|
1029
|
+
minHeight: "44px",
|
|
1030
|
+
padding: "0 18px",
|
|
1031
|
+
borderRadius: "14px",
|
|
1032
|
+
background: palette.background,
|
|
1033
|
+
border: palette.border,
|
|
1034
|
+
color: palette.color,
|
|
1035
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
1036
|
+
opacity: disabled ? 0.45 : 1,
|
|
1037
|
+
fontSize: "14px",
|
|
1038
|
+
fontWeight: 700,
|
|
1039
|
+
letterSpacing: "0.01em",
|
|
1040
|
+
transition: "all 0.2s ease",
|
|
1041
|
+
boxShadow: variant === "primary" && !disabled ? "0 16px 32px rgba(37, 99, 235, 0.28)" : "none"
|
|
1042
|
+
};
|
|
1043
|
+
};
|
|
1044
|
+
const buildStatusChipStyle = (active) => ({
|
|
1045
|
+
display: "inline-flex",
|
|
1046
|
+
alignItems: "center",
|
|
1047
|
+
gap: "8px",
|
|
1048
|
+
padding: "8px 12px",
|
|
1049
|
+
borderRadius: "999px",
|
|
1050
|
+
backgroundColor: active ? "rgba(34, 197, 94, 0.12)" : "rgba(248, 113, 113, 0.12)",
|
|
1051
|
+
border: active ? "1px solid rgba(34, 197, 94, 0.22)" : "1px solid rgba(248, 113, 113, 0.22)",
|
|
1052
|
+
color: active ? "#86efac" : "#fca5a5",
|
|
748
1053
|
fontSize: "12px",
|
|
749
|
-
fontWeight:
|
|
1054
|
+
fontWeight: 700
|
|
1055
|
+
});
|
|
1056
|
+
const statusItems = [
|
|
1057
|
+
{ label: "Ready", value: Boolean(embedState.isReady) },
|
|
1058
|
+
{ label: "Played", value: Boolean(embedState.hasPlayedOnce) },
|
|
1059
|
+
{ label: "Try Now", value: Boolean(embedState.tryNow?.available) },
|
|
1060
|
+
{ label: "Buy Now", value: Boolean(embedState.buyNow?.available) }
|
|
1061
|
+
];
|
|
1062
|
+
const diagnosticGroups = [
|
|
1063
|
+
{
|
|
1064
|
+
title: "Compatibility",
|
|
1065
|
+
items: [
|
|
1066
|
+
{
|
|
1067
|
+
detail: "Playruo currently expects a non-mobile browser.",
|
|
1068
|
+
label: "Desktop browser",
|
|
1069
|
+
value: diagnostics.desktopBrowser
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
detail: "The embed flow is tuned for Chromium-based browsers.",
|
|
1073
|
+
label: "Chromium browser",
|
|
1074
|
+
value: diagnostics.chromiumBrowser
|
|
1075
|
+
},
|
|
1076
|
+
{
|
|
1077
|
+
detail: "Keyboard lock works best when the page is not itself embedded.",
|
|
1078
|
+
label: "Top-level tab",
|
|
1079
|
+
value: diagnostics.topLevelContext
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
detail: "HTTPS or localhost unlocks the best browser APIs.",
|
|
1083
|
+
label: "Secure context",
|
|
1084
|
+
value: diagnostics.secureContext
|
|
1085
|
+
}
|
|
1086
|
+
]
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
title: "Gameplay APIs",
|
|
1090
|
+
items: [
|
|
1091
|
+
{
|
|
1092
|
+
detail: "Needed for the immersive play flow.",
|
|
1093
|
+
label: "Fullscreen API",
|
|
1094
|
+
value: diagnostics.fullscreenSupported
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
detail: "Needed for raw mouse capture on the iframe.",
|
|
1098
|
+
label: "Pointer lock",
|
|
1099
|
+
value: diagnostics.pointerLockSupported
|
|
1100
|
+
},
|
|
1101
|
+
{
|
|
1102
|
+
detail: "Used to keep Escape reserved while fullscreen is active.",
|
|
1103
|
+
label: "Keyboard lock",
|
|
1104
|
+
value: diagnostics.keyboardLockSupported
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
detail: "Lets the game read connected controllers.",
|
|
1108
|
+
label: "Gamepad API",
|
|
1109
|
+
value: diagnostics.gamepadSupported
|
|
1110
|
+
}
|
|
1111
|
+
]
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
title: "Performance",
|
|
1115
|
+
items: [
|
|
1116
|
+
{
|
|
1117
|
+
detail: "Improves the overall runtime budget for the experience.",
|
|
1118
|
+
label: "Cross-origin isolated",
|
|
1119
|
+
value: diagnostics.crossOriginIsolation
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
detail: "Important for heavier threaded workloads.",
|
|
1123
|
+
label: "SharedArrayBuffer",
|
|
1124
|
+
value: diagnostics.sharedArrayBufferSupported
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
detail: "Confirms modern rendering features are reachable.",
|
|
1128
|
+
label: "WebGL2",
|
|
1129
|
+
value: diagnostics.webgl2Supported
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
detail: "Confirms the runtime can execute compiled game code paths.",
|
|
1133
|
+
label: "WebAssembly",
|
|
1134
|
+
value: diagnostics.webAssemblySupported
|
|
1135
|
+
}
|
|
1136
|
+
]
|
|
1137
|
+
},
|
|
1138
|
+
{
|
|
1139
|
+
title: "Embed wiring",
|
|
1140
|
+
items: [
|
|
1141
|
+
{
|
|
1142
|
+
detail: "The iframe allow list includes fullscreen access.",
|
|
1143
|
+
label: "Iframe fullscreen allow",
|
|
1144
|
+
value: diagnostics.iframeAllowsFullscreen
|
|
1145
|
+
},
|
|
1146
|
+
{
|
|
1147
|
+
detail: "The iframe allow list includes gamepad access.",
|
|
1148
|
+
label: "Iframe gamepad allow",
|
|
1149
|
+
value: diagnostics.iframeAllowsGamepad
|
|
1150
|
+
},
|
|
1151
|
+
{
|
|
1152
|
+
detail: "The iframe sandbox includes pointer-lock permission.",
|
|
1153
|
+
label: "Iframe pointer-lock allow",
|
|
1154
|
+
value: diagnostics.iframeAllowsPointerLock
|
|
1155
|
+
},
|
|
1156
|
+
{
|
|
1157
|
+
detail: "Needed for UUID persistence and session continuity.",
|
|
1158
|
+
label: "Local storage",
|
|
1159
|
+
value: diagnostics.localStorageSupported
|
|
1160
|
+
}
|
|
1161
|
+
]
|
|
1162
|
+
}
|
|
1163
|
+
];
|
|
1164
|
+
const criticalDiagnosticChecks = [
|
|
1165
|
+
{ label: "Desktop browser", value: diagnostics.desktopBrowser },
|
|
1166
|
+
{ label: "Chromium browser", value: diagnostics.chromiumBrowser },
|
|
1167
|
+
{ label: "Fullscreen API", value: diagnostics.fullscreenSupported },
|
|
1168
|
+
{ label: "Pointer lock", value: diagnostics.pointerLockSupported }
|
|
1169
|
+
];
|
|
1170
|
+
const warningDiagnosticChecks = [
|
|
1171
|
+
{ label: "Top-level tab", value: diagnostics.topLevelContext },
|
|
1172
|
+
{ label: "Secure context", value: diagnostics.secureContext },
|
|
1173
|
+
{ label: "Cross-origin isolation", value: diagnostics.crossOriginIsolation },
|
|
1174
|
+
{ label: "SharedArrayBuffer", value: diagnostics.sharedArrayBufferSupported },
|
|
1175
|
+
{ label: "Keyboard lock", value: diagnostics.keyboardLockSupported },
|
|
1176
|
+
{ label: "Gamepad API", value: diagnostics.gamepadSupported },
|
|
1177
|
+
{ label: "WebGL2", value: diagnostics.webgl2Supported }
|
|
1178
|
+
];
|
|
1179
|
+
const blockingDiagnostics = criticalDiagnosticChecks.filter((item) => !item.value);
|
|
1180
|
+
const advisoryDiagnostics = warningDiagnosticChecks.filter((item) => !item.value);
|
|
1181
|
+
const diagnosticsVerdict = blockingDiagnostics.length > 0 ? {
|
|
1182
|
+
label: "Blocked",
|
|
1183
|
+
tone: "#fca5a5",
|
|
1184
|
+
background: "rgba(127, 29, 29, 0.28)",
|
|
1185
|
+
border: "1px solid rgba(248, 113, 113, 0.24)",
|
|
1186
|
+
text: "A core requirement is missing for the intended embed flow."
|
|
1187
|
+
} : advisoryDiagnostics.length > 0 ? {
|
|
1188
|
+
label: "Limited",
|
|
1189
|
+
tone: "#fde68a",
|
|
1190
|
+
background: "rgba(120, 53, 15, 0.24)",
|
|
1191
|
+
border: "1px solid rgba(245, 158, 11, 0.22)",
|
|
1192
|
+
text: "The embed should run, but some features or performance may be reduced."
|
|
1193
|
+
} : {
|
|
1194
|
+
label: "Ready",
|
|
1195
|
+
tone: "#86efac",
|
|
1196
|
+
background: "rgba(20, 83, 45, 0.24)",
|
|
1197
|
+
border: "1px solid rgba(34, 197, 94, 0.22)",
|
|
1198
|
+
text: "All key browser, performance, and iframe capabilities are present."
|
|
750
1199
|
};
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
1200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1201
|
+
"div",
|
|
1202
|
+
{
|
|
1203
|
+
className: props.className,
|
|
1204
|
+
style: {
|
|
1205
|
+
position: "relative",
|
|
1206
|
+
minHeight: "100vh",
|
|
1207
|
+
overflow: "hidden",
|
|
1208
|
+
padding: "32px 20px 48px",
|
|
1209
|
+
background: "radial-gradient(circle at top left, rgba(56, 189, 248, 0.18) 0%, rgba(2, 6, 23, 0) 34%), radial-gradient(circle at 85% 10%, rgba(37, 99, 235, 0.18) 0%, rgba(2, 6, 23, 0) 26%), linear-gradient(180deg, #020617 0%, #050816 48%, #020617 100%)",
|
|
1210
|
+
color: "#e5e7eb"
|
|
1211
|
+
},
|
|
1212
|
+
children: [
|
|
1213
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1214
|
+
"div",
|
|
1215
|
+
{
|
|
1216
|
+
style: {
|
|
1217
|
+
position: "absolute",
|
|
1218
|
+
inset: 0,
|
|
1219
|
+
overflow: "hidden",
|
|
1220
|
+
pointerEvents: "none"
|
|
1221
|
+
},
|
|
1222
|
+
children: [
|
|
1223
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1224
|
+
"div",
|
|
1225
|
+
{
|
|
1226
|
+
style: {
|
|
1227
|
+
position: "absolute",
|
|
1228
|
+
top: "-120px",
|
|
1229
|
+
left: "-120px",
|
|
1230
|
+
width: "320px",
|
|
1231
|
+
height: "320px",
|
|
1232
|
+
borderRadius: "999px",
|
|
1233
|
+
background: "rgba(56, 189, 248, 0.12)",
|
|
1234
|
+
filter: "blur(60px)"
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
),
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1239
|
+
"div",
|
|
1240
|
+
{
|
|
1241
|
+
style: {
|
|
1242
|
+
position: "absolute",
|
|
1243
|
+
right: "-80px",
|
|
1244
|
+
top: "120px",
|
|
1245
|
+
width: "280px",
|
|
1246
|
+
height: "280px",
|
|
1247
|
+
borderRadius: "999px",
|
|
1248
|
+
background: "rgba(37, 99, 235, 0.12)",
|
|
1249
|
+
filter: "blur(60px)"
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
)
|
|
1253
|
+
]
|
|
1254
|
+
}
|
|
1255
|
+
),
|
|
1256
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { position: "relative", maxWidth: "1280px", margin: "0 auto" }, children: [
|
|
783
1257
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
784
|
-
"
|
|
1258
|
+
"div",
|
|
785
1259
|
{
|
|
786
|
-
type: "button",
|
|
787
1260
|
style: {
|
|
788
|
-
...
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
fontWeight: "600"
|
|
1261
|
+
...panelStyle,
|
|
1262
|
+
marginBottom: "24px",
|
|
1263
|
+
padding: "28px",
|
|
1264
|
+
background: "linear-gradient(135deg, rgba(15, 23, 42, 0.92) 0%, rgba(8, 15, 30, 0.98) 55%, rgba(15, 23, 42, 0.92) 100%)"
|
|
793
1265
|
},
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
1266
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1267
|
+
"div",
|
|
1268
|
+
{
|
|
1269
|
+
style: {
|
|
1270
|
+
display: "flex",
|
|
1271
|
+
flexWrap: "wrap",
|
|
1272
|
+
gap: "20px",
|
|
1273
|
+
justifyContent: "space-between",
|
|
1274
|
+
alignItems: "flex-start"
|
|
1275
|
+
},
|
|
1276
|
+
children: [
|
|
1277
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { maxWidth: "720px" }, children: [
|
|
1278
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1279
|
+
"div",
|
|
1280
|
+
{
|
|
1281
|
+
style: {
|
|
1282
|
+
display: "inline-flex",
|
|
1283
|
+
alignItems: "center",
|
|
1284
|
+
gap: "10px",
|
|
1285
|
+
padding: "6px 12px",
|
|
1286
|
+
borderRadius: "999px",
|
|
1287
|
+
backgroundColor: "rgba(56, 189, 248, 0.12)",
|
|
1288
|
+
border: "1px solid rgba(125, 211, 252, 0.18)",
|
|
1289
|
+
color: "#7dd3fc",
|
|
1290
|
+
fontSize: "11px",
|
|
1291
|
+
fontWeight: 700,
|
|
1292
|
+
letterSpacing: "0.12em",
|
|
1293
|
+
textTransform: "uppercase"
|
|
1294
|
+
},
|
|
1295
|
+
children: "\u{1F9EA} Playruo QA Surface"
|
|
1296
|
+
}
|
|
1297
|
+
),
|
|
1298
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1299
|
+
"h1",
|
|
1300
|
+
{
|
|
1301
|
+
style: {
|
|
1302
|
+
margin: "16px 0 12px 0",
|
|
1303
|
+
fontSize: "clamp(32px, 4vw, 46px)",
|
|
1304
|
+
lineHeight: 1.05,
|
|
1305
|
+
letterSpacing: "-0.04em",
|
|
1306
|
+
color: "#f8fafc"
|
|
1307
|
+
},
|
|
1308
|
+
children: "Embed Tester"
|
|
1309
|
+
}
|
|
1310
|
+
),
|
|
1311
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1312
|
+
"p",
|
|
1313
|
+
{
|
|
1314
|
+
style: {
|
|
1315
|
+
margin: 0,
|
|
1316
|
+
maxWidth: "640px",
|
|
1317
|
+
color: "#94a3b8",
|
|
1318
|
+
fontSize: "16px",
|
|
1319
|
+
lineHeight: 1.7
|
|
1320
|
+
},
|
|
1321
|
+
children: "Edit configuration safely, apply changes only when you decide to, and keep runtime feedback visible without the UI fighting your typing."
|
|
1322
|
+
}
|
|
1323
|
+
)
|
|
1324
|
+
] }),
|
|
1325
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1326
|
+
"div",
|
|
1327
|
+
{
|
|
1328
|
+
style: {
|
|
1329
|
+
display: "grid",
|
|
1330
|
+
gap: "12px",
|
|
1331
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))",
|
|
1332
|
+
flex: "1 1 320px"
|
|
1333
|
+
},
|
|
1334
|
+
children: [
|
|
1335
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1336
|
+
"div",
|
|
1337
|
+
{
|
|
1338
|
+
style: {
|
|
1339
|
+
padding: "16px",
|
|
1340
|
+
borderRadius: "18px",
|
|
1341
|
+
backgroundColor: "rgba(15, 23, 42, 0.72)",
|
|
1342
|
+
border: "1px solid rgba(148, 163, 184, 0.14)"
|
|
1343
|
+
},
|
|
1344
|
+
children: [
|
|
1345
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: "12px", color: "#94a3b8", marginBottom: "8px" }, children: "Active host" }),
|
|
1346
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#f8fafc", fontSize: "16px", fontWeight: 700 }, children: displayHost })
|
|
1347
|
+
]
|
|
1348
|
+
}
|
|
1349
|
+
),
|
|
1350
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1351
|
+
"div",
|
|
1352
|
+
{
|
|
1353
|
+
style: {
|
|
1354
|
+
padding: "16px",
|
|
1355
|
+
borderRadius: "18px",
|
|
1356
|
+
backgroundColor: hasPendingConfigChanges ? "rgba(35, 23, 8, 0.72)" : "rgba(15, 23, 42, 0.72)",
|
|
1357
|
+
border: hasPendingConfigChanges ? "1px solid rgba(245, 158, 11, 0.24)" : "1px solid rgba(148, 163, 184, 0.14)"
|
|
1358
|
+
},
|
|
1359
|
+
children: [
|
|
1360
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: "12px", color: "#94a3b8", marginBottom: "8px" }, children: "Config state" }),
|
|
1361
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1362
|
+
"div",
|
|
1363
|
+
{
|
|
1364
|
+
style: {
|
|
1365
|
+
display: "flex",
|
|
1366
|
+
alignItems: "center",
|
|
1367
|
+
gap: "10px",
|
|
1368
|
+
color: hasPendingConfigChanges ? "#fbbf24" : "#86efac",
|
|
1369
|
+
fontSize: "16px",
|
|
1370
|
+
fontWeight: 700
|
|
1371
|
+
},
|
|
1372
|
+
children: [
|
|
1373
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: buildIndicatorDotStyle(hasPendingConfigChanges) }),
|
|
1374
|
+
hasPendingConfigChanges ? `${pendingChangeCount} pending change(s)` : "Everything applied"
|
|
1375
|
+
]
|
|
1376
|
+
}
|
|
1377
|
+
)
|
|
1378
|
+
]
|
|
1379
|
+
}
|
|
1380
|
+
)
|
|
1381
|
+
]
|
|
1382
|
+
}
|
|
1383
|
+
)
|
|
1384
|
+
]
|
|
1385
|
+
}
|
|
1386
|
+
)
|
|
798
1387
|
}
|
|
799
|
-
)
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
1388
|
+
),
|
|
1389
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "24px", alignItems: "flex-start" }, children: [
|
|
1390
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: "1 1 380px", minWidth: "320px" }, children: [
|
|
1391
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { ...panelStyle, marginBottom: "18px" }, children: [
|
|
1392
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1393
|
+
"div",
|
|
1394
|
+
{
|
|
1395
|
+
style: {
|
|
1396
|
+
display: "flex",
|
|
1397
|
+
flexWrap: "wrap",
|
|
1398
|
+
justifyContent: "space-between",
|
|
1399
|
+
gap: "12px",
|
|
1400
|
+
marginBottom: "18px"
|
|
1401
|
+
},
|
|
1402
|
+
children: [
|
|
1403
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
1404
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: sectionTitleStyle, children: "Configuration" }),
|
|
1405
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { style: { ...helperTextStyle, marginTop: "6px" }, children: [
|
|
1406
|
+
"Draft values stay local until you press ",
|
|
1407
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { style: { color: "#e2e8f0" }, children: "Apply" }),
|
|
1408
|
+
"."
|
|
1409
|
+
] })
|
|
1410
|
+
] }),
|
|
1411
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: buildIndicatorStyle(hasPendingConfigChanges), children: [
|
|
1412
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: buildIndicatorDotStyle(hasPendingConfigChanges) }),
|
|
1413
|
+
hasPendingConfigChanges ? "Not applied" : "Applied"
|
|
1414
|
+
] })
|
|
1415
|
+
]
|
|
1416
|
+
}
|
|
1417
|
+
),
|
|
1418
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "grid", gap: "16px" }, children: [
|
|
1419
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
1420
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { htmlFor: "operation", style: labelStyle, children: [
|
|
1421
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Operation" }),
|
|
1422
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: buildIndicatorStyle(isOperationPending), children: [
|
|
1423
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: buildIndicatorDotStyle(isOperationPending) }),
|
|
1424
|
+
isOperationPending ? "Pending" : "Live"
|
|
1425
|
+
] })
|
|
1426
|
+
] }),
|
|
1427
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: buildInputShellStyle(isOperationPending), children: [
|
|
1428
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1429
|
+
"input",
|
|
1430
|
+
{
|
|
1431
|
+
id: "operation",
|
|
1432
|
+
style: inputStyle,
|
|
1433
|
+
onChange: (e) => setOperationDraft(e.target.value),
|
|
1434
|
+
placeholder: "e.g. iframe",
|
|
1435
|
+
value: operationDraft
|
|
1436
|
+
}
|
|
1437
|
+
),
|
|
1438
|
+
isOperationPending && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1439
|
+
"span",
|
|
1440
|
+
{
|
|
1441
|
+
"aria-hidden": "true",
|
|
1442
|
+
style: {
|
|
1443
|
+
fontSize: "16px",
|
|
1444
|
+
color: "#fbbf24",
|
|
1445
|
+
fontWeight: 700
|
|
1446
|
+
},
|
|
1447
|
+
children: "!"
|
|
1448
|
+
}
|
|
1449
|
+
)
|
|
1450
|
+
] }),
|
|
1451
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { style: helperTextStyle, children: [
|
|
1452
|
+
"Applied value: ",
|
|
1453
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { style: codeStyle, children: appliedOperation })
|
|
1454
|
+
] })
|
|
1455
|
+
] }),
|
|
1456
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
1457
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { htmlFor: "storeUrl", style: labelStyle, children: [
|
|
1458
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Store URL" }),
|
|
1459
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: buildIndicatorStyle(isStoreUrlPending), children: [
|
|
1460
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: buildIndicatorDotStyle(isStoreUrlPending) }),
|
|
1461
|
+
isStoreUrlPending ? "Pending" : "Live"
|
|
1462
|
+
] })
|
|
1463
|
+
] }),
|
|
1464
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: buildInputShellStyle(isStoreUrlPending), children: [
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1466
|
+
"input",
|
|
1467
|
+
{
|
|
1468
|
+
id: "storeUrl",
|
|
1469
|
+
style: inputStyle,
|
|
1470
|
+
onChange: (e) => setStoreUrlDraft(e.target.value),
|
|
1471
|
+
placeholder: "https://store.example.com",
|
|
1472
|
+
value: storeUrlDraft
|
|
1473
|
+
}
|
|
1474
|
+
),
|
|
1475
|
+
isStoreUrlPending && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1476
|
+
"span",
|
|
1477
|
+
{
|
|
1478
|
+
"aria-hidden": "true",
|
|
1479
|
+
style: {
|
|
1480
|
+
fontSize: "16px",
|
|
1481
|
+
color: "#fbbf24",
|
|
1482
|
+
fontWeight: 700
|
|
1483
|
+
},
|
|
1484
|
+
children: "!"
|
|
1485
|
+
}
|
|
1486
|
+
)
|
|
1487
|
+
] }),
|
|
1488
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { style: helperTextStyle, children: [
|
|
1489
|
+
"Applied value: ",
|
|
1490
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { style: codeStyle, children: appliedStoreUrl })
|
|
1491
|
+
] })
|
|
1492
|
+
] })
|
|
1493
|
+
] }),
|
|
1494
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1495
|
+
"div",
|
|
1496
|
+
{
|
|
1497
|
+
style: {
|
|
1498
|
+
display: "flex",
|
|
1499
|
+
flexWrap: "wrap",
|
|
1500
|
+
gap: "12px",
|
|
1501
|
+
marginTop: "20px"
|
|
1502
|
+
},
|
|
1503
|
+
children: [
|
|
1504
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1505
|
+
"button",
|
|
1506
|
+
{
|
|
1507
|
+
type: "button",
|
|
1508
|
+
style: buildButtonStyle("primary", !hasPendingConfigChanges),
|
|
1509
|
+
disabled: !hasPendingConfigChanges,
|
|
1510
|
+
onClick: handleApply,
|
|
1511
|
+
children: "Apply"
|
|
1512
|
+
}
|
|
1513
|
+
),
|
|
1514
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1515
|
+
"button",
|
|
1516
|
+
{
|
|
1517
|
+
type: "button",
|
|
1518
|
+
style: buildButtonStyle("secondary"),
|
|
1519
|
+
onClick: handleRestartSession,
|
|
1520
|
+
children: "Restart Session"
|
|
1521
|
+
}
|
|
1522
|
+
),
|
|
1523
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1524
|
+
"button",
|
|
1525
|
+
{
|
|
1526
|
+
type: "button",
|
|
1527
|
+
style: buildButtonStyle("ghost", !hasPendingConfigChanges),
|
|
1528
|
+
disabled: !hasPendingConfigChanges,
|
|
1529
|
+
onClick: handleResetDrafts,
|
|
1530
|
+
children: "Reset Drafts"
|
|
1531
|
+
}
|
|
1532
|
+
)
|
|
1533
|
+
]
|
|
1534
|
+
}
|
|
1535
|
+
)
|
|
1536
|
+
] }),
|
|
1537
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { ...panelStyle, marginBottom: "18px" }, children: [
|
|
1538
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: sectionTitleStyle, children: "Runtime status" }),
|
|
1539
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "10px", marginTop: "16px" }, children: statusItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: buildStatusChipStyle(item.value), children: [
|
|
1540
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: item.value ? "\u25CF" : "\u25CB" }),
|
|
1541
|
+
item.label
|
|
1542
|
+
] }, item.label)) }),
|
|
1543
|
+
!embedState.tryNow?.available && embedState.tryNow?.status && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { style: { ...helperTextStyle, marginTop: "14px" }, children: [
|
|
1544
|
+
"Try Now reason: ",
|
|
1545
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#cbd5e1" }, children: embedState.tryNow.status })
|
|
1546
|
+
] })
|
|
909
1547
|
] }),
|
|
910
|
-
|
|
1548
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { ...panelStyle, marginBottom: "18px" }, children: [
|
|
1549
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: sectionTitleStyle, children: "Browser diagnostics" }),
|
|
1550
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1551
|
+
"div",
|
|
1552
|
+
{
|
|
1553
|
+
style: {
|
|
1554
|
+
marginTop: "16px",
|
|
1555
|
+
padding: "16px 18px",
|
|
1556
|
+
borderRadius: "20px",
|
|
1557
|
+
background: diagnosticsVerdict.background,
|
|
1558
|
+
border: diagnosticsVerdict.border
|
|
1559
|
+
},
|
|
1560
|
+
children: [
|
|
1561
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1562
|
+
"div",
|
|
1563
|
+
{
|
|
1564
|
+
style: {
|
|
1565
|
+
display: "flex",
|
|
1566
|
+
flexWrap: "wrap",
|
|
1567
|
+
justifyContent: "space-between",
|
|
1568
|
+
gap: "12px",
|
|
1569
|
+
alignItems: "center"
|
|
1570
|
+
},
|
|
1571
|
+
children: [
|
|
1572
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
1573
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1574
|
+
"div",
|
|
1575
|
+
{
|
|
1576
|
+
style: {
|
|
1577
|
+
color: diagnosticsVerdict.tone,
|
|
1578
|
+
fontSize: "12px",
|
|
1579
|
+
fontWeight: 700,
|
|
1580
|
+
letterSpacing: "0.1em",
|
|
1581
|
+
textTransform: "uppercase"
|
|
1582
|
+
},
|
|
1583
|
+
children: "Diagnostics verdict"
|
|
1584
|
+
}
|
|
1585
|
+
),
|
|
1586
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#f8fafc", fontSize: "20px", fontWeight: 700, marginTop: "6px" }, children: diagnosticsVerdict.label })
|
|
1587
|
+
] }),
|
|
1588
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#cbd5e1", fontSize: "13px", maxWidth: "420px", lineHeight: 1.6 }, children: diagnosticsVerdict.text })
|
|
1589
|
+
]
|
|
1590
|
+
}
|
|
1591
|
+
),
|
|
1592
|
+
(blockingDiagnostics.length > 0 || advisoryDiagnostics.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1593
|
+
"div",
|
|
1594
|
+
{
|
|
1595
|
+
style: {
|
|
1596
|
+
display: "grid",
|
|
1597
|
+
gap: "10px",
|
|
1598
|
+
marginTop: "16px"
|
|
1599
|
+
},
|
|
1600
|
+
children: [
|
|
1601
|
+
blockingDiagnostics.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { color: "#fca5a5", fontSize: "13px", lineHeight: 1.6 }, children: [
|
|
1602
|
+
"Blocking: ",
|
|
1603
|
+
blockingDiagnostics.map((item) => item.label).join(", ")
|
|
1604
|
+
] }),
|
|
1605
|
+
advisoryDiagnostics.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { color: "#fde68a", fontSize: "13px", lineHeight: 1.6 }, children: [
|
|
1606
|
+
"Worth checking: ",
|
|
1607
|
+
advisoryDiagnostics.map((item) => item.label).join(", ")
|
|
1608
|
+
] })
|
|
1609
|
+
]
|
|
1610
|
+
}
|
|
1611
|
+
)
|
|
1612
|
+
]
|
|
1613
|
+
}
|
|
1614
|
+
),
|
|
1615
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1616
|
+
"div",
|
|
1617
|
+
{
|
|
1618
|
+
style: {
|
|
1619
|
+
display: "grid",
|
|
1620
|
+
gap: "14px",
|
|
1621
|
+
marginTop: "18px"
|
|
1622
|
+
},
|
|
1623
|
+
children: diagnosticGroups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1624
|
+
"div",
|
|
1625
|
+
{
|
|
1626
|
+
style: {
|
|
1627
|
+
padding: "16px",
|
|
1628
|
+
borderRadius: "20px",
|
|
1629
|
+
backgroundColor: "rgba(15, 23, 42, 0.42)",
|
|
1630
|
+
border: "1px solid rgba(148, 163, 184, 0.12)"
|
|
1631
|
+
},
|
|
1632
|
+
children: [
|
|
1633
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1634
|
+
"div",
|
|
1635
|
+
{
|
|
1636
|
+
style: {
|
|
1637
|
+
color: "#e2e8f0",
|
|
1638
|
+
fontSize: "14px",
|
|
1639
|
+
fontWeight: 700,
|
|
1640
|
+
marginBottom: "14px"
|
|
1641
|
+
},
|
|
1642
|
+
children: group.title
|
|
1643
|
+
}
|
|
1644
|
+
),
|
|
1645
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1646
|
+
"div",
|
|
1647
|
+
{
|
|
1648
|
+
style: {
|
|
1649
|
+
display: "grid",
|
|
1650
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(190px, 1fr))",
|
|
1651
|
+
gap: "12px"
|
|
1652
|
+
},
|
|
1653
|
+
children: group.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1654
|
+
"div",
|
|
1655
|
+
{
|
|
1656
|
+
style: {
|
|
1657
|
+
padding: "14px 16px",
|
|
1658
|
+
borderRadius: "18px",
|
|
1659
|
+
backgroundColor: item.value ? "rgba(8, 31, 17, 0.72)" : "rgba(42, 12, 12, 0.52)",
|
|
1660
|
+
border: item.value ? "1px solid rgba(34, 197, 94, 0.18)" : "1px solid rgba(248, 113, 113, 0.18)"
|
|
1661
|
+
},
|
|
1662
|
+
children: [
|
|
1663
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#94a3b8", fontSize: "12px", marginBottom: "8px" }, children: item.label }),
|
|
1664
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1665
|
+
"div",
|
|
1666
|
+
{
|
|
1667
|
+
style: {
|
|
1668
|
+
display: "flex",
|
|
1669
|
+
alignItems: "center",
|
|
1670
|
+
gap: "8px",
|
|
1671
|
+
color: item.value ? "#86efac" : "#fca5a5",
|
|
1672
|
+
fontWeight: 700
|
|
1673
|
+
},
|
|
1674
|
+
children: [
|
|
1675
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: item.value ? "\u2713" : "\u2715" }),
|
|
1676
|
+
item.value ? "Available" : "Missing"
|
|
1677
|
+
]
|
|
1678
|
+
}
|
|
1679
|
+
),
|
|
1680
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#94a3b8", fontSize: "12px", lineHeight: 1.5, marginTop: "10px" }, children: item.detail })
|
|
1681
|
+
]
|
|
1682
|
+
},
|
|
1683
|
+
item.label
|
|
1684
|
+
))
|
|
1685
|
+
}
|
|
1686
|
+
)
|
|
1687
|
+
]
|
|
1688
|
+
},
|
|
1689
|
+
group.title
|
|
1690
|
+
))
|
|
1691
|
+
}
|
|
1692
|
+
)
|
|
1693
|
+
] }),
|
|
1694
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: panelStyle, children: [
|
|
1695
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1696
|
+
"div",
|
|
1697
|
+
{
|
|
1698
|
+
style: {
|
|
1699
|
+
display: "flex",
|
|
1700
|
+
justifyContent: "space-between",
|
|
1701
|
+
alignItems: "center",
|
|
1702
|
+
gap: "12px",
|
|
1703
|
+
marginBottom: "16px"
|
|
1704
|
+
},
|
|
1705
|
+
children: [
|
|
1706
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: sectionTitleStyle, children: "Event log" }),
|
|
1707
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { ...codeStyle, padding: "4px 10px" }, children: [
|
|
1708
|
+
eventLog.length,
|
|
1709
|
+
" recent events"
|
|
1710
|
+
] })
|
|
1711
|
+
]
|
|
1712
|
+
}
|
|
1713
|
+
),
|
|
1714
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1715
|
+
"div",
|
|
1716
|
+
{
|
|
1717
|
+
style: {
|
|
1718
|
+
background: "linear-gradient(180deg, rgba(2, 6, 23, 0.88) 0%, rgba(2, 6, 23, 0.64) 100%)",
|
|
1719
|
+
padding: "14px",
|
|
1720
|
+
borderRadius: "18px",
|
|
1721
|
+
minHeight: "220px",
|
|
1722
|
+
height: "min(46vh, 420px)",
|
|
1723
|
+
overflowY: "auto",
|
|
1724
|
+
fontFamily: '"SF Mono", "Roboto Mono", monospace',
|
|
1725
|
+
fontSize: "12px",
|
|
1726
|
+
border: "1px solid rgba(148, 163, 184, 0.12)"
|
|
1727
|
+
},
|
|
1728
|
+
children: eventLog.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "grid", gap: "10px" }, children: eventLog.map((event) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1729
|
+
"div",
|
|
1730
|
+
{
|
|
1731
|
+
style: {
|
|
1732
|
+
paddingBottom: "10px",
|
|
1733
|
+
borderBottom: "1px solid rgba(148, 163, 184, 0.08)"
|
|
1734
|
+
},
|
|
1735
|
+
children: [
|
|
1736
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#64748b", marginBottom: "4px" }, children: event.timestamp }),
|
|
1737
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#e2e8f0", lineHeight: 1.6 }, children: event.message })
|
|
1738
|
+
]
|
|
1739
|
+
},
|
|
1740
|
+
event.id
|
|
1741
|
+
)) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#64748b" }, children: "No events yet. Start a session or apply a config change." })
|
|
1742
|
+
}
|
|
1743
|
+
)
|
|
1744
|
+
] })
|
|
1745
|
+
] }),
|
|
1746
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { flex: "1 1 560px", minWidth: "320px" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { ...panelStyle, padding: "24px" }, children: [
|
|
911
1747
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
912
|
-
"
|
|
1748
|
+
"div",
|
|
913
1749
|
{
|
|
914
|
-
type: "button",
|
|
915
1750
|
style: {
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
fontWeight: "600",
|
|
923
|
-
cursor: actions.canTryNow ? "pointer" : "not-allowed",
|
|
924
|
-
opacity: actions.canTryNow ? 1 : 0.5
|
|
925
|
-
},
|
|
926
|
-
disabled: !actions.canTryNow,
|
|
927
|
-
onMouseEnter: (e) => {
|
|
928
|
-
if (actions.canTryNow) {
|
|
929
|
-
e.currentTarget.style.backgroundColor = "#15803d";
|
|
930
|
-
}
|
|
931
|
-
},
|
|
932
|
-
onMouseLeave: (e) => {
|
|
933
|
-
if (actions.canTryNow) {
|
|
934
|
-
e.currentTarget.style.backgroundColor = "#16a34a";
|
|
935
|
-
}
|
|
936
|
-
},
|
|
937
|
-
onClick: () => {
|
|
938
|
-
setHasUserClicked(true);
|
|
939
|
-
setShowIframe(true);
|
|
940
|
-
addEvent(embedState.hasPlayedOnce ? "User clicked - Resuming game" : "User clicked - Starting game with tryNow");
|
|
941
|
-
actions.tryNow();
|
|
1751
|
+
display: "flex",
|
|
1752
|
+
flexWrap: "wrap",
|
|
1753
|
+
justifyContent: "space-between",
|
|
1754
|
+
alignItems: "center",
|
|
1755
|
+
gap: "12px",
|
|
1756
|
+
marginBottom: "16px"
|
|
942
1757
|
},
|
|
943
1758
|
children: [
|
|
944
|
-
"
|
|
945
|
-
|
|
1759
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
1760
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: sectionTitleStyle, children: "Embed preview" }),
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { ...helperTextStyle, marginTop: "6px" }, children: "The live iframe always reflects the applied configuration." })
|
|
1762
|
+
] }),
|
|
1763
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "10px" }, children: [
|
|
1764
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { ...codeStyle, padding: "6px 10px" }, children: [
|
|
1765
|
+
"Host: ",
|
|
1766
|
+
displayHost
|
|
1767
|
+
] }),
|
|
1768
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { ...codeStyle, padding: "6px 10px" }, children: [
|
|
1769
|
+
"Operation: ",
|
|
1770
|
+
appliedOperation
|
|
1771
|
+
] })
|
|
1772
|
+
] })
|
|
946
1773
|
]
|
|
947
1774
|
}
|
|
948
1775
|
),
|
|
949
|
-
|
|
950
|
-
"
|
|
1776
|
+
hasPendingConfigChanges && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1777
|
+
"div",
|
|
951
1778
|
{
|
|
952
|
-
type: "button",
|
|
953
1779
|
style: {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1780
|
+
display: "flex",
|
|
1781
|
+
alignItems: "center",
|
|
1782
|
+
gap: "12px",
|
|
1783
|
+
padding: "14px 16px",
|
|
1784
|
+
marginBottom: "16px",
|
|
1785
|
+
borderRadius: "18px",
|
|
1786
|
+
backgroundColor: "rgba(35, 23, 8, 0.72)",
|
|
1787
|
+
border: "1px solid rgba(245, 158, 11, 0.22)",
|
|
1788
|
+
color: "#fde68a"
|
|
961
1789
|
},
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1790
|
+
children: [
|
|
1791
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: buildIndicatorDotStyle(true) }),
|
|
1792
|
+
"Draft values are ready but not applied to the iframe yet."
|
|
1793
|
+
]
|
|
1794
|
+
}
|
|
1795
|
+
),
|
|
1796
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1797
|
+
"div",
|
|
1798
|
+
{
|
|
1799
|
+
style: {
|
|
1800
|
+
position: "relative",
|
|
1801
|
+
minHeight: "640px",
|
|
1802
|
+
overflow: "hidden",
|
|
1803
|
+
borderRadius: "24px",
|
|
1804
|
+
border: "1px solid rgba(148, 163, 184, 0.14)",
|
|
1805
|
+
background: "linear-gradient(180deg, rgba(3, 7, 18, 0.86) 0%, rgba(2, 6, 23, 1) 100%)",
|
|
1806
|
+
boxShadow: "inset 0 1px 0 rgba(255, 255, 255, 0.04)"
|
|
967
1807
|
},
|
|
968
|
-
children:
|
|
1808
|
+
children: [
|
|
1809
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1810
|
+
"div",
|
|
1811
|
+
{
|
|
1812
|
+
style: {
|
|
1813
|
+
display: "flex",
|
|
1814
|
+
alignItems: "center",
|
|
1815
|
+
justifyContent: "space-between",
|
|
1816
|
+
gap: "12px",
|
|
1817
|
+
padding: "14px 18px",
|
|
1818
|
+
borderBottom: "1px solid rgba(148, 163, 184, 0.08)",
|
|
1819
|
+
backgroundColor: "rgba(15, 23, 42, 0.52)"
|
|
1820
|
+
},
|
|
1821
|
+
children: [
|
|
1822
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
1823
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { width: "10px", height: "10px", borderRadius: "999px", backgroundColor: "#f97316" } }),
|
|
1824
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { width: "10px", height: "10px", borderRadius: "999px", backgroundColor: "#facc15" } }),
|
|
1825
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { width: "10px", height: "10px", borderRadius: "999px", backgroundColor: "#4ade80" } })
|
|
1826
|
+
] }),
|
|
1827
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: "#94a3b8", fontSize: "12px", fontFamily: '"SF Mono", "Roboto Mono", monospace' }, children: [
|
|
1828
|
+
"/embed?operation=",
|
|
1829
|
+
appliedOperation
|
|
1830
|
+
] })
|
|
1831
|
+
]
|
|
1832
|
+
}
|
|
1833
|
+
),
|
|
1834
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1835
|
+
PlayruoEmbed,
|
|
1836
|
+
{
|
|
1837
|
+
baseUrl: props.baseUrl,
|
|
1838
|
+
className: "w-full h-full absolute inset-0",
|
|
1839
|
+
iframeRef,
|
|
1840
|
+
onDemoCompleted: handleDemoCompleted,
|
|
1841
|
+
onError: handleError,
|
|
1842
|
+
onEvent: handleEvent,
|
|
1843
|
+
onPurchaseRequest: handlePurchaseRequest,
|
|
1844
|
+
onReady: handleReady,
|
|
1845
|
+
onStateChange: handleStateChange,
|
|
1846
|
+
operation: appliedOperation,
|
|
1847
|
+
renderState: ({ actions, message, status }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: !hasUserClicked && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1848
|
+
"div",
|
|
1849
|
+
{
|
|
1850
|
+
style: {
|
|
1851
|
+
position: "absolute",
|
|
1852
|
+
inset: "53px 0 0 0",
|
|
1853
|
+
display: "flex",
|
|
1854
|
+
alignItems: "center",
|
|
1855
|
+
justifyContent: "center",
|
|
1856
|
+
padding: "24px",
|
|
1857
|
+
background: "linear-gradient(180deg, rgba(2, 6, 23, 0.4) 0%, rgba(2, 6, 23, 0.84) 70%, rgba(2, 6, 23, 0.9) 100%)",
|
|
1858
|
+
backdropFilter: "blur(12px)",
|
|
1859
|
+
zIndex: 50
|
|
1860
|
+
},
|
|
1861
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1862
|
+
"div",
|
|
1863
|
+
{
|
|
1864
|
+
style: {
|
|
1865
|
+
width: "min(100%, 420px)",
|
|
1866
|
+
padding: "28px",
|
|
1867
|
+
borderRadius: "28px",
|
|
1868
|
+
border: "1px solid rgba(148, 163, 184, 0.18)",
|
|
1869
|
+
background: "linear-gradient(180deg, rgba(15, 23, 42, 0.94) 0%, rgba(7, 12, 24, 0.98) 100%)",
|
|
1870
|
+
boxShadow: "0 32px 72px rgba(0, 0, 0, 0.35)"
|
|
1871
|
+
},
|
|
1872
|
+
children: [
|
|
1873
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1874
|
+
"div",
|
|
1875
|
+
{
|
|
1876
|
+
style: {
|
|
1877
|
+
display: "inline-flex",
|
|
1878
|
+
alignItems: "center",
|
|
1879
|
+
gap: "10px",
|
|
1880
|
+
padding: "6px 12px",
|
|
1881
|
+
borderRadius: "999px",
|
|
1882
|
+
backgroundColor: "rgba(56, 189, 248, 0.12)",
|
|
1883
|
+
border: "1px solid rgba(125, 211, 252, 0.18)",
|
|
1884
|
+
color: "#7dd3fc",
|
|
1885
|
+
fontSize: "11px",
|
|
1886
|
+
fontWeight: 700,
|
|
1887
|
+
letterSpacing: "0.08em",
|
|
1888
|
+
textTransform: "uppercase"
|
|
1889
|
+
},
|
|
1890
|
+
children: "Live overlay"
|
|
1891
|
+
}
|
|
1892
|
+
),
|
|
1893
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1894
|
+
"h4",
|
|
1895
|
+
{
|
|
1896
|
+
style: {
|
|
1897
|
+
margin: "18px 0 10px 0",
|
|
1898
|
+
color: "#f8fafc",
|
|
1899
|
+
fontSize: "28px",
|
|
1900
|
+
letterSpacing: "-0.03em"
|
|
1901
|
+
},
|
|
1902
|
+
children: embedState.hasPlayedOnce ? "Resume the session" : "Start the demo"
|
|
1903
|
+
}
|
|
1904
|
+
),
|
|
1905
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { style: { margin: 0, color: "#94a3b8", lineHeight: 1.7 }, children: [
|
|
1906
|
+
"Status: ",
|
|
1907
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#f8fafc", fontWeight: 700 }, children: status })
|
|
1908
|
+
] }),
|
|
1909
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { margin: "10px 0 0 0", color: "#cbd5e1", lineHeight: 1.7 }, children: message }),
|
|
1910
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "12px", marginTop: "24px" }, children: [
|
|
1911
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1912
|
+
"button",
|
|
1913
|
+
{
|
|
1914
|
+
type: "button",
|
|
1915
|
+
style: buildButtonStyle("primary", !actions.canTryNow),
|
|
1916
|
+
disabled: !actions.canTryNow,
|
|
1917
|
+
onClick: () => {
|
|
1918
|
+
setHasUserClicked(true);
|
|
1919
|
+
setShowIframe(true);
|
|
1920
|
+
addEvent(
|
|
1921
|
+
embedState.hasPlayedOnce ? "User clicked - Resuming game" : "User clicked - Starting game with tryNow"
|
|
1922
|
+
);
|
|
1923
|
+
actions.tryNow();
|
|
1924
|
+
},
|
|
1925
|
+
children: [
|
|
1926
|
+
"\u{1F3AE} ",
|
|
1927
|
+
embedState.hasPlayedOnce ? "Resume game" : "Try demo now"
|
|
1928
|
+
]
|
|
1929
|
+
}
|
|
1930
|
+
),
|
|
1931
|
+
actions.canBuyNow && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1932
|
+
"button",
|
|
1933
|
+
{
|
|
1934
|
+
type: "button",
|
|
1935
|
+
style: buildButtonStyle("secondary"),
|
|
1936
|
+
onClick: () => {
|
|
1937
|
+
addEvent("Buy Now clicked");
|
|
1938
|
+
actions.buyNow();
|
|
1939
|
+
},
|
|
1940
|
+
children: "Buy Now"
|
|
1941
|
+
}
|
|
1942
|
+
)
|
|
1943
|
+
] })
|
|
1944
|
+
]
|
|
1945
|
+
}
|
|
1946
|
+
)
|
|
1947
|
+
}
|
|
1948
|
+
) }),
|
|
1949
|
+
showIframe,
|
|
1950
|
+
storeUrl: appliedStoreUrl
|
|
1951
|
+
},
|
|
1952
|
+
key
|
|
1953
|
+
)
|
|
1954
|
+
]
|
|
969
1955
|
}
|
|
970
1956
|
)
|
|
971
|
-
] }) })
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
] }) })
|
|
978
|
-
] })
|
|
979
|
-
] }) });
|
|
1957
|
+
] }) })
|
|
1958
|
+
] })
|
|
1959
|
+
] })
|
|
1960
|
+
]
|
|
1961
|
+
}
|
|
1962
|
+
);
|
|
980
1963
|
};
|
|
981
1964
|
|
|
982
1965
|
// src/post-message-types.ts
|
|
@@ -984,7 +1967,7 @@ var isPlayruoEmbedMessage = (data) => {
|
|
|
984
1967
|
if (!data || typeof data !== "object") return false;
|
|
985
1968
|
const msg = data;
|
|
986
1969
|
if (typeof msg.type !== "string") return false;
|
|
987
|
-
return msg.type === "playruo_ready" || msg.type === "playruo_state_update" || msg.type === "playruo_purchase_request" || msg.type === "playruo_demo_completed" || msg.type === "playruo_error" || msg.type === "playruo_session_over" || msg.type === "playruo_stream_start" || msg.type === "playruo_stream_stop";
|
|
1970
|
+
return msg.type === "playruo_ready" || msg.type === "playruo_state_update" || msg.type === "playruo_purchase_request" || msg.type === "playruo_demo_completed" || msg.type === "playruo_error" || msg.type === "playruo_session_over" || msg.type === "playruo_stream_start" || msg.type === "playruo_stream_stop" || msg.type === "REQUEST_EXIT_FULLSCREEN" || msg.type === "playruo_event";
|
|
988
1971
|
};
|
|
989
1972
|
var isPlayruoInternalMessage = (data) => {
|
|
990
1973
|
if (!data || typeof data !== "object") return false;
|