feat(dashboard): implement responsive header with tab scrolling and overflow menus

Add comprehensive responsive header system with Google-quality UX:

Tab Navigation:
- Add TabScrollManager for horizontal scrolling tabs
- Left/Right navigation arrows appear when scrollable
- Edge fade indicators show more content exists
- Smooth scroll behavior with momentum
- Progressive sizing: full → icon+name → icon-only
- Automatic scroll position tracking

Button Overflow System:
- Add HeaderOverflowManager with ResizeObserver
- Three responsive modes based on container width:
  * Full mode (>900px): all buttons visible
  * Overflow mode (500-900px): priority + "More" (⋮) menu
  * Compact mode (<500px): priority + hamburger (☰) menu
- Priority buttons (Lock + Edit) always visible
- Smooth transitions between modes

Dropdown Menu:
- Professional slide-down animation
- Full keyboard navigation (arrows, Home, End, Escape)
- Click-outside-to-close behavior
- ARIA attributes for accessibility
- Focus management and trap
- Auto-refresh on edit mode changes
- High z-index (10003) ensures visibility above all UI

Cross-Tab Widget Dragging:
- Add collision detection for widget placement
- Implement moveWidgetToTab() with collision avoidance
- Find available positions in target tab automatically
- Update dragDrop.js to detect tab hover
- Visual feedback with tab highlight on hover
- Proper widget positioning after cross-tab move

Additional Features:
- Sort Tab button for current-tab-only auto-layout
- Mobile optimizations with compact buttons
- Responsive breakpoints at 768px and 480px
- Hardware-accelerated animations
- Touch-friendly 44px minimum targets

Files changed:
- New: tabScrollManager.js, headerOverflowManager.js
- Modified: dashboardTemplate.html, dashboardIntegration.js
- Modified: dashboardManager.js, dragDrop.js, style.css
- Modified: editModeManager.js (lock state default)
This commit is contained in:
Lucas 'Paperboy' Rose-Winters
2025-10-27 14:48:38 +11:00
parent 45c5853dcb
commit f566ad1d93
8 changed files with 1474 additions and 41 deletions
+457 -2
View File
@@ -1052,6 +1052,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
width: 100%;
flex: 1;
overflow-y: auto;
overflow-x: visible; /* Allow horizontal overflow for dropdown menu */
min-height: 0;
}
@@ -1062,6 +1063,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
padding: 0;
gap: 0.5rem;
flex-wrap: wrap;
overflow: visible; /* Prevent clipping of dropdown menu */
}
.rpg-dashboard-header-left,
@@ -1069,16 +1071,58 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
flex-wrap: nowrap;
}
/* Position context for dropdown menu */
.rpg-dashboard-header-right {
position: relative;
}
/* Ensure buttons stay compact on mobile */
@media (max-width: 768px) {
.rpg-dashboard-header-right {
gap: 0.25rem;
}
.rpg-dashboard-btn {
padding: 0.4rem;
width: 1.8rem;
height: 1.8rem;
font-size: 0.8rem;
}
}
/* Tab Navigation Wrapper */
.rpg-tab-nav-wrapper {
position: relative;
display: flex;
align-items: center;
flex: 1;
min-width: 0;
overflow: hidden;
}
/* Scrollable Tabs Container */
.rpg-dashboard-tabs {
display: flex;
align-items: center;
gap: 0.25rem;
flex-wrap: wrap;
flex-wrap: nowrap;
overflow-x: auto;
overflow-y: hidden;
scroll-behavior: smooth;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE/Edge */
padding: 0.25rem 0;
}
/* Hide scrollbar */
.rpg-dashboard-tabs::-webkit-scrollbar {
display: none;
}
/* Individual Tab */
.rpg-dashboard-tab {
display: inline-flex;
align-items: center;
@@ -1094,6 +1138,8 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
cursor: pointer;
transition: all 0.2s;
opacity: 0.6;
flex-shrink: 0;
white-space: nowrap;
}
.rpg-dashboard-tab:hover {
@@ -1110,6 +1156,7 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
.rpg-tab-icon {
font-size: 1.1rem;
flex-shrink: 0;
}
.rpg-tab-name {
@@ -1123,6 +1170,109 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
margin-left: 0.3rem;
}
/* Tab Navigation Arrows */
.rpg-tab-nav-arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 10;
display: none;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
padding: 0;
border: 1px solid var(--SmartThemeBorderColor);
background: var(--SmartThemeBlurTintColor);
color: var(--SmartThemeBodyColor);
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
opacity: 0;
pointer-events: none;
}
.rpg-tab-nav-arrow.visible {
display: flex;
opacity: 0.8;
pointer-events: auto;
}
.rpg-tab-nav-arrow:hover {
opacity: 1;
background: var(--SmartThemeQuoteColor);
transform: translateY(-50%) scale(1.05);
}
.rpg-tab-nav-left {
left: 0;
}
.rpg-tab-nav-right {
right: 0;
}
/* Fade Indicators */
.rpg-tab-fade {
position: absolute;
top: 0;
bottom: 0;
width: 3rem;
z-index: 5;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s;
}
.rpg-tab-fade.visible {
opacity: 1;
}
.rpg-tab-fade-left {
left: 0;
background: linear-gradient(
to right,
var(--SmartThemeBlurTintColor) 0%,
transparent 100%
);
}
.rpg-tab-fade-right {
right: 0;
background: linear-gradient(
to left,
var(--SmartThemeBlurTintColor) 0%,
transparent 100%
);
}
/* Responsive Tab Sizing */
@media (max-width: 768px) {
.rpg-dashboard-tab {
padding: 0.4rem;
min-width: 2rem;
}
.rpg-tab-icon {
font-size: 1rem;
}
.rpg-tab-name {
display: none !important;
}
}
@media (max-width: 480px) {
.rpg-dashboard-tab {
padding: 0.3rem;
min-width: 1.8rem;
}
.rpg-tab-icon {
font-size: 0.9rem;
}
}
.rpg-dashboard-btn {
display: inline-flex;
align-items: center;
@@ -1148,6 +1298,311 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
font-size: 0.9rem;
}
/* ========================================
Header Dropdown Menu
======================================== */
/* Dropdown Menu Container */
.rpg-dropdown-menu {
position: absolute;
top: calc(100% + 0.5rem);
right: 0;
min-width: 200px;
max-width: 300px;
background: var(--SmartThemeBlurTintColor);
border: 1px solid var(--SmartThemeBorderColor);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
z-index: 10003; /* Above modals (10000) and mobile toggle (10002) */
overflow: hidden;
animation: slideDown 0.2s ease-out;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Menu Item */
.rpg-dropdown-item {
display: flex;
align-items: center;
gap: 0.75rem;
width: 100%;
padding: 0.75rem 1rem;
border: none;
background: transparent;
color: var(--SmartThemeBodyColor);
text-align: left;
cursor: pointer;
transition: background 0.15s;
font-size: 0.9rem;
}
.rpg-dropdown-item:hover,
.rpg-dropdown-item:focus {
background: var(--SmartThemeQuoteColor);
outline: none;
}
.rpg-dropdown-item:active {
transform: scale(0.98);
}
.rpg-dropdown-item i {
width: 1.2rem;
text-align: center;
flex-shrink: 0;
font-size: 0.9rem;
}
.rpg-dropdown-item span {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Empty state */
.rpg-dropdown-empty {
padding: 1rem;
text-align: center;
color: var(--SmartThemeBodyColor);
opacity: 0.6;
font-size: 0.85rem;
}
/* Menu button active state */
.rpg-dashboard-btn[aria-expanded="true"] {
background: var(--SmartThemeQuoteColor);
border-color: var(--rpg-highlight);
}
/* Priority buttons always visible */
.rpg-priority-btn {
order: -1;
}
/* Overflow/Hamburger menu buttons */
.rpg-overflow-menu-btn,
.rpg-hamburger-menu-btn {
order: 1000;
}
/* Responsive adjustments for dropdown */
@media (max-width: 768px) {
.rpg-dropdown-menu {
min-width: 180px;
right: -0.5rem;
}
.rpg-dropdown-item {
padding: 0.65rem 0.85rem;
font-size: 0.85rem;
}
.rpg-dropdown-item i {
font-size: 0.85rem;
}
}
@media (max-width: 480px) {
.rpg-dropdown-menu {
min-width: 160px;
max-width: calc(100vw - 2rem);
}
.rpg-dropdown-item {
padding: 0.6rem 0.75rem;
gap: 0.5rem;
}
}
/* ========================================
Dashboard Modals
======================================== */
/* Modal Overlay */
.rpg-modal {
display: none; /* Hidden by default, shown with display: flex */
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
z-index: 10000;
justify-content: center;
align-items: center;
}
/* Modal Content Container */
.rpg-modal-content {
background: var(--SmartThemeBlurTintColor);
border: 2px solid var(--SmartThemeBorderColor);
border-radius: 8px;
max-width: 600px;
max-height: 80vh;
overflow: auto;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}
/* Modal Header */
.rpg-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
border-bottom: 1px solid var(--SmartThemeBorderColor);
}
.rpg-modal-header h3 {
margin: 0;
color: var(--SmartThemeBodyColor);
display: flex;
align-items: center;
gap: 0.5rem;
}
.rpg-modal-close {
background: transparent;
border: none;
color: var(--SmartThemeBodyColor);
font-size: 1.5rem;
cursor: pointer;
padding: 0.25rem 0.5rem;
transition: all 0.2s;
}
.rpg-modal-close:hover {
color: var(--rpg-highlight);
transform: scale(1.1);
}
/* Modal Body */
.rpg-modal-body {
padding: 1rem;
}
/* Modal Footer */
.rpg-modal-footer {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
padding: 1rem;
border-top: 1px solid var(--SmartThemeBorderColor);
}
/* Widget Grid in Modal */
.rpg-widget-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 1rem;
}
/* Widget Card */
.rpg-widget-card {
padding: 1rem;
border: 2px solid var(--SmartThemeBorderColor);
border-radius: 8px;
background: var(--SmartThemeQuoteColor);
text-align: center;
transition: all 0.2s;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.rpg-widget-card:hover {
border-color: var(--rpg-highlight);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.rpg-widget-card-icon {
font-size: 2.5rem;
margin-bottom: 0.25rem;
}
.rpg-widget-card-name {
font-size: 0.95rem;
font-weight: 600;
color: var(--SmartThemeBodyColor);
}
.rpg-widget-card-description {
font-size: 0.75rem;
color: var(--SmartThemeFastUISliderColColor);
line-height: 1.3;
}
.rpg-widget-card-add {
padding: 0.5rem 1rem;
background: var(--rpg-highlight);
border: none;
border-radius: 4px;
color: white;
cursor: pointer;
font-weight: 600;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
.rpg-widget-card-add:hover {
background: rgba(var(--rpg-highlight-rgb, 233, 69, 96), 0.8);
transform: scale(1.05);
}
/* Modal Buttons */
.rpg-btn-primary,
.rpg-btn-secondary {
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
font-weight: 600;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 0.5rem;
}
.rpg-btn-primary {
background: var(--rpg-highlight);
border: none;
color: white;
}
.rpg-btn-primary:hover {
background: rgba(var(--rpg-highlight-rgb, 233, 69, 96), 0.8);
}
.rpg-btn-secondary {
background: transparent;
border: 1px solid var(--SmartThemeBorderColor);
color: var(--SmartThemeBodyColor);
}
.rpg-btn-secondary:hover {
background: var(--SmartThemeQuoteColor);
}
/* Tab Drop Zone Highlight */
.rpg-dashboard-tab.drop-target {
background: var(--rpg-highlight) !important;
color: white !important;
transform: scale(1.1);
box-shadow: 0 0 12px var(--rpg-highlight);
}
.rpg-dashboard-grid {
position: relative;
width: 100%;