From d823d8fd81c8046df412a73064c937cc26543361 Mon Sep 17 00:00:00 2001 From: Anthony <29609366+anthony-hyo@users.noreply.github.com> Date: Mon, 22 Sep 2025 23:32:09 -0300 Subject: [PATCH 01/12] extension: Add per-site configuration settings modal --- web/packages/extension/assets/css/options.css | 213 +++++++- web/packages/extension/assets/options.html | 497 +++++++++++++++++- 2 files changed, 703 insertions(+), 7 deletions(-) diff --git a/web/packages/extension/assets/css/options.css b/web/packages/extension/assets/css/options.css index e199d4c77eff..75989f593a7e 100644 --- a/web/packages/extension/assets/css/options.css +++ b/web/packages/extension/assets/css/options.css @@ -12,12 +12,217 @@ padding: 24px 32px; } -#advanced-options { - color: var(--ruffle-orange); - font-size: 28px; - margin: 8px auto 0; +hr { + border: none; + height: 1px; + background-color: #546da3; + margin: 20px 0; + width: 100%; } #reset-settings { margin: 0 auto; } + +.option-title { + border-bottom: 2px solid var(--ruffle-light-blue); + padding-bottom: 8px; + margin-block-end: 0; + font-size: 1.2em; + color: var(--ruffle-orange); +} + +.option-description { + opacity: 0.8; + margin-block: 0.2em; +} + +/* Per-site settings */ + +#per-site-list { + display: flex; + flex-direction: column; + gap: 8px; +} + +.per-site-entry { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px; + border-radius: 8px; + background: var(--ruffle-dark-blue); +} + +.per-site-entry .site-domain { + font-weight: bold; +} + +#site-entry-new { + align-self: flex-start; +} + +/* Modal */ + +.modal-open { + overflow: hidden; +} + +.modal-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgb(0 0 0 / 70%); + display: none; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.modal-content { + background: var(--ruffle-blue); + border: 2px solid var(--ruffle-light-blue); + padding: 25px; + border-radius: 8px; + width: 90%; + max-width: 800px; + max-height: 90vh; + overflow-y: auto; + box-shadow: 0 5px 15px rgb(0 0 0 / 50%); + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); +} + +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.modal-header h3 { + margin: 0; + color: var(--ruffle-orange); +} + +.modal-close-btn { + font-size: 1.5rem; + cursor: pointer; + border: none; + background: none; + color: #aaa; +} + +.modal-body { + margin-top: 20px; +} + +.modal-footer { + margin-top: 25px; + display: flex; + gap: 10px; + justify-content: flex-end; +} + +/* Modal Scrollbar */ + +:root { + --scrollbar-width: 8px; + --scrollbar-track: rgb(255 255 255 / 10%); + --scrollbar-thumb: rgb(255 255 255 / 30%); + --scrollbar-thumb-hover: rgb(255 255 255 / 50%); + --scrollbar-border-radius: 4px; +} + +/* Webkit browsers (Chrome, Safari, Edge) */ +.modal-content::-webkit-scrollbar { + width: var(--scrollbar-width); + height: var(--scrollbar-width); +} + +.modal-content::-webkit-scrollbar-track { + background: var(--scrollbar-track); + border-radius: var(--scrollbar-border-radius); +} + +.modal-content::-webkit-scrollbar-thumb { + background: var(--scrollbar-thumb); + border-radius: var(--scrollbar-border-radius); + transition: background-color 0.2s ease; +} + +.modal-content::-webkit-scrollbar-thumb:hover { + background: var(--scrollbar-thumb-hover); +} + +.modal-content::-webkit-scrollbar-corner { + background: var(--scrollbar-track); +} + +.modal-content::-webkit-scrollbar-button { + display: none; +} + +/* Sections */ + +.settings-section > * { + margin-bottom: 20px; + padding-bottom: 15px; + border-bottom: 2px solid var(--ruffle-light-blue); +} + +.settings-section > :last-child { + margin-bottom: 0; + padding-bottom: 0; + border-bottom: none; +} + +.settings-section-title { + font-size: 1.1em; + font-weight: bold; + color: var(--ruffle-orange); + margin-bottom: 10px; +} + +/* Per-site override options */ + +.settings-option { + display: grid; + grid-template-columns: 40px 1fr; + align-items: start; + gap: 15px; + padding: 12px 0; + border-bottom: 1px solid var(--ruffle-light-blue); +} + +.settings-option-toggle { + margin: auto 0; +} + +.settings-option:last-child { + border-bottom: none; +} + +.settings-option .settings-option-control.settings-option-disabled { + pointer-events: none; + opacity: 0.5; +} + +/* Per-site override option label and description */ + +.settings-option-control { + display: flex; + flex-direction: column; + gap: 5px; +} + +.settings-option-control label { + font-weight: bold; +} + +.settings-option-control small { + font-size: 0.8em; + color: #ccc; + opacity: 0.8; +} diff --git a/web/packages/extension/assets/options.html b/web/packages/extension/assets/options.html index 6431a4121f44..571aa18d883d 100644 --- a/web/packages/extension/assets/options.html +++ b/web/packages/extension/assets/options.html @@ -16,7 +16,10 @@
nightly YYYY-MM-DD
+
+

Global Settings

+
@@ -33,7 +36,9 @@
-
Advanced Options
+ +

Advanced Options

+
@@ -59,15 +64,501 @@
- +
- +
+ +

Per-Site Options

+ +

Override global options for specific websites.

+ +
+
+ example.com +
+ + +
+
+ +
+ example.com +
+ + +
+
+
+ + +
+ + + + + From 3401ed49fbe71894e10e259b9f52cb8cabb0aabd Mon Sep 17 00:00:00 2001 From: Anthony <29609366+anthony-hyo@users.noreply.github.com> Date: Tue, 23 Sep 2025 02:27:55 -0300 Subject: [PATCH 02/12] extension: Improve per-site settings with detailed descriptions and select inputs --- web/packages/extension/assets/options.html | 67 +++++++++++++--------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/web/packages/extension/assets/options.html b/web/packages/extension/assets/options.html index 571aa18d883d..360e70012e3d 100644 --- a/web/packages/extension/assets/options.html +++ b/web/packages/extension/assets/options.html @@ -153,7 +153,7 @@

Site-Specific Settings

- HTML color for the background (null for SWF default). + HTML color for the background.
@@ -162,9 +162,9 @@

Site-Specific Settings

Controls letterbox behavior when container size doesn't match movie size.
@@ -191,11 +191,11 @@

Site-Specific Settings

Controls how Ruffle is layered with other content.
@@ -205,28 +205,43 @@

Site-Specific Settings

- + Equivalent to Stage.scaleMode (e.g., "showAll", "noBorder", "exactFit", "noScale").
-
- -
- - - Equivalent to Stage.align (e.g., "TL", "TR", "BL", "BR", "T", "B", "L", "R"). -
-
+
+ +
+ + + Equivalent to Stage.align. Choose how content is anchored in the container. +
+
-
- -
- - - Equivalent to Stage.quality (e.g., "low", "medium", "high", "best"). -
-
+
+ +
+ + + Equivalent to Stage.quality (e.g., "low", "medium", "high", "best"). +
+
From f1aa35ebf48fa3200cc967ff9c8c22c75b5caae4 Mon Sep 17 00:00:00 2001 From: Anthony <29609366+anthony-hyo@users.noreply.github.com> Date: Thu, 25 Sep 2025 05:15:24 -0300 Subject: [PATCH 03/12] extension: Add missing per-site configuration options --- web/packages/extension/assets/options.html | 137 ++++++++++++++++++--- 1 file changed, 123 insertions(+), 14 deletions(-) diff --git a/web/packages/extension/assets/options.html b/web/packages/extension/assets/options.html index 360e70012e3d..381ba7a0bb6f 100644 --- a/web/packages/extension/assets/options.html +++ b/web/packages/extension/assets/options.html @@ -181,6 +181,27 @@

Site-Specific Settings

Show unmute overlay when player is muted.
+ +
+ +
+ + + Whether or not to show a splash screen before the SWF has loaded with Ruffle (backwards-compatibility). +
+
+ +
+ +
+ + + Values that may be passed to and loaded by the movie. +
+
@@ -242,7 +263,20 @@

Site-Specific Settings

Equivalent to Stage.quality (e.g., "low", "medium", "high", "best").
- + +
+ +
+ + + Defines the scrolling behavior of Flash content on the web page. +
+
+
Performance
@@ -319,6 +353,46 @@

Site-Specific Settings

Console logging level for this site.
+ +
+ +
+ + + The URL at which Ruffle can load its extra files (i.e. '.wasm'). +
+
+ +
+ +
+ + + Enable polyfills on the page for legacy Flash content. +
+
+ +
+ +
+ + + List of font URLs separated by comma to load. +
+
+ + +
@@ -385,6 +459,54 @@

Site-Specific Settings

Prefer real Adobe Flash Player if available.
+ + + + + + + +
+ +
+ + + List of origins separated by comma to which credentials can be sent. +
+
+ +
+ +
+ + + Mapping of gamepad buttons to ActionScript key codes. +
+
+ + +
@@ -500,19 +622,6 @@

Site-Specific Settings

Base directory/URL for resolving relative paths in SWF.
- -
- -
- - - How scrolling Flash content affects the web page. -
-
From 65b5a20e885c349f650f88e46f7df884f2c620f5 Mon Sep 17 00:00:00 2001 From: Anthony <29609366+anthony-hyo@users.noreply.github.com> Date: Fri, 26 Sep 2025 02:37:39 -0300 Subject: [PATCH 04/12] extension: Improve label discovery in getElement --- web/packages/extension/src/common.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web/packages/extension/src/common.ts b/web/packages/extension/src/common.ts index 4dec1094742b..29f1f7cb3b72 100644 --- a/web/packages/extension/src/common.ts +++ b/web/packages/extension/src/common.ts @@ -111,7 +111,13 @@ class SelectOption implements OptionElement { } function getElement(option: Element): OptionElement { - const label = option.getElementsByTagName("label")[0]!; + const element = option.querySelector( + "input, select", + )!; + + const label = option.querySelector( + `label[for="${element.id}"]`, + )!; const [input] = option.getElementsByTagName("input"); if (input) { From 4e5351337f7788d4aba1921e8e98e25a77df429f Mon Sep 17 00:00:00 2001 From: Anthony <29609366+anthony-hyo@users.noreply.github.com> Date: Fri, 26 Sep 2025 02:50:25 -0300 Subject: [PATCH 05/12] extension: Improve getElement elements discovery and validation --- web/packages/extension/src/common.ts | 33 ++++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/web/packages/extension/src/common.ts b/web/packages/extension/src/common.ts index 29f1f7cb3b72..9c9550aea8da 100644 --- a/web/packages/extension/src/common.ts +++ b/web/packages/extension/src/common.ts @@ -113,26 +113,31 @@ class SelectOption implements OptionElement { function getElement(option: Element): OptionElement { const element = option.querySelector( "input, select", - )!; + ); + + if (!element) { + throw new Error( + "No input or select element found inside the option container.", + ); + } const label = option.querySelector( `label[for="${element.id}"]`, - )!; - - const [input] = option.getElementsByTagName("input"); - if (input) { - if (input.type === "checkbox") { - return new CheckboxOption(input, label); - } + ); - if (input.type === "number") { - return new NumberOption(input, label); - } + if (!label) { + throw new Error(`No label found with for="${element.id}"`); } - const [select] = option.getElementsByTagName("select"); - if (select) { - return new SelectOption(select, label); + if (element instanceof HTMLInputElement) { + switch (element.type) { + case "checkbox": + return new CheckboxOption(element, label); + case "number": + return new NumberOption(element, label); + } + } else if (element instanceof HTMLSelectElement) { + return new SelectOption(element, label); } throw new Error("Unknown option element"); From eee073c8d0b5450e6d16cc28f5611c2c429c11a9 Mon Sep 17 00:00:00 2001 From: Anthony <29609366+anthony-hyo@users.noreply.github.com> Date: Sat, 27 Sep 2025 01:12:55 -0300 Subject: [PATCH 06/12] extension: New form styles --- web/packages/extension/assets/css/form.css | 95 ++++++++++++++++++++++ web/packages/extension/assets/options.html | 1 + 2 files changed, 96 insertions(+) create mode 100644 web/packages/extension/assets/css/form.css diff --git a/web/packages/extension/assets/css/form.css b/web/packages/extension/assets/css/form.css new file mode 100644 index 000000000000..b5499e39bf5f --- /dev/null +++ b/web/packages/extension/assets/css/form.css @@ -0,0 +1,95 @@ +.form-element { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 5px; +} + +.form-element .form-label { + font-weight: bold; +} + +.form-element .form-group { + display: flex; + flex-direction: column; + gap: 5px; +} + +.form-type-number { + width: 60px; +} + +.form-type-text { + width: 124px; +} + +/* Switch - Based on "Pure CSS Slider Checkboxes": https://codepen.io/Qvcool/pen/bdzVYW */ + +.form-type-switch { + position: relative; +} + +.form-type-switch input { + margin: 1px 0 0; + cursor: pointer; + opacity: 0; + position: absolute; + z-index: 1; + top: 0; + left: 0; + background: red; + width: 40px; + height: 20px; +} + +.form-type-switch, +.form-type-switch .slider, +.form-type-switch .slider:before { + height: 20px; +} + +.form-type-switch input:checked + .slider:before { + background-color: var(--ruffle-orange); + content: ""; + padding-left: 6px; +} + +.form-type-switch input:checked + .slider:after { + left: 21px; +} + +.form-type-switch .slider { + position: relative; + padding-left: 46px; +} + +.form-type-switch .slider:before, .form-type-switch .slider:after { + position: absolute; + border-radius: 10px; + transition: background-color 0.3s, left 0.3s; +} + +.form-type-switch .slider:before { + content: ""; + color: #fff; + box-sizing: border-box; + padding-left: 23px; + font-size: 12px; + line-height: 20px; + background-color: #888; + left: 0; + top: 0; + height: 20px; + width: 40px; + border-radius: 10px; +} + +.form-type-switch .slider:after { + content: ""; + letter-spacing: 20px; + background: #fff; + left: 1px; + top: 1px; + height: 18px; + width: 18px; +} diff --git a/web/packages/extension/assets/options.html b/web/packages/extension/assets/options.html index 381ba7a0bb6f..202010db8671 100644 --- a/web/packages/extension/assets/options.html +++ b/web/packages/extension/assets/options.html @@ -7,6 +7,7 @@ Ruffle Settings + From fcda2c0c0bf766cdf33f10769f41d33b1e1b3054 Mon Sep 17 00:00:00 2001 From: Anthony <29609366+anthony-hyo@users.noreply.github.com> Date: Sat, 27 Sep 2025 01:13:29 -0300 Subject: [PATCH 07/12] extension: Remove inline JS --- web/packages/extension/assets/options.html | 49 -------------------- web/packages/extension/src/options.ts | 52 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 49 deletions(-) diff --git a/web/packages/extension/assets/options.html b/web/packages/extension/assets/options.html index 202010db8671..e889c7c5eaf7 100644 --- a/web/packages/extension/assets/options.html +++ b/web/packages/extension/assets/options.html @@ -635,55 +635,6 @@

Site-Specific Settings

- - diff --git a/web/packages/extension/src/options.ts b/web/packages/extension/src/options.ts index 4257116dc35c..2955f9913486 100644 --- a/web/packages/extension/src/options.ts +++ b/web/packages/extension/src/options.ts @@ -30,5 +30,57 @@ window.addEventListener("DOMContentLoaded", async () => { } }); } + + const modal = document.getElementById("site-settings-modal")!; + const addNewBtn = document.getElementById("site-entry-new")!; + const closeBtns = document.querySelectorAll( + ".modal-close-btn, #modal-cancel-btn", + ); + + const openModal = () => { + modal.style.display = "flex"; + document.body.classList.add("modal-open"); + }; + + const closeModal = () => { + modal.style.display = "none"; + document.body.classList.remove("modal-open"); + }; + + addNewBtn.addEventListener("click", openModal); + + closeBtns.forEach((btn) => btn.addEventListener("click", closeModal)); + + document.querySelectorAll(".edit-site-btn").forEach((btn) => { + btn.addEventListener("click", openModal); + }); + + document.querySelectorAll(".settings-option").forEach((option) => { + const switchEl = option.querySelector( + ".settings-option-toggle", + )!; + const controlId = switchEl.dataset["optionId"]; + const controlContainer = document.getElementById( + `control-${controlId}`, + ); + + if (!controlContainer) { + console.warn(`Element with id control-${controlId} not found.`); + return; + } + + const toggleControl = () => { + if (switchEl.checked) { + controlContainer.classList.remove("settings-option-disabled"); + } else { + controlContainer.classList.add("settings-option-disabled"); + } + }; + + switchEl.addEventListener("change", toggleControl); + + toggleControl(); + }); + bindOptions(); }); From 107fcc496f2da456618e7f124ad81066e8349df6 Mon Sep 17 00:00:00 2001 From: Anthony <29609366+anthony-hyo@users.noreply.github.com> Date: Sat, 27 Sep 2025 01:15:24 -0300 Subject: [PATCH 08/12] extension: Refactor options layout with the new form styles --- web/packages/extension/assets/options.html | 73 +++++++++++++--------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/web/packages/extension/assets/options.html b/web/packages/extension/assets/options.html index e889c7c5eaf7..9771a2a5843b 100644 --- a/web/packages/extension/assets/options.html +++ b/web/packages/extension/assets/options.html @@ -18,59 +18,74 @@
nightly YYYY-MM-DD
-
+

Global Settings

-
- - +
+ +
+ +
+
-
- - +
+ +
+ +
+
-
- - +
+ +
+ +
+
-
- - +
+ +
+ +
+
-

Advanced Options

+

Advanced Options

-
- - +
+ +
+ +
+
-
- -
-
- -
-
- - +
+ +
-
- - +
+ +

Per-Site Options

From e19cf15d0a926ea5f109311d2741efee386a1245 Mon Sep 17 00:00:00 2001 From: Anthony <29609366+anthony-hyo@users.noreply.github.com> Date: Sat, 27 Sep 2025 01:16:42 -0300 Subject: [PATCH 09/12] extension: Dynamic setting generation --- web/packages/extension/assets/css/options.css | 32 +- web/packages/extension/assets/options.html | 525 +------------- web/packages/extension/src/options.ts | 662 ++++++++++++++++++ 3 files changed, 710 insertions(+), 509 deletions(-) diff --git a/web/packages/extension/assets/css/options.css b/web/packages/extension/assets/css/options.css index 75989f593a7e..fc05b429e37b 100644 --- a/web/packages/extension/assets/css/options.css +++ b/web/packages/extension/assets/css/options.css @@ -21,24 +21,30 @@ hr { } #reset-settings { - margin: 0 auto; + display: block; + margin-left: auto; + margin-right: auto; } .option-title { border-bottom: 2px solid var(--ruffle-light-blue); padding-bottom: 8px; - margin-block-end: 0; + margin-block-end: 10px; font-size: 1.2em; color: var(--ruffle-orange); } .option-description { opacity: 0.8; - margin-block: 0.2em; + margin-block: 15px; + margin-left: 5px; } /* Per-site settings */ +.per-site { +} + #per-site-list { display: flex; flex-direction: column; @@ -59,7 +65,8 @@ hr { } #site-entry-new { - align-self: flex-start; + display: block; + margin: 10px 0 10px auto; } /* Modal */ @@ -167,9 +174,7 @@ hr { /* Sections */ .settings-section > * { - margin-bottom: 20px; padding-bottom: 15px; - border-bottom: 2px solid var(--ruffle-light-blue); } .settings-section > :last-child { @@ -192,7 +197,6 @@ hr { grid-template-columns: 40px 1fr; align-items: start; gap: 15px; - padding: 12px 0; border-bottom: 1px solid var(--ruffle-light-blue); } @@ -217,12 +221,18 @@ hr { gap: 5px; } -.settings-option-control label { - font-weight: bold; -} - .settings-option-control small { font-size: 0.8em; color: #ccc; opacity: 0.8; } + +.settings-row { + display: flex; + justify-content: space-between; + align-items: center; +} + +.settings-row label { + font-weight: bold; +} diff --git a/web/packages/extension/assets/options.html b/web/packages/extension/assets/options.html index 9771a2a5843b..e5da4af34303 100644 --- a/web/packages/extension/assets/options.html +++ b/web/packages/extension/assets/options.html @@ -92,25 +92,27 @@

Per-Site Options

Override global options for specific websites.

-
-
- example.com -
- - +
+
+
+ example.com +
+ + +
-
-
- example.com -
- - +
+ example.com +
+ + +
-
- + +
@@ -127,7 +129,7 @@

Site-Specific Settings