From 82591514cd7be0edacc2784ed3e5d4c666365584 Mon Sep 17 00:00:00 2001 From: Deeman Date: Thu, 26 Feb 2026 19:49:46 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20collapsible=20admin=20sidebar=20?= =?UTF-8?q?=E2=80=94=20groups,=20section-map,=20localStorage=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces flat 20-link sidebar with collapsible section groups: - Multi-item sections (Marketplace, Content, Email, System) are collapsible with animated chevron; active section always expands - Single-item sections (Dashboard, Suppliers, Billing, Analytics, Pipeline) render as direct links — no toggle overhead - pSEO merged into Content; Users moved into System; new Billing slot - Unread badge surfaces on Email group header when collapsed - localStorage persists per-section open/closed state (key: admin_sidebar_v1) - Mobile: group headers hidden, all items shown in horizontal scroll (preserves existing mobile behavior exactly) - section_map Jinja dict derives active_section from existing admin_page — no route changes needed Co-Authored-By: Claude Sonnet 4.6 --- .../admin/templates/admin/base_admin.html | 315 ++++++++++++++---- 1 file changed, 246 insertions(+), 69 deletions(-) diff --git a/web/src/padelnomics/admin/templates/admin/base_admin.html b/web/src/padelnomics/admin/templates/admin/base_admin.html index a153220..3559bf6 100644 --- a/web/src/padelnomics/admin/templates/admin/base_admin.html +++ b/web/src/padelnomics/admin/templates/admin/base_admin.html @@ -9,24 +9,71 @@ } .admin-sidebar__title { padding: 0 1rem 1rem; font-size: 0.8125rem; font-weight: 700; color: #0F172A; - border-bottom: 1px solid #E2E8F0; margin-bottom: 0.5rem; + border-bottom: 1px solid #E2E8F0; margin-bottom: 0.25rem; } - .admin-sidebar__section { - padding: 0.5rem 0 0.25rem; font-size: 0.5625rem; font-weight: 700; - text-transform: uppercase; letter-spacing: 0.06em; color: #94A3B8; - padding-left: 1rem; - } - .admin-nav a { + + /* ── Direct links (single-item sections) ── */ + .sidebar-direct { display: flex; align-items: center; gap: 8px; padding: 8px 1rem; font-size: 0.8125rem; color: #64748B; text-decoration: none; transition: all 0.1s; } + .sidebar-direct:hover { background: #EFF6FF; color: #1D4ED8; } + .sidebar-direct.active { background: #EFF6FF; color: #1D4ED8; font-weight: 600; border-right: 3px solid #1D4ED8; } + .sidebar-direct svg { width: 16px; height: 16px; flex-shrink: 0; } + + /* ── Collapsible group header ── */ + .sidebar-group__header { + display: flex; align-items: center; gap: 7px; width: 100%; + padding: 8px 1rem; font-size: 0.5625rem; font-weight: 700; + text-transform: uppercase; letter-spacing: 0.06em; color: #94A3B8; + background: none; border: none; cursor: pointer; transition: color 0.12s; + margin-top: 0.375rem; + } + .sidebar-group__header:hover { color: #1D4ED8; } + .sidebar-group__header .header-icon { width: 13px; height: 13px; flex-shrink: 0; } + .sidebar-group.active-section .sidebar-group__header { color: #1D4ED8; } + .sidebar-group__chevron { + width: 11px; height: 11px; margin-left: auto; flex-shrink: 0; color: #CBD5E1; + transition: transform 0.2s ease; + } + .sidebar-group.collapsed .sidebar-group__chevron { transform: rotate(-90deg); } + + /* Badge on group header (shows unread count even when collapsed) */ + .sidebar-header-badge { + font-size: 9px; padding: 1px 5px; border-radius: 9999px; + background: #EF4444; color: white; font-weight: 700; margin-left: 1px; + } + + /* ── Collapsible items container ── */ + .sidebar-group__items { + overflow: hidden; max-height: 400px; transition: max-height 0.25s ease; + } + .sidebar-group.collapsed .sidebar-group__items { max-height: 0; } + + /* ── Links inside groups ── */ + .admin-nav a { + display: flex; align-items: center; gap: 8px; + padding: 7px 1rem 7px 2.125rem; font-size: 0.8125rem; color: #64748B; + text-decoration: none; transition: all 0.1s; + } .admin-nav a:hover { background: #EFF6FF; color: #1D4ED8; } .admin-nav a.active { background: #EFF6FF; color: #1D4ED8; font-weight: 600; border-right: 3px solid #1D4ED8; } .admin-nav a svg { width: 16px; height: 16px; flex-shrink: 0; } .admin-main { flex: 1; padding: 2rem; overflow-y: auto; } + /* ── Confirm dialog ── */ + #confirm-dialog { + border: none; border-radius: 12px; padding: 1.5rem; max-width: 380px; width: 90%; + box-shadow: 0 20px 60px rgba(0,0,0,0.15), 0 4px 16px rgba(0,0,0,0.08); + position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0; + } + #confirm-dialog::backdrop { background: rgba(15,23,42,0.45); backdrop-filter: blur(3px); } + #confirm-dialog p { margin: 0 0 1.25rem; font-size: 0.9375rem; color: #0F172A; line-height: 1.55; } + #confirm-dialog .dialog-actions { display: flex; gap: 0.5rem; justify-content: flex-end; } + + /* ── Mobile ── */ @media (max-width: 768px) { .admin-layout { flex-direction: column; } .admin-sidebar { @@ -34,9 +81,16 @@ overflow-x: auto; border-right: none; border-bottom: 1px solid #E2E8F0; } .admin-sidebar__title { display: none; } - .admin-sidebar__section { display: none; } - .admin-nav { display: flex; flex: none; padding: 0; gap: 2px; } + .sidebar-group__header { display: none; } + .sidebar-group { display: contents; } + .sidebar-group__items, + .sidebar-group.collapsed .sidebar-group__items { + max-height: none !important; overflow: visible; + display: flex; flex: none; gap: 2px; + } + .admin-nav { display: flex; flex: none; padding: 0; gap: 2px; align-items: center; } .admin-nav a { padding: 8px 12px; white-space: nowrap; border-right: none !important; border-radius: 6px; } + .sidebar-direct { padding: 8px 12px; white-space: nowrap; border-right: none !important; border-radius: 6px; } .admin-main { padding: 1rem; } } @@ -44,85 +98,163 @@ {% endblock %} {% block content %} +{%- set _section_map = { + 'dashboard': 'overview', + 'marketplace': 'marketplace', 'leads': 'marketplace', + 'suppliers': 'suppliers', + 'articles': 'content', 'scenarios': 'content', 'templates': 'content', 'pseo': 'content', + 'emails': 'email', 'inbox': 'email', 'compose': 'email', 'gallery': 'email', 'audiences': 'email', 'outreach': 'email', + 'billing': 'billing', + 'seo': 'analytics', + 'pipeline': 'pipeline', + 'users': 'system', 'flags': 'system', 'tasks': 'system', 'feedback': 'system', +} -%} +{%- set active_section = _section_map.get(admin_page|default(''), 'overview') -%} + + + +

+
+ + +
+
+ {% endblock %}