web: Add changes to make shadow template one tsx element

This commit is contained in:
Daniel Jacobs 2024-07-17 16:17:32 -04:00 committed by Nathan Adams
parent f56c43882f
commit 1275656b9e
3 changed files with 596 additions and 709 deletions

View File

@ -3,7 +3,7 @@ interface Error {
} }
interface SVGSVGElement { interface SVGSVGElement {
xmlns?: string; xmlns?: string;
"xmlns:xlink"?: string; scale?: string | number;
} }
interface SVGPathElement { interface SVGPathElement {
fill?: string; fill?: string;
@ -17,10 +17,7 @@ interface SVGTextElement {
interface SVGCircleElement { interface SVGCircleElement {
fill?: string; fill?: string;
} }
interface SVGUseElement {
"xlink:href"?: string;
}
interface HTMLInputElement { interface HTMLInputElement {
autoCapitalize?: string; autocapitalize?: string;
autoComplete?: string; autocorrect?: string;
} }

View File

@ -1,6 +1,6 @@
import type { RuffleHandle, ZipWriter } from "../dist/ruffle_web"; import type { RuffleHandle, ZipWriter } from "../dist/ruffle_web";
import { createRuffleBuilder } from "./load-ruffle"; import { createRuffleBuilder } from "./load-ruffle";
import { applyStaticStyles, ruffleShadowTemplate } from "./shadow-template"; import { ruffleShadowTemplate } from "./shadow-template";
import { lookupElement } from "./internal/register-element"; import { lookupElement } from "./internal/register-element";
import { DEFAULT_CONFIG } from "./config"; import { DEFAULT_CONFIG } from "./config";
import type { DataLoadOptions, URLLoadOptions } from "./load-options"; import type { DataLoadOptions, URLLoadOptions } from "./load-options";
@ -119,7 +119,6 @@ class Point {
export class RufflePlayer extends HTMLElement { export class RufflePlayer extends HTMLElement {
private readonly shadow: ShadowRoot; private readonly shadow: ShadowRoot;
private readonly dynamicStyles: HTMLStyleElement; private readonly dynamicStyles: HTMLStyleElement;
private readonly staticStyles: HTMLStyleElement;
private readonly container: HTMLElement; private readonly container: HTMLElement;
private readonly playButton: HTMLElement; private readonly playButton: HTMLElement;
private readonly unmuteOverlay: HTMLElement; private readonly unmuteOverlay: HTMLElement;
@ -231,9 +230,6 @@ export class RufflePlayer extends HTMLElement {
this.dynamicStyles = this.shadow.getElementById( this.dynamicStyles = this.shadow.getElementById(
"dynamic-styles", "dynamic-styles",
) as HTMLStyleElement; ) as HTMLStyleElement;
this.staticStyles = this.shadow.getElementById(
"static-styles",
) as HTMLStyleElement;
this.container = this.shadow.getElementById("container")!; this.container = this.shadow.getElementById("container")!;
this.playButton = this.shadow.getElementById("play-button")!; this.playButton = this.shadow.getElementById("play-button")!;
this.playButton.addEventListener("click", () => this.play()); this.playButton.addEventListener("click", () => this.play());
@ -529,7 +525,6 @@ export class RufflePlayer extends HTMLElement {
*/ */
connectedCallback(): void { connectedCallback(): void {
this.updateStyles(); this.updateStyles();
applyStaticStyles(this.staticStyles);
} }
/** /**

View File

@ -1,34 +1,13 @@
import { text } from "./internal/i18n"; import { text } from "./internal/i18n";
/** /*
* Insert all rules from array in the style sheet.
* *
* @param sheet The style sheet to which to apply the rules. * The shadow template which is used to fill the actual Ruffle player element
* @param rules An array of rules to be applied. * on the page.
*/
function insertRules(sheet: CSSStyleSheet, rules: Array<string>) {
for (const rule of rules) {
try {
sheet.insertRule(rule);
} catch (_err) {
// Ignore unsupported rules
}
}
}
/**
* The default styles to apply to the shadow template.
* This function must be run after the shadow template is added to the page.
* *
* @param styleElement The static style element to which to add the rules
*/ */
export function applyStaticStyles(styleElement: HTMLStyleElement) { const css = `
if (!styleElement.sheet) { :host {
return;
}
const rules = [
`:host {
all: initial; all: initial;
pointer-events: inherit; pointer-events: inherit;
@ -46,22 +25,22 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
user-select: none; user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
}`, }
/* Ruffle's width/height CSS interferes with Safari's fullscreen CSS. */ /* Ruffle's width/height CSS interferes with Safari's fullscreen CSS. */
/* Ensure that Safari's fullscreen mode actually fills the screen. */ /* Ensure that Safari's fullscreen mode actually fills the screen. */
`:host(:-webkit-full-screen) { :host(:-webkit-full-screen) {
display: block; display: block;
width: 100% !important; width: 100% !important;
height: 100% !important; height: 100% !important;
}`, }
`.hidden { .hidden {
display: none !important; display: none !important;
}`, }
/* All of these use the dimensions specified by the embed. */ /* All of these use the dimensions specified by the embed. */
`#container, #container,
#play-button, #play-button,
#unmute-overlay, #unmute-overlay,
#unmute-overlay .background, #unmute-overlay .background,
@ -73,29 +52,29 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
}`, }
`#container { #container {
overflow: hidden; overflow: hidden;
}`, }
`#container canvas { #container canvas {
width: 100%; width: 100%;
height: 100%; height: 100%;
}`, }
`#play-button, #play-button,
#unmute-overlay { #unmute-overlay {
cursor: pointer; cursor: pointer;
display: none; display: none;
}`, }
`#unmute-overlay .background { #unmute-overlay .background {
background: black; background: black;
opacity: 0.7; opacity: 0.7;
}`, }
`#play-button .icon, #play-button .icon,
#unmute-overlay .icon { #unmute-overlay .icon {
position: absolute; position: absolute;
top: 50%; top: 50%;
@ -106,15 +85,15 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
max-height: 384px; max-height: 384px;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
opacity: 0.8; opacity: 0.8;
}`, }
`#play-button:hover .icon, #play-button:hover .icon,
#unmute-overlay:hover .icon { #unmute-overlay:hover .icon {
opacity: 1; opacity: 1;
}`, }
/* Includes inverted colors from play button! */ /* Includes inverted colors from play button! */
`#panic { #panic {
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;
background: linear-gradient(180deg, #fd3a40 0%, #fda138 100%); background: linear-gradient(180deg, #fd3a40 0%, #fda138 100%);
@ -122,37 +101,37 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
display: flex; display: flex;
flex-flow: column; flex-flow: column;
justify-content: space-around; justify-content: space-around;
}`, }
`#panic a { #panic a {
color: var(--ruffle-blue); color: var(--ruffle-blue);
font-weight: bold; font-weight: bold;
}`, }
`#panic-title { #panic-title {
font-size: xxx-large; font-size: xxx-large;
font-weight: bold; font-weight: bold;
}`, }
`#panic-body.details { #panic-body.details {
flex: 0.9; flex: 0.9;
margin: 0 10px; margin: 0 10px;
}`, }
`#panic-body textarea { #panic-body textarea {
width: 100%; width: 100%;
height: 100%; height: 100%;
resize: none; resize: none;
}`, }
`#panic ul { #panic ul {
padding: 0; padding: 0;
display: flex; display: flex;
list-style-type: none; list-style-type: none;
justify-content: space-evenly; justify-content: space-evenly;
}`, }
`#message-overlay { #message-overlay {
position: absolute; position: absolute;
background: var(--ruffle-blue); background: var(--ruffle-blue);
color: var(--ruffle-orange); color: var(--ruffle-orange);
@ -162,28 +141,28 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
overflow: auto; overflow: auto;
}`, }
`#message-overlay .message { #message-overlay .message {
text-align: center; text-align: center;
max-height: 100%; max-height: 100%;
max-width: 100%; max-width: 100%;
padding: 5%; padding: 5%;
font-size: 20px; font-size: 20px;
}`, }
`#message-overlay p { #message-overlay p {
margin: 0.5em 0; margin: 0.5em 0;
}`, }
`#message-overlay .message div { #message-overlay .message div {
display: flex; display: flex;
justify-content: center; justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
column-gap: 1em; column-gap: 1em;
}`, }
`#message-overlay a, #message-overlay button { #message-overlay a, #message-overlay button {
cursor: pointer; cursor: pointer;
background: var(--ruffle-blue); background: var(--ruffle-blue);
color: var(--ruffle-orange); color: var(--ruffle-orange);
@ -194,13 +173,13 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
padding: 10px; padding: 10px;
text-decoration: none; text-decoration: none;
margin: 2% 0; margin: 2% 0;
}`, }
`#message-overlay a:hover, #message-overlay button:hover { #message-overlay a:hover, #message-overlay button:hover {
background: #ffffff4c; background: #ffffff4c;
}`, }
`#continue-btn { #continue-btn {
cursor: pointer; cursor: pointer;
background: var(--ruffle-blue); background: var(--ruffle-blue);
color: var(--ruffle-orange); color: var(--ruffle-orange);
@ -209,20 +188,20 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
font-size: 20px; font-size: 20px;
border-radius: 20px; border-radius: 20px;
padding: 10px; padding: 10px;
}`, }
`#continue-btn:hover { #continue-btn:hover {
background: #ffffff4c; background: #ffffff4c;
}`, }
`#context-menu-overlay, .modal { #context-menu-overlay, .modal {
width: 100%; width: 100%;
height: 100%; height: 100%;
z-index: 1; z-index: 1;
position: absolute; position: absolute;
}`, }
`#context-menu { #context-menu {
color: rgb(var(--modal-foreground-rgb)); color: rgb(var(--modal-foreground-rgb));
background-color: var(--modal-background); background-color: var(--modal-background);
border: 1px solid gray; border: 1px solid gray;
@ -234,92 +213,92 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
white-space: nowrap; white-space: nowrap;
padding: 3px 0; padding: 3px 0;
margin: 0; margin: 0;
}`, }
`#context-menu .menu-item { #context-menu .menu-item {
padding: 5px 10px; padding: 5px 10px;
color: rgb(var(--modal-foreground-rgb)); color: rgb(var(--modal-foreground-rgb));
}`, }
`#context-menu .menu-item.disabled { #context-menu .menu-item.disabled {
cursor: default; cursor: default;
color: rgba(var(--modal-foreground-rgb), 0.5); color: rgba(var(--modal-foreground-rgb), 0.5);
}`, }
`#context-menu .menu-item:not(.disabled):hover { #context-menu .menu-item:not(.disabled):hover {
background-color: rgba(var(--modal-foreground-rgb), 0.15); background-color: rgba(var(--modal-foreground-rgb), 0.15);
}`, }
`#context-menu .menu-separator hr { #context-menu .menu-separator hr {
border: none; border: none;
border-bottom: 1px solid rgba(var(--modal-foreground-rgb), 0.2); border-bottom: 1px solid rgba(var(--modal-foreground-rgb), 0.2);
margin: 3px; margin: 3px;
}`, }
`#splash-screen { #splash-screen {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: var(--splash-screen-background, var(--preloader-background, var(--ruffle-blue))); background: var(--splash-screen-background, var(--preloader-background, var(--ruffle-blue)));
align-items: center; align-items: center;
justify-content: center; justify-content: center;
}`, }
`.loadbar { .loadbar {
width: 100%; width: 100%;
max-width: 316px; max-width: 316px;
max-height: 10px; max-height: 10px;
height: 20%; height: 20%;
background: #253559; background: #253559;
}`, }
`.loadbar-inner { .loadbar-inner {
width: 0px; width: 0px;
max-width: 100%; max-width: 100%;
height: 100%; height: 100%;
background: var(--ruffle-orange); background: var(--ruffle-orange);
}`, }
`.logo { .logo {
display: var(--logo-display, block); display: var(--logo-display, block);
max-width: 380px; max-width: 380px;
max-height: 150px; max-height: 150px;
}`, }
`.loading-animation { .loading-animation {
max-width: 28px; max-width: 28px;
max-height: 28px; max-height: 28px;
margin-bottom: 2%; margin-bottom: 2%;
width: 10%; width: 10%;
aspect-ratio: 1; aspect-ratio: 1;
}`, }
`.spinner { .spinner {
stroke-dasharray: 180; stroke-dasharray: 180;
stroke-dashoffset: 135; stroke-dashoffset: 135;
stroke: var(--ruffle-orange); stroke: var(--ruffle-orange);
transform-origin: 50% 50%; transform-origin: 50% 50%;
animation: rotate 1.5s linear infinite; animation: rotate 1.5s linear infinite;
}`, }
`@keyframes rotate { @keyframes rotate {
to { to {
transform: rotate(360deg); transform: rotate(360deg);
} }
}`, }
`#virtual-keyboard { #virtual-keyboard {
position: absolute; position: absolute;
opacity: 0; opacity: 0;
top: -100px; top: -100px;
width: 1px; width: 1px;
height: 1px; height: 1px;
}`, }
`.modal { .modal {
background-color: #0008; background-color: #0008;
}`, }
`.modal-area { .modal-area {
position: relative; position: relative;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
@ -329,22 +308,22 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
padding: 8px 12px; padding: 8px 12px;
border-radius: 12px; border-radius: 12px;
box-shadow: 0 2px 6px 0px #0008; box-shadow: 0 2px 6px 0px #0008;
}`, }
`#modal-area { #modal-area {
width: 450px; width: 450px;
height: 300px; height: 300px;
}`, }
`.close-modal { .close-modal {
width: 16px; width: 16px;
height: 16px; height: 16px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='16px' viewBox='0 -960 960 960' width='16px' fill='black'%3E%3Cpath d='M480-392 300-212q-18 18-44 18t-44-18q-18-18-18-44t18-44l180-180-180-180q-18-18-18-44t18-44q18-18 44-18t44 18l180 180 180-180q18-18 44-18t44 18q18 18 18 44t-18 44L568-480l180 180q18 18 18 44t-18 44q-18 18-44 18t-44-18L480-392Z'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='16px' viewBox='0 -960 960 960' width='16px' fill='black'%3E%3Cpath d='M480-392 300-212q-18 18-44 18t-44-18q-18-18-18-44t18-44l180-180-180-180q-18-18-18-44t18-44q18-18 44-18t44 18l180 180 180-180q18-18 44-18t44 18q18 18 18 44t-18 44L568-480l180 180q18 18 18 44t-18 44q-18 18-44 18t-44-18L480-392Z'/%3E%3C/svg%3E");
cursor: pointer; cursor: pointer;
filter: var(--modal-foreground-filter); filter: var(--modal-foreground-filter);
}`, }
`.modal-button { .modal-button {
display: inline-block; display: inline-block;
background-color: rgba(var(--modal-foreground-rgb), 0.2); background-color: rgba(var(--modal-foreground-rgb), 0.2);
color: rgb(var(--modal-foreground-rgb)); color: rgb(var(--modal-foreground-rgb));
@ -352,40 +331,40 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
padding: 4px 8px; padding: 4px 8px;
border-radius: 6px; border-radius: 6px;
cursor: pointer; cursor: pointer;
}`, }
`:not(#volume-controls) > .close-modal { :not(#volume-controls) > .close-modal {
position: absolute; position: absolute;
top: 14px; top: 14px;
right: 16px; right: 16px;
}`, }
`.general-save-options { .general-save-options {
text-align: center; text-align: center;
padding-bottom: 8px; padding-bottom: 8px;
border-bottom: 2px solid rgba(var(--modal-foreground-rgb), 0.3); border-bottom: 2px solid rgba(var(--modal-foreground-rgb), 0.3);
}`, }
`#local-saves { #local-saves {
color: inherit; color: inherit;
border-collapse: collapse; border-collapse: collapse;
overflow-y: auto; overflow-y: auto;
display: block; display: block;
height: calc(100% - 45px); height: calc(100% - 45px);
min-height: 30px; min-height: 30px;
}`, }
`#local-saves td { #local-saves td {
border-bottom: 2px solid rgba(var(--modal-foreground-rgb), 0.15); border-bottom: 2px solid rgba(var(--modal-foreground-rgb), 0.15);
height: 30px; height: 30px;
}`, }
`#local-saves td:nth-child(1) { #local-saves td:nth-child(1) {
width: 100%; width: 100%;
word-break: break-all; word-break: break-all;
}`, }
`.save-option { .save-option {
display: inline-block; display: inline-block;
width: 24px; width: 24px;
height: 24px; height: 24px;
@ -393,189 +372,136 @@ export function applyStaticStyles(styleElement: HTMLStyleElement) {
filter: var(--modal-foreground-filter); filter: var(--modal-foreground-filter);
vertical-align: middle; vertical-align: middle;
opacity: 0.4; opacity: 0.4;
}`, }
`#local-saves > tr:hover .save-option { #local-saves > tr:hover .save-option {
opacity: 1; opacity: 1;
}`, }
`#download-save { #download-save {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 -960 960 960' width='24px' fill='black'%3E%3Cpath d='M480-337q-8 0-15-2.5t-13-8.5L308-492q-12-12-11.5-28t11.5-28q12-12 28.5-12.5T365-549l75 75v-286q0-17 11.5-28.5T480-800q17 0 28.5 11.5T520-760v286l75-75q12-12 28.5-11.5T652-548q11 12 11.5 28T652-492L508-348q-6 6-13 8.5t-15 2.5ZM240-160q-33 0-56.5-23.5T160-240v-80q0-17 11.5-28.5T200-360q17 0 28.5 11.5T240-320v80h480v-80q0-17 11.5-28.5T760-360q17 0 28.5 11.5T800-320v80q0 33-23.5 56.5T720-160H240Z'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 -960 960 960' width='24px' fill='black'%3E%3Cpath d='M480-337q-8 0-15-2.5t-13-8.5L308-492q-12-12-11.5-28t11.5-28q12-12 28.5-12.5T365-549l75 75v-286q0-17 11.5-28.5T480-800q17 0 28.5 11.5T520-760v286l75-75q12-12 28.5-11.5T652-548q11 12 11.5 28T652-492L508-348q-6 6-13 8.5t-15 2.5ZM240-160q-33 0-56.5-23.5T160-240v-80q0-17 11.5-28.5T200-360q17 0 28.5 11.5T240-320v80h480v-80q0-17 11.5-28.5T760-360q17 0 28.5 11.5T800-320v80q0 33-23.5 56.5T720-160H240Z'/%3E%3C/svg%3E");
}`, }
`#replace-save { #replace-save {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 -1080 960 1200' width='24px' fill='black'%3E%3Cpath d='M440-367v127q0 17 11.5 28.5T480-200q17 0 28.5-11.5T520-240v-127l36 36q6 6 13.5 9t15 2.5q7.5-.5 14.5-3.5t13-9q11-12 11.5-28T612-388L508-492q-6-6-13-8.5t-15-2.5q-8 0-15 2.5t-13 8.5L348-388q-12 12-11.5 28t12.5 28q12 11 28 11.5t28-11.5l35-35ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h287q16 0 30.5 6t25.5 17l194 194q11 11 17 25.5t6 30.5v447q0 33-23.5 56.5T720-80H240Zm280-560q0 17 11.5 28.5T560-600h160L520-800v160Z'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 -1080 960 1200' width='24px' fill='black'%3E%3Cpath d='M440-367v127q0 17 11.5 28.5T480-200q17 0 28.5-11.5T520-240v-127l36 36q6 6 13.5 9t15 2.5q7.5-.5 14.5-3.5t13-9q11-12 11.5-28T612-388L508-492q-6-6-13-8.5t-15-2.5q-8 0-15 2.5t-13 8.5L348-388q-12 12-11.5 28t12.5 28q12 11 28 11.5t28-11.5l35-35ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h287q16 0 30.5 6t25.5 17l194 194q11 11 17 25.5t6 30.5v447q0 33-23.5 56.5T720-80H240Zm280-560q0 17 11.5 28.5T560-600h160L520-800v160Z'/%3E%3C/svg%3E");
}`, }
`#delete-save { #delete-save {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 -1020 960 1080' width='24px' fill='black'%3E%3Cpath d='M280-120q-33 0-56.5-23.5T200-200v-520q-17 0-28.5-11.5T160-760q0-17 11.5-28.5T200-800h160q0-17 11.5-28.5T400-840h160q17 0 28.5 11.5T600-800h160q17 0 28.5 11.5T800-760q0 17-11.5 28.5T760-720v520q0 33-23.5 56.5T680-120H280Zm120-160q17 0 28.5-11.5T440-320v-280q0-17-11.5-28.5T400-640q-17 0-28.5 11.5T360-600v280q0 17 11.5 28.5T400-280Zm160 0q17 0 28.5-11.5T600-320v-280q0-17-11.5-28.5T560-640q-17 0-28.5 11.5T520-600v280q0 17 11.5 28.5T560-280Z'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 -1020 960 1080' width='24px' fill='black'%3E%3Cpath d='M280-120q-33 0-56.5-23.5T200-200v-520q-17 0-28.5-11.5T160-760q0-17 11.5-28.5T200-800h160q0-17 11.5-28.5T400-840h160q17 0 28.5 11.5T600-800h160q17 0 28.5 11.5T800-760q0 17-11.5 28.5T760-720v520q0 33-23.5 56.5T680-120H280Zm120-160q17 0 28.5-11.5T440-320v-280q0-17-11.5-28.5T400-640q-17 0-28.5 11.5T360-600v280q0 17 11.5 28.5T400-280Zm160 0q17 0 28.5-11.5T600-320v-280q0-17-11.5-28.5T560-640q-17 0-28.5 11.5T520-600v280q0 17 11.5 28.5T560-280Z'/%3E%3C/svg%3E");
}`, }
`.replace-save { .replace-save {
display: none; display: none;
}`, }
`#video-modal .modal-area { #video-modal .modal-area {
width: 95%; width: 95%;
height: 95%; height: 95%;
box-sizing: border-box; box-sizing: border-box;
}`, }
`#video-holder { #video-holder {
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
padding: 36px 4px 6px; padding: 36px 4px 6px;
}`, }
`#video-holder video { #video-holder video {
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: black; background-color: black;
}`, }
`#volume-controls { #volume-controls {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px; gap: 6px;
}`, }
`#mute-checkbox { #mute-checkbox {
display: none; display: none;
}`, }
`label[for="mute-checkbox"] { label[for="mute-checkbox"] {
width: 24px; width: 24px;
height: 24px; height: 24px;
line-height: 0; line-height: 0;
cursor: pointer; cursor: pointer;
filter: var(--modal-foreground-filter); filter: var(--modal-foreground-filter);
}`, }
`#volume-mute { #volume-mute {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 -960 960 960' width='24px' fill='black'%3E%3Cpath d='m719.13-419.35-71.67 71.68Q634.78-335 617.13-335t-30.33-12.67q-12.67-12.68-12.67-30.33t12.67-30.33L658.48-480l-71.68-71.67q-12.67-12.68-12.67-30.33t12.67-30.33Q599.48-625 617.13-625t30.33 12.67l71.67 71.68 71.67-71.68Q803.48-625 821.13-625t30.33 12.67q12.67 12.68 12.67 30.33t-12.67 30.33L779.78-480l71.68 71.67q12.67 12.68 12.67 30.33t-12.67 30.33Q838.78-335 821.13-335t-30.33-12.67l-71.67-71.68ZM278-357.87H161.22q-17.66 0-30.33-12.67-12.67-12.68-12.67-30.33v-158.26q0-17.65 12.67-30.33 12.67-12.67 30.33-12.67H278l130.15-129.91q20.63-20.63 46.98-9.45 26.35 11.19 26.35 39.77v443.44q0 28.58-26.35 39.77-26.35 11.18-46.98-9.45L278-357.87Z'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 -960 960 960' width='24px' fill='black'%3E%3Cpath d='m719.13-419.35-71.67 71.68Q634.78-335 617.13-335t-30.33-12.67q-12.67-12.68-12.67-30.33t12.67-30.33L658.48-480l-71.68-71.67q-12.67-12.68-12.67-30.33t12.67-30.33Q599.48-625 617.13-625t30.33 12.67l71.67 71.68 71.67-71.68Q803.48-625 821.13-625t30.33 12.67q12.67 12.68 12.67 30.33t-12.67 30.33L779.78-480l71.68 71.67q12.67 12.68 12.67 30.33t-12.67 30.33Q838.78-335 821.13-335t-30.33-12.67l-71.67-71.68ZM278-357.87H161.22q-17.66 0-30.33-12.67-12.67-12.68-12.67-30.33v-158.26q0-17.65 12.67-30.33 12.67-12.67 30.33-12.67H278l130.15-129.91q20.63-20.63 46.98-9.45 26.35 11.19 26.35 39.77v443.44q0 28.58-26.35 39.77-26.35 11.18-46.98-9.45L278-357.87Z'/%3E%3C/svg%3E");
}`, }
`#volume-min { #volume-min {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='161 -960 960 960' width='24px' fill='black'%3E%3Cpath d='M438.65-357.87H321.87q-17.65 0-30.33-12.67-12.67-12.68-12.67-30.33v-158.26q0-17.65 12.67-30.33 12.68-12.67 30.33-12.67h116.78L568.8-732.04q20.63-20.63 46.98-9.45 26.35 11.19 26.35 39.77v443.44q0 28.58-26.35 39.77-26.35 11.18-46.98-9.45L438.65-357.87Z'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='161 -960 960 960' width='24px' fill='black'%3E%3Cpath d='M438.65-357.87H321.87q-17.65 0-30.33-12.67-12.67-12.68-12.67-30.33v-158.26q0-17.65 12.67-30.33 12.68-12.67 30.33-12.67h116.78L568.8-732.04q20.63-20.63 46.98-9.45 26.35 11.19 26.35 39.77v443.44q0 28.58-26.35 39.77-26.35 11.18-46.98-9.45L438.65-357.87Z'/%3E%3C/svg%3E");
}`, }
`#volume-mid { #volume-mid {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='80 -960 960 960' width='24px' fill='black'%3E%3Cpath d='M357.98-357.87H241.2q-17.66 0-30.33-12.67-12.67-12.68-12.67-30.33v-158.26q0-17.65 12.67-30.33 12.67-12.67 30.33-12.67h116.78L487.65-731.8q20.63-20.64 47.1-9.57 26.47 11.07 26.47 39.65v443.44q0 28.58-26.47 39.65t-47.1-9.57L357.98-357.87ZM741.8-480q0 42.48-20.47 80.09-20.48 37.61-54.94 60.82-10.22 5.98-20.19.25-9.98-5.73-9.98-17.44v-248.44q0-11.71 9.98-17.32 9.97-5.61 20.19.37 34.46 23.71 54.94 61.45Q741.8-522.48 741.8-480Z'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='80 -960 960 960' width='24px' fill='black'%3E%3Cpath d='M357.98-357.87H241.2q-17.66 0-30.33-12.67-12.67-12.68-12.67-30.33v-158.26q0-17.65 12.67-30.33 12.67-12.67 30.33-12.67h116.78L487.65-731.8q20.63-20.64 47.1-9.57 26.47 11.07 26.47 39.65v443.44q0 28.58-26.47 39.65t-47.1-9.57L357.98-357.87ZM741.8-480q0 42.48-20.47 80.09-20.48 37.61-54.94 60.82-10.22 5.98-20.19.25-9.98-5.73-9.98-17.44v-248.44q0-11.71 9.98-17.32 9.97-5.61 20.19.37 34.46 23.71 54.94 61.45Q741.8-522.48 741.8-480Z'/%3E%3C/svg%3E");
}`, }
`#volume-max { #volume-max {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='9 -960 960 960' width='24px' fill='black'%3E%3Cpath d='M754.22-480.5q0-78.52-41.88-143.9-41.88-65.38-111.91-98.62-14.47-6.74-20.47-20.96-6-14.22-.53-28.93 5.74-15.72 20.34-22.46t29.58 0q92.48 42.46 147.97 127.05 55.48 84.6 55.48 187.82t-55.48 187.82q-55.49 84.59-147.97 127.05-14.98 6.74-29.58 0-14.6-6.74-20.34-22.46-5.47-14.71.53-28.93 6-14.22 20.47-20.96 70.03-33.24 111.91-98.62 41.88-65.38 41.88-143.9ZM286.98-357.87H170.2q-17.66 0-30.33-12.67-12.67-12.68-12.67-30.33v-158.26q0-17.65 12.67-30.33 12.67-12.67 30.33-12.67h116.78L416.65-731.8q20.63-20.64 47.1-9.57 26.47 11.07 26.47 39.65v443.44q0 28.58-26.47 39.65t-47.1-9.57L286.98-357.87ZM670.8-480q0 42.48-20.47 80.09-20.48 37.61-54.94 60.82-10.22 5.98-20.19.25-9.98-5.73-9.98-17.44v-248.44q0-11.71 9.98-17.32 9.97-5.61 20.19.37 34.46 23.71 54.94 61.45Q670.8-522.48 670.8-480Z'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='9 -960 960 960' width='24px' fill='black'%3E%3Cpath d='M754.22-480.5q0-78.52-41.88-143.9-41.88-65.38-111.91-98.62-14.47-6.74-20.47-20.96-6-14.22-.53-28.93 5.74-15.72 20.34-22.46t29.58 0q92.48 42.46 147.97 127.05 55.48 84.6 55.48 187.82t-55.48 187.82q-55.49 84.59-147.97 127.05-14.98 6.74-29.58 0-14.6-6.74-20.34-22.46-5.47-14.71.53-28.93 6-14.22 20.47-20.96 70.03-33.24 111.91-98.62 41.88-65.38 41.88-143.9ZM286.98-357.87H170.2q-17.66 0-30.33-12.67-12.67-12.68-12.67-30.33v-158.26q0-17.65 12.67-30.33 12.67-12.67 30.33-12.67h116.78L416.65-731.8q20.63-20.64 47.1-9.57 26.47 11.07 26.47 39.65v443.44q0 28.58-26.47 39.65t-47.1-9.57L286.98-357.87ZM670.8-480q0 42.48-20.47 80.09-20.48 37.61-54.94 60.82-10.22 5.98-20.19.25-9.98-5.73-9.98-17.44v-248.44q0-11.71 9.98-17.32 9.97-5.61 20.19.37 34.46 23.71 54.94 61.45Q670.8-522.48 670.8-480Z'/%3E%3C/svg%3E");
}`, }
`#volume-slider-text { #volume-slider-text {
width: 4.8ch; width: 4.8ch;
text-align: center; text-align: center;
user-select: none; user-select: none;
}`, }
`#hardware-acceleration-modal .modal-area { #hardware-acceleration-modal .modal-area {
text-align: center; text-align: center;
padding: 16px 48px; padding: 16px 48px;
width: 95%; width: 95%;
box-sizing: border-box; box-sizing: border-box;
}`, }
`#acceleration-text { #acceleration-text {
display: block; display: block;
margin-bottom: 8px; margin-bottom: 8px;
}`, }
`#clipboard-modal h2 { #clipboard-modal h2 {
margin-top: 4px; margin-top: 4px;
margin-right: 36px; margin-right: 36px;
}`, }
`#clipboard-modal p:last-child { #clipboard-modal p:last-child {
margin-bottom: 2px; margin-bottom: 2px;
}`, }
/* Handle preferred color scheme. */ /* Handle preferred color scheme. */
`@media (prefers-color-scheme: light) { @media (prefers-color-scheme: light) {
:host { :host {
--modal-background: #fafafa; --modal-background: #fafafa;
--modal-foreground-rgb: 0, 0, 0; --modal-foreground-rgb: 0, 0, 0;
--modal-foreground-filter: none; --modal-foreground-filter: none;
} }
}`, }
`@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:host { :host {
--modal-background: #282828; --modal-background: #282828;
--modal-foreground-rgb: 221, 221, 221; --modal-foreground-rgb: 221, 221, 221;
--modal-foreground-filter: invert(90%); --modal-foreground-filter: invert(90%);
} }
}`, }`;
];
insertRules(styleElement.sheet, rules);
}
/**
* Create and return a new HTML Element with the given arguments.
*
* @param tag The HTML tag name of the new element.
* @param id The id of the new element.
* @param className The class name of the new element.
* @param attributes A hash of attributes for the new element.
* @param ns The namespace of the new element.
*
* @returns The newly created Element
*/
function createElement(
tag: string,
id?: string,
className?: string,
attributes?: Record<string, string>,
ns?: string,
): Element {
const element = ns
? document.createElementNS(ns, tag)
: document.createElement(tag);
if (id) {
element.id = id;
}
if (className && ns) {
element.classList.add(className);
} else if (className) {
element.className = className;
}
if (attributes) {
for (const [key, attr] of Object.entries(attributes)) {
element.setAttribute(key, attr);
}
}
return element;
}
/**
*
* @param parentElement The node to which to append a child element.
* @param childElement The node to be appended to the parent element.
*/
function appendElement(parentElement: Node, childElement: Node) {
parentElement.appendChild(childElement);
}
/**
* The shadow template which is used to fill the actual Ruffle player element
* on the page.
*
*/
export const ruffleShadowTemplate = document.createElement("template");
const staticStyles = createElement("style", "static-styles");
const dynamicStyles = createElement("style", "dynamic-styles");
const shortcutModifier = navigator.userAgent.includes("Mac OS X") const shortcutModifier = navigator.userAgent.includes("Mac OS X")
? "Command" ? "Command"
: "Ctrl"; : "Ctrl";
const container = ( export const ruffleShadowTemplate = (
<template>
<style>
{ css }
</style>
<style id="dynamic-styles"></style>
<div id="container"> <div id="container">
<div id="play-button"> <div id="play-button">
<div class="icon"> <div class="icon">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" viewBox="0 0 250 250" width="100%" height="100%"> <svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" viewBox="0 0 250 250" width="100%" height="100%">
<defs> <defs>
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="125" y1="0" x2="125" y2="250" spreadMethod="pad"> <linearGradient id="a" gradientUnits="userSpaceOnUse" x1="125" y1="0" x2="125" y2="250" spreadMethod="pad">
<stop offset="0%" stop-color="#FDA138"></stop> <stop offset="0%" stop-color="#FDA138"></stop>
@ -586,14 +512,14 @@ const container = (
<path fill="#FFF" d="M87 55v140l100-70L87 55z"></path> <path fill="#FFF" d="M87 55v140l100-70L87 55z"></path>
</g> </g>
</defs> </defs>
<use xlink:href="#b"></use> <use href="#b"></use>
</svg> </svg>
</div> </div>
</div> </div>
<div id="unmute-overlay"> <div id="unmute-overlay">
<div class="background"></div> <div class="background"></div>
<div class="icon"> <div class="icon">
<svg id="unmute-overlay-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" viewBox="0 0 512 584" width="100%" height="100%" scale="0.8"> <svg id="unmute-overlay-svg" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" viewBox="0 0 512 584" width="100%" height="100%" scale="0.8">
<path fill="#FFF" stroke="#FFF" d="m457.941 256 47.029-47.029c9.372-9.373 9.372-24.568 0-33.941-9.373-9.373-24.568-9.373-33.941 0l-47.029 47.029-47.029-47.029c-9.373-9.373-24.568-9.373-33.941 0-9.372 9.373-9.372 24.568 0 33.941l47.029 47.029-47.029 47.029c-9.372 9.373-9.372 24.568 0 33.941 4.686 4.687 10.827 7.03 16.97 7.03s12.284-2.343 16.971-7.029l47.029-47.03 47.029 47.029c4.687 4.687 10.828 7.03 16.971 7.03s12.284-2.343 16.971-7.029c9.372-9.373 9.372-24.568 0-33.941z"></path> <path fill="#FFF" stroke="#FFF" d="m457.941 256 47.029-47.029c9.372-9.373 9.372-24.568 0-33.941-9.373-9.373-24.568-9.373-33.941 0l-47.029 47.029-47.029-47.029c-9.373-9.373-24.568-9.373-33.941 0-9.372 9.373-9.372 24.568 0 33.941l47.029 47.029-47.029 47.029c-9.372 9.373-9.372 24.568 0 33.941 4.686 4.687 10.827 7.03 16.97 7.03s12.284-2.343 16.971-7.029l47.029-47.03 47.029 47.029c4.687 4.687 10.828 7.03 16.971 7.03s12.284-2.343 16.971-7.029c9.372-9.373 9.372-24.568 0-33.941z"></path>
<path fill="#FFF" stroke="#FFF" d="m99 160h-55c-24.301 0-44 19.699-44 44v104c0 24.301 19.699 44 44 44h55c2.761 0 5-2.239 5-5v-182c0-2.761-2.239-5-5-5z"></path> <path fill="#FFF" stroke="#FFF" d="m99 160h-55c-24.301 0-44 19.699-44 44v104c0 24.301 19.699 44 44 44h55c2.761 0 5-2.239 5-5v-182c0-2.761-2.239-5-5-5z"></path>
<path fill="#FFF" stroke="#FFF" d="m280 56h-24c-5.269 0-10.392 1.734-14.578 4.935l-103.459 79.116c-1.237.946-1.963 2.414-1.963 3.972v223.955c0 1.557.726 3.026 1.963 3.972l103.459 79.115c4.186 3.201 9.309 4.936 14.579 4.936h23.999c13.255 0 24-10.745 24-24v-352.001c0-13.255-10.745-24-24-24z"></path> <path fill="#FFF" stroke="#FFF" d="m280 56h-24c-5.269 0-10.392 1.734-14.578 4.935l-103.459 79.116c-1.237.946-1.963 2.414-1.963 3.972v223.955c0 1.557.726 3.026 1.963 3.972l103.459 79.115c4.186 3.201 9.309 4.936 14.579 4.936h23.999c13.255 0 24-10.745 24-24v-352.001c0-13.255-10.745-24-24-24z"></path>
@ -603,10 +529,8 @@ const container = (
</svg> </svg>
</div> </div>
</div> </div>
<input id="virtual-keyboard" type="text" autocomplete="off" autocapitalize="none" autocorrect="off" /> <input id="virtual-keyboard" type="text" autocomplete="off" autocorrect="off" autocapitalize="none" />
</div> </div>
);
const splashScreen = (
<div id="splash-screen" class="hidden"> <div id="splash-screen" class="hidden">
<svg class="logo" preserveAspectRatio="xMidYMid" viewBox="0 0 380 150"> <svg class="logo" preserveAspectRatio="xMidYMid" viewBox="0 0 380 150">
<g> <g>
@ -621,8 +545,6 @@ const splashScreen = (
<div class="loadbar-inner"></div> <div class="loadbar-inner"></div>
</div> </div>
</div> </div>
);
const saveManager = (
<div id="save-manager" class="modal hidden"> <div id="save-manager" class="modal hidden">
<div id="modal-area" class="modal-area"> <div id="modal-area" class="modal-area">
<span class="close-modal"></span> <span class="close-modal"></span>
@ -632,8 +554,6 @@ const saveManager = (
<table id="local-saves"></table> <table id="local-saves"></table>
</div> </div>
</div> </div>
);
const volumeControlsModal = (
<div id="volume-controls-modal" class="modal hidden"> <div id="volume-controls-modal" class="modal hidden">
<div class="modal-area"> <div class="modal-area">
<div id="volume-controls"> <div id="volume-controls">
@ -648,16 +568,12 @@ const volumeControlsModal = (
</div> </div>
</div> </div>
</div> </div>
);
const videoModal = (
<div id="video-modal" class="modal hidden"> <div id="video-modal" class="modal hidden">
<div class="modal-area"> <div class="modal-area">
<span class="close-modal"></span> <span class="close-modal"></span>
<div id="video-holder"></div> <div id="video-holder"></div>
</div> </div>
</div> </div>
);
const hardwareModal = (
<div id="hardware-acceleration-modal" class="modal hidden"> <div id="hardware-acceleration-modal" class="modal hidden">
<div class="modal-area"> <div class="modal-area">
<span class="close-modal"></span> <span class="close-modal"></span>
@ -667,8 +583,6 @@ const hardwareModal = (
</a> </a>
</div> </div>
</div> </div>
);
const clipboardModal = (
<div id="clipboard-modal" class="modal hidden"> <div id="clipboard-modal" class="modal hidden">
<div class="modal-area"> <div class="modal-area">
<span class="close-modal"></span> <span class="close-modal"></span>
@ -688,27 +602,8 @@ const clipboardModal = (
</p> </p>
</div> </div>
</div> </div>
);
const contextMenuOverlay = (
<div id="context-menu-overlay" class="hidden"> <div id="context-menu-overlay" class="hidden">
<ul id="context-menu"></ul> <ul id="context-menu"></ul>
</div> </div>
); </template>
appendElement(ruffleShadowTemplate.content, staticStyles); ) as HTMLTemplateElement;
appendElement(ruffleShadowTemplate.content, dynamicStyles);
// Container append
appendElement(ruffleShadowTemplate.content, container);
// Splash screen append
appendElement(ruffleShadowTemplate.content, splashScreen);
// Save manager append
appendElement(ruffleShadowTemplate.content, saveManager);
// Volume control append
appendElement(ruffleShadowTemplate.content, volumeControlsModal);
// Video modal append
appendElement(ruffleShadowTemplate.content, videoModal);
// Hardware acceleration modal append
appendElement(ruffleShadowTemplate.content, hardwareModal);
// Clipboard modal append
appendElement(ruffleShadowTemplate.content, clipboardModal);
// Context menu overlay append
appendElement(ruffleShadowTemplate.content, contextMenuOverlay);