Răsfoiți Sursa

Completamente responsive

Celestino Rey 6 luni în urmă
părinte
comite
f3229dbd12
2 a modificat fișierele cu 326 adăugiri și 8 ștergeri
  1. 38 0
      static/dashboard.js
  2. 288 8
      static/index.html

+ 38 - 0
static/dashboard.js

@@ -650,3 +650,41 @@ async function deleteISO(name) {
     }
 }
 
+// Mobile responsive - Toggle sidebar
+function toggleSidebar() {
+    const sidebar = document.querySelector('.sidebar');
+    
+    // Para móviles (max-width 768px), mostrar/ocultar el sidebar
+    if (window.innerWidth <= 768) {
+        if (sidebar.classList.contains('show')) {
+            sidebar.classList.remove('show');
+            sidebar.classList.add('hidden');
+        } else {
+            sidebar.classList.remove('hidden');
+            sidebar.classList.add('show');
+        }
+    }
+}
+
+// Cerrar sidebar cuando se selecciona una VM en móvil
+const originalSelectVM = window.selectVM;
+window.selectVM = function(vmName) {
+    originalSelectVM(vmName);
+    
+    // Cerrar sidebar en móvil después de seleccionar
+    if (window.innerWidth <= 768) {
+        const sidebar = document.querySelector('.sidebar');
+        sidebar.classList.remove('show');
+        sidebar.classList.add('hidden');
+    }
+};
+
+// Cerrar sidebar cuando se abre un modal
+document.addEventListener('shown.bs.modal', function() {
+    if (window.innerWidth <= 768) {
+        const sidebar = document.querySelector('.sidebar');
+        sidebar.classList.remove('show');
+        sidebar.classList.add('hidden');
+    }
+});
+

+ 288 - 8
static/index.html

@@ -33,6 +33,15 @@
             box-shadow: 2px 0 5px rgba(0,0,0,0.1);
             display: flex;
             flex-direction: column;
+            transition: transform 0.3s ease;
+        }
+        
+        .sidebar.hidden {
+            transform: translateX(-100%);
+            position: absolute;
+            left: 0;
+            height: 100vh;
+            z-index: 1000;
         }
         
         .sidebar-header {
@@ -70,6 +79,7 @@
             display: flex;
             justify-content: space-between;
             align-items: center;
+            flex-wrap: wrap;
         }
         
         .vm-item:hover {
@@ -85,12 +95,14 @@
         
         .vm-item-name {
             flex: 1;
+            min-width: 120px;
         }
         
         .vm-item-badge {
             font-size: 0.75rem;
             padding: 3px 8px;
             border-radius: 4px;
+            margin-left: auto;
         }
         
         .sidebar-actions {
@@ -99,10 +111,12 @@
             flex-shrink: 0;
             display: flex;
             gap: 8px;
+            flex-wrap: wrap;
         }
         
         .sidebar-actions button {
             flex: 1;
+            min-width: 45px;
             padding: 8px 12px;
             font-size: 0.9rem;
         }
@@ -124,17 +138,32 @@
             align-items: center;
             flex-shrink: 0;
             box-shadow: 0 2px 4px rgba(0,0,0,0.05);
+            flex-wrap: wrap;
+            gap: 10px;
         }
         
         .top-bar h2 {
             margin: 0;
             color: #333;
+            font-size: 1.5rem;
+        }
+        
+        .top-bar-toggle {
+            display: none;
+            background: #667eea;
+            color: white;
+            border: none;
+            padding: 8px 12px;
+            border-radius: 5px;
+            cursor: pointer;
+            font-size: 1.2rem;
         }
         
         .content-area {
             flex: 1;
             overflow-y: auto;
             padding: 25px;
+            overflow-x: hidden;
         }
         
         .empty-state {
@@ -145,6 +174,7 @@
             height: 100%;
             color: #999;
             text-align: center;
+            padding: 20px;
         }
         
         .empty-state i {
@@ -155,7 +185,7 @@
         
         .vm-details {
             display: grid;
-            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
             gap: 20px;
         }
         
@@ -182,6 +212,10 @@
             font-size: 1rem;
         }
         
+        .card-body {
+            padding: 15px;
+        }
+        
         .badge-running {
             background-color: #28a745;
         }
@@ -217,12 +251,14 @@
         .info-value {
             color: #333;
             margin-top: 3px;
+            word-break: break-all;
         }
         
         /* Tabs */
         .nav-tabs {
             border-bottom: 2px solid #e9ecef;
             margin-bottom: 20px;
+            flex-wrap: wrap;
         }
         
         .nav-tabs .nav-link {
@@ -230,6 +266,8 @@
             border: none;
             border-bottom: 3px solid transparent;
             font-weight: 500;
+            padding: 0.5rem 1rem;
+            font-size: 0.95rem;
         }
         
         .nav-tabs .nav-link:hover {
@@ -253,16 +291,258 @@
         .actions-group h5 {
             color: #667eea;
             margin-bottom: 15px;
+            font-size: 1rem;
         }
         
         .btn-action {
             margin-right: 10px;
             margin-bottom: 10px;
+            display: inline-block;
+        }
+        
+        /* Modal adjustments */
+        .modal-dialog {
+            margin: 10px;
+        }
+        
+        .modal-content {
+            max-height: 90vh;
+            overflow-y: auto;
+        }
+        
+        /* Tablet */
+        @media (max-width: 1024px) {
+            .sidebar {
+                width: 280px;
+            }
+            
+            .top-bar {
+                padding: 12px 15px;
+            }
+            
+            .top-bar h2 {
+                font-size: 1.3rem;
+            }
+            
+            .content-area {
+                padding: 15px;
+            }
+            
+            .vm-details {
+                grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
+                gap: 15px;
+            }
         }
         
+        /* Mobile */
         @media (max-width: 768px) {
+            .dashboard-container {
+                flex-direction: column;
+            }
+            
             .sidebar {
-                width: 250px;
+                width: 100%;
+                height: auto;
+                max-height: 0;
+                overflow: hidden;
+                position: fixed;
+                top: 0;
+                left: 0;
+                z-index: 999;
+                transition: max-height 0.3s ease;
+            }
+            
+            .sidebar.show {
+                max-height: calc(100vh - 50px);
+            }
+            
+            .sidebar.hidden {
+                transform: none;
+                max-height: 0;
+            }
+            
+            .main-content {
+                width: 100%;
+                height: 100%;
+            }
+            
+            .top-bar {
+                padding: 10px 15px;
+                order: -1;
+                flex-wrap: nowrap;
+            }
+            
+            .top-bar h2 {
+                font-size: 1.2rem;
+                min-width: auto;
+                flex: 1;
+            }
+            
+            .top-bar-toggle {
+                display: block;
+                margin-left: auto;
+            }
+            
+            #topBarActions {
+                width: 100%;
+                margin-top: 10px;
+                display: flex;
+                gap: 8px;
+                flex-wrap: wrap;
+            }
+            
+            #topBarActions button {
+                flex: 1;
+                min-width: 70px;
+                padding: 6px 8px;
+                font-size: 0.85rem;
+            }
+            
+            .content-area {
+                padding: 15px 12px;
+                max-width: 100%;
+            }
+            
+            .empty-state {
+                padding: 20px 10px;
+            }
+            
+            .empty-state i {
+                font-size: 3rem;
+                margin-bottom: 15px;
+            }
+            
+            .empty-state h5 {
+                font-size: 1.1rem;
+            }
+            
+            .empty-state p {
+                font-size: 0.9rem;
+            }
+            
+            .vm-details {
+                grid-template-columns: 1fr;
+                gap: 15px;
+            }
+            
+            .card {
+                border-radius: 8px;
+            }
+            
+            .card-header {
+                padding: 12px;
+            }
+            
+            .card-body {
+                padding: 12px;
+            }
+            
+            .card-title {
+                font-size: 0.95rem;
+            }
+            
+            .info-label {
+                font-size: 0.85rem;
+            }
+            
+            .info-value {
+                font-size: 0.9rem;
+            }
+            
+            .nav-tabs .nav-link {
+                padding: 0.4rem 0.8rem;
+                font-size: 0.85rem;
+            }
+            
+            .btn-action {
+                width: 100%;
+                margin-right: 0;
+                margin-bottom: 8px;
+                display: block;
+            }
+            
+            .sidebar-actions button {
+                padding: 6px 10px;
+                font-size: 0.85rem;
+            }
+            
+            .modal-dialog {
+                margin: 5px;
+            }
+            
+            .modal {
+                --bs-modal-margin: 5px;
+            }
+        }
+        
+        /* Small phones */
+        @media (max-width: 480px) {
+            .top-bar h2 {
+                font-size: 1rem;
+            }
+            
+            .top-bar {
+                padding: 8px 10px;
+            }
+            
+            .content-area {
+                padding: 10px 8px;
+            }
+            
+            .vm-details {
+                gap: 10px;
+            }
+            
+            .card-header {
+                padding: 10px;
+            }
+            
+            .card-body {
+                padding: 10px;
+            }
+            
+            .info-item {
+                padding: 8px 0;
+            }
+            
+            .modal-dialog {
+                margin: 0;
+                width: 95vw;
+            }
+            
+            #topBarActions {
+                flex-direction: column;
+            }
+            
+            #topBarActions button {
+                width: 100%;
+            }
+            
+            .btn-action {
+                font-size: 0.8rem;
+                padding: 6px;
+            }
+            
+            .sidebar-header h4 {
+                font-size: 1.2rem;
+            }
+            
+            .sidebar-header p {
+                font-size: 0.8rem;
+            }
+            
+            .vm-item {
+                padding: 10px 12px;
+                font-size: 0.9rem;
+            }
+            
+            .nav-tabs {
+                margin-bottom: 15px;
+            }
+            
+            .nav-tabs .nav-link {
+                padding: 0.35rem 0.6rem;
+                font-size: 0.8rem;
             }
         }
     </style>
@@ -270,7 +550,7 @@
 <body>
     <div class="dashboard-container">
         <!-- Sidebar -->
-        <div class="sidebar">
+        <div class="sidebar hidden" id="sidebar">
             <div class="sidebar-header">
                 <h4><i class="bi bi-display"></i> VirtManager</h4>
                 <p>Virtual Machine Dashboard</p>
@@ -298,11 +578,11 @@
         <!-- Main Content -->
         <div class="main-content">
             <div class="top-bar">
-                <div>
-                    <h2 id="currentVMName">VirtManager</h2>
-                </div>
-                <div id="topBarActions">
-                </div>
+                <h2 id="currentVMName">VirtManager</h2>
+                <button class="top-bar-toggle" onclick="toggleSidebar()" title="Menú">
+                    <i class="bi bi-list"></i>
+                </button>
+                <div id="topBarActions"></div>
             </div>
             
             <div class="content-area" id="contentArea">