feat: redesigned dashboard UI with editorial aesthetic and RTL support
Deploy HiHala Dashboard / deploy (push) Successful in 9s

- Replace Dashboard/Comparison with DashboardDemo/PeriodSelectorDemo as primary pages at / and /comparison
- New editorial design: DM Serif Display + Outfit fonts, inline period picker, multi-select filters for museum/channel/district
- Full Arabic RTL support with IBM Plex Sans Arabic; EN/AR toggle synced to global LanguageContext
- Bar/pie chart toggle + absolute/percent toggle for museum, channel, district charts
- Refined top nav: transparent inactive links, accent active state, visual separator between nav links and utilities
- DateRangePicker, MultiSelect, FilterControls shared components added
- NavDemo: sidebar layout alternative (accessible at /nav-demo)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
fahed
2026-04-19 17:58:33 +03:00
parent 0f6881309c
commit c8c3465233
13 changed files with 2819 additions and 178 deletions
+464 -72
View File
@@ -2,6 +2,19 @@
HiHala Dashboard - Minimalist Luxury
======================================== */
/* Screen-reader only utility */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
white-space: nowrap;
border: 0;
}
:root {
--bg: #f8fafc;
--surface: #ffffff;
@@ -223,14 +236,15 @@ html[dir="rtl"] {
.nav-bar {
background: var(--surface);
border-bottom: 1px solid var(--border);
padding: 0 32px;
height: 64px;
padding: 0 28px;
height: 56px;
display: flex;
align-items: center;
justify-content: center;
position: sticky;
top: 0;
z-index: 100;
box-shadow: 0 1px 0 var(--border), 0 2px 8px rgba(0,0,0,0.04);
}
.nav-content {
@@ -244,52 +258,67 @@ html[dir="rtl"] {
.nav-brand {
display: flex;
align-items: center;
gap: 10px;
gap: 9px;
}
.nav-brand-icon {
color: var(--brand-icon);
flex-shrink: 0;
}
.nav-brand-text {
font-family: 'DM Sans', 'Inter', -apple-system, sans-serif;
font-size: 1.25rem;
display: flex;
align-items: baseline;
gap: 5px;
}
.nav-brand-name {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 0.9375rem;
font-weight: 700;
color: var(--brand-text);
color: var(--text-primary);
letter-spacing: -0.02em;
}
.nav-brand-tag {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 0.6875rem;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--text-muted);
}
.data-source-select {
appearance: none;
-webkit-appearance: none;
background: transparent;
border: none;
color: var(--brand-icon);
color: var(--accent);
font-family: inherit;
font-size: inherit;
font-size: 0.8125rem;
font-weight: 500;
cursor: pointer;
padding: 2px 20px 2px 6px;
margin-inline-start: 4px;
border-radius: 6px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%233b82f6' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
padding: 2px 18px 2px 4px;
border-radius: 5px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='11' viewBox='0 0 24 24' fill='none' stroke='%232563eb' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 4px center;
transition: background-color 0.15s ease;
background-position: right 3px center;
transition: background-color 0.12s;
margin-inline-start: 2px;
}
.data-source-select:hover {
background-color: rgba(59, 130, 246, 0.08);
background-color: var(--accent-light);
}
.data-source-select:focus {
outline: 2px solid var(--accent);
outline-offset: 1px;
background-color: rgba(59, 130, 246, 0.12);
}
.data-source-select option {
color: var(--brand-text);
color: var(--text-primary);
background: var(--surface);
font-weight: 500;
}
@@ -300,81 +329,94 @@ html[dir="rtl"] {
.nav-links {
display: flex;
gap: 8px;
align-items: center;
gap: 2px;
}
/* Separator between nav links and utility buttons */
.nav-sep {
display: block;
width: 1px;
height: 20px;
background: var(--border);
margin: 0 8px;
flex-shrink: 0;
align-self: center;
}
.nav-link {
color: var(--text-secondary);
color: var(--text-muted);
text-decoration: none;
padding: 10px 20px;
padding: 7px 13px;
border-radius: 8px;
font-size: 0.9375rem;
font-weight: 600;
transition: all 0.2s;
font-size: 0.875rem;
font-weight: 500;
transition: background 0.12s, color 0.12s;
display: flex;
align-items: center;
gap: 8px;
background: var(--bg);
border: 1px solid transparent;
gap: 7px;
background: transparent;
border: none;
white-space: nowrap;
}
.nav-link svg {
flex-shrink: 0;
opacity: 0.7;
opacity: 0.6;
transition: opacity 0.12s;
}
.nav-link:hover {
background: var(--surface);
border-color: var(--border);
background: var(--muted-light);
color: var(--text-primary);
}
.nav-link:hover svg {
opacity: 1;
opacity: 0.85;
}
.nav-link.active {
background: var(--primary);
color: var(--text-inverse);
border-color: var(--primary);
background: var(--accent-light);
color: var(--accent);
font-weight: 600;
}
.nav-link.active svg {
opacity: 1;
}
/* Language Toggle Button */
/* Utility icon buttons (theme + lang toggle) */
.nav-lang-toggle {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 8px 14px;
border-radius: 8px;
gap: 5px;
height: 32px;
padding: 0 10px;
border-radius: 7px;
font-size: 0.75rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
transition: background 0.12s, color 0.12s;
background: transparent;
border: 1px solid var(--border);
border: none;
color: var(--text-muted);
min-width: 44px;
letter-spacing: 0.02em;
white-space: nowrap;
}
.nav-lang-toggle:hover {
background: var(--surface);
background: var(--muted-light);
color: var(--text-primary);
border-color: var(--primary);
}
.nav-lang-toggle:active {
transform: scale(0.96);
transform: scale(0.95);
}
/* RTL adjustments */
html[dir="rtl"] .nav-lang-toggle {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
/* Offline Badge */
@@ -382,11 +424,11 @@ html[dir="rtl"] .nav-lang-toggle {
display: flex;
align-items: center;
gap: 5px;
padding: 6px 12px;
padding: 4px 10px;
background: var(--warning-bg);
color: var(--warning-text);
border-radius: 6px;
font-size: 0.75rem;
font-size: 0.6875rem;
font-weight: 600;
border: 1px solid var(--warning-border);
}
@@ -400,27 +442,28 @@ html[dir="rtl"] .nav-lang-toggle {
display: flex;
align-items: center;
justify-content: center;
padding: 8px 10px;
border-radius: 8px;
width: 32px;
height: 32px;
border-radius: 7px;
cursor: pointer;
transition: all 0.2s ease;
transition: background 0.12s, color 0.12s;
background: transparent;
border: 1px solid var(--border);
border: none;
color: var(--text-muted);
flex-shrink: 0;
}
.nav-refresh-btn:hover {
background: var(--surface);
background: var(--muted-light);
color: var(--text-primary);
border-color: var(--primary);
}
.nav-refresh-btn:active {
transform: scale(0.96);
transform: scale(0.95);
}
.nav-refresh-btn:disabled {
opacity: 0.5;
opacity: 0.4;
cursor: not-allowed;
}
@@ -672,6 +715,13 @@ table tbody tr:hover {
justify-content: space-between;
align-items: center;
cursor: pointer;
background: none;
border: none;
width: 100%;
padding: 0;
text-align: left;
font: inherit;
color: inherit;
}
.controls-header h3 {
@@ -762,6 +812,292 @@ table tbody tr:hover {
border-color: var(--accent);
}
/* Always-visible period selector row (Dashboard) */
.period-selector-row {
display: flex;
align-items: center;
margin-bottom: 12px;
}
/* Comparison period row (bare, no collapsible wrapper) */
.comparison-periods {
margin-bottom: 12px;
}
/* Period Picker (legacy) */
.period-picker { width: 100%; }
.period-picker-row { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end; }
/* ── DateRangePicker ─────────────────────────── */
.drp {
position: relative;
display: inline-block;
}
.drp-standalone {
padding: 8px 0 4px;
}
.drp-trigger {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 9px 14px;
background: var(--surface);
border: 1.5px solid var(--border);
border-radius: var(--radius);
cursor: pointer;
font-size: 0.9rem;
font-weight: 600;
color: var(--text-primary);
white-space: nowrap;
transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
letter-spacing: -0.01em;
}
.drp-trigger:hover {
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08);
}
.drp-trigger.drp-open {
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
background: var(--accent-light, #dbeafe);
color: var(--accent);
}
.drp-cal-icon {
color: var(--text-muted);
flex-shrink: 0;
transition: color 0.15s;
}
.drp-trigger.drp-open .drp-cal-icon {
color: var(--accent);
}
.drp-trigger-label {
font-variant-numeric: tabular-nums;
}
.drp-chevron {
color: var(--text-muted);
flex-shrink: 0;
}
/* Panel */
.drp-panel {
position: absolute;
top: calc(100% + 6px);
left: 0;
z-index: 300;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: 0 12px 32px rgba(0,0,0,0.12), 0 2px 6px rgba(0,0,0,0.06);
padding: 16px;
width: min(324px, calc(100vw - 32px));
animation: drpIn 140ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes drpIn {
from { opacity: 0; transform: translateY(-6px) scale(0.98); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
/* Year nav */
.drp-year-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 14px;
padding-bottom: 12px;
border-bottom: 1px solid var(--border);
}
.drp-year-val {
font-size: 1.125rem;
font-weight: 700;
color: var(--text-primary);
letter-spacing: -0.02em;
}
.drp-year-btn {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: 1px solid var(--border);
border-radius: 7px;
background: var(--bg);
color: var(--text-secondary);
cursor: pointer;
transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.drp-year-btn:hover:not(:disabled) {
background: var(--accent);
border-color: var(--accent);
color: var(--text-inverse);
}
.drp-year-btn:disabled {
opacity: 0.3;
cursor: not-allowed;
}
/* Section labels */
.drp-group-label {
font-size: 0.625rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
margin: 10px 0 6px;
}
.drp-year-row + .drp-group-label {
margin-top: 0;
}
/* Chips */
.drp-chips {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.drp-chip {
padding: 4px 9px;
border: 1px solid var(--border);
border-radius: 6px;
background: transparent;
color: var(--text-secondary);
font-size: 0.8rem;
font-weight: 500;
cursor: pointer;
transition: background 0.1s, border-color 0.1s, color 0.1s;
letter-spacing: 0.01em;
}
.drp-chip:hover {
border-color: var(--accent);
color: var(--accent);
background: var(--accent-light);
}
.drp-chip.drp-chip-active {
background: var(--accent);
border-color: var(--accent);
color: var(--text-inverse);
font-weight: 600;
}
.drp-chip-wide {
padding-left: 12px;
padding-right: 12px;
}
/* Season chips — base (all browsers) */
.drp-chip-season {
border-color: var(--border);
color: var(--text-secondary);
}
.drp-chip-season:hover {
border-color: var(--accent);
color: var(--accent);
background: var(--accent-light);
}
.drp-chip-season.drp-chip-active {
background: var(--accent);
border-color: var(--accent);
color: var(--text-inverse);
}
/* Enhanced with color-mix where supported */
@supports (color: color-mix(in srgb, red, blue)) {
.drp-chip-season {
border-color: color-mix(in srgb, var(--sc, var(--border)) 50%, var(--border));
color: var(--sc, var(--text-secondary));
}
.drp-chip-season:hover {
border-color: var(--sc, var(--accent));
color: var(--sc, var(--accent));
background: color-mix(in srgb, var(--sc, var(--accent)) 8%, transparent);
}
.drp-chip-season.drp-chip-active {
background: var(--sc, var(--accent));
border-color: var(--sc, var(--accent));
}
}
/* Divider + custom inputs */
.drp-divider {
height: 1px;
background: var(--border);
margin: 12px 0 10px;
}
.drp-custom {
display: flex;
align-items: flex-end;
gap: 8px;
}
.drp-custom-field {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.drp-custom-field label {
font-size: 0.625rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.07em;
color: var(--text-muted);
}
.drp-custom-field input[type="date"] {
padding: 7px 9px;
border: 1px solid var(--border);
border-radius: 7px;
font-size: 0.825rem;
background: var(--bg);
color: var(--text-primary);
width: 100%;
transition: border-color 0.12s, box-shadow 0.12s;
}
.drp-custom-field input[type="date"]:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.12);
}
.drp-custom-sep {
font-size: 0.75rem;
color: var(--text-muted);
padding-bottom: 9px;
flex-shrink: 0;
}
/* Right-align panel when near viewport edge */
@media (max-width: 480px) {
.drp-panel {
left: auto;
right: 0;
width: 290px;
}
}
/* Multi-select */
.multi-select {
position: relative;
@@ -1147,6 +1483,62 @@ tr.editing td {
padding: 0 12px;
}
/* Comparison Period Picker Layout */
.comparison-periods {
display: flex;
align-items: flex-start;
gap: 24px;
width: 100%;
}
.comparison-period-block {
flex: 1;
min-width: 0;
}
.comparison-period-label {
font-size: 0.6875rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
margin-bottom: 8px;
padding: 3px 8px;
border-radius: 4px;
display: inline-block;
}
.comparison-period-label.curr-label {
background: rgba(37, 99, 235, 0.1);
color: var(--accent);
}
.comparison-period-label.prev-label {
background: var(--muted-light);
color: var(--text-muted);
}
.comparison-period-vs {
align-self: center;
font-size: 0.875rem;
font-weight: 700;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 0 4px;
flex-shrink: 0;
}
@media (max-width: 900px) {
.comparison-periods {
flex-direction: column;
gap: 20px;
}
.comparison-period-vs {
align-self: flex-start;
padding: 4px 0;
}
}
/* Comparison Metrics */
.comparison-grid {
display: grid;
@@ -1420,12 +1812,12 @@ tr.editing td {
width: 8px;
height: 8px;
border-radius: 4px;
padding: 8px;
padding: 18px;
background-clip: content-box;
cursor: pointer;
transition: all 0.3s ease;
min-width: 24px;
min-height: 24px;
transition: background 0.3s ease, width 0.3s ease;
min-width: 44px;
min-height: 44px;
display: flex;
align-items: center;
justify-content: center;
@@ -1585,28 +1977,28 @@ tr.editing td {
.nav-links {
display: none;
}
.nav-bar {
padding: 12px 16px;
height: auto;
padding: 0 16px;
height: 52px;
}
.nav-content {
justify-content: center;
}
.nav-brand-text {
font-size: 1rem;
.nav-brand-name {
font-size: 0.9375rem;
}
.nav-brand-icon {
width: 18px;
height: 18px;
}
.data-source-select {
font-size: 0.9rem;
padding: 2px 18px 2px 4px;
font-size: 0.8125rem;
padding: 2px 16px 2px 4px;
}
/* Mobile Bottom Navigation */
@@ -1859,10 +2251,10 @@ tr.editing td {
@media (max-width: 400px) {
/* Very small screens */
.nav-bar {
padding: 6px 8px;
padding: 0 8px;
}
.nav-brand {
.nav-brand-name {
font-size: 0.875rem;
}