From c1a474580714c02cb57b3cf24f7bbd607ff59367 Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Sat, 22 Aug 2026 19:20:56 +0000
Subject: [PATCH 01/24] Add Vue SPA scaffolding with https dev server
---
.env.example | 11 +
.gitignore | 3 +
package-lock.json | 1363 ++++++++++++++++-
package.json | 7 +-
src_assets/common/assets/web/Navbar.vue | 150 --
src_assets/common/assets/web/NavbarSimple.vue | 20 -
src_assets/common/assets/web/index.html | 307 +---
src_assets/common/assets/web/src/App.vue | 13 +
.../assets/web/{ => src/assets}/sunshine.css | 0
.../web/{ => src/components}/Checkbox.vue | 0
.../assets/web/src/components/Layout.vue | 19 +
.../assets/web/src/components/Navbar.vue | 107 ++
.../web/{ => src/components}/Notification.vue | 0
.../{ => src/components}/PlatformLayout.vue | 0
.../web/{ => src/components}/ResourceCard.vue | 0
.../web/{ => src/components}/SimpleIcon.vue | 0
.../web/{ => src/components}/ThemeToggle.vue | 79 +-
.../components}/configs/tabs/Advanced.vue | 0
.../components}/configs/tabs/AudioVideo.vue | 0
.../configs/tabs/ContainerEncoders.vue | 0
.../components}/configs/tabs/Files.vue | 0
.../components}/configs/tabs/General.vue | 0
.../components}/configs/tabs/Inputs.vue | 0
.../components}/configs/tabs/Network.vue | 0
.../tabs/audiovideo/AdapterNameSelector.vue | 0
.../tabs/audiovideo/DisplayDeviceOptions.vue | 0
.../tabs/audiovideo/DisplayModesSettings.vue | 0
.../tabs/audiovideo/DisplayOutputSelector.vue | 0
.../configs/tabs/encoders/AmdAmfEncoder.vue | 0
.../tabs/encoders/IntelQuickSyncEncoder.vue | 0
.../tabs/encoders/NvidiaNvencEncoder.vue | 0
.../configs/tabs/encoders/SoftwareEncoder.vue | 0
.../configs/tabs/encoders/VAAPIEncoder.vue | 0
.../tabs/encoders/VideotoolboxEncoder.vue | 0
.../configs/tabs/encoders/VulkanEncoder.vue | 0
src_assets/common/assets/web/src/main.js | 10 +
.../common/assets/web/src/router/index.js | 65 +
.../assets/web/{ => src/utils}/fetch_utils.js | 2 +-
.../common/assets/web/{ => src/utils}/init.js | 4 +-
.../assets/web/{ => src/utils}/locale.js | 5 +-
.../web/{ => src/utils}/platform-i18n.js | 0
.../web/{ => src/utils}/sunshine_version.js | 0
.../assets/web/{ => src/utils}/theme.js | 0
.../common/assets/web/src/views/AppsView.vue | 8 +
.../assets/web/src/views/ConfigView.vue | 8 +
.../assets/web/src/views/FeaturedView.vue | 8 +
.../common/assets/web/src/views/IndexView.vue | 8 +
.../assets/web/src/views/LogoutView.vue | 8 +
.../assets/web/src/views/PasswordView.vue | 8 +
.../common/assets/web/src/views/PinView.vue | 8 +
.../web/src/views/TroubleshootingView.vue | 8 +
.../assets/web/src/views/WelcomeView.vue | 8 +
.../assets/web/{ => src/views}/apps.html | 0
.../assets/web/{ => src/views}/config.html | 0
.../assets/web/{ => src/views}/featured.html | 0
.../common/assets/web/src/views/index.html | 295 ++++
.../assets/web/{ => src/views}/logout.html | 0
.../assets/web/{ => src/views}/password.html | 0
.../assets/web/{ => src/views}/pin.html | 0
.../web/{ => src/views}/troubleshooting.html | 0
.../assets/web/{ => src/views}/welcome.html | 0
.../common/assets/web/template_header.html | 6 -
tests/CMakeLists.txt | 4 +-
vite.config.js | 104 +-
64 files changed, 2028 insertions(+), 618 deletions(-)
create mode 100644 .env.example
delete mode 100644 src_assets/common/assets/web/Navbar.vue
delete mode 100644 src_assets/common/assets/web/NavbarSimple.vue
create mode 100644 src_assets/common/assets/web/src/App.vue
rename src_assets/common/assets/web/{ => src/assets}/sunshine.css (100%)
rename src_assets/common/assets/web/{ => src/components}/Checkbox.vue (100%)
create mode 100644 src_assets/common/assets/web/src/components/Layout.vue
create mode 100644 src_assets/common/assets/web/src/components/Navbar.vue
rename src_assets/common/assets/web/{ => src/components}/Notification.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/PlatformLayout.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/ResourceCard.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/SimpleIcon.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/ThemeToggle.vue (74%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/Advanced.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/AudioVideo.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/ContainerEncoders.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/Files.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/General.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/Inputs.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/Network.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/audiovideo/AdapterNameSelector.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/audiovideo/DisplayDeviceOptions.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/audiovideo/DisplayModesSettings.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/audiovideo/DisplayOutputSelector.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/encoders/AmdAmfEncoder.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/encoders/IntelQuickSyncEncoder.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/encoders/NvidiaNvencEncoder.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/encoders/SoftwareEncoder.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/encoders/VAAPIEncoder.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/encoders/VideotoolboxEncoder.vue (100%)
rename src_assets/common/assets/web/{ => src/components}/configs/tabs/encoders/VulkanEncoder.vue (100%)
create mode 100644 src_assets/common/assets/web/src/main.js
create mode 100644 src_assets/common/assets/web/src/router/index.js
rename src_assets/common/assets/web/{ => src/utils}/fetch_utils.js (94%)
rename src_assets/common/assets/web/{ => src/utils}/init.js (95%)
rename src_assets/common/assets/web/{ => src/utils}/locale.js (85%)
rename src_assets/common/assets/web/{ => src/utils}/platform-i18n.js (100%)
rename src_assets/common/assets/web/{ => src/utils}/sunshine_version.js (100%)
rename src_assets/common/assets/web/{ => src/utils}/theme.js (100%)
create mode 100644 src_assets/common/assets/web/src/views/AppsView.vue
create mode 100644 src_assets/common/assets/web/src/views/ConfigView.vue
create mode 100644 src_assets/common/assets/web/src/views/FeaturedView.vue
create mode 100644 src_assets/common/assets/web/src/views/IndexView.vue
create mode 100644 src_assets/common/assets/web/src/views/LogoutView.vue
create mode 100644 src_assets/common/assets/web/src/views/PasswordView.vue
create mode 100644 src_assets/common/assets/web/src/views/PinView.vue
create mode 100644 src_assets/common/assets/web/src/views/TroubleshootingView.vue
create mode 100644 src_assets/common/assets/web/src/views/WelcomeView.vue
rename src_assets/common/assets/web/{ => src/views}/apps.html (100%)
rename src_assets/common/assets/web/{ => src/views}/config.html (100%)
rename src_assets/common/assets/web/{ => src/views}/featured.html (100%)
create mode 100644 src_assets/common/assets/web/src/views/index.html
rename src_assets/common/assets/web/{ => src/views}/logout.html (100%)
rename src_assets/common/assets/web/{ => src/views}/password.html (100%)
rename src_assets/common/assets/web/{ => src/views}/pin.html (100%)
rename src_assets/common/assets/web/{ => src/views}/troubleshooting.html (100%)
rename src_assets/common/assets/web/{ => src/views}/welcome.html (100%)
delete mode 100644 src_assets/common/assets/web/template_header.html
diff --git a/.env.example b/.env.example
new file mode 100644
index 00000000000..ea140e0adbc
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,11 @@
+# Copy this file to .env to override Vite dev server settings locally.
+# Uncomment and adjust as needed; unset variables fall back to Vite's defaults.
+
+# Bind the dev server to all interfaces (needed for devcontainer/Codespaces port forwarding).
+# VITE_DEV_HOST=0.0.0.0
+
+# Port for the Vite dev server (`npm run dev-server`).
+# VITE_DEV_PORT=5173
+
+# Base URL of a running `sunshine` backend to proxy /api, /images, and /covers requests to.
+# VITE_BACKEND_URL=https://localhost:47990
diff --git a/.gitignore b/.gitignore
index c8babd4080f..1ef62d9e99d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,6 +45,9 @@ docs/doxyconfig*
# npm
node_modules/
+# local Vite dev server overrides
+.env
+
# Translations
*.mo
*.pot
diff --git a/package-lock.json b/package-lock.json
index 0cfcb854fb8..d761f7d0b99 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,14 +14,17 @@
"marked": "18.0.11",
"vue": "3.5.41",
"vue-i18n": "11.4.10",
+ "vue-router": "4.6.4",
"vue3-simple-icons": "16.10.0"
},
"devDependencies": {
"@codecov/vite-plugin": "2.0.1",
+ "@vitejs/plugin-basic-ssl": "2.3.0",
"@vitejs/plugin-vue": "6.0.8",
+ "@vitejs/plugin-vue-jsx": "5.1.6",
"serve": "14.2.6",
"vite": "6.4.3",
- "vite-plugin-ejs": "2.0.0"
+ "vite-plugin-vue-devtools": "8.1.5"
}
},
"node_modules/@actions/core": {
@@ -90,6 +93,277 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helpers": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@babel/core/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node_modules/@babel/core/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz",
+ "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/parser": "^7.29.8",
+ "@babel/types": "^7.29.8",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz",
+ "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz",
+ "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-member-expression-to-functions": "^7.29.7",
+ "@babel/helper-optimise-call-expression": "^7.29.7",
+ "@babel/helper-replace-supers": "^7.29.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz",
+ "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz",
+ "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz",
+ "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^7.29.7",
+ "@babel/helper-optimise-call-expression": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz",
+ "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-string-parser": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
@@ -108,6 +382,28 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/parser": {
"version": "7.29.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
@@ -123,6 +419,169 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@babel/plugin-proposal-decorators": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.7.tgz",
+ "integrity": "sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/plugin-syntax-decorators": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-decorators": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.29.7.tgz",
+ "integrity": "sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-attributes": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz",
+ "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-meta": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+ "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz",
+ "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-typescript": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz",
+ "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typescript": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz",
+ "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.29.7",
+ "@babel/helper-create-class-features-plugin": "^7.29.7",
+ "@babel/helper-plugin-utils": "^7.29.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7",
+ "@babel/plugin-syntax-typescript": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz",
+ "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.8",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.8",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.8",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
"node_modules/@babel/types": {
"version": "7.29.8",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
@@ -674,12 +1133,51 @@
"url": "https://github.com/sponsors/kazupon"
}
},
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT"
},
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
"node_modules/@lucide/vue": {
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/@lucide/vue/-/vue-1.33.0.tgz",
@@ -697,9 +1195,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -881,6 +1376,12 @@
"@octokit/openapi-types": "^28.0.0"
}
},
+ "node_modules/@polka/url": {
+ "version": "1.0.0-next.29",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
+ "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
+ "dev": true
+ },
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
@@ -991,9 +1492,6 @@
"arm"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1008,9 +1506,6 @@
"arm"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1025,9 +1520,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1042,9 +1534,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1059,9 +1548,6 @@
"loong64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1076,9 +1562,6 @@
"loong64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1093,9 +1576,6 @@
"ppc64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1110,9 +1590,6 @@
"ppc64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1127,9 +1604,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1144,9 +1618,6 @@
"riscv64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1161,9 +1632,6 @@
"s390x"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1178,9 +1646,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1195,9 +1660,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -1295,6 +1757,29 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/node": {
+ "version": "24.13.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
+ "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
+ "dev": true,
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "undici-types": "~7.18.0"
+ }
+ },
+ "node_modules/@vitejs/plugin-basic-ssl": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.3.0.tgz",
+ "integrity": "sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ==",
+ "dev": true,
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
"node_modules/@vitejs/plugin-vue": {
"version": "6.0.8",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.8.tgz",
@@ -1312,6 +1797,76 @@
"vue": "^3.2.25"
}
},
+ "node_modules/@vitejs/plugin-vue-jsx": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-5.1.6.tgz",
+ "integrity": "sha512-YXvi4as2clxt6DFw5+a0tTA97ntiQXm/raR8ofNj3aNwwdlVGTiG2gp7EvfZW17P50acL/9bP0ccF4XnqNmlgA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.29.0",
+ "@babel/plugin-syntax-typescript": "^7.29.7",
+ "@babel/plugin-transform-typescript": "^7.29.7",
+ "@rolldown/pluginutils": "^1.0.1",
+ "@vue/babel-plugin-jsx": "^2.0.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+ "vue": "^3.0.0"
+ }
+ },
+ "node_modules/@vue/babel-helper-vue-transform-on": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-2.0.1.tgz",
+ "integrity": "sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==",
+ "dev": true
+ },
+ "node_modules/@vue/babel-plugin-jsx": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-2.0.1.tgz",
+ "integrity": "sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/plugin-syntax-jsx": "^7.27.1",
+ "@babel/template": "^7.27.2",
+ "@babel/traverse": "^7.28.4",
+ "@babel/types": "^7.28.4",
+ "@vue/babel-helper-vue-transform-on": "2.0.1",
+ "@vue/babel-plugin-resolve-type": "2.0.1",
+ "@vue/shared": "^3.5.22"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vue/babel-plugin-resolve-type": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-2.0.1.tgz",
+ "integrity": "sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/parser": "^7.28.4",
+ "@vue/compiler-sfc": "^3.5.22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@vue/compiler-core": {
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.41.tgz",
@@ -1368,6 +1923,37 @@
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
+ "node_modules/@vue/devtools-core": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-8.2.1.tgz",
+ "integrity": "sha512-s/VfAY9oDTb/kFEWmy461jaFde2MIV1RO/gi1vwM+PAZBZ/Pc2Ndu3BNBdZUze8QDUuyYvElbEEGA83syjJfzA==",
+ "dev": true,
+ "dependencies": {
+ "@vue/devtools-kit": "^8.2.1",
+ "@vue/devtools-shared": "^8.2.1"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.0"
+ }
+ },
+ "node_modules/@vue/devtools-kit": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.2.1.tgz",
+ "integrity": "sha512-FIGIuq3AWReEpbAHY/cRGeHDfI0qOb8OCQ3YjbEAX04uaxIDbGc9rhkbVcG7rnfHPXE3RsU5KrWOu9V/okd8AQ==",
+ "dev": true,
+ "dependencies": {
+ "@vue/devtools-shared": "^8.2.1",
+ "birpc": "^2.6.1",
+ "hookable": "^5.5.3",
+ "perfect-debounce": "^2.0.0"
+ }
+ },
+ "node_modules/@vue/devtools-shared": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.2.1.tgz",
+ "integrity": "sha512-Fkac7lUdGReh6pVOi3AYPRGe82LQqRmAfThW7RRligOAP0ZA/Z1z9XLHDM9dv34pV2HRc79DK8uKPeG2fLnA/g==",
+ "dev": true
+ },
"node_modules/@vue/reactivity": {
"version": "3.5.41",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.41.tgz",
@@ -1537,6 +2123,15 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/ansis": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz",
+ "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==",
+ "dev": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/arch": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
@@ -1572,6 +2167,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.11.18",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.18.tgz",
+ "integrity": "sha512-1iEmLEYSiE1SeBoAfPo/Mnx3PzfzHUkDK61ASkCpuk3YXugYLH5DYK1SzqV55F8FMI6s0F+/tCP7Polz1QRjxw==",
+ "dev": true,
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/before-after-hook": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz",
@@ -1579,6 +2186,15 @@
"dev": true,
"license": "Apache-2.0"
},
+ "node_modules/birpc": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz",
+ "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/bootstrap": {
"version": "5.3.8",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz",
@@ -1645,6 +2261,54 @@
"concat-map": "0.0.1"
}
},
+ "node_modules/browserslist": {
+ "version": "4.28.8",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz",
+ "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "baseline-browser-mapping": "^2.11.12",
+ "caniuse-lite": "^1.0.30001809",
+ "electron-to-chromium": "^1.5.402",
+ "node-releases": "^2.0.53",
+ "update-browserslist-db": "^1.3.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/bundle-name": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+ "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+ "dev": true,
+ "dependencies": {
+ "run-applescript": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -1668,6 +2332,26 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001809",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz",
+ "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ]
+ },
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -1815,6 +2499,12 @@
"url": "https://opencollective.com/express"
}
},
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -1866,6 +2556,46 @@
"node": ">=4.0.0"
}
},
+ "node_modules/default-browser": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz",
+ "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==",
+ "dev": true,
+ "dependencies": {
+ "bundle-name": "^4.1.0",
+ "default-browser-id": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser-id": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz",
+ "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/define-lazy-prop": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+ "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -1873,19 +2603,11 @@
"dev": true,
"license": "MIT"
},
- "node_modules/ejs": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ejs/-/ejs-6.0.1.tgz",
- "integrity": "sha512-UaaM14yby8U3k02ihS1Bmj5Kz2d7CCQM1scxpgs4Mhkq8F1wR2gl3+Ts4h5Ne4Mnt7M9m4Dw7jsuMr3+xO4vZA==",
- "dev": true,
- "license": "Apache-2.0",
- "peer": true,
- "bin": {
- "ejs": "bin/cli.js"
- },
- "engines": {
- "node": ">=0.12.18"
- }
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.412",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.412.tgz",
+ "integrity": "sha512-z4rMe3esBzlzovKHj4gxJnsCGZRK5l4baUvm+gCGJBPE+gsyUMKsuU9tnEUtI1dOebXz1ytAPGjvXhmQ7rIPwA==",
+ "dev": true
},
"node_modules/emoji-regex": {
"version": "9.2.2",
@@ -1906,6 +2628,15 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
+ "node_modules/error-stack-parser-es": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz",
+ "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/esbuild": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
@@ -1948,6 +2679,15 @@
"@esbuild/win32-x64": "0.25.12"
}
},
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@@ -2035,6 +2775,15 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/get-stream": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
@@ -2058,6 +2807,12 @@
"node": ">=8"
}
},
+ "node_modules/hookable": {
+ "version": "5.5.3",
+ "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
+ "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
+ "dev": true
+ },
"node_modules/human-signals": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -2101,6 +2856,51 @@
"node": ">=8"
}
},
+ "node_modules/is-in-ssh": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz",
+ "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==",
+ "dev": true,
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-inside-container": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+ "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+ "dev": true,
+ "dependencies": {
+ "is-docker": "^3.0.0"
+ },
+ "bin": {
+ "is-inside-container": "cli.js"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-inside-container/node_modules/is-docker": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+ "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+ "dev": true,
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-port-reachable": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-4.0.0.tgz",
@@ -2147,6 +2947,24 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
@@ -2161,6 +2979,33 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/kolorist": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
+ "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
+ "dev": true
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -2255,6 +3100,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/mrmime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
+ "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@@ -2290,6 +3144,15 @@
"node": ">= 0.6"
}
},
+ "node_modules/node-releases": {
+ "version": "2.0.53",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz",
+ "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -2303,6 +3166,25 @@
"node": ">=8"
}
},
+ "node_modules/obug": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz",
+ "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/sxzz",
+ "https://opencollective.com/debug"
+ ],
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/ohash": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.12.tgz",
+ "integrity": "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==",
+ "dev": true
+ },
"node_modules/on-headers": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
@@ -2329,6 +3211,26 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/open": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/open/-/open-11.0.1.tgz",
+ "integrity": "sha512-NzwMUB6C1D0+Kd+9iMS/H4k+Ck3cTX6Ckyfr/gAGlmvSE1LUQZnEZvWBi4PYmMwH/S5SMeTXnE+9uAz8uF+pWw==",
+ "dev": true,
+ "dependencies": {
+ "default-browser": "^5.4.0",
+ "define-lazy-prop": "^3.0.0",
+ "is-in-ssh": "^1.0.0",
+ "is-inside-container": "^1.0.0",
+ "powershell-utils": "^0.2.0",
+ "wsl-utils": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/path-is-inside": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
@@ -2353,6 +3255,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true
+ },
+ "node_modules/perfect-debounce": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz",
+ "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==",
+ "dev": true
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -2400,6 +3314,18 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/powershell-utils": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.0.tgz",
+ "integrity": "sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==",
+ "dev": true,
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/range-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
@@ -2506,6 +3432,18 @@
"fsevents": "~2.3.2"
}
},
+ "node_modules/run-applescript": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz",
+ "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -2635,6 +3573,20 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/sirv": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
+ "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
+ "dev": true,
+ "dependencies": {
+ "@polka/url": "^1.0.0-next.24",
+ "mrmime": "^2.0.0",
+ "totalist": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -2728,6 +3680,15 @@
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
+ "node_modules/totalist": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+ "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
@@ -2751,6 +3712,20 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/typescript": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
+ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
+ "optional": true,
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
"node_modules/undici": {
"version": "6.28.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
@@ -2761,6 +3736,14 @@
"node": ">=18.17"
}
},
+ "node_modules/undici-types": {
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
+ "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
+ "dev": true,
+ "optional": true,
+ "peer": true
+ },
"node_modules/universal-user-agent": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz",
@@ -2782,6 +3765,52 @@
"node": ">=14.0.0"
}
},
+ "node_modules/unplugin-utils": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.2.tgz",
+ "integrity": "sha512-xVToRh2CTmLk2HnEG7ac4rl1MJTT3RFkpS8B++/SnB0kXvuaavD+n3m/vrzyWQOdJNSZQACnbz01pnppbwV5BA==",
+ "dev": true,
+ "dependencies": {
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz",
+ "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
"node_modules/update-check": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz",
@@ -2878,15 +3907,162 @@
}
}
},
- "node_modules/vite-plugin-ejs": {
+ "node_modules/vite-dev-rpc": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/vite-plugin-ejs/-/vite-plugin-ejs-2.0.0.tgz",
- "integrity": "sha512-oz72iYfUTgFVl1SVRkaNYsRUx/THorgknwyRvhwBu3RMaigibKcl0T4tkUXw0h8w5JmnBEfPCKcingmTxen3Ng==",
+ "resolved": "https://registry.npmjs.org/vite-dev-rpc/-/vite-dev-rpc-2.0.0.tgz",
+ "integrity": "sha512-yKwbTwdHKSD2k/aGqyWpPHepo45OQc8lH3/6IfT4ZqeKE26ooKvi4WIEKzqWav8v+9Is8u1k8q54hvOmqASazA==",
"dev": true,
- "license": "MIT",
+ "dependencies": {
+ "birpc": "^4.0.0",
+ "vite-hot-client": "^2.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 || ^8.0.0"
+ }
+ },
+ "node_modules/vite-dev-rpc/node_modules/birpc": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.2.0.tgz",
+ "integrity": "sha512-KxgKcZPfrtzJDDALHPguGpGJUrzdgpymyiQQgzFjWreHMOpWrnFNVREr5J48x2DBh8ZVioscrV1SBkDipGiX+Q==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/vite-hot-client": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.2.0.tgz",
+ "integrity": "sha512-76Zs9zrHbH7M7wqeyooGQKdX+yg0pQ0xuQ1PbFp4z5a0Lzn2e5IPFoCswnmqZ4GiwqB4Jo3WcDAMO9jARTJl8w==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0"
+ }
+ },
+ "node_modules/vite-plugin-inspect": {
+ "version": "11.4.1",
+ "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.4.1.tgz",
+ "integrity": "sha512-ShOFe2PURXGvRS5OrgmOLZOCwDTD7dEBVt0tMpFPKb9AsvqXKCRGM8QgKrUbRbJYFXScHvDPpGRd28rYidC0tA==",
+ "dev": true,
+ "dependencies": {
+ "ansis": "^4.3.0",
+ "error-stack-parser-es": "^1.0.5",
+ "obug": "^2.1.1",
+ "ohash": "^2.0.11",
+ "open": "^11.0.0",
+ "perfect-debounce": "^2.1.0",
+ "sirv": "^3.0.2",
+ "unplugin-utils": "^0.3.1",
+ "vite-dev-rpc": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vite": "^6.0.0 || ^7.0.0-0 || ^8.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@nuxt/kit": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-plugin-vue-devtools": {
+ "version": "8.1.5",
+ "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-8.1.5.tgz",
+ "integrity": "sha512-QSVntSN0sbVV08CZntMWOfF8McyPyYyYd19sChLjxYyFCC7Fcpey74ztw1uCCU23wTmR2yWPb92uaxVD4Lw0Fg==",
+ "dev": true,
+ "dependencies": {
+ "@vue/devtools-core": "^8.1.5",
+ "@vue/devtools-kit": "^8.1.5",
+ "@vue/devtools-shared": "^8.1.5",
+ "sirv": "^3.0.2",
+ "vite-plugin-inspect": "^11.3.3",
+ "vite-plugin-vue-inspector": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=v14.21.3"
+ },
+ "peerDependencies": {
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/vite-plugin-vue-inspector": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-6.0.0.tgz",
+ "integrity": "sha512-OpyITJLgZNibxlrik1EmRtvXHDjLRxNPsWkGFTERZs2LgMEdG4W0WoFt5GIgp3a3jRou+eJR8U1zOBk/XQgEbw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.23.0",
+ "@babel/plugin-proposal-decorators": "^7.23.0",
+ "@babel/plugin-syntax-import-attributes": "^7.22.5",
+ "@babel/plugin-syntax-import-meta": "^7.10.4",
+ "@babel/plugin-transform-typescript": "^7.22.15",
+ "@vue/babel-plugin-jsx": "^1.1.5",
+ "@vue/compiler-dom": "^3.3.4",
+ "kolorist": "^1.8.0",
+ "magic-string": "^0.30.4"
+ },
+ "peerDependencies": {
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/vite-plugin-vue-inspector/node_modules/@vue/babel-helper-vue-transform-on": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz",
+ "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==",
+ "dev": true
+ },
+ "node_modules/vite-plugin-vue-inspector/node_modules/@vue/babel-plugin-jsx": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz",
+ "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/plugin-syntax-jsx": "^7.27.1",
+ "@babel/template": "^7.27.2",
+ "@babel/traverse": "^7.28.0",
+ "@babel/types": "^7.28.2",
+ "@vue/babel-helper-vue-transform-on": "1.5.0",
+ "@vue/babel-plugin-resolve-type": "1.5.0",
+ "@vue/shared": "^3.5.18"
+ },
"peerDependencies": {
- "ejs": ">=3",
- "vite": ">=5.0.0"
+ "@babel/core": "^7.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-plugin-vue-inspector/node_modules/@vue/babel-plugin-resolve-type": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz",
+ "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/parser": "^7.28.0",
+ "@vue/compiler-sfc": "^3.5.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
}
},
"node_modules/vue": {
@@ -2931,6 +4107,20 @@
"vue": "^3.0.0"
}
},
+ "node_modules/vue-router": {
+ "version": "4.6.4",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz",
+ "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
+ }
+ },
"node_modules/vue3-simple-icons": {
"version": "16.10.0",
"resolved": "https://registry.npmjs.org/vue3-simple-icons/-/vue3-simple-icons-16.10.0.tgz",
@@ -3010,6 +4200,55 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/wsl-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.0.tgz",
+ "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==",
+ "dev": true,
+ "dependencies": {
+ "is-wsl": "^3.1.0",
+ "powershell-utils": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/wsl-utils/node_modules/is-wsl": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz",
+ "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==",
+ "dev": true,
+ "dependencies": {
+ "is-inside-container": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/wsl-utils/node_modules/powershell-utils": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz",
+ "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==",
+ "dev": true,
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true
+ },
"node_modules/zod": {
"version": "3.25.76",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
diff --git a/package.json b/package.json
index 56cb311257e..5ec83db8fe0 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"scripts": {
"build": "vite build --debug",
"build-clean": "vite build --debug --emptyOutDir",
- "dev": "vite build --watch",
+ "dev": "vite",
"serve": "serve ./tests/fixtures/http --no-port-switching"
},
"type": "module",
@@ -15,13 +15,16 @@
"marked": "18.0.11",
"vue": "3.5.41",
"vue-i18n": "11.4.10",
+ "vue-router": "4.6.4",
"vue3-simple-icons": "16.10.0"
},
"devDependencies": {
"@codecov/vite-plugin": "2.0.1",
+ "@vitejs/plugin-basic-ssl": "2.3.0",
"@vitejs/plugin-vue": "6.0.8",
+ "@vitejs/plugin-vue-jsx": "5.1.6",
"serve": "14.2.6",
"vite": "6.4.3",
- "vite-plugin-ejs": "2.0.0"
+ "vite-plugin-vue-devtools": "8.1.5"
}
}
diff --git a/src_assets/common/assets/web/Navbar.vue b/src_assets/common/assets/web/Navbar.vue
deleted file mode 100644
index dc5afd68d2f..00000000000
--- a/src_assets/common/assets/web/Navbar.vue
+++ /dev/null
@@ -1,150 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src_assets/common/assets/web/NavbarSimple.vue b/src_assets/common/assets/web/NavbarSimple.vue
deleted file mode 100644
index 82a9ca086e4..00000000000
--- a/src_assets/common/assets/web/NavbarSimple.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
diff --git a/src_assets/common/assets/web/index.html b/src_assets/common/assets/web/index.html
index bff44590824..8e6bd41c15a 100644
--- a/src_assets/common/assets/web/index.html
+++ b/src_assets/common/assets/web/index.html
@@ -1,295 +1,14 @@
-
-
-
-
- <%- header %>
-
-
-
-
-
-
{{ $t('index.welcome') }}
-
{{ $t('index.description') }}
-
-
-
-
-
-
-
-
-
-
-
-
{{ $t('index.virtualhid_not_installed_title') }}
-
{{ $t('index.virtualhid_not_installed_desc') }}
-
-
-
{{ $t('index.virtualhid_outdated_title') }}
-
{{ $t('index.virtualhid_outdated_desc', { version: virtualhid.version, supported_versions: virtualhid.supported_versions }) }}
-
-
-
-
-
- {{ $t('index.fix_now') }}
-
-
-
-
-
-
-
-
-
{{ $t('index.virtualhid_missing_vigembus_installed_title') }}
-
{{ $t('index.virtualhid_missing_vigembus_installed_desc') }}
-
-
-
-
-
-
-
-
-
-
-
Version {{version.version}}
-
-
- {{ $t('index.loading_latest') }}
-
-
-
-
- {{ $t('index.version_dirty') }} 🌇
-
-
-
-
- {{ $t('index.installed_version_not_stable') }}
-
-
-
-
-
- {{ $t('index.version_latest') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ Sunshine
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/App.vue b/src_assets/common/assets/web/src/App.vue
new file mode 100644
index 00000000000..be0a23fba65
--- /dev/null
+++ b/src_assets/common/assets/web/src/App.vue
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/src_assets/common/assets/web/sunshine.css b/src_assets/common/assets/web/src/assets/sunshine.css
similarity index 100%
rename from src_assets/common/assets/web/sunshine.css
rename to src_assets/common/assets/web/src/assets/sunshine.css
diff --git a/src_assets/common/assets/web/Checkbox.vue b/src_assets/common/assets/web/src/components/Checkbox.vue
similarity index 100%
rename from src_assets/common/assets/web/Checkbox.vue
rename to src_assets/common/assets/web/src/components/Checkbox.vue
diff --git a/src_assets/common/assets/web/src/components/Layout.vue b/src_assets/common/assets/web/src/components/Layout.vue
new file mode 100644
index 00000000000..d5e63d89be8
--- /dev/null
+++ b/src_assets/common/assets/web/src/components/Layout.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/components/Navbar.vue b/src_assets/common/assets/web/src/components/Navbar.vue
new file mode 100644
index 00000000000..46008cc00c2
--- /dev/null
+++ b/src_assets/common/assets/web/src/components/Navbar.vue
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/Notification.vue b/src_assets/common/assets/web/src/components/Notification.vue
similarity index 100%
rename from src_assets/common/assets/web/Notification.vue
rename to src_assets/common/assets/web/src/components/Notification.vue
diff --git a/src_assets/common/assets/web/PlatformLayout.vue b/src_assets/common/assets/web/src/components/PlatformLayout.vue
similarity index 100%
rename from src_assets/common/assets/web/PlatformLayout.vue
rename to src_assets/common/assets/web/src/components/PlatformLayout.vue
diff --git a/src_assets/common/assets/web/ResourceCard.vue b/src_assets/common/assets/web/src/components/ResourceCard.vue
similarity index 100%
rename from src_assets/common/assets/web/ResourceCard.vue
rename to src_assets/common/assets/web/src/components/ResourceCard.vue
diff --git a/src_assets/common/assets/web/SimpleIcon.vue b/src_assets/common/assets/web/src/components/SimpleIcon.vue
similarity index 100%
rename from src_assets/common/assets/web/SimpleIcon.vue
rename to src_assets/common/assets/web/src/components/SimpleIcon.vue
diff --git a/src_assets/common/assets/web/ThemeToggle.vue b/src_assets/common/assets/web/src/components/ThemeToggle.vue
similarity index 74%
rename from src_assets/common/assets/web/ThemeToggle.vue
rename to src_assets/common/assets/web/src/components/ThemeToggle.vue
index 0bddebf84c3..7f3f4e85fbe 100644
--- a/src_assets/common/assets/web/ThemeToggle.vue
+++ b/src_assets/common/assets/web/src/components/ThemeToggle.vue
@@ -1,5 +1,5 @@
+
+
+ Apps
+ TODO: migrate content from src/views/apps.html
+
diff --git a/src_assets/common/assets/web/src/views/ConfigView.vue b/src_assets/common/assets/web/src/views/ConfigView.vue
new file mode 100644
index 00000000000..dff195a4dfe
--- /dev/null
+++ b/src_assets/common/assets/web/src/views/ConfigView.vue
@@ -0,0 +1,8 @@
+
+
+
+ Config
+ TODO: migrate content from src/views/config.html
+
diff --git a/src_assets/common/assets/web/src/views/FeaturedView.vue b/src_assets/common/assets/web/src/views/FeaturedView.vue
new file mode 100644
index 00000000000..56888ab8e97
--- /dev/null
+++ b/src_assets/common/assets/web/src/views/FeaturedView.vue
@@ -0,0 +1,8 @@
+
+
+
+ Featured
+ TODO: migrate content from src/views/featured.html
+
diff --git a/src_assets/common/assets/web/src/views/IndexView.vue b/src_assets/common/assets/web/src/views/IndexView.vue
new file mode 100644
index 00000000000..3462a7ef658
--- /dev/null
+++ b/src_assets/common/assets/web/src/views/IndexView.vue
@@ -0,0 +1,8 @@
+
+
+
+ Index
+ TODO: migrate content from src/views/index.html
+
diff --git a/src_assets/common/assets/web/src/views/LogoutView.vue b/src_assets/common/assets/web/src/views/LogoutView.vue
new file mode 100644
index 00000000000..65cd9b85811
--- /dev/null
+++ b/src_assets/common/assets/web/src/views/LogoutView.vue
@@ -0,0 +1,8 @@
+
+
+
+ Logout
+ TODO: migrate content from src/views/logout.html
+
diff --git a/src_assets/common/assets/web/src/views/PasswordView.vue b/src_assets/common/assets/web/src/views/PasswordView.vue
new file mode 100644
index 00000000000..2fec3f27ace
--- /dev/null
+++ b/src_assets/common/assets/web/src/views/PasswordView.vue
@@ -0,0 +1,8 @@
+
+
+
+ Password
+ TODO: migrate content from src/views/password.html
+
diff --git a/src_assets/common/assets/web/src/views/PinView.vue b/src_assets/common/assets/web/src/views/PinView.vue
new file mode 100644
index 00000000000..d070ae6f2bd
--- /dev/null
+++ b/src_assets/common/assets/web/src/views/PinView.vue
@@ -0,0 +1,8 @@
+
+
+
+ Pin
+ TODO: migrate content from src/views/pin.html
+
diff --git a/src_assets/common/assets/web/src/views/TroubleshootingView.vue b/src_assets/common/assets/web/src/views/TroubleshootingView.vue
new file mode 100644
index 00000000000..a30e8abbbd0
--- /dev/null
+++ b/src_assets/common/assets/web/src/views/TroubleshootingView.vue
@@ -0,0 +1,8 @@
+
+
+
+ Troubleshooting
+ TODO: migrate content from src/views/troubleshooting.html
+
diff --git a/src_assets/common/assets/web/src/views/WelcomeView.vue b/src_assets/common/assets/web/src/views/WelcomeView.vue
new file mode 100644
index 00000000000..648bcbaf890
--- /dev/null
+++ b/src_assets/common/assets/web/src/views/WelcomeView.vue
@@ -0,0 +1,8 @@
+
+
+
+ Welcome
+ TODO: migrate content from src/views/welcome.html
+
diff --git a/src_assets/common/assets/web/apps.html b/src_assets/common/assets/web/src/views/apps.html
similarity index 100%
rename from src_assets/common/assets/web/apps.html
rename to src_assets/common/assets/web/src/views/apps.html
diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/src/views/config.html
similarity index 100%
rename from src_assets/common/assets/web/config.html
rename to src_assets/common/assets/web/src/views/config.html
diff --git a/src_assets/common/assets/web/featured.html b/src_assets/common/assets/web/src/views/featured.html
similarity index 100%
rename from src_assets/common/assets/web/featured.html
rename to src_assets/common/assets/web/src/views/featured.html
diff --git a/src_assets/common/assets/web/src/views/index.html b/src_assets/common/assets/web/src/views/index.html
new file mode 100644
index 00000000000..bff44590824
--- /dev/null
+++ b/src_assets/common/assets/web/src/views/index.html
@@ -0,0 +1,295 @@
+
+
+
+
+ <%- header %>
+
+
+
+
+
+
{{ $t('index.welcome') }}
+
{{ $t('index.description') }}
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t('index.virtualhid_not_installed_title') }}
+
{{ $t('index.virtualhid_not_installed_desc') }}
+
+
+
{{ $t('index.virtualhid_outdated_title') }}
+
{{ $t('index.virtualhid_outdated_desc', { version: virtualhid.version, supported_versions: virtualhid.supported_versions }) }}
+
+
+
+
+
+ {{ $t('index.fix_now') }}
+
+
+
+
+
+
+
+
+
{{ $t('index.virtualhid_missing_vigembus_installed_title') }}
+
{{ $t('index.virtualhid_missing_vigembus_installed_desc') }}
+
+
+
+
+
+
+
+
+
+
+
Version {{version.version}}
+
+
+ {{ $t('index.loading_latest') }}
+
+
+
+
+ {{ $t('index.version_dirty') }} 🌇
+
+
+
+
+ {{ $t('index.installed_version_not_stable') }}
+
+
+
+
+
+ {{ $t('index.version_latest') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/logout.html b/src_assets/common/assets/web/src/views/logout.html
similarity index 100%
rename from src_assets/common/assets/web/logout.html
rename to src_assets/common/assets/web/src/views/logout.html
diff --git a/src_assets/common/assets/web/password.html b/src_assets/common/assets/web/src/views/password.html
similarity index 100%
rename from src_assets/common/assets/web/password.html
rename to src_assets/common/assets/web/src/views/password.html
diff --git a/src_assets/common/assets/web/pin.html b/src_assets/common/assets/web/src/views/pin.html
similarity index 100%
rename from src_assets/common/assets/web/pin.html
rename to src_assets/common/assets/web/src/views/pin.html
diff --git a/src_assets/common/assets/web/troubleshooting.html b/src_assets/common/assets/web/src/views/troubleshooting.html
similarity index 100%
rename from src_assets/common/assets/web/troubleshooting.html
rename to src_assets/common/assets/web/src/views/troubleshooting.html
diff --git a/src_assets/common/assets/web/welcome.html b/src_assets/common/assets/web/src/views/welcome.html
similarity index 100%
rename from src_assets/common/assets/web/welcome.html
rename to src_assets/common/assets/web/src/views/welcome.html
diff --git a/src_assets/common/assets/web/template_header.html b/src_assets/common/assets/web/template_header.html
deleted file mode 100644
index 9fc206b1c5a..00000000000
--- a/src_assets/common/assets/web/template_header.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-Sunshine
-
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index a578bb58fce..6a7b3de4297 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -191,10 +191,10 @@ add_executable(${PROJECT_NAME}
# Using configure_file ensures files are copied when they change between builds
set(INTEGRATION_TEST_FILES
"src/config.cpp"
- "src_assets/common/assets/web/config.html"
+ "src_assets/common/assets/web/src/views/config.html"
"docs/configuration.md"
"src_assets/common/assets/web/public/assets/locale/en.json"
- "src_assets/common/assets/web/configs/tabs/General.vue"
+ "src_assets/common/assets/web/src/components/configs/tabs/General.vue"
"src_assets/linux/misc/60-sunshine.rules"
)
diff --git a/vite.config.js b/vite.config.js
index 568aae41cf9..f93565ae195 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,19 +1,13 @@
-import { fileURLToPath, URL } from 'node:url'
import fs from 'fs';
import { resolve } from 'path'
-import { defineConfig } from 'vite'
-import { ViteEjsPlugin } from "vite-plugin-ejs";
+import { defineConfig, loadEnv } from 'vite'
import { codecovVitePlugin } from "@codecov/vite-plugin";
import vue from '@vitejs/plugin-vue'
+import vueJsx from '@vitejs/plugin-vue-jsx'
+import vueDevTools from 'vite-plugin-vue-devtools'
+import basicSsl from '@vitejs/plugin-basic-ssl'
import process from 'process'
-/**
- * Before actually building the pages with Vite, we do an intermediate build step using ejs
- * Importing this separately and joining them using ejs
- * allows us to split some repeating HTML that cannot be added
- * by Vue itself (e.g. style/script loading, common meta head tags, Widgetbot)
- * The vite-plugin-ejs handles this automatically
- */
let assetsSrcPath = 'src_assets/common/assets/web';
let assetsDstPath = 'build/assets/web';
@@ -40,42 +34,62 @@ else {
}
}
-let header = fs.readFileSync(resolve(assetsSrcPath, "template_header.html"))
-
// https://vitejs.dev/config/
-export default defineConfig({
- resolve: {
- alias: {
- vue: 'vue/dist/vue.esm-bundler.js'
- }
- },
- base: './',
- plugins: [
- vue(),
- ViteEjsPlugin({ header }),
- // The Codecov vite plugin should be after all other plugins
- codecovVitePlugin({
- enableBundleAnalysis: true,
- bundleName: "sunshine",
- uploadToken: process.env.CODECOV_TOKEN,
- gitService: "github",
- }),
- ],
- root: resolve(assetsSrcPath),
- build: {
- outDir: resolve(assetsDstPath),
- rollupOptions: {
- input: {
- apps: resolve(assetsSrcPath, 'apps.html'),
- config: resolve(assetsSrcPath, 'config.html'),
- featured: resolve(assetsSrcPath, 'featured.html'),
- index: resolve(assetsSrcPath, 'index.html'),
- logout: resolve(assetsSrcPath, 'logout.html'),
- password: resolve(assetsSrcPath, 'password.html'),
- pin: resolve(assetsSrcPath, 'pin.html'),
- troubleshooting: resolve(assetsSrcPath, 'troubleshooting.html'),
- welcome: resolve(assetsSrcPath, 'welcome.html'),
+export default defineConfig(({ command, mode }) => {
+ const env = loadEnv(mode, process.cwd(), 'VITE_');
+ const backendUrl = env.VITE_BACKEND_URL;
+
+ return {
+ resolve: {
+ alias: {
+ vue: 'vue/dist/vue.esm-bundler.js',
+ // Frontend `src/`, not the repo-root C++ `src/` directory.
+ '@': resolve(assetsSrcPath, 'src'),
+ }
+ },
+ base: './',
+ plugins: [
+ // Files like /images/*.png live in public/, and Vite forbids importing publicDir
+ // contents as JS modules in dev, so don't let Vue's compiler turn
+ //
into a build-time import.
+ vue({ template: { transformAssetUrls: false } }),
+ vueJsx(),
+ vueDevTools(),
+ // HTTPS only matters for `vite dev`; the production build is served by the backend.
+ ...(command === 'serve' ? [basicSsl()] : []),
+ // The Codecov vite plugin should be after all other plugins
+ codecovVitePlugin({
+ enableBundleAnalysis: true,
+ bundleName: "sunshine",
+ uploadToken: process.env.CODECOV_TOKEN,
+ gitService: "github",
+ }),
+ ],
+ root: resolve(assetsSrcPath),
+ server: {
+ // Bind address/port for `vite dev`; override via VITE_DEV_HOST / VITE_DEV_PORT in .env
+ // (e.g. VITE_DEV_HOST=0.0.0.0 for devcontainer/Codespaces port forwarding).
+ host: env.VITE_DEV_HOST,
+ port: Number(env.VITE_DEV_PORT) ?? 5173,
+ // WSL2/devcontainer bind mounts don't reliably propagate inotify events, so poll instead.
+ watch: {
+ usePolling: true,
+ },
+ proxy: {
+ '/api': {
+ target: backendUrl,
+ changeOrigin: true,
+ secure: false, // the backend uses a self-signed certificate
+ },
+ },
+ },
+ build: {
+ outDir: resolve(assetsDstPath),
+ rollupOptions: {
+ input: {
+ index: resolve(assetsSrcPath, 'index.html'),
+ },
},
},
- },
+ };
})
From bddd19f5f60aca28c8218e5419565f0d37a6bb2f Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Sun, 23 Aug 2026 17:57:50 +0000
Subject: [PATCH 02/24] Add components
---
.../assets/web/src/components/AlertBox.vue | 58 +++++++++++++
.../assets/web/src/components/FeatureCard.vue | 30 +++++++
.../assets/web/src/components/FormGroup.vue | 26 ++++++
.../web/src/components/LoadingSpinner.vue | 20 +++++
.../assets/web/src/components/Modal.vue | 81 +++++++++++++++++++
.../assets/web/src/components/StatusAlert.vue | 31 +++++++
6 files changed, 246 insertions(+)
create mode 100644 src_assets/common/assets/web/src/components/AlertBox.vue
create mode 100644 src_assets/common/assets/web/src/components/FeatureCard.vue
create mode 100644 src_assets/common/assets/web/src/components/FormGroup.vue
create mode 100644 src_assets/common/assets/web/src/components/LoadingSpinner.vue
create mode 100644 src_assets/common/assets/web/src/components/Modal.vue
create mode 100644 src_assets/common/assets/web/src/components/StatusAlert.vue
diff --git a/src_assets/common/assets/web/src/components/AlertBox.vue b/src_assets/common/assets/web/src/components/AlertBox.vue
new file mode 100644
index 00000000000..0600a5f5565
--- /dev/null
+++ b/src_assets/common/assets/web/src/components/AlertBox.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ action.label }}
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/components/FeatureCard.vue b/src_assets/common/assets/web/src/components/FeatureCard.vue
new file mode 100644
index 00000000000..344303ca3e6
--- /dev/null
+++ b/src_assets/common/assets/web/src/components/FeatureCard.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
{{ title }}
+
{{ description }}
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/components/FormGroup.vue b/src_assets/common/assets/web/src/components/FormGroup.vue
new file mode 100644
index 00000000000..f9c05e0f0d8
--- /dev/null
+++ b/src_assets/common/assets/web/src/components/FormGroup.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
{{ description }}
+
+
+
+
diff --git a/src_assets/common/assets/web/src/components/LoadingSpinner.vue b/src_assets/common/assets/web/src/components/LoadingSpinner.vue
new file mode 100644
index 00000000000..fd9c7956e7a
--- /dev/null
+++ b/src_assets/common/assets/web/src/components/LoadingSpinner.vue
@@ -0,0 +1,20 @@
+
+
+ {{ label }}
+
+
+
+
diff --git a/src_assets/common/assets/web/src/components/Modal.vue b/src_assets/common/assets/web/src/components/Modal.vue
new file mode 100644
index 00000000000..ac6db9ef923
--- /dev/null
+++ b/src_assets/common/assets/web/src/components/Modal.vue
@@ -0,0 +1,81 @@
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/components/StatusAlert.vue b/src_assets/common/assets/web/src/components/StatusAlert.vue
new file mode 100644
index 00000000000..914132cb1df
--- /dev/null
+++ b/src_assets/common/assets/web/src/components/StatusAlert.vue
@@ -0,0 +1,31 @@
+
+
+ {{ $t('_common.error') }} {{ error }}
+
+
+ {{ $t('_common.success') }} {{ successMessage }}
+
+
+
+
From 4aa71178a91e17ca985abc249e859bbe0a5b29fa Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Sun, 23 Aug 2026 17:58:01 +0000
Subject: [PATCH 03/24] Migrate index page
---
.../common/assets/web/src/views/IndexView.vue | 233 +++++++++++++-
.../common/assets/web/src/views/index.html | 295 ------------------
2 files changed, 227 insertions(+), 301 deletions(-)
delete mode 100644 src_assets/common/assets/web/src/views/index.html
diff --git a/src_assets/common/assets/web/src/views/IndexView.vue b/src_assets/common/assets/web/src/views/IndexView.vue
index 3462a7ef658..3dd0e0d6cea 100644
--- a/src_assets/common/assets/web/src/views/IndexView.vue
+++ b/src_assets/common/assets/web/src/views/IndexView.vue
@@ -1,8 +1,229 @@
-
-
- Index
- TODO: migrate content from src/views/index.html
+ {{ $t('index.welcome') }}
+ {{ $t('index.description') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t('index.virtualhid_not_installed_title') }}
+
{{ $t('index.virtualhid_not_installed_desc') }}
+
+
+
{{ $t('index.virtualhid_outdated_title') }}
+
{{ $t('index.virtualhid_outdated_desc', {
+ version: virtualhid.version, supported_versions:
+ virtualhid.supported_versions }) }}
+
+
+
+
+ {{ $t('index.virtualhid_missing_vigembus_installed_title') }}
+ {{ $t('index.virtualhid_missing_vigembus_installed_desc') }}
+
+
+
+
+ {{ $t('index.virtualhid_license_required_title') }}
+ {{ $t('index.virtualhid_license_required_desc') }}
+
+
+
+
+
+
Version {{ version.version }}
+
+
+ {{ $t('index.loading_latest') }}
+
+
+
+ {{ $t('index.version_dirty') }} 🌇
+
+
+
+ {{ $t('index.installed_version_not_stable') }}
+
+
+ {{ $t('index.version_latest') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/views/index.html b/src_assets/common/assets/web/src/views/index.html
deleted file mode 100644
index bff44590824..00000000000
--- a/src_assets/common/assets/web/src/views/index.html
+++ /dev/null
@@ -1,295 +0,0 @@
-
-
-
-
- <%- header %>
-
-
-
-
-
-
{{ $t('index.welcome') }}
-
{{ $t('index.description') }}
-
-
-
-
-
-
-
-
-
-
-
-
{{ $t('index.virtualhid_not_installed_title') }}
-
{{ $t('index.virtualhid_not_installed_desc') }}
-
-
-
{{ $t('index.virtualhid_outdated_title') }}
-
{{ $t('index.virtualhid_outdated_desc', { version: virtualhid.version, supported_versions: virtualhid.supported_versions }) }}
-
-
-
-
-
- {{ $t('index.fix_now') }}
-
-
-
-
-
-
-
-
-
{{ $t('index.virtualhid_missing_vigembus_installed_title') }}
-
{{ $t('index.virtualhid_missing_vigembus_installed_desc') }}
-
-
-
-
-
-
-
-
-
-
-
Version {{version.version}}
-
-
- {{ $t('index.loading_latest') }}
-
-
-
-
- {{ $t('index.version_dirty') }} 🌇
-
-
-
-
- {{ $t('index.installed_version_not_stable') }}
-
-
-
-
-
- {{ $t('index.version_latest') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
From fdf7d23e62116406f1fdc48382fbe62109f9d9a1 Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Sun, 23 Aug 2026 22:37:45 +0000
Subject: [PATCH 04/24] Add release notes accordion
---
.../assets/web/public/assets/locale/en.json | 1 +
.../common/assets/web/src/assets/sunshine.css | 17 +++++++++
.../common/assets/web/src/views/IndexView.vue | 37 +++++++++++++++----
3 files changed, 47 insertions(+), 8 deletions(-)
diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json
index 26a809231d9..47d4163a27d 100644
--- a/src_assets/common/assets/web/public/assets/locale/en.json
+++ b/src_assets/common/assets/web/public/assets/locale/en.json
@@ -450,6 +450,7 @@
"loading_latest": "Loading latest release...",
"new_pre_release": "A new Pre-Release Version is Available!",
"new_stable": "A new Stable Version is Available!",
+ "release_notes": "Release Notes",
"startup_errors": "Attention! Sunshine detected these errors during startup. We STRONGLY RECOMMEND fixing them before streaming.",
"version_dirty": "Thank you for helping to make Sunshine a better software!",
"version_latest": "You are running the latest version of Sunshine",
diff --git a/src_assets/common/assets/web/src/assets/sunshine.css b/src_assets/common/assets/web/src/assets/sunshine.css
index dd9c9d2e42c..38d8ea23fd0 100644
--- a/src_assets/common/assets/web/src/assets/sunshine.css
+++ b/src_assets/common/assets/web/src/assets/sunshine.css
@@ -1052,6 +1052,23 @@ body {
color: var(--color-text-base) !important;
}
+.release-notes-toggle::after {
+ display: none;
+}
+
+.release-notes-toggle .icon {
+ transition: transform var(--transition-fast, 0.2s);
+}
+
+.release-notes-toggle[aria-expanded="true"] .icon {
+ transform: rotate(-90deg);
+}
+
+.release-notes-accordion .accordion-body {
+ max-height: 400px;
+ overflow-y: auto;
+}
+
.offcanvas {
background-color: var(--color-surface) !important;
}
diff --git a/src_assets/common/assets/web/src/views/IndexView.vue b/src_assets/common/assets/web/src/views/IndexView.vue
index 3dd0e0d6cea..6ff0597c59b 100644
--- a/src_assets/common/assets/web/src/views/IndexView.vue
+++ b/src_assets/common/assets/web/src/views/IndexView.vue
@@ -26,7 +26,8 @@
{{ $t('index.virtualhid_outdated_title') }}
{{ $t('index.virtualhid_outdated_desc', {
version: virtualhid.version, supported_versions:
- virtualhid.supported_versions }) }}
+ virtualhid.supported_versions
+ }) }}
@@ -75,14 +76,32 @@
{{ $t(release.labelKey) }}
{{ release.version.release.name }}
-
-
- {{ $t('index.download') }}
-
+
+
+
-
-
-
@@ -100,6 +119,7 @@ import ResourceCard from '../components/ResourceCard.vue'
import SunshineVersion from '../utils/sunshine_version'
import {
AlertCircle,
+ ChevronLeft,
FileText,
Wrench,
Package,
@@ -119,6 +139,7 @@ export default {
AlertBox,
ResourceCard,
AlertCircle,
+ ChevronLeft,
Download
},
data() {
From 455b9a546b4f0991f2cece387293f920127b4457 Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Sun, 23 Aug 2026 19:01:12 +0000
Subject: [PATCH 05/24] Migrate welcome page
---
.../assets/web/src/views/WelcomeView.vue | 98 ++++++++++++++-
.../common/assets/web/src/views/welcome.html | 119 ------------------
2 files changed, 92 insertions(+), 125 deletions(-)
delete mode 100644 src_assets/common/assets/web/src/views/welcome.html
diff --git a/src_assets/common/assets/web/src/views/WelcomeView.vue b/src_assets/common/assets/web/src/views/WelcomeView.vue
index 648bcbaf890..02f5dc16a23 100644
--- a/src_assets/common/assets/web/src/views/WelcomeView.vue
+++ b/src_assets/common/assets/web/src/views/WelcomeView.vue
@@ -1,8 +1,94 @@
-
-
- Welcome
- TODO: migrate content from src/views/welcome.html
+ {{ $t('welcome.greeting') }}
+ {{ $t('welcome.create_creds') }}
+
+
+
+
+ {{ $t('welcome.create_creds_alert') }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/views/welcome.html b/src_assets/common/assets/web/src/views/welcome.html
deleted file mode 100644
index 7d8d7cc36ab..00000000000
--- a/src_assets/common/assets/web/src/views/welcome.html
+++ /dev/null
@@ -1,119 +0,0 @@
-
-
-
-
- <%- header %>
-
-
-
-
-
-
- {{ $t('welcome.greeting') }}
- {{ $t('welcome.create_creds') }}
-
-
-
-
- {{ $t('welcome.create_creds_alert') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
From 5920ddd624e8d080bda46eea7c0f1b395292e7bc Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Sun, 23 Aug 2026 22:43:22 +0000
Subject: [PATCH 06/24] Migrate pin page
---
.../common/assets/web/src/views/PinView.vue | 79 ++++++++++++++--
.../common/assets/web/src/views/pin.html | 90 -------------------
2 files changed, 73 insertions(+), 96 deletions(-)
delete mode 100644 src_assets/common/assets/web/src/views/pin.html
diff --git a/src_assets/common/assets/web/src/views/PinView.vue b/src_assets/common/assets/web/src/views/PinView.vue
index d070ae6f2bd..a0e8f4d0a3d 100644
--- a/src_assets/common/assets/web/src/views/PinView.vue
+++ b/src_assets/common/assets/web/src/views/PinView.vue
@@ -1,8 +1,75 @@
-
-
- Pin
- TODO: migrate content from src/views/pin.html
+ {{ $t('pin.pin_pairing') }}
+
+
+
diff --git a/src_assets/common/assets/web/src/views/pin.html b/src_assets/common/assets/web/src/views/pin.html
deleted file mode 100644
index 6be11b2d125..00000000000
--- a/src_assets/common/assets/web/src/views/pin.html
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
- <%- header %>
-
-
-
-
-
-
{{ $t('pin.pin_pairing') }}
-
-
-
-
-
From 7adb6d94fff836da68d1a82f30a02efd0978db50 Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Mon, 24 Aug 2026 01:09:33 +0000
Subject: [PATCH 07/24] Migrate AppsView
---
.../assets/web/src/components/Modal.vue | 25 +-
.../common/assets/web/src/views/AppsView.vue | 919 ++++++++++++++-
.../common/assets/web/src/views/apps.html | 1049 -----------------
3 files changed, 937 insertions(+), 1056 deletions(-)
delete mode 100644 src_assets/common/assets/web/src/views/apps.html
diff --git a/src_assets/common/assets/web/src/components/Modal.vue b/src_assets/common/assets/web/src/components/Modal.vue
index ac6db9ef923..b42ae17cadc 100644
--- a/src_assets/common/assets/web/src/components/Modal.vue
+++ b/src_assets/common/assets/web/src/components/Modal.vue
@@ -3,7 +3,9 @@
@@ -37,6 +39,11 @@ export default {
keyboard: {
type: Boolean,
default: true
+ },
+ // Raises this modal above any already-open modal instead of sharing z-index.
+ stacked: {
+ type: Boolean,
+ default: false
}
},
emits: ['update:modelValue', 'close'],
@@ -60,12 +67,16 @@ export default {
keyboard: this.keyboard
})
this.$refs.modalEl.addEventListener('hidden.bs.modal', this.handleHidden)
+ if (this.stacked) {
+ this.$refs.modalEl.addEventListener('show.bs.modal', this.raiseZIndex)
+ }
if (this.modelValue) {
this.bsModal.show()
}
},
beforeUnmount() {
this.$refs.modalEl.removeEventListener('hidden.bs.modal', this.handleHidden)
+ this.$refs.modalEl.removeEventListener('show.bs.modal', this.raiseZIndex)
this.bsModal?.dispose()
},
methods: {
@@ -75,6 +86,18 @@ export default {
handleHidden() {
this.$emit('update:modelValue', false)
this.$emit('close')
+ },
+ raiseZIndex() {
+ const modalEl = this.$refs.modalEl
+ const openCount = document.querySelectorAll('.modal.show').length
+ const z = 1055 + (openCount + 1) * 20
+ modalEl.style.zIndex = z
+
+ requestAnimationFrame(() => {
+ const backdrops = document.querySelectorAll('.modal-backdrop')
+ const backdrop = backdrops[backdrops.length - 1]
+ if (backdrop) backdrop.style.zIndex = z - 10
+ })
}
}
}
diff --git a/src_assets/common/assets/web/src/views/AppsView.vue b/src_assets/common/assets/web/src/views/AppsView.vue
index daf09996cba..b87a00e5cd1 100644
--- a/src_assets/common/assets/web/src/views/AppsView.vue
+++ b/src_assets/common/assets/web/src/views/AppsView.vue
@@ -1,8 +1,915 @@
-
-
- Apps
- TODO: migrate content from src/views/apps.html
+
+
{{ $t('apps.applications_title') }} ({{ appCountLabel }})
+
{{ $t('apps.applications_desc') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
![]()
+
+ {{ app.name.charAt(0).toUpperCase() }}
+
+
+
+
+ {{ app.cmd }}
+
+
+
+ {{ app['working-dir'] }}
+
+
+ {{ $t('apps.badge_admin') }}
+ {{ $t('apps.badge_detached')
+ }}
+ {{
+ $t('apps.badge_app_prep') }}
+ {{
+ $t('apps.badge_no_global_prep') }}
+ {{ $t('apps.badge_auto_detach') }}
+
+
+
+
+
{{ app.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t('apps.no_search_results') }}
+
+
+
+
+
+
+
{{ $t('apps.no_applications') }}
+
+
+
+
+
+ {{ editModalTitle }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t('apps.cmd_prep_desc') }}
+
+
+
{{ $t('_common.do_cmd') }}
+
+
+ {{ $t('_common.undo_cmd') }}
+
+
+ {{ $t('_common.run_as') }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('apps.detached_cmds_desc') }}
+ {{ $t('_common.note') }} {{ $t('apps.detached_cmds_note') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('apps.cmd_desc') }}
+ {{ $t('_common.note') }} {{ $t('apps.cmd_note') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t('apps.env_vars_about') }}
+ {{ $t('apps.env_vars_desc') }}
+
+
+
+
+ | {{ $t('apps.env_var_name') }} |
+ |
+
+
+
+
+ | SUNSHINE_APP_ID |
+ {{ $t('apps.env_app_id') }} |
+
+
+ | SUNSHINE_APP_NAME |
+ {{ $t('apps.env_app_name') }} |
+
+
+ | SUNSHINE_CLIENT_WIDTH |
+ {{ $t('apps.env_client_width') }} |
+
+
+ | SUNSHINE_CLIENT_HEIGHT |
+ {{ $t('apps.env_client_height') }} |
+
+
+ | SUNSHINE_CLIENT_FPS |
+ {{ $t('apps.env_client_fps') }} |
+
+
+ | SUNSHINE_CLIENT_HDR |
+ {{ $t('apps.env_client_hdr') }} |
+
+
+ | SUNSHINE_CLIENT_GCMAP |
+ {{ $t('apps.env_client_gcmap') }} |
+
+
+ | SUNSHINE_CLIENT_HOST_AUDIO |
+ {{ $t('apps.env_client_host_audio') }} |
+
+
+ | SUNSHINE_CLIENT_ENABLE_SOPS |
+ {{ $t('apps.env_client_enable_sops') }} |
+
+
+ | SUNSHINE_CLIENT_AUDIO_CONFIGURATION |
+ {{ $t('apps.env_client_audio_config') }} |
+
+
+
+
{{ $t('apps.env_qres_example') }}
+
cmd /C <{{ $t('apps.env_qres_path') }}>\QRes.exe /X:%SUNSHINE_CLIENT_WIDTH% /Y:%SUNSHINE_CLIENT_HEIGHT% /R:%SUNSHINE_CLIENT_FPS%
+
+
{{
+ $t('apps.env_xrandr_example') }}
+
sh -c "xrandr --output HDMI-1 --mode \"${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT}\" --rate ${SUNSHINE_CLIENT_FPS}"
+
+
{{ $t('apps.env_displayplacer_example') }}
+
sh -c "displayplacer "id:<screenId> res:${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} hz:${SUNSHINE_CLIENT_FPS} scaling:on origin:(0,0) degree:0""
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('apps.searching_covers') }}
+ {{ $t('apps.covers_found') }} ({{ coverCandidates.length }})
+ {{ $t('apps.no_covers_found') }}
+
+
+
+
+
+
+
+
{{ $t('_common.note') }} {{ $t('apps.cover_search_hint') }}
+
IGDB
+
+
+
+
+
+
+
+
![]()
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('apps.delete_title') }}
+
+ {{ deleteTarget.name }}
+
+
+
+
+
+
+
+
+
+ {{ fileBrowserTitle || $t('file_browser.title') }}
+
+
+
+
+
+
+
+ {{ fileBrowserError }}
+
+
+
+
+
+
+
+ {{ $t('file_browser.empty') }}
+
+
+
+
+
+ {{ fileBrowserSelectedPath }}
+
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/views/apps.html b/src_assets/common/assets/web/src/views/apps.html
deleted file mode 100644
index 32b3e0af9ed..00000000000
--- a/src_assets/common/assets/web/src/views/apps.html
+++ /dev/null
@@ -1,1049 +0,0 @@
-
-
-
-
- <%- header %>
-
-
-
-
-
-
-
{{ $t('apps.applications_title') }} ({{ appCountLabel }})
-
{{ $t('apps.applications_desc') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
![]()
-
- {{ app.name.charAt(0).toUpperCase() }}
-
-
-
-
- {{ app.cmd }}
-
-
-
- {{ app['working-dir'] }}
-
-
- {{ $t('apps.badge_admin') }}
- {{ $t('apps.badge_detached') }}
- {{ $t('apps.badge_app_prep') }}
- {{ $t('apps.badge_no_global_prep') }}
- {{ $t('apps.badge_auto_detach') }}
-
-
-
-
-
{{ app.name }}
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ $t('apps.no_search_results') }}
-
-
-
-
-
-
-
{{ $t('apps.no_applications') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ deleteTarget.name }}
-
-
-
-
-
-
-
-
-
-
-
-
From 0357480aa94e84896d358ef9946e3bcbff4b1177 Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Mon, 24 Aug 2026 01:37:53 +0000
Subject: [PATCH 08/24] Migrate featured apps page
---
.../common/assets/web/src/assets/sunshine.css | 3 +
.../web/src/components/FeaturedAppCard.vue | 233 ++++++++
.../web/src/components/ScreenshotModal.vue | 110 ++++
.../assets/web/src/views/FeaturedView.vue | 134 ++++-
.../common/assets/web/src/views/featured.html | 498 ------------------
5 files changed, 474 insertions(+), 504 deletions(-)
create mode 100644 src_assets/common/assets/web/src/components/FeaturedAppCard.vue
create mode 100644 src_assets/common/assets/web/src/components/ScreenshotModal.vue
delete mode 100644 src_assets/common/assets/web/src/views/featured.html
diff --git a/src_assets/common/assets/web/src/assets/sunshine.css b/src_assets/common/assets/web/src/assets/sunshine.css
index 38d8ea23fd0..3cb492c12c6 100644
--- a/src_assets/common/assets/web/src/assets/sunshine.css
+++ b/src_assets/common/assets/web/src/assets/sunshine.css
@@ -2805,7 +2805,10 @@ p {
right: var(--spacing-lg);
z-index: 3;
background: rgba(0, 0, 0, 0.5);
+ border: none;
border-radius: 50%;
+ color: white;
+ cursor: pointer;
padding: var(--spacing-sm);
transition: background var(--transition-fast), transform var(--transition-fast);
}
diff --git a/src_assets/common/assets/web/src/components/FeaturedAppCard.vue b/src_assets/common/assets/web/src/components/FeaturedAppCard.vue
new file mode 100644
index 00000000000..fc1b9480b5f
--- /dev/null
+++ b/src_assets/common/assets/web/src/components/FeaturedAppCard.vue
@@ -0,0 +1,233 @@
+
+
+
+
+
+
![]()
+
+
+
+
+
+
{{ app.name }}
+
{{ app.tagline }}
+
+
{{ $t('featured.official') }}
+
+
+
{{ app.description }}
+
+
+
+
+
+ {{ formatNumber(app.github.stars) }}
+
+
+
+ {{ formatNumber(app.github.forks) }}
+
+
+
+ {{ formatNumber(app.github.openIssues) }}
+
+
+
+
+
+
+ {{ $t('featured.last_updated') }}: {{ formatDate(app.github.lastUpdated).relative }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ platformName(platform) }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/components/ScreenshotModal.vue b/src_assets/common/assets/web/src/components/ScreenshotModal.vue
new file mode 100644
index 00000000000..361f6e548d6
--- /dev/null
+++ b/src_assets/common/assets/web/src/components/ScreenshotModal.vue
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ index + 1 }} / {{ screenshots.length }}
+
+
+
![Screenshot]()
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/views/FeaturedView.vue b/src_assets/common/assets/web/src/views/FeaturedView.vue
index 56888ab8e97..157e8999a79 100644
--- a/src_assets/common/assets/web/src/views/FeaturedView.vue
+++ b/src_assets/common/assets/web/src/views/FeaturedView.vue
@@ -1,8 +1,130 @@
-
-
- Featured
- TODO: migrate content from src/views/featured.html
+
+
{{ $t('featured.title') }}
+
{{ $t('featured.description') }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('_common.error') }}
+
+ {{ error }}
+
+
+
+
+
+
+
+
+
{{ $t('featured.no_apps') }}
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/views/featured.html b/src_assets/common/assets/web/src/views/featured.html
deleted file mode 100644
index c927805960a..00000000000
--- a/src_assets/common/assets/web/src/views/featured.html
+++ /dev/null
@@ -1,498 +0,0 @@
-
-
-
-
- <%- header %>
-
-
-
-
-
-
-
{{ $t('featured.title') }}
-
{{ $t('featured.description') }}
-
-
-
-
-
-
-
-
- {{ $t('_common.loading') }}
-
-
-
-
-
-
{{ $t('_common.error') }}
-
{{ error }}
-
-
-
-
-
-
-
-
-
-
![]()
-
-
-
-
-
-
{{ app.name }}
-
{{ app.tagline }}
-
-
{{ $t('featured.official') }}
-
-
-
{{ app.description }}
-
-
-
-
-
- {{ formatNumber(app.github.stars) }}
-
-
-
- {{ formatNumber(app.github.forks) }}
-
-
-
- {{ formatNumber(app.github.openIssues) }}
-
-
-
-
-
-
- {{ $t('featured.last_updated') }}: {{ formatDate(app.github.lastUpdated).relative }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ platformName(platform) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ $t('featured.no_apps') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ selectedScreenshotIndex + 1 }} / {{ currentAppScreenshots.length }}
-
-
-
![Screenshot]()
-
-
-
-
-
-
-
-
From 03283a2414754364a1a115cf5d6af0f00b402b8c Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Mon, 24 Aug 2026 01:58:40 +0000
Subject: [PATCH 09/24] Update import to use @ paths
---
src_assets/common/assets/web/src/App.vue | 2 +-
.../web/src/components/FeaturedAppCard.vue | 2 +-
.../assets/web/src/components/Layout.vue | 4 ++--
.../assets/web/src/components/Navbar.vue | 2 +-
.../assets/web/src/components/ResourceCard.vue | 2 +-
.../assets/web/src/components/ThemeToggle.vue | 2 +-
.../src/components/configs/tabs/Advanced.vue | 2 +-
.../src/components/configs/tabs/AudioVideo.vue | 14 +++++++-------
.../configs/tabs/ContainerEncoders.vue | 14 +++++++-------
.../src/components/configs/tabs/General.vue | 2 +-
.../web/src/components/configs/tabs/Inputs.vue | 4 ++--
.../src/components/configs/tabs/Network.vue | 2 +-
.../tabs/audiovideo/AdapterNameSelector.vue | 4 ++--
.../tabs/audiovideo/DisplayDeviceOptions.vue | 4 ++--
.../tabs/audiovideo/DisplayModesSettings.vue | 4 ++--
.../tabs/audiovideo/DisplayOutputSelector.vue | 4 ++--
.../configs/tabs/encoders/AmdAmfEncoder.vue | 2 +-
.../tabs/encoders/IntelQuickSyncEncoder.vue | 2 +-
.../tabs/encoders/NvidiaNvencEncoder.vue | 2 +-
.../configs/tabs/encoders/VAAPIEncoder.vue | 2 +-
.../tabs/encoders/VideotoolboxEncoder.vue | 2 +-
src_assets/common/assets/web/src/main.js | 6 +++---
.../common/assets/web/src/router/index.js | 18 +++++++++---------
.../common/assets/web/src/utils/fetch_utils.js | 2 +-
src_assets/common/assets/web/src/utils/init.js | 2 +-
.../common/assets/web/src/views/AppsView.vue | 12 ++++++------
.../assets/web/src/views/FeaturedView.vue | 8 ++++----
.../common/assets/web/src/views/IndexView.vue | 6 +++---
.../common/assets/web/src/views/PinView.vue | 4 ++--
.../assets/web/src/views/WelcomeView.vue | 8 ++++----
30 files changed, 72 insertions(+), 72 deletions(-)
diff --git a/src_assets/common/assets/web/src/App.vue b/src_assets/common/assets/web/src/App.vue
index be0a23fba65..5b3859d24c7 100644
--- a/src_assets/common/assets/web/src/App.vue
+++ b/src_assets/common/assets/web/src/App.vue
@@ -3,7 +3,7 @@
-
- Config
- TODO: migrate content from src/views/config.html
+
+
{{ $t('config.configuration') }}
+
{{ $t('config.configuration_desc') }}
+
+
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/views/config.html b/src_assets/common/assets/web/src/views/config.html
deleted file mode 100644
index f8df1ae4d24..00000000000
--- a/src_assets/common/assets/web/src/views/config.html
+++ /dev/null
@@ -1,657 +0,0 @@
-
-
-
-
- <%- header %>
-
-
-
-
-
-
-
{{ $t('config.configuration') }}
-
{{ $t('config.configuration_desc') }}
-
-
-
-
-
-
-
-
-
-
-
-
From f9ebe7482351ba57ad4507a70705882f0c65b5dc Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Mon, 24 Aug 2026 02:17:55 +0000
Subject: [PATCH 11/24] Migrate troubleshooting page
---
.../assets/web/src/components/AlertBox.vue | 6 +-
.../web/src/views/TroubleshootingView.vue | 1104 ++++++++++++++-
.../assets/web/src/views/troubleshooting.html | 1181 -----------------
3 files changed, 1101 insertions(+), 1190 deletions(-)
delete mode 100644 src_assets/common/assets/web/src/views/troubleshooting.html
diff --git a/src_assets/common/assets/web/src/components/AlertBox.vue b/src_assets/common/assets/web/src/components/AlertBox.vue
index 0600a5f5565..f4a54ca004e 100644
--- a/src_assets/common/assets/web/src/components/AlertBox.vue
+++ b/src_assets/common/assets/web/src/components/AlertBox.vue
@@ -1,9 +1,9 @@
-
-
+
+
-
+
diff --git a/src_assets/common/assets/web/src/views/TroubleshootingView.vue b/src_assets/common/assets/web/src/views/TroubleshootingView.vue
index a30e8abbbd0..813687b2718 100644
--- a/src_assets/common/assets/web/src/views/TroubleshootingView.vue
+++ b/src_assets/common/assets/web/src/views/TroubleshootingView.vue
@@ -1,8 +1,1100 @@
-
-
- Troubleshooting
- TODO: migrate content from src/views/troubleshooting.html
+ {{ $t('troubleshooting.troubleshooting') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t('troubleshooting.virtual_gamepad_drivers') }}
+
{{ $t('troubleshooting.virtual_gamepad_drivers_desc') }}
+
+
+
+
+
+
+
+
+ | {{ $t('troubleshooting.driver_name') }} |
+ {{ $t('troubleshooting.driver_installed_version') }} |
+ {{ $t('troubleshooting.driver_latest_version') }} |
+ {{ $t('troubleshooting.driver_supported_versions') }} |
+ {{ $t('troubleshooting.driver_status') }} |
+
+ {{ $t('troubleshooting.driver_download') }}
+ |
+
+
+
+
+ | {{ $t('troubleshooting.virtualhid_driver') }} |
+ {{ driverVersion(virtualhid) }} |
+
+
+
+
+
+
+ {{ driverLatestVersion(virtualhidRelease) }}
+
+ {{ driverReleaseStatusText(virtualhid, virtualhidRelease) }}
+ |
+ {{ virtualhid.supported_versions }} |
+
+
+ {{ driverStatusText(virtualhid) }}
+
+ |
+
+
+
+ {{ $t('troubleshooting.driver_download') }}
+
+ |
+
+
+ | {{ $t('troubleshooting.vigembus_driver') }} |
+ {{ driverVersion(vigembus) }} |
+
+
+
+
+
+
+ {{ driverLatestVersion(vigembusRelease) }}
+
+ {{ driverReleaseStatusText(vigembus, vigembusRelease) }}
+ |
+ {{ vigembus.supported_versions }} |
+
+
+ {{ driverStatusText(vigembus) }}
+
+ |
+
+
+
+ {{ $t('troubleshooting.driver_download') }}
+
+ |
+
+
+
+
+
+
+
+
+
+
{{ $t('troubleshooting.virtualhid_license') }}
+
{{ $t('troubleshooting.virtualhid_license_desc') }}
+
+
{{ licenseStatusText() }}
+
+
+
+ {{ licenseError }}
+
+
+ {{ virtualhidLicense.message || $t('troubleshooting.virtualhid_license_unavailable') }}
+
+
+
+
+ - {{ $t('troubleshooting.virtualhid_license_plan') }}
+ - {{ virtualhidLicense.plan_name }}
+
+
+ - {{ $t('troubleshooting.virtualhid_license_activations') }}
+ - {{ licenseActivationText() }}
+
+
+ - {{ $t('troubleshooting.virtualhid_license_active_devices') }}
+ - {{ virtualhidLicense.active_devices }}
+
+
+ - {{ $t('troubleshooting.virtualhid_license_customer') }}
+ - {{ virtualhidLicense.customer_email }}
+
+
+
+
+ {{ virtualhidLicense.message }}
+
+
+
+
+
+
+
+
+
+
+
{{ $t('troubleshooting.virtualhid_license_key_desc') }}
+
+
+
+
+
+
{{ $t('troubleshooting.virtualhid_license_machine_activated') }}
+
{{ $t('troubleshooting.virtualhid_license_machine_activated_desc') }}
+
+
+
+
+
+
+
+
+
{{ $t('troubleshooting.force_close') }}
+
{{ $t('troubleshooting.force_close_desc') }}
+
+ {{ $t('troubleshooting.force_close_success') }}
+
+
+ {{ $t('troubleshooting.force_close_error') }}
+
+
+
+
+
+
+
+
+
+
{{ $t('troubleshooting.restart_sunshine') }}
+
{{ $t('troubleshooting.restart_sunshine_desc') }}
+
+ {{ $t('troubleshooting.restart_sunshine_success') }}
+
+
+
+
+
+
+
+
+
+
{{ $t('troubleshooting.dd_reset') }}
+
{{ $t('troubleshooting.dd_reset_desc') }}
+
+ {{ $t('troubleshooting.dd_reset_success') }}
+
+
+ {{ $t('troubleshooting.dd_reset_error') }}
+
+
+
+
+
+
+
+
+
+
{{ $t('troubleshooting.unpair_title') }}
+
{{ $t('troubleshooting.unpair_desc') }}
+
+
+
{{ $t('_common.success') }} {{ $t('troubleshooting.unpair_single_success') }}
+
+
+
+ {{ $t('troubleshooting.unpair_all_success') }}
+
+
+ {{ $t('troubleshooting.unpair_all_error') }}
+
+
+
+
+
+
+
+ -
+ {{ $t('troubleshooting.unpair_single_no_devices') }}
+
+
+
+
+
+
+
{{ $t('troubleshooting.logs') }}
+
+
{{ $t('troubleshooting.logs_desc') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src_assets/common/assets/web/src/views/troubleshooting.html b/src_assets/common/assets/web/src/views/troubleshooting.html
deleted file mode 100644
index 75e0fa290bd..00000000000
--- a/src_assets/common/assets/web/src/views/troubleshooting.html
+++ /dev/null
@@ -1,1181 +0,0 @@
-
-
-
-
- <%- header %>
-
-
-
-
-
-
{{ $t('troubleshooting.troubleshooting') }}
-
-
-
-
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.virtualhid_benefit_gamepads_title') }}
-
{{ $t('troubleshooting.virtualhid_benefit_gamepads') }}
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.virtualhid_benefit_mouse_title') }}
-
{{ $t('troubleshooting.virtualhid_benefit_mouse') }}
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.virtualhid_benefit_features_title') }}
-
{{ $t('troubleshooting.virtualhid_benefit_features') }}
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.virtualhid_benefit_maintained_title') }}
-
{{ $t('troubleshooting.virtualhid_benefit_maintained') }}
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.virtual_gamepad_drivers') }}
-
{{ $t('troubleshooting.virtual_gamepad_drivers_desc') }}
-
-
-
-
-
-
-
-
- | {{ $t('troubleshooting.driver_name') }} |
- {{ $t('troubleshooting.driver_installed_version') }} |
- {{ $t('troubleshooting.driver_latest_version') }} |
- {{ $t('troubleshooting.driver_supported_versions') }} |
- {{ $t('troubleshooting.driver_status') }} |
-
- {{ $t('troubleshooting.driver_download') }}
- |
-
-
-
-
- | {{ $t('troubleshooting.virtualhid_driver') }} |
- {{ driverVersion(virtualhid) }} |
-
-
-
-
-
-
- {{ driverLatestVersion(virtualhidRelease) }}
-
- {{ driverReleaseStatusText(virtualhid, virtualhidRelease) }}
- |
- {{ virtualhid.supported_versions }} |
-
-
- {{ driverStatusText(virtualhid) }}
-
- |
-
-
-
- {{ $t('troubleshooting.driver_download') }}
-
- |
-
-
- | {{ $t('troubleshooting.vigembus_driver') }} |
- {{ driverVersion(vigembus) }} |
-
-
-
-
-
-
- {{ driverLatestVersion(vigembusRelease) }}
-
- {{ driverReleaseStatusText(vigembus, vigembusRelease) }}
- |
- {{ vigembus.supported_versions }} |
-
-
- {{ driverStatusText(vigembus) }}
-
- |
-
-
-
- {{ $t('troubleshooting.driver_download') }}
-
- |
-
-
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.virtualhid_license') }}
-
{{ $t('troubleshooting.virtualhid_license_desc') }}
-
-
{{ licenseStatusText() }}
-
-
-
-
-
-
{{ virtualhidLicense.message || $t('troubleshooting.virtualhid_license_unavailable') }}
-
-
-
-
- - {{ $t('troubleshooting.virtualhid_license_plan') }}
- - {{ virtualhidLicense.plan_name }}
-
-
- - {{ $t('troubleshooting.virtualhid_license_activations') }}
- - {{ licenseActivationText() }}
-
-
- - {{ $t('troubleshooting.virtualhid_license_active_devices') }}
- - {{ virtualhidLicense.active_devices }}
-
-
- - {{ $t('troubleshooting.virtualhid_license_customer') }}
- - {{ virtualhidLicense.customer_email }}
-
-
-
-
- {{ virtualhidLicense.message }}
-
-
-
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.virtualhid_license_key_desc') }}
-
-
-
-
-
-
{{ $t('troubleshooting.virtualhid_license_machine_activated') }}
-
{{ $t('troubleshooting.virtualhid_license_machine_activated_desc') }}
-
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.force_close') }}
-
{{ $t('troubleshooting.force_close_desc') }}
-
-
- {{ $t('troubleshooting.force_close_success') }}
-
-
-
- {{ $t('troubleshooting.force_close_error') }}
-
-
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.restart_sunshine') }}
-
{{ $t('troubleshooting.restart_sunshine_desc') }}
-
-
- {{ $t('troubleshooting.restart_sunshine_success') }}
-
-
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.dd_reset') }}
-
{{ $t('troubleshooting.dd_reset_desc') }}
-
-
- {{ $t('troubleshooting.dd_reset_success') }}
-
-
-
- {{ $t('troubleshooting.dd_reset_error') }}
-
-
-
-
-
-
-
-
-
-
-
{{ $t('troubleshooting.unpair_title') }}
-
-
-
{{ $t('troubleshooting.unpair_desc') }}
-
-
-
{{ $t('_common.success') }} {{ $t('troubleshooting.unpair_single_success') }}
-
-
-
-
- {{ $t('troubleshooting.unpair_all_success') }}
-
-
-
- {{ $t('troubleshooting.unpair_all_error') }}
-
-
-
-
- -
- {{ $t('troubleshooting.unpair_single_no_devices') }}
-
-
-
-
-
-
-
{{ $t('troubleshooting.logs') }}
-
-
{{ $t('troubleshooting.logs_desc') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
From 08d2bfa48cb59033f9aaf1ba118e90c228b45187 Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Mon, 24 Aug 2026 02:31:06 +0000
Subject: [PATCH 12/24] Migrate password change page
---
.../assets/web/src/views/PasswordView.vue | 104 ++++++++++++++-
.../common/assets/web/src/views/password.html | 121 ------------------
2 files changed, 98 insertions(+), 127 deletions(-)
delete mode 100644 src_assets/common/assets/web/src/views/password.html
diff --git a/src_assets/common/assets/web/src/views/PasswordView.vue b/src_assets/common/assets/web/src/views/PasswordView.vue
index 2fec3f27ace..6dfb21d58cd 100644
--- a/src_assets/common/assets/web/src/views/PasswordView.vue
+++ b/src_assets/common/assets/web/src/views/PasswordView.vue
@@ -1,8 +1,100 @@
-
-
- Password
- TODO: migrate content from src/views/password.html
+
+
{{ $t('password.password_change') }}
+
{{ $t('password.password_change_desc') }}
+
+
+
+
diff --git a/src_assets/common/assets/web/src/views/password.html b/src_assets/common/assets/web/src/views/password.html
deleted file mode 100644
index f20bc9218fd..00000000000
--- a/src_assets/common/assets/web/src/views/password.html
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
-
- <%- header %>
-
-
-
-
-
-
-
{{ $t('password.password_change') }}
-
{{ $t('password.password_change_desc') }}
-
-
-
-
-
From 1d7806ce6f4f55c8b7c5d10564327ca6dfcf8ab3 Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Mon, 24 Aug 2026 09:00:25 +0000
Subject: [PATCH 13/24] Fix bug with some bootstrap components not working on
load
---
src_assets/common/assets/web/src/utils/init.js | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/src_assets/common/assets/web/src/utils/init.js b/src_assets/common/assets/web/src/utils/init.js
index 1383f160402..ce3ce14521d 100644
--- a/src_assets/common/assets/web/src/utils/init.js
+++ b/src_assets/common/assets/web/src/utils/init.js
@@ -5,10 +5,7 @@ import 'bootstrap/dist/css/bootstrap.min.css'
// Makes themes load and style correctly.
import '../assets/sunshine.css'
-// must import even if not implicitly using here
-// https://github.com/aurelia/skeleton-navigation/issues/894
-// https://discourse.aurelia.io/t/bootstrap-import-bootstrap-breaks-dropdown-menu-in-navbar/641/9
-import 'bootstrap/dist/js/bootstrap'
+import 'bootstrap'
export function initApp(app, config) {
//Wait for locale initialization, then render
From d3207a18867d69522bf689b0cc3fa78ad8ab5cd9 Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Mon, 24 Aug 2026 09:00:56 +0000
Subject: [PATCH 14/24] Refactor theme swtiching logic
---
.../assets/web/src/components/ThemeToggle.vue | 178 +++++++-----------
.../common/assets/web/src/utils/theme.js | 100 ++--------
2 files changed, 86 insertions(+), 192 deletions(-)
diff --git a/src_assets/common/assets/web/src/components/ThemeToggle.vue b/src_assets/common/assets/web/src/components/ThemeToggle.vue
index f1a89f2c229..c8cc6c8bb50 100644
--- a/src_assets/common/assets/web/src/components/ThemeToggle.vue
+++ b/src_assets/common/assets/web/src/components/ThemeToggle.vue
@@ -1,6 +1,6 @@
-
+
-
+
{{ $t('navbar.toggle_theme') }}
diff --git a/src_assets/common/assets/web/src/utils/theme.js b/src_assets/common/assets/web/src/utils/theme.js
index b7e7c4437fe..a509c8a0b5f 100644
--- a/src_assets/common/assets/web/src/utils/theme.js
+++ b/src_assets/common/assets/web/src/utils/theme.js
@@ -1,3 +1,5 @@
+import { ref } from 'vue'
+
const getStoredTheme = () => localStorage.getItem('theme')
const setStoredTheme = theme => localStorage.setItem('theme', theme)
@@ -10,6 +12,11 @@ export const getPreferredTheme = () => {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
+// The active theme, kept reactive so components render theme-dependent UI
+// (active icon, active menu item, toggle label) through Vue instead of
+// querying/mutating the DOM directly.
+export const currentTheme = ref(getPreferredTheme())
+
// Define which themes are dark (for Bootstrap compatibility)
const darkThemes = new Set([
'dark',
@@ -28,7 +35,6 @@ const setTheme = theme => {
const preferredTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
document.documentElement.dataset.bsTheme = preferredTheme
document.documentElement.dataset.theme = preferredTheme
- console.log(`Theme set to auto (resolved to: ${preferredTheme})`)
} else {
// Set Bootstrap's data-bs-theme to 'light' or 'dark' for Bootstrap's own styles
const bsTheme = darkThemes.has(theme) ? 'dark' : 'light'
@@ -36,95 +42,29 @@ const setTheme = theme => {
// Set our custom data-theme attribute for our color schemes
document.documentElement.dataset.theme = theme
- console.log(`Theme set to: ${theme} (Bootstrap: ${bsTheme})`)
- }
-}
-
-export const showActiveTheme = (theme, focus = false) => {
- const themeSwitcher = document.querySelector('#bd-theme')
-
- if (!themeSwitcher) {
- return
- }
-
- const themeSwitcherText = document.querySelector('#bd-theme-text')
- const activeThemeIcon = document.querySelector('.theme-icon-active svg')
- const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
-
- if (!btnToActive) {
- return
- }
-
- const btnIcon = btnToActive.querySelector('svg')
-
- if (!activeThemeIcon || !btnIcon) {
- return
- }
-
- document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
- element.classList.remove('active')
- element.setAttribute('aria-pressed', 'false')
- })
-
- btnToActive.classList.add('active')
- btnToActive.setAttribute('aria-pressed', 'true')
-
- // Clone the SVG icon from the active button to the theme switcher
- const clonedIcon = btnIcon.cloneNode(true)
- activeThemeIcon.parentNode.replaceChild(clonedIcon, activeThemeIcon)
-
- const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.textContent.trim()})`
- themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
-
- if (focus) {
- themeSwitcher.focus()
}
}
-const applyTheme = theme => {
+export function selectTheme(theme) {
setStoredTheme(theme)
setTheme(theme)
- showActiveTheme(theme, true)
+ currentTheme.value = theme
}
-const pickRandomTheme = () => {
+export function pickRandomTheme(themeValues) {
const current = getStoredTheme()
- const values = Array.from(document.querySelectorAll('[data-bs-theme-value]'))
- .map(el => el.dataset.bsThemeValue)
- .filter(value => value !== 'auto' && value !== current)
+ const values = themeValues.filter(value => value !== current)
return values[Math.floor(Math.random() * values.length)] // NOSONAR(javascript:S2245) random not used for cryptography here
}
-export function setupThemeToggleListener() {
- document.querySelectorAll('[data-bs-theme-value]')
- .forEach(toggle => {
- toggle.addEventListener('click', () => applyTheme(toggle.dataset.bsThemeValue))
- })
-
- const randomToggle = document.querySelector('#bd-theme-random')
- if (randomToggle) {
- randomToggle.addEventListener('click', () => applyTheme(pickRandomTheme()))
- }
-
- showActiveTheme(getPreferredTheme(), false)
-}
-
export function loadAutoTheme() {
- (() => {
- 'use strict'
-
- setTheme(getPreferredTheme())
-
- window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
- const storedTheme = getStoredTheme()
- // Only auto-switch if theme is set to 'auto'
- if (storedTheme === 'auto' || !storedTheme) {
- setTheme(getPreferredTheme())
- }
- })
-
- window.addEventListener('DOMContentLoaded', () => {
- showActiveTheme(getPreferredTheme())
- })
- })()
+ setTheme(getPreferredTheme())
+
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
+ const storedTheme = getStoredTheme()
+ // Only auto-switch if theme is set to 'auto'
+ if (storedTheme === 'auto' || !storedTheme) {
+ setTheme(getPreferredTheme())
+ }
+ })
}
From cfa8b78d42bbab7c38a925d9fe82bbcc41faf962 Mon Sep 17 00:00:00 2001
From: Abhishek
Date: Mon, 24 Aug 2026 09:01:13 +0000
Subject: [PATCH 15/24] Make navbar sticky
---
src_assets/common/assets/web/src/components/Navbar.vue | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src_assets/common/assets/web/src/components/Navbar.vue b/src_assets/common/assets/web/src/components/Navbar.vue
index 720ec4ed4c3..d11f17f0ebb 100644
--- a/src_assets/common/assets/web/src/components/Navbar.vue
+++ b/src_assets/common/assets/web/src/components/Navbar.vue
@@ -1,8 +1,9 @@
-