refactor: split Marketplace, Server, Home, AppDetails views; minor frontend quality fixes

- F29-F32: Split 4 views (Marketplace 1293→505, Server 1132→486, Home 1059→394, AppDetails 1036→386)
- F20: Add aria-current="page" to Dashboard nav links
- F21: Add 150ms search debounce in Marketplace and Apps views
- F22: Reduce backdrop-filter blur to 8px on mobile for GPU performance
- F23: Track and clear WebSocket connect check interval in all paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-21 03:01:38 +00:00
co-authored by Claude Opus 4.6
parent afd7405b1a
commit 69e25410b0
20 changed files with 2713 additions and 3206 deletions
+11 -4
View File
@@ -315,7 +315,7 @@ let appsAnimationDone = false
</script>
<script setup lang="ts">
import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
import { computed, ref, watch, onMounted, onBeforeUnmount } from 'vue'
import { useRouter, useRoute, RouterLink } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useAppStore } from '../stores/app'
@@ -365,8 +365,15 @@ function isServiceContainer(id: string): boolean {
return false
}
// Search
// Search (debounced to avoid filtering on every keystroke)
const searchQuery = ref('')
const debouncedSearchQuery = ref('')
let searchDebounceTimer: ReturnType<typeof setTimeout> | undefined
watch(searchQuery, (val) => {
clearTimeout(searchDebounceTimer)
searchDebounceTimer = setTimeout(() => { debouncedSearchQuery.value = val }, 150)
})
onBeforeUnmount(() => { clearTimeout(searchDebounceTimer) })
// Category filter (same categories as App Store)
const selectedCategory = ref('all')
@@ -527,8 +534,8 @@ const sortedPackageEntries = computed(() => {
})
const filteredPackageEntries = computed(() => {
if (!searchQuery.value) return sortedPackageEntries.value
const q = searchQuery.value.toLowerCase()
if (!debouncedSearchQuery.value) return sortedPackageEntries.value
const q = debouncedSearchQuery.value.toLowerCase()
return sortedPackageEntries.value.filter(([id, pkg]) =>
(pkg.manifest?.title ?? '').toLowerCase().includes(q) ||
(pkg.manifest?.description?.short ?? '').toLowerCase().includes(q) ||