diff --git a/app/components/Settings/Toggle.client.vue b/app/components/Settings/Toggle.client.vue
index 29b07f6b62..20b9fd0c12 100644
--- a/app/components/Settings/Toggle.client.vue
+++ b/app/components/Settings/Toggle.client.vue
@@ -54,12 +54,13 @@ const id = useId()
{{ label }}
@@ -68,37 +69,10 @@ const id = useId()
diff --git a/app/plugins/input-switch-polyfill.client.ts b/app/plugins/input-switch-polyfill.client.ts
new file mode 100644
index 0000000000..1cb57ccc92
--- /dev/null
+++ b/app/plugins/input-switch-polyfill.client.ts
@@ -0,0 +1,30 @@
+export default defineNuxtPlugin({
+ // Don't hold up hydration for a polyfill that only the settings page needs.
+ parallel: true,
+ async setup() {
+ if (!('switch' in HTMLInputElement.prototype)) {
+ // @ts-expect-error input-switch-polyfill ships no types; imported for its side effect only
+ await import('input-switch-polyfill')
+
+ // The polyfill reads `accent-color` once at upgrade time and freezes the
+ // resolved color as `--switch-accent` in each element's inline style.
+ // Re-sync whenever the accent or color-mode changes so switches react live.
+ const syncSwitchAccent = () => {
+ const switches = document.querySelectorAll('input.switch')
+ const [first] = switches
+ if (!first) return
+ // All switches share the same cascade; read from the first one.
+ const color = getComputedStyle(first).getPropertyValue('accent-color').trim()
+ if (!color || color === 'auto') return
+ for (const el of switches) {
+ el.style.setProperty('--switch-accent', color)
+ }
+ }
+
+ new MutationObserver(syncSwitchAccent).observe(document.documentElement, {
+ attributes: true,
+ attributeFilter: ['style', 'class'],
+ })
+ }
+ },
+})
diff --git a/nuxt.config.ts b/nuxt.config.ts
index 5c7f2fec77..4f96c35513 100644
--- a/nuxt.config.ts
+++ b/nuxt.config.ts
@@ -32,7 +32,7 @@ export default defineNuxtConfig({
storageKey: 'npmx-color-mode',
},
- css: ['~/assets/main.css'],
+ css: ['~/assets/main.css', 'input-switch-polyfill/input-switch-polyfill.css'],
runtimeConfig: {
sessionPassword: '',
diff --git a/package.json b/package.json
index d4d7c45d72..3bbece17cc 100644
--- a/package.json
+++ b/package.json
@@ -90,6 +90,7 @@
"forges": "^0.3.2",
"gray-matter": "4.0.3",
"hls.js": "1.7.0",
+ "input-switch-polyfill": "1.12.0",
"ipaddr.js": "2.5.0",
"marked": "18.0.9",
"module-replacements": "3.3.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5808e48986..d80ed5a0f9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -207,6 +207,9 @@ importers:
hls.js:
specifier: 1.7.0
version: 1.7.0
+ input-switch-polyfill:
+ specifier: 1.12.0
+ version: 1.12.0
ipaddr.js:
specifier: 2.5.0
version: 2.5.0
@@ -7489,6 +7492,9 @@ packages:
resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ input-switch-polyfill@1.12.0:
+ resolution: {integrity: sha512-4IF+lwC4jjInFPWWjHDcVJWvWiTHm1RnGa+P9uLhOleal69NPbUnrcPHJJhuexyUqOnyA0QenXhtZNuZX4gqWA==}
+
internal-slot@1.1.0:
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
engines: {node: '>= 0.4'}
@@ -19379,6 +19385,8 @@ snapshots:
ini@4.1.1: {}
+ input-switch-polyfill@1.12.0: {}
+
internal-slot@1.1.0:
dependencies:
es-errors: 1.3.0