eed42a260a
The TopNav and each sticky sub-header pinned beneath it (Gallery's filter bar, the Browse/Series/Settings/Subscriptions tabs bars) each painted their OWN dark-to-transparent gradient (Gallery) or a solid surface band (the rest), so the fade read as happening twice — dark, fade out, then dark again — instead of one gradient flowing from the nav down through the sub-nav. Operator asked to treat the sub-nav as part of the nav with a single gradient. New shared .fc-chrome-continues primitive (app.css): the nav fades from opaque to a shared --fc-chrome-seam alpha (on views flagged meta.stickyChrome), and the sub-header continues from that exact seam alpha to transparent over its own height. Both reference the same var so the alphas meet at the 64px boundary — no re-darkening, no doubling. Percentage stops keep it spanning the filter bar's expanding refine panel; the primitive's blur keeps tabs/controls legible where the old solid bars had none. --fc-chrome-seam is the single tuning knob. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
113 lines
4.0 KiB
Vue
113 lines
4.0 KiB
Vue
<template>
|
|
<!-- Centered, width-capped column so the tab strip + every panel sit in a
|
|
tidy centered measure rather than stretching full-width (operator
|
|
2026-06-18). v-container is margin-auto by default; the cap keeps long
|
|
maintenance/import panels readable. -->
|
|
<v-container class="pt-2 pb-6 fc-settings">
|
|
<!-- Sticky tabs: operator-flagged 2026-05-25 — long Import / Maintenance
|
|
panels pushed the tab strip out of the viewport, forcing a scroll-
|
|
to-top just to change tab. AppShell's TopNav is 64px sticky, so the
|
|
tab strip lives directly under it. The .fc-chrome-continues fade
|
|
continues the nav's gradient across the strip (operator 2026-07-13). -->
|
|
<v-tabs
|
|
v-model="tab" color="accent" class="mb-4 fc-chrome-continues"
|
|
style="position: sticky; top: 64px; z-index: 4;"
|
|
>
|
|
<v-tab value="overview">Overview</v-tab>
|
|
<v-tab value="activity">Activity</v-tab>
|
|
<v-tab value="cleanup">Cleanup</v-tab>
|
|
<v-tab value="maintenance">Maintenance</v-tab>
|
|
</v-tabs>
|
|
|
|
<v-window v-model="tab">
|
|
<v-window-item value="overview">
|
|
<SystemStatsCards :stats="system.stats" />
|
|
<SystemActivitySummary
|
|
class="mt-4"
|
|
@open-activity="tab = 'activity'"
|
|
/>
|
|
<!-- Health strip (2026-07-02): the same GPU + downloads panels the
|
|
Activity tab uses — Overview answers "is everything healthy?"
|
|
across ALL systems, not just the Celery queues above. -->
|
|
<div class="fc-health-row mt-4">
|
|
<GpuActivityPanel @open-maintenance="tab = 'maintenance'" />
|
|
<DownloadsActivityPanel />
|
|
</div>
|
|
<v-alert
|
|
v-if="system.stats && (system.stats.tasks.pending + system.stats.tasks.queued) > 0"
|
|
type="info" variant="tonal" class="mt-4" closable
|
|
>
|
|
{{ system.stats.tasks.pending + system.stats.tasks.queued }} import task(s) pending.
|
|
<v-btn variant="text" size="small" @click="tab = 'activity'">View in Activity</v-btn>
|
|
</v-alert>
|
|
</v-window-item>
|
|
|
|
<v-window-item value="activity">
|
|
<SystemActivityTab @open-maintenance="tab = 'maintenance'" />
|
|
</v-window-item>
|
|
|
|
<v-window-item value="cleanup">
|
|
<CleanupView />
|
|
</v-window-item>
|
|
|
|
<v-window-item value="maintenance">
|
|
<MaintenancePanel />
|
|
</v-window-item>
|
|
</v-window>
|
|
</v-container>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
|
import { useSystemStore } from '../stores/system.js'
|
|
import SystemStatsCards from '../components/settings/SystemStatsCards.vue'
|
|
import SystemActivitySummary from '../components/settings/SystemActivitySummary.vue'
|
|
import SystemActivityTab from '../components/settings/SystemActivityTab.vue'
|
|
import GpuActivityPanel from '../components/settings/GpuActivityPanel.vue'
|
|
import DownloadsActivityPanel from '../components/settings/DownloadsActivityPanel.vue'
|
|
import MaintenancePanel from '../components/settings/MaintenancePanel.vue'
|
|
import CleanupView from './CleanupView.vue'
|
|
import { useMLStore } from '../stores/ml.js'
|
|
|
|
const tab = ref('overview')
|
|
const system = useSystemStore()
|
|
const mlStore = useMLStore()
|
|
|
|
let pollId = null
|
|
|
|
function startPolling() {
|
|
if (pollId) return
|
|
system.refreshStats()
|
|
pollId = setInterval(() => {
|
|
if (!document.hidden) system.refreshStats()
|
|
}, 5000)
|
|
}
|
|
|
|
function stopPolling() {
|
|
if (pollId) { clearInterval(pollId); pollId = null }
|
|
}
|
|
|
|
onMounted(startPolling)
|
|
onUnmounted(stopPolling)
|
|
|
|
watch(tab, (t) => {
|
|
if (t === 'maintenance') mlStore.loadSettings()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* Centered, capped measure for the whole Settings surface (tabs + panels). */
|
|
.fc-settings {
|
|
max-width: 1140px;
|
|
}
|
|
/* Overview health strip: the two pulse panels side by side, stacking on
|
|
narrow screens. Cancel the panels' own bottom margin — the row owns gaps. */
|
|
.fc-health-row {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
|
|
gap: 16px;
|
|
align-items: start;
|
|
}
|
|
.fc-health-row :deep(.v-card) { margin-bottom: 0 !important; }
|
|
</style>
|