feat(unified-mobile-material-design): Complete US-111 - CacheStatsView Mobile Material Design
Implemented by Ralph autonomous loop. Iteration: 1 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,44 @@
|
||||
<template>
|
||||
<div class="cache-stats-view">
|
||||
<div class="stats-header">
|
||||
<div class="cache-stats-view" :class="{ 'mobile-layout': isMobile }">
|
||||
<!-- US-111: Mobile Material Design Top Bar -->
|
||||
<MobileTopBar
|
||||
v-if="isMobile"
|
||||
title="Statistici Cache"
|
||||
:show-menu="true"
|
||||
:actions="mobileTopBarActions"
|
||||
@menu-click="toggleMobileMenu"
|
||||
@action-click="handleTopBarAction"
|
||||
/>
|
||||
|
||||
<!-- US-111: Mobile Hamburger Menu -->
|
||||
<Sidebar v-if="isMobile" v-model:visible="mobileMenuVisible" position="left" class="mobile-sidebar">
|
||||
<template #header>
|
||||
<div class="sidebar-header">
|
||||
<span class="sidebar-title">ROA2WEB</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="sidebar-menu">
|
||||
<router-link to="/data-entry" class="sidebar-item">
|
||||
<i class="pi pi-receipt"></i>
|
||||
<span>Bonuri</span>
|
||||
</router-link>
|
||||
<router-link to="/reports/cache-stats" class="sidebar-item active">
|
||||
<i class="pi pi-database"></i>
|
||||
<span>Statistici Cache</span>
|
||||
</router-link>
|
||||
<router-link to="/reports/dashboard" class="sidebar-item">
|
||||
<i class="pi pi-chart-bar"></i>
|
||||
<span>Rapoarte</span>
|
||||
</router-link>
|
||||
<router-link to="/data-entry/ocr-metrics" class="sidebar-item">
|
||||
<i class="pi pi-cog"></i>
|
||||
<span>Setări</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</Sidebar>
|
||||
|
||||
<!-- Desktop Header -->
|
||||
<div class="stats-header" v-if="!isMobile">
|
||||
<h1>Cache Statistics</h1>
|
||||
<div class="actions">
|
||||
<Button
|
||||
@@ -178,11 +216,14 @@
|
||||
/>
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
<!-- US-111: Mobile Bottom Navigation -->
|
||||
<MobileBottomNav v-if="isMobile" :items="mobileBottomNavItems" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { ref, computed, onMounted, onUnmounted } from "vue";
|
||||
import { useCacheStore } from "@reports/stores/cacheStore";
|
||||
import { useCompanyStore } from "@reports/stores/sharedStores";
|
||||
import { useToast } from "primevue/usetoast";
|
||||
@@ -196,6 +237,11 @@ import InputSwitch from "primevue/inputswitch";
|
||||
import Dialog from "primevue/dialog";
|
||||
import RadioButton from "primevue/radiobutton";
|
||||
import Message from "primevue/message";
|
||||
import Sidebar from "primevue/sidebar";
|
||||
|
||||
// US-111: Mobile Material Design components
|
||||
import MobileTopBar from "@shared/components/mobile/MobileTopBar.vue";
|
||||
import MobileBottomNav from "@shared/components/mobile/MobileBottomNav.vue";
|
||||
|
||||
const cacheStore = useCacheStore();
|
||||
const companyStore = useCompanyStore();
|
||||
@@ -209,6 +255,49 @@ const userCacheEnabled = ref(true);
|
||||
const showClearDialog = ref(false);
|
||||
const clearScope = ref("current");
|
||||
|
||||
// US-111: Mobile state
|
||||
const isMobile = ref(window.innerWidth < 768);
|
||||
const mobileMenuVisible = ref(false);
|
||||
|
||||
// US-111: Toggle mobile hamburger menu
|
||||
const toggleMobileMenu = () => {
|
||||
mobileMenuVisible.value = !mobileMenuVisible.value;
|
||||
};
|
||||
|
||||
// US-111: Mobile TopBar actions (refresh only for cache stats)
|
||||
const mobileTopBarActions = computed(() => [
|
||||
{
|
||||
icon: "pi pi-refresh",
|
||||
label: "Actualizează",
|
||||
tooltip: "Actualizează statistici",
|
||||
},
|
||||
]);
|
||||
|
||||
// US-111: Handle top bar action clicks
|
||||
const handleTopBarAction = (action) => {
|
||||
if (action.icon === "pi pi-refresh") {
|
||||
loadStats();
|
||||
}
|
||||
};
|
||||
|
||||
// US-111: Bottom nav items for MobileBottomNav component
|
||||
const mobileBottomNavItems = computed(() => [
|
||||
{ to: "/data-entry", icon: "pi pi-receipt", label: "Bonuri" },
|
||||
{
|
||||
to: "/reports/cache-stats",
|
||||
icon: "pi pi-database",
|
||||
label: "Cache",
|
||||
active: true,
|
||||
},
|
||||
{ to: "/reports/dashboard", icon: "pi pi-chart-bar", label: "Rapoarte" },
|
||||
{ to: "/data-entry/ocr-metrics", icon: "pi pi-cog", label: "Setări" },
|
||||
]);
|
||||
|
||||
// US-111: Handle window resize
|
||||
const handleResize = () => {
|
||||
isMobile.value = window.innerWidth < 768;
|
||||
};
|
||||
|
||||
const responseTimesTable = computed(() => {
|
||||
if (!stats.value?.response_times) return [];
|
||||
|
||||
@@ -314,14 +403,21 @@ function clearError() {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// US-111: Add resize listener for mobile detection
|
||||
window.addEventListener("resize", handleResize);
|
||||
loadStats();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
// US-111: Remove resize listener
|
||||
window.removeEventListener("resize", handleResize);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Container - Uses global .app-container pattern */
|
||||
.cache-stats-view {
|
||||
padding: 2rem;
|
||||
padding: var(--space-xl);
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -331,7 +427,7 @@ onMounted(() => {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
margin-bottom: var(--space-xl);
|
||||
}
|
||||
|
||||
.stats-header h1 {
|
||||
@@ -341,29 +437,29 @@ onMounted(() => {
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||
gap: 1.5rem;
|
||||
gap: var(--space-lg);
|
||||
}
|
||||
|
||||
.status-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
.status-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
.status-item label {
|
||||
font-weight: 600;
|
||||
font-weight: var(--font-semibold);
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
@@ -373,14 +469,14 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.hit-rate h3 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
margin: 0 0 var(--space-sm) 0;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.hit-rate p {
|
||||
margin: 0 0 1rem 0;
|
||||
margin: 0 0 var(--space-md) 0;
|
||||
color: var(--text-color-secondary);
|
||||
font-size: 0.9rem;
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.queries-list {
|
||||
@@ -390,7 +486,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.queries-list li {
|
||||
padding: 0.5rem 0;
|
||||
padding: var(--space-sm) 0;
|
||||
border-bottom: 1px solid var(--surface-border);
|
||||
}
|
||||
|
||||
@@ -399,8 +495,8 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.average-row {
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem;
|
||||
margin-top: var(--space-md);
|
||||
padding-top: var(--space-md);
|
||||
border-top: 2px solid var(--surface-border);
|
||||
text-align: center;
|
||||
}
|
||||
@@ -412,7 +508,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.details-list li {
|
||||
padding: 0.5rem 0;
|
||||
padding: var(--space-sm) 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
@@ -420,26 +516,100 @@ onMounted(() => {
|
||||
.clear-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
gap: var(--space-md);
|
||||
margin-top: var(--space-md);
|
||||
}
|
||||
|
||||
.p-field-radiobutton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.response-times-card {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
/* ================================================
|
||||
US-111: Mobile Layout Styles
|
||||
================================================ */
|
||||
|
||||
.mobile-layout {
|
||||
padding: 0;
|
||||
padding-top: 56px; /* MobileTopBar height */
|
||||
padding-bottom: 56px; /* MobileBottomNav height */
|
||||
}
|
||||
|
||||
.mobile-layout .stats-grid {
|
||||
padding: var(--space-sm);
|
||||
gap: var(--space-sm);
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
/* Mobile sidebar styles */
|
||||
.mobile-sidebar .sidebar-header {
|
||||
padding: var(--space-md);
|
||||
border-bottom: 1px solid var(--surface-border);
|
||||
}
|
||||
|
||||
.mobile-sidebar .sidebar-title {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: var(--font-bold);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.mobile-sidebar .sidebar-menu {
|
||||
padding: var(--space-sm) 0;
|
||||
}
|
||||
|
||||
.mobile-sidebar .sidebar-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-md);
|
||||
padding: var(--space-md) var(--space-lg);
|
||||
color: var(--text-color);
|
||||
text-decoration: none;
|
||||
transition: background-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.mobile-sidebar .sidebar-item:hover,
|
||||
.mobile-sidebar .sidebar-item:active {
|
||||
background: var(--surface-hover);
|
||||
}
|
||||
|
||||
.mobile-sidebar .sidebar-item.active {
|
||||
background: var(--blue-50);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.mobile-sidebar .sidebar-item i {
|
||||
font-size: var(--text-xl);
|
||||
width: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* ================================================
|
||||
Dark Mode Support for Mobile
|
||||
================================================ */
|
||||
|
||||
[data-theme="dark"] .mobile-sidebar .sidebar-item.active {
|
||||
background: var(--blue-900);
|
||||
color: var(--blue-400);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme]) .mobile-sidebar .sidebar-item.active {
|
||||
background: var(--blue-900);
|
||||
color: var(--blue-400);
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive - Cache stats specific adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.stats-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 1rem;
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
|
||||
Reference in New Issue
Block a user