04/18 fix web app responsive

This commit is contained in:
2026-04-18 15:04:42 -04:00
parent 20d1d08b5e
commit 83c8d0eea5
3 changed files with 334 additions and 15 deletions
+288 -15
View File
@@ -80,6 +80,18 @@ ul {
box-shadow: var(--shadow); box-shadow: var(--shadow);
padding: 40px 36px; padding: 40px 36px;
} }
@media (max-width: 480px) {
.auth-container {
padding: 12px;
}
.auth-card {
padding: 28px 20px;
border-radius: 12px;
}
.auth-title {
font-size: 20px;
}
}
.auth-logo { .auth-logo {
display: flex; display: flex;
@@ -1347,39 +1359,300 @@ ul {
} }
/* ── Responsive ──────────────────────────────────────────────────── */ /* ── Responsive ──────────────────────────────────────────────────── */
/* Mobile top bar — hidden on tablet+ */
.mobile-topbar {
display: none;
align-items: center;
gap: 12px;
padding: 0 16px;
height: 54px;
background: var(--color-sidebar-bg);
color: #fff;
flex-shrink: 0;
position: sticky;
top: 0;
z-index: 50;
}
.btn-mobile-menu {
font-size: 22px;
color: rgba(255, 255, 255, 0.8);
background: none;
border: none;
padding: 4px 6px;
cursor: pointer;
flex-shrink: 0;
}
.btn-mobile-menu:hover {
color: #fff;
}
.mobile-logo {
flex: 1;
font-size: 16px;
font-weight: 700;
color: #fff;
}
.btn-fab-mobile {
width: 36px;
height: 36px;
font-size: 20px;
flex-shrink: 0;
}
/* Sidebar backdrop — only active on mobile */
.sidebar-backdrop {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 89;
}
.sidebar-backdrop.open {
display: block;
}
/* ── Phone (≤ 640px) ─────────────────────────────────────────────── */
@media (max-width: 640px) { @media (max-width: 640px) {
/* Layout: stack topbar above main, no sidebar space in flow */
.app-layout {
flex-direction: column;
height: 100vh;
overflow: hidden;
}
/* Topbar always visible */
.mobile-topbar {
display: flex;
}
/* Sidebar slides in from the left as an overlay */
.sidebar { .sidebar {
width: 72px; position: fixed;
overflow-y: visible; top: 0;
left: 0;
bottom: 0;
width: 260px !important; /* always full-width on mobile regardless of collapsed state */
z-index: 90;
transform: translateX(-100%);
transition: transform 0.25s ease;
overflow-y: auto;
} }
.sidebar-header .logo-text, .sidebar.mobile-open {
.sidebar-label { transform: translateX(0);
opacity: 0;
max-width: 0;
} }
.sidebar-section-header { /* Show all labels inside the mobile overlay sidebar */
opacity: 0; .sidebar .sidebar-label {
pointer-events: none; opacity: 1 !important;
height: 0; max-width: none !important;
padding: 0;
} }
.sidebar-item { .sidebar .sidebar-section-header {
justify-content: center; opacity: 1 !important;
padding: 10px 0; height: auto !important;
padding: 12px 16px 4px !important;
} }
.sidebar .sidebar-item {
justify-content: flex-start !important;
padding: 9px 16px !important;
overflow: hidden !important;
}
.sidebar .sidebar-item::after {
display: none !important;
}
/* Hide desktop collapse toggle on mobile */
.btn-sidebar-toggle {
display: none;
}
/* Main area fills everything below topbar */
.vault-main {
flex: 1;
overflow: hidden;
}
/* Tighter padding */
.vault-header { .vault-header {
padding: 12px 16px; padding: 12px 16px;
gap: 8px;
}
.vault-title {
font-size: 16px;
} }
.vault-list { .vault-list {
padding: 8px 16px 16px; padding: 8px 12px 80px;
} /* bottom pad for FAB */
.panel-body {
padding: 16px;
}
.security-dashboard {
padding: 12px;
gap: 16px;
}
/* Search takes full width, hide sort */
.vault-toolbar {
gap: 8px;
}
.search-wrapper {
max-width: none;
} }
.sort-wrapper { .sort-wrapper {
display: none; display: none;
} }
/* FAB in header is hidden on mobile (use topbar FAB) */
.vault-header .btn-fab {
display: none;
}
/* Forms */
.form-row { .form-row {
flex-direction: column; flex-direction: column;
gap: 0; gap: 0;
} }
.modal {
padding: 20px;
}
.modal-actions {
flex-wrap: wrap;
}
/* Security stats wrap */
.security-summary {
padding: 16px;
gap: 12px;
}
.sec-score {
font-size: 40px;
}
.sec-stats {
gap: 8px;
}
.sec-stat {
padding: 8px 12px;
min-width: 68px;
}
.sec-stat-num {
font-size: 22px;
}
/* Modal: full-screen on phones */
.modal-overlay {
padding: 0;
align-items: flex-end;
}
.modal {
max-width: 100%;
max-height: 92vh;
border-radius: 16px 16px 0 0;
padding: 20px 16px;
}
.modal-settings {
max-width: 100%;
}
.modal-item {
max-width: 100%;
}
/* Detail label stacks above value on small screens */
.detail-field {
flex-direction: column;
gap: 4px;
}
.detail-label {
width: auto;
}
}
/* ── Tablet (641px 1024px) ─────────────────────────────────────── */
@media (min-width: 641px) and (max-width: 1024px) {
/* Sidebar always shows as icon rail on tablet — user can expand with toggle */
.sidebar:not(.collapsed) {
width: 200px;
}
/* Slightly tighter padding */
.vault-header {
padding: 14px 18px;
}
.vault-list {
padding: 10px 18px 18px;
}
.panel-body {
padding: 16px 18px;
}
.security-dashboard {
padding: 16px;
gap: 16px;
}
/* Search a bit narrower */
.search-wrapper {
max-width: 280px;
}
/* Security stats wrap gracefully */
.security-summary {
flex-wrap: wrap;
gap: 12px;
}
.sec-stats {
flex-wrap: wrap;
gap: 10px;
}
/* Form rows stay side-by-side */
.form-row {
flex-direction: row;
}
/* Modal fits tablet width */
.modal {
max-width: 460px;
}
}
/* ── Laptop (1025px 1440px) ───────────────────────────────────── */
@media (min-width: 1025px) and (max-width: 1440px) {
/* Full sidebar, comfortable padding */
.vault-header {
padding: 16px 24px;
}
.vault-list {
padding: 12px 24px 24px;
}
.security-dashboard {
padding: 20px 24px;
}
}
/* ── Large PC (> 1440px) ────────────────────────────────────────── */
@media (min-width: 1441px) {
/* Wider sidebar, more generous spacing */
.sidebar:not(.collapsed) {
width: 260px;
}
.vault-header {
padding: 18px 32px;
}
.vault-list {
padding: 16px 32px 32px;
}
.panel-body {
padding: 24px 32px;
}
.security-dashboard {
padding: 24px 32px;
gap: 28px;
}
.search-wrapper {
max-width: 440px;
}
.modal {
max-width: 520px;
}
.modal-settings {
max-width: 580px;
}
} }
/* ── Settings — new sections (Phase 6) ──────────────────────────── */ /* ── Settings — new sections (Phase 6) ──────────────────────────── */
+28
View File
@@ -2645,6 +2645,34 @@ const Vault = (() => {
}); });
} }
// Mobile sidebar: hamburger opens overlay, backdrop/item-click closes it
const backdrop = document.getElementById("sidebar-backdrop");
const mobileMenuBtn = document.getElementById("btn-mobile-menu");
function openMobileSidebar() {
sidebar?.classList.add("mobile-open");
backdrop?.classList.add("open");
document.body.style.overflow = "hidden";
}
function closeMobileSidebar() {
sidebar?.classList.remove("mobile-open");
backdrop?.classList.remove("open");
document.body.style.overflow = "";
}
mobileMenuBtn?.addEventListener("click", openMobileSidebar);
backdrop?.addEventListener("click", closeMobileSidebar);
// Close mobile sidebar whenever a nav item is clicked
document.querySelectorAll(".sidebar-item").forEach((item) => {
item.addEventListener("click", () => {
if (window.innerWidth <= 640) closeMobileSidebar();
});
});
// Mobile FAB mirrors the desktop add-item button
document
.getElementById("btn-add-item-mobile")
?.addEventListener("click", () => {
document.getElementById("btn-add-item")?.click();
});
if (!VaultSession.getKey()) { if (!VaultSession.getKey()) {
showUnlockOverlay(); showUnlockOverlay();
} else { } else {
+18
View File
@@ -1,6 +1,24 @@
{% extends "base.html" %} {% block title %}My Vault — PassKeeper{% endblock %} {% extends "base.html" %} {% block title %}My Vault — PassKeeper{% endblock %}
{% block body_class %}vault-page{% endblock %} {% block body %} {% block body_class %}vault-page{% endblock %} {% block body %}
<div class="app-layout"> <div class="app-layout">
<!-- ── Mobile top bar (phones only) ────────────────────────────── -->
<div class="mobile-topbar" id="mobile-topbar">
<button class="btn-mobile-menu" id="btn-mobile-menu" aria-label="Open menu">
</button>
<span class="mobile-logo">🔒 PassKeeper</span>
<button
class="btn-fab btn-fab-mobile"
id="btn-add-item-mobile"
title="Add item"
>
+
</button>
</div>
<!-- ── Sidebar backdrop (mobile) ───────────────────────────────── -->
<div class="sidebar-backdrop" id="sidebar-backdrop"></div>
<!-- ── Sidebar ─────────────────────────────────────────────────── --> <!-- ── Sidebar ─────────────────────────────────────────────────── -->
<aside class="sidebar" id="sidebar"> <aside class="sidebar" id="sidebar">
<div class="sidebar-header"> <div class="sidebar-header">