multi comma

This commit is contained in:
firestar5683
2026-09-14 13:03:17 -05:00
parent fc852fed06
commit 71649a2ac1
4 changed files with 91 additions and 14 deletions
@@ -361,7 +361,7 @@ ul { list-style: none; margin: 0; padding: 0; }
.gx-appbar .gx-appbar__back,
.gx-appbar .gx-theme-toggle,
.gx-appbar .gx-appbar__pin {
.gx-appbar .gx-appbar__menu {
background: var(--glass-bg);
backdrop-filter: var(--glass-blur);
-webkit-backdrop-filter: var(--glass-blur);
@@ -376,7 +376,8 @@ ul { list-style: none; margin: 0; padding: 0; }
}
.gx-appbar .gx-appbar__back:active,
.gx-appbar .gx-theme-toggle:active { transform: scale(0.92); }
.gx-appbar .gx-theme-toggle:active,
.gx-appbar .gx-appbar__menu:active { transform: scale(0.92); }
.gx-appbar__title {
background: linear-gradient(135deg, #8b6cc5 0%, #5ec8c8 55%, #d4789c 100%);
@@ -464,8 +465,7 @@ ul { list-style: none; margin: 0; padding: 0; }
.gx-icon-btn:active { transform: scale(0.9); }
.gx-icon-btn i { font-size: 1.3rem; }
.gx-back-btn { display: none; }
.gx-menu-btn { display: inline-flex; }
.gx-appbar .gx-appbar__pin { display: none; }
.gx-appbar__menu { display: inline-flex; }
.gx-searchwrap {
align-items: center;
@@ -1724,6 +1724,24 @@ button.gx-chip:hover {
.gx-nav-item i { font-size: 1.3rem; width: 24px; }
.gx-device-picker__name {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.gx-device-picker__current {
background: var(--glass-active-bg);
border: 1px solid var(--glass-border);
border-radius: var(--radius-full);
color: var(--primary);
font-size: var(--fs-xs);
margin-left: auto;
padding: 3px 8px;
white-space: nowrap;
}
.gx-scrim {
align-items: center;
background: rgba(0, 0, 0, 0.6);
@@ -2252,17 +2270,14 @@ button.gx-chip:hover {
@media (max-width: 767px) {
.liquid-glass-nav { display: flex; }
.gx-menu-btn { display: none; }
.gx-back-btn { display: inline-flex; }
.gx-appbar__search { flex: 1; min-width: 0; }
.gx-status-pill { display: none; }
.gx-appbar .gx-appbar__pin { display: inline-flex; }
.gx-content { padding-left: var(--sp-3); padding-right: var(--sp-3); }
}
@media (min-width: 768px) {
.liquid-glass-nav { display: none; }
.gx-menu-btn { display: inline-flex; }
.gx-back-btn { display: none; }
.gx-content { padding-bottom: var(--sp-6); }
}
@@ -2,6 +2,7 @@ import { store, navigate, goBack, toolHref, toggleTheme, toggleNavPinned } from
import { api } from "../api.js"
import { usePolling } from "../composables.js"
import { languageState, setLanguage, t } from "../i18n.js"
import { DevicePicker } from "./DevicePicker.js"
const NAV = {
recordings: [
@@ -33,6 +34,7 @@ const BOTTOM_NAV = [
export const AppShell = {
name: "AppShell",
components: { DevicePicker },
data() {
return { store, BOTTOM_NAV, NAV }
},
@@ -115,9 +117,6 @@ export const AppShell = {
<i class="bi bi-arrow-left"></i>
</button>
<div class="gx-appbar__pill">
<button type="button" class="gx-icon-btn gx-menu-btn" :aria-label="tr('Menu')" @click="store.drawerOpen = true">
<i class="bi bi-list"></i>
</button>
<span class="gx-appbar__home" role="button" tabindex="0"
:aria-label="tr('Galaxy home')" @click="goHome" @keydown.enter="goHome" @keydown.space.prevent="goHome">
<span class="gx-appbar__title">Galaxy</span>
@@ -140,10 +139,8 @@ export const AppShell = {
:title="isLight ? tr('Dark mode') : tr('Light mode')" @click="themeToggle">
<i class="bi" :class="isLight ? 'bi-moon-stars-fill' : 'bi-sun-fill'"></i>
</button>
<button type="button" class="gx-icon-btn gx-appbar__pin" :aria-pressed="navPinned"
:aria-label="navPinned ? tr('Unpin navigation') : tr('Pin navigation')"
:title="navPinned ? tr('Unpin navigation') : tr('Pin navigation')" @click="toggleNavPin">
<i class="bi" :class="navPinned ? 'bi-pin-angle-fill' : 'bi-pin-angle'"></i>
<button type="button" class="gx-icon-btn gx-appbar__menu" :aria-label="tr('Menu')" :title="tr('Menu')" @click="store.drawerOpen = true">
<i class="bi bi-list"></i>
</button>
</header>
@@ -160,6 +157,7 @@ export const AppShell = {
<i class="bi" :class="navPinned ? 'bi-pin-angle-fill' : 'bi-pin-angle'"></i>
</button>
</div>
<DevicePicker />
<div class="gx-nav-section">
<div class="gx-nav-section__title">{{ tr("Main") }}</div>
<a class="gx-nav-item" :class="{ active: isActive('/') }" @click.prevent="navTo('/')">
@@ -0,0 +1,52 @@
const SLUG_RE = /^[A-Za-z0-9]{16}$/
export const DevicePicker = {
name: "DevicePicker",
data() {
return {
devices: [],
activeSlug: "",
loading: true,
}
},
computed: {
hasMultipleDevices() { return this.devices.length > 1 },
},
methods: {
async loadDevices() {
try {
const response = await fetch("/_gateway/devices", { cache: "no-store" })
if (!response.ok) return
const data = await response.json()
this.activeSlug = SLUG_RE.test(data?.activeSlug || "") ? data.activeSlug : ""
this.devices = Array.isArray(data?.devices)
? data.devices.filter((device) => SLUG_RE.test(device?.slug || "") && device?.path)
: []
} catch (error) {
// Local Galaxy instances do not have the gateway directory endpoint.
} finally {
this.loading = false
}
},
selectDevice(device) {
if (!device?.path || device.slug === this.activeSlug) return
window.location.assign(device.path)
},
},
mounted() {
this.loadDevices()
},
template: `
<div v-if="!loading && hasMultipleDevices" class="gx-nav-section gx-device-picker">
<div class="gx-nav-section__title">Commas</div>
<a v-for="device in devices" :key="device.slug" class="gx-nav-item gx-device-picker__item"
:class="{ active: device.slug === activeSlug }" :href="device.path"
:aria-current="device.slug === activeSlug ? 'page' : undefined"
@click.prevent="selectDevice(device)">
<i class="bi bi-cpu"></i>
<span class="gx-device-picker__name">{{ device.name }}</span>
<span v-if="device.slug === activeSlug" class="gx-device-picker__current">Current</span>
</a>
</div>
`,
}
@@ -26,6 +26,7 @@ def test_ui_app_shell_files_exist():
"js/params.js",
"js/i18n.js",
"js/components/AppShell.js",
"js/components/DevicePicker.js",
"js/components/GalaxyModal.js",
"js/components/GalaxySection.js",
"js/components/GalaxyEmbed.js",
@@ -62,6 +63,17 @@ def test_ui_index_wires_vue_and_mount_point():
assert 'apple-mobile-web-app-title" content="Galaxy"' in index
def test_ui_device_picker_uses_gateway_directory_and_preserves_local_galaxy():
picker = _read("js/components/DevicePicker.js")
shell = _read("js/components/AppShell.js")
assert 'fetch("/_gateway/devices"' in picker
assert "hasMultipleDevices" in picker
assert "window.location.assign(device.path)" in picker
assert '<DevicePicker />' in shell
assert "Local Galaxy instances do not have the gateway directory endpoint." in picker
def test_ui_uses_same_backend_endpoints():
settings = _read("js/views/Settings.js")
params = _read("js/params.js")