# UI Improvement Pass Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Replace the default Vuetify blue palette with a cool slate/navy monitoring-dashboard theme, lift the nav branding, add a WebSocket status indicator, improve Dashboard layout, fix a dark-mode bug in Subscriptions, and add per-page UX improvements to Downloads and Credentials.
**Architecture:** All changes are purely frontend (Vue 3 + Vuetify 3). No backend changes, no new API endpoints. Each task touches one file and can be built/verified independently with `npm run build` from the `frontend/` directory.
**Tech Stack:** Vue 3.4, Vuetify 3.5, Pinia, Vite 5 — all in `frontend/src/`.
---
## File Structure
| File | What changes |
|------|-------------|
| `frontend/src/plugins/vuetify.js` | Full palette replacement; component defaults update |
| `frontend/src/App.vue` | Nav brand header; nav item rounding/density; app bar border + WS indicator |
| `frontend/src/views/Dashboard.vue` | Number-forward stat cards; action bar split; running pulse animation; consistent empty states |
| `frontend/src/views/Subscriptions.vue` | Replace `bg-grey-lighten-4` with `bg-surface` on expanded rows |
| `frontend/src/views/Downloads.vue` | Add `exclude_superseded` filter toggle below existing filters |
| `frontend/src/views/Credentials.vue` | Configured vs unconfigured card visual treatment |
---
## Task 1: Color System & Component Defaults
**Files:**
- Modify: `frontend/src/plugins/vuetify.js` (full replacement)
**Context:** The current file sets identical colours for dark and light themes (both use `#1976D2` blue). We replace both themes entirely and add a `VChip` default. The existing `VCard: { elevation: 2 }` and `VBtn: { variant: 'flat' }` defaults are updated, not added from scratch.
- [ ] **Step 1: Replace `frontend/src/plugins/vuetify.js` with the new palette**
```js
import 'vuetify/styles'
import '@mdi/font/css/materialdesignicons.css'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
export default createVuetify({
components,
directives,
theme: {
defaultTheme: 'dark',
themes: {
dark: {
dark: true,
colors: {
background: '#0F172A',
surface: '#1E293B',
primary: '#60A5FA',
secondary: '#94A3B8',
error: '#F87171',
warning: '#FBBF24',
success: '#34D399',
info: '#38BDF8',
},
},
light: {
dark: false,
colors: {
background: '#F1F5F9',
surface: '#FFFFFF',
primary: '#2563EB',
secondary: '#475569',
error: '#EF4444',
warning: '#F59E0B',
success: '#10B981',
info: '#0EA5E9',
},
},
},
},
defaults: {
VCard: {
elevation: 0,
border: true,
},
VBtn: {
variant: 'flat',
},
VChip: {
rounded: 'md',
},
},
})
```
- [ ] **Step 2: Verify build passes**
```bash
cd frontend && npm run build
```
Expected: exits 0, no errors. Warnings about unused variables are OK.
- [ ] **Step 3: Visual check**
```bash
cd frontend && npm run dev
```
Open the app. Cards should now have a border instead of a shadow. Background should be deep navy in dark mode, cool light grey in light mode. Primary colour is a steel blue (`#60A5FA`), not the old Material blue.
- [ ] **Step 4: Commit**
```bash
git add frontend/src/plugins/vuetify.js
git commit -m "feat(ui): replace palette with slate/navy monitoring dashboard theme"
```
---
## Task 2: Nav Drawer Brand Header & App Bar
**Files:**
- Modify: `frontend/src/App.vue`
**Context:** Current `App.vue` uses a plain `v-list-item` for the brand block (lines 4–8). The nav list uses `density="compact"` (line 10) with no rounding or active-color. The app bar has `elevation="1"`. The `wsStore` is already imported and called (line 59, `wsStore.init()`), so `wsStore.isConnected` is available in the template without any new imports.
- [ ] **Step 1: Replace the entire `` block in `App.vue`**
Replace the template (lines 1–47, inclusive of the closing `` tag) with:
```html
mdi-download-network
GallerySubscriber
Download Manager
{{ currentPageTitle }}
mdi-circle
{{ wsStore.isConnected ? 'Real-time updates active' : 'Disconnected — real-time updates paused' }}
{{ isDark ? 'mdi-weather-sunny' : 'mdi-weather-night' }}
{{ notification.message }}
Close
```
The `` tag:
```html
```
- [ ] **Step 6: Verify build passes**
```bash
cd frontend && npm run build
```
Expected: exits 0.
- [ ] **Step 7: Visual check**
```bash
cd frontend && npm run dev
```
- All three empty states have consistent centered icon + body text + caption layout
- If a download is running, its list item has a pulsing left border
- [ ] **Step 8: Commit**
```bash
git add frontend/src/views/Dashboard.vue
git commit -m "feat(ui): consistent empty states and running pulse on Dashboard"
```
---
## Task 5: Subscriptions Dark Mode Fix
**Files:**
- Modify: `frontend/src/views/Subscriptions.vue` (one line change)
**Context:** Line 157 in Subscriptions.vue has `class="ml-8 bg-grey-lighten-4"` on the inner expanded-row table. `bg-grey-lighten-4` is a hardcoded Vuetify grey utility class that does not adapt to dark mode — it forces a light background in both themes, making text unreadable in dark mode. Replace with `bg-surface`, which resolves to the current theme's surface colour.
- [ ] **Step 1: Fix the expanded row background class**
Find (around line 157):
```html
```
Replace with:
```html
```
- [ ] **Step 2: Verify build passes**
```bash
cd frontend && npm run build
```
Expected: exits 0.
- [ ] **Step 3: Visual check in dark mode**
```bash
cd frontend && npm run dev
```
Go to Subscriptions, expand a subscription row. The inner source table should have the same dark background as the rest of the UI, not a forced light grey.
- [ ] **Step 4: Commit**
```bash
git add frontend/src/views/Subscriptions.vue
git commit -m "fix(ui): use bg-surface on expanded subscription rows for dark mode compat"
```
---
## Task 6: Downloads — Exclude Superseded Filter
**Files:**
- Modify: `frontend/src/views/Downloads.vue`
**Context:** The Downloads page has a filter row with four `md="3"` columns (Status, Source, From Date, To Date) filling the full 12 columns. The existing `loadDownloads()` function already accepts arbitrary params and passes them to `downloadsStore.fetchDownloads()`, which supports `exclude_superseded`. We add a new `v-row` below the existing filter row.
- [ ] **Step 1: Add the `filterExcludeSuperseded` ref in `