diff --git a/src_assets/common/assets/web/apps.html b/src_assets/common/assets/web/apps.html index 8525749092e..c398014622b 100644 --- a/src_assets/common/assets/web/apps.html +++ b/src_assets/common/assets/web/apps.html @@ -14,27 +14,37 @@

{{ $t('apps.applications_title') }} ({{ appCountLab -
- - - -
- - - - - +
+ +
+ + + +
+ + + + + +
@@ -71,7 +81,7 @@
{{ app.name }}
{{ $t('apps.edit') }} - @@ -416,7 +426,7 @@

{{ $t('apps.env_vars_about') }}

sh -c "displayplacer "id:<screenId> res:${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} hz:${SUNSHINE_CLIENT_FPS} scaling:on origin:(0,0) degree:0""
@@ -569,7 +579,6 @@ data() { return { apps: [], - showEditForm: false, editForm: null, detachedCmd: "", coverSearching: false, @@ -589,6 +598,7 @@ fileBrowserTypedPath: "", searchQuery: "", sortMode: "default", + deleteTarget: null, version: null, githubVersion: null, }; @@ -646,14 +656,21 @@ ? `${total}` : `${shown} / ${total}`; }, + editModalTitle() { + if (!this.editForm) { + return ""; + } + const action = this.editForm.index === -1 + ? this.$t("apps.add_new") + : this.$t("apps.edit"); + + return this.editForm.name + ? `${action}: ${this.editForm.name}` + : action; + }, }, created() { - fetch("./api/apps") - .then((r) => r.json()) - .then((r) => { - console.log(r); - this.apps = r.apps; - }); + this.loadApps(); fetch("./api/config") .then(r => r.json()) @@ -683,8 +700,7 @@ detached: [], "image-path": "" }; - this.editForm.index = -1; - this.showEditForm = true; + this.openEditModal(); }, editApp(id) { this.editForm = JSON.parse(JSON.stringify(this.apps[id])); @@ -707,22 +723,34 @@ if (this.editForm["exit-timeout"] === undefined) { this.editForm["exit-timeout"] = 5; } - this.showEditForm = true; - }, - showDeleteForm(id) { - let resp = confirm( - "Are you sure to delete " + this.apps[id].name + "?" - ); - if (resp) { - apiFetch("./api/apps/" + id, { - method: "DELETE", - headers: { - "Content-Type": "application/json" - }, - }).then((r) => { - if (r.status === 200) document.location.reload(); + this.openEditModal(); + }, + showDeleteModal(id) { + this.deleteTarget = { index: id, name: this.apps[id].name }; + this.$nextTick(() => { + Modal.getOrCreateInstance(this.$refs.deleteModal).show(); + }); + }, + closeDeleteModal() { + const modal = Modal.getInstance(this.$refs.deleteModal); + if (modal) modal.hide(); + }, + loadApps() { + return fetch("./api/apps") + .then((r) => r.json()) + .then((r) => { + this.apps = r.apps; }); - } + }, + confirmDelete() { + apiFetch("./api/apps/" + this.deleteTarget.index, { + method: "DELETE", + headers: { + "Content-Type": "application/json" + }, + }).then((r) => { + if (r.status === 200) document.location.reload(); + }); }, addPrepCmd() { let template = { @@ -747,6 +775,8 @@ this.coverCandidates = []; this.coverSearchQuery = ""; + this.showStacked(this.$refs.coverFinderModal); + // Perform initial search with app name this.performCoverSearch(); }, @@ -844,7 +874,7 @@ this.fileBrowserTypedPath = startPath || ''; this.fileBrowserError = ''; this.fileBrowserNavigate(startPath || ''); - Modal.getOrCreateInstance(this.$refs.fileBrowserModal).show(); + this.showStacked(this.$refs.fileBrowserModal); }, fileBrowserClose() { const modal = Modal.getInstance(this.$refs.fileBrowserModal); @@ -944,6 +974,32 @@ else this.sortMode = "default"; }, + openEditModal() { + // Use $nextTick because if the edit version of the modal is created too early, it breaks... + this.$nextTick(() => { + Modal.getOrCreateInstance(this.$refs.editModal).show(); + }); + }, + closeEditModal() { + const modal = Modal.getInstance(this.$refs.editModal); + if (modal) modal.hide(); + }, + // We need to update the z-index since bootstrap gives all modals the same z-index + // Fixes the stacking issue of modals (cover finder / file browser) + showStacked(modalEl) { + modalEl.addEventListener('show.bs.modal', () => { + 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; + }); + }, { once: true }); + Modal.getOrCreateInstance(modalEl).show(); + }, }, }); diff --git a/src_assets/common/assets/web/public/assets/css/sunshine.css b/src_assets/common/assets/web/public/assets/css/sunshine.css index a8efdffdfbf..b7cb502345e 100644 --- a/src_assets/common/assets/web/public/assets/css/sunshine.css +++ b/src_assets/common/assets/web/public/assets/css/sunshine.css @@ -682,6 +682,7 @@ body { .modal-header, .modal-footer { border-color: var(--color-border) !important; + background-color: var(--color-surface-raised) !important; } .list-group-item { @@ -1713,7 +1714,7 @@ p { } .apps-toolbar .input-group { - max-width: 18rem; + width: 14rem; } .apps-toolbar .btn-outline-secondary { 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 f4eee2cdccf..a74d3d0a555 100644 --- a/src_assets/common/assets/web/public/assets/locale/en.json +++ b/src_assets/common/assets/web/public/assets/locale/en.json @@ -50,6 +50,8 @@ "covers_found": "Covers Found", "cover_search_hint": "Search names should match IGDB naming conventions.", "delete": "Delete", + "delete_confirm": "Are you sure you want to delete {name}?", + "delete_title": "Delete Application", "detached_cmds": "Detached Commands", "detached_cmds_add": "Add Detached Command", "detached_cmds_desc": "A list of commands to be run in the background.",