From c9cfb58896d3d09cac581e819f0321a10b5effbd Mon Sep 17 00:00:00 2001 From: fahed Date: Tue, 28 Apr 2026 12:22:07 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20mobile=20UX=20overhaul=20=E2=80=94=20col?= =?UTF-8?q?lapsible=20filters,=20settings=20nav,=20responsive=20layout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Settings link to desktop nav bar for admin users - Rewrite Settings page from table layout to responsive card list (fixes unusable mobile state) - Filter bar (Dashboard + Comparison): collapsible panel on mobile via display:contents trick; stacked full-width dropdowns replace horizontal scroll - Active filter count badge shown in collapsed filter header - AltMultiSelect dropdowns go full-width on mobile to prevent viewport overflow - Chart control separators hidden on mobile to avoid crowding - Metric grid: 2-col at ≤700px, 1-col at ≤480px - Comparison period cards: smaller font and tighter padding at ≤680px - Page shell padding reduced on mobile (48px→20px top, 24px→16px sides) - Settings page gets correct 80px bottom padding for mobile nav Co-Authored-By: Claude Sonnet 4.6 --- src/App.css | 308 +++++++++++++++++++++++++++++----- src/App.tsx | 8 + src/components/Comparison.tsx | 26 ++- src/components/Dashboard.tsx | 34 ++-- src/components/Settings.tsx | 289 ++++++++++++++----------------- 5 files changed, 447 insertions(+), 218 deletions(-) diff --git a/src/App.css b/src/App.css index ba4e807..1a038f9 100644 --- a/src/App.css +++ b/src/App.css @@ -1360,33 +1360,208 @@ table tbody tr:hover { font-size: 0.8125rem; font-weight: 600; border: 1px solid; + white-space: nowrap; } -.season-edit-name { +/* Settings card list */ +.settings-list { + display: flex; + flex-direction: column; + gap: 6px; + margin-bottom: 16px; +} + +.settings-loading { + text-align: center; + padding: 24px; + color: var(--text-muted); +} + +.settings-item { + border: 1px solid var(--border); + border-radius: 8px; + overflow: hidden; +} + +.settings-item--editing { + border-color: var(--accent); +} + +.settings-item-row { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 14px; + flex-wrap: wrap; +} + +.settings-dates { + color: var(--text-secondary); + font-size: 0.8125rem; + flex: 1; + min-width: 0; +} + +.settings-item-actions { display: flex; gap: 6px; - align-items: center; + flex-shrink: 0; } -.season-edit-name input[type="text"] { +.settings-item-form { + padding: 14px 16px; + background: var(--bg); + border-top: 1px solid var(--border); + display: flex; + flex-direction: column; + gap: 10px; +} + +/* Form primitives used in Settings */ +.form-row { + display: flex; + gap: 8px; + align-items: flex-end; + flex-wrap: wrap; +} + +.form-input { + padding: 8px 10px; + border: 1px solid var(--border); + border-radius: 6px; + font-size: 0.8125rem; + background: var(--surface); + color: var(--text-primary); flex: 1; - min-width: 80px; + min-width: 120px; } -.season-edit-name input[type="color"] { - width: 32px; - height: 32px; +.form-input--sm { + flex: 0 0 80px; + min-width: 0; +} + +.form-color { + width: 38px; + height: 38px; padding: 2px; border: 1px solid var(--border); border-radius: 6px; cursor: pointer; + flex-shrink: 0; } -.season-actions { +.form-field { display: flex; + flex-direction: column; + gap: 4px; + flex: 1; + min-width: 140px; +} + +.form-label { + font-size: 0.6875rem; + color: var(--text-muted); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.form-actions { + display: flex; + gap: 8px; +} + +/* Add-new form strip at bottom of each card */ +.settings-add-form { + border-top: 2px dashed var(--border); + padding-top: 14px; + display: flex; + flex-direction: column; + gap: 10px; +} + +.settings-add-title { + font-size: 0.8125rem; + font-weight: 600; + color: var(--text-muted); +} + +/* User item */ +.settings-user-info { + display: flex; + align-items: center; + gap: 8px; + flex: 1; + min-width: 0; + flex-wrap: wrap; +} + +.settings-user-name { + font-weight: 600; + color: var(--text-primary); +} + +.settings-user-pin { + font-size: 0.75rem; + color: var(--text-muted); + background: var(--bg); + padding: 2px 6px; + border-radius: 4px; + border: 1px solid var(--border); +} + +.settings-user-role { + font-size: 0.75rem; + color: var(--text-secondary); + text-transform: capitalize; +} + +.settings-user-access { + display: flex; + gap: 4px; + flex-wrap: wrap; + align-items: center; +} + +/* Access checkboxes in edit panel */ +.access-columns { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); + gap: 16px; +} + +.access-col-title { + font-weight: 600; + font-size: 0.8125rem; + margin-bottom: 8px; + display: flex; + align-items: center; gap: 6px; } +.access-check { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 0; + cursor: pointer; + font-size: 0.875rem; + border-bottom: 1px solid var(--border); +} + +.access-check:last-child { + border-bottom: none; +} + +.access-check input[type="checkbox"] { + width: 17px; + height: 17px; + cursor: pointer; + accent-color: var(--accent); + flex-shrink: 0; +} + .access-badge { display: inline-block; font-size: 0.7rem; @@ -1403,13 +1578,14 @@ table tbody tr:hover { } .btn-small { - padding: 4px 10px; + padding: 6px 12px; font-size: 0.75rem; border-radius: 6px; border: 1px solid var(--border); background: var(--surface); color: var(--text-primary); cursor: pointer; + white-space: nowrap; } .btn-small:hover { @@ -1432,27 +1608,6 @@ table tbody tr:hover { color: white; } -tr.add-row td { - border-top: 2px dashed var(--border); - padding-top: 12px; -} - -tr.editing td { - background: var(--hover); -} - -.settings-page input[type="text"], -.settings-page input[type="number"], -.settings-page input[type="date"], -.settings-page select { - padding: 8px 10px; - border: 1px solid var(--border); - border-radius: 6px; - font-size: 0.8125rem; - background: var(--surface); - color: var(--text-primary); -} - .period-display { background: var(--bg); padding: 16px; @@ -2092,9 +2247,20 @@ tr.editing td { /* Add padding to main content for bottom nav */ .dashboard, - .comparison { + .comparison, + .settings-page { padding-bottom: 80px; } + + .settings-page { + padding-inline: 16px; + padding-top: 20px; + } + + .settings-item-actions { + width: 100%; + justify-content: flex-end; + } .data-source-toggle { margin-left: 8px; @@ -2556,9 +2722,16 @@ html[dir="rtl"] .exportable-chart-wrapper .chart-export-btn.visible { /* ── filter bar ── */ .alt-filter-bar { display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin-bottom:32px; padding:14px 20px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius); } +/* display:contents makes head/body transparent to parent flex on desktop */ +.alt-filter-head { display:contents; } +.alt-filter-body { display:contents; } .alt-filter-label { font-size:.6875rem; font-weight:700; text-transform:uppercase; letter-spacing:.08em; color:var(--text-muted); white-space:nowrap; } .alt-filter-sep { width:1px; height:20px; background:var(--border); flex-shrink:0; } .alt-filter-spacer { flex:1; min-width:0; } +.alt-filter-toggle { display:none; } /* hidden on desktop, shown on mobile */ +.alt-filter-badge { display:none; } /* hidden on desktop, active count shown on mobile */ +.alt-filter-chevron { transition:transform .2s; } +.alt-filter-chevron--open { transform:rotate(180deg); } .alt-vat-toggle { display:flex; align-items:center; border:1px solid var(--border); border-radius:8px; overflow:hidden; } .alt-vat-opt { font-family:var(--alt-body-font); font-size:.75rem; font-weight:500; padding:5px 10px; background:var(--surface); color:var(--text-muted); cursor:pointer; border:none; transition:background .1s,color .1s; } .alt-vat-opt--on { background:var(--accent); color:var(--text-inverse); } @@ -2600,18 +2773,74 @@ html[dir="rtl"] .exportable-chart-wrapper .chart-export-btn.visible { /* ── charts (Comparison) — single-column grid, taller wrap ── */ .alt-charts { display:grid; grid-template-columns:1fr; gap:24px; } -/* ── responsive (Dashboard) ── */ +/* ── responsive (Dashboard + Comparison) ── */ @media (max-width:700px) { + /* Page shell */ + .alt-page { padding:20px 16px 90px; } + .alt-page-title { font-size:1.75rem; } + .alt-page-sub { margin-bottom:24px; } + + /* Filter bar — switch to collapsible stacked layout */ + .alt-filter-bar { flex-direction:column; align-items:stretch; padding:0; gap:0; flex-wrap:nowrap; } + .alt-filter-head { + display:flex; align-items:center; gap:8px; + padding:12px 14px; + } + .alt-filter-body { + display:none; flex-direction:column; gap:10px; + padding:12px 14px; border-top:1px solid var(--border); + } + .alt-filter-bar--open .alt-filter-body { display:flex; } + + /* Toggle button */ + .alt-filter-toggle { + display:flex; align-items:center; justify-content:center; + width:30px; height:30px; margin-left:auto; flex-shrink:0; + border:1px solid var(--border); border-radius:8px; + background:var(--surface); color:var(--text-muted); cursor:pointer; + transition:border-color .15s, color .15s; + } + .alt-filter-toggle:hover { border-color:var(--accent); color:var(--accent); } + + /* Active-count badge */ + .alt-filter-badge { + display:inline-flex; align-items:center; justify-content:center; + min-width:18px; height:18px; padding:0 5px; border-radius:9px; + background:var(--accent); color:var(--text-inverse); + font-size:.6875rem; font-weight:700; line-height:1; + } + + /* Full-width dropdowns */ + .alt-filter-body .altms { width:100%; } + .alt-filter-body .altms-trigger { width:100%; justify-content:space-between; box-sizing:border-box; } + .alt-filter-body .altms-label { max-width:none; flex:1; text-align:start; } + .alt-filter-body .altms-dropdown { width:100%; min-width:0; } + + /* Hide vertical separator and spacer in stacked layout */ + .alt-filter-body .alt-filter-sep { display:none; } + .alt-filter-body .alt-filter-spacer { display:none; } + + /* VAT toggle: align to start */ + .alt-filter-body .alt-vat-toggle { align-self:flex-start; } + + /* Charts grid */ .dalt-hero-name { font-size:1.875rem; } .dalt-charts-grid { grid-template-columns:1fr; } .dalt-chart-full { grid-column:auto; } + + /* Metric cards — 2 col at 700px */ .alt-metrics { grid-template-columns:1fr 1fr; } - .alt-page-title { font-size:1.75rem; } - .altms-label { max-width:100px; } - .alt-filter-bar { overflow-x:auto; flex-wrap:nowrap; padding-inline:12px; -webkit-overflow-scrolling:touch; } - .altms-trigger { flex-shrink:0; } - .alt-vat-toggle { flex-shrink:0; } - .alt-filter-spacer { display:none; } + + /* Chart controls — allow separator to break line */ + .alt-chart-controls { row-gap:4px; } + .alt-ctrl-sep { display:none; } +} + +/* Very small screens */ +@media (max-width:480px) { + .alt-metrics { grid-template-columns:1fr; } + .alt-metric { padding:18px 16px; } + .alt-metric-value { font-size:1.5rem; } } /* ── responsive (Comparison) ── */ @@ -2620,7 +2849,8 @@ html[dir="rtl"] .exportable-chart-wrapper .chart-export-btn.visible { .alt-card--current,.alt-card--previous { border-radius:var(--radius); } .alt-vs { flex-direction:row; padding:10px 0; } .alt-vs-line { position:static; width:100%; height:1px; } - .alt-period-name { font-size:1.75rem; } + .alt-period-name { font-size:1.5rem; } + .alt-card-body { padding:16px 18px 14px; } .alt-chart-header { flex-direction:column; } } diff --git a/src/App.tsx b/src/App.tsx index 21e89da..afa05ac 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -237,6 +237,14 @@ function App() { {t('nav.comparison')} + {userRole === 'admin' && ( + + + {t('nav.settings')} + + )}