feat(ui): number-forward stat cards and split action bar on Dashboard

This commit is contained in:
2026-03-19 18:29:19 -04:00
parent f132c115c9
commit b419ee8b32
+39 -55
View File
@@ -1,72 +1,52 @@
<template> <template>
<div> <div>
<v-row> <v-row>
<!-- Stats Cards -->
<v-col cols="12" md="3"> <v-col cols="12" md="3">
<v-card> <v-card>
<v-card-text class="d-flex align-center"> <v-card-text style="border-left: 4px solid rgb(var(--v-theme-primary)); padding-left: 20px">
<v-avatar color="primary" size="48" class="mr-4"> <div class="text-h3 font-weight-bold">{{ sourcesStore.sources.length }}</div>
<v-icon>mdi-account-multiple</v-icon> <div class="text-caption text-medium-emphasis">Total Sources</div>
</v-avatar>
<div>
<div class="text-h4">{{ sourcesStore.sources.length }}</div>
<div class="text-caption">Total Sources</div>
</div>
</v-card-text> </v-card-text>
</v-card> </v-card>
</v-col> </v-col>
<v-col cols="12" md="3"> <v-col cols="12" md="3">
<v-card> <v-card>
<v-card-text class="d-flex align-center"> <v-card-text style="border-left: 4px solid rgb(var(--v-theme-success)); padding-left: 20px">
<v-avatar color="success" size="48" class="mr-4"> <div class="text-h3 font-weight-bold">{{ stats?.completed || 0 }}</div>
<v-icon>mdi-check-circle</v-icon> <div class="text-caption text-medium-emphasis">Completed Downloads</div>
</v-avatar>
<div>
<div class="text-h4">{{ stats?.completed || 0 }}</div>
<div class="text-caption">Completed Downloads</div>
</div>
</v-card-text> </v-card-text>
</v-card> </v-card>
</v-col> </v-col>
<v-col cols="12" md="3"> <v-col cols="12" md="3">
<v-card> <v-card>
<v-card-text class="d-flex align-center"> <v-card-text style="border-left: 4px solid rgb(var(--v-theme-error)); padding-left: 20px">
<v-avatar color="error" size="48" class="mr-4"> <div class="text-h3 font-weight-bold">{{ stats?.active_failed || 0 }}</div>
<v-icon>mdi-alert-circle</v-icon> <div class="text-caption text-medium-emphasis">Failed Downloads</div>
</v-avatar>
<div>
<div class="text-h4">{{ stats?.active_failed || 0 }}</div>
<div class="text-caption">Failed Downloads</div>
</div>
</v-card-text> </v-card-text>
</v-card> </v-card>
</v-col> </v-col>
<v-col cols="12" md="3"> <v-col cols="12" md="3">
<v-card> <v-card>
<v-card-text class="d-flex align-center"> <v-card-text style="border-left: 4px solid rgb(var(--v-theme-warning)); padding-left: 20px">
<v-avatar color="warning" size="48" class="mr-4"> <div class="text-h3 font-weight-bold">{{ activeDownloadsCount }}</div>
<v-icon>mdi-clock-outline</v-icon> <div class="text-caption text-medium-emphasis">Active Downloads</div>
</v-avatar> <div class="text-caption text-medium-emphasis" v-if="stats?.queued || stats?.running">
<div> {{ stats?.queued || 0 }} queued · {{ stats?.running || 0 }} running
<div class="text-h4">{{ activeDownloadsCount }}</div>
<div class="text-caption">Active Downloads</div>
<div class="text-caption text-grey" v-if="stats?.queued || stats?.running">
{{ stats?.queued || 0 }} queued, {{ stats?.running || 0 }} running
</div>
</div> </div>
</v-card-text> </v-card-text>
</v-card> </v-card>
</v-col> </v-col>
</v-row> </v-row>
<!-- Quick Actions --> <!-- Quick Actions & Status -->
<v-row class="mt-4"> <v-row class="mt-4">
<v-col cols="12"> <v-col cols="12">
<v-card> <v-card>
<v-card-text class="d-flex align-center ga-4 flex-wrap"> <!-- Row 1: Action buttons -->
<v-card-text class="d-flex align-center ga-3 flex-wrap pb-3">
<v-btn <v-btn
color="primary" color="primary"
prepend-icon="mdi-refresh" prepend-icon="mdi-refresh"
@@ -94,25 +74,29 @@
> >
Reset Stuck ({{ stuckRunningCount }}) Reset Stuck ({{ stuckRunningCount }})
</v-btn> </v-btn>
<v-spacer /> </v-card-text>
<!-- Credential Status -->
<div class="d-flex align-center ga-2"> <v-divider />
<v-icon size="small" class="mr-1">mdi-key</v-icon>
<span class="text-body-2 text-grey mr-2">Auth:</span> <!-- Row 2: Status info -->
<v-chip <v-card-text class="d-flex align-center ga-2 flex-wrap pt-3">
v-for="platform in supportedPlatforms" <v-icon size="small">mdi-key</v-icon>
:key="platform" <span class="text-body-2 text-medium-emphasis mr-1">Auth:</span>
:color="credentialsStore.hasPlatformCredentials(platform) ? 'success' : 'grey'" <v-chip
:variant="credentialsStore.hasPlatformCredentials(platform) ? 'tonal' : 'outlined'" v-for="platform in supportedPlatforms"
size="x-small" :key="platform"
:to="credentialsStore.hasPlatformCredentials(platform) ? undefined : '/credentials'" :color="credentialsStore.hasPlatformCredentials(platform) ? 'success' : 'grey'"
> :variant="credentialsStore.hasPlatformCredentials(platform) ? 'tonal' : 'outlined'"
<v-icon start size="x-small">{{ getPlatformIcon(platform) }}</v-icon> size="x-small"
{{ platform }} :to="credentialsStore.hasPlatformCredentials(platform) ? undefined : '/credentials'"
</v-chip> >
</div> <v-icon start size="x-small">{{ getPlatformIcon(platform) }}</v-icon>
{{ platform }}
</v-chip>
<v-divider vertical class="mx-2" /> <v-divider vertical class="mx-2" />
<div class="text-body-2 text-grey d-flex align-center">
<div class="text-body-2 text-medium-emphasis d-flex align-center">
<v-icon size="small" class="mr-1">mdi-harddisk</v-icon> <v-icon size="small" class="mr-1">mdi-harddisk</v-icon>
Storage: {{ storageStats?.total_size_formatted || 'Calculating...' }} Storage: {{ storageStats?.total_size_formatted || 'Calculating...' }}
<span v-if="storageStats?.file_count" class="ml-2"> <span v-if="storageStats?.file_count" class="ml-2">