fix(D5): add responsive dashboard breakpoints

Move fixed shell dimensions into responsive classes so sub-1024px layouts hide the right panel, turn the sidebar into a bottom nav, and keep dashboard content usable with adaptive grids and horizontal screener scrolling.

Refs: docs/AUDIT_REDESIGN.md item D5.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
This commit is contained in:
Saravana Achu Mac 2026-05-04 16:41:48 -07:00
parent ce25712e59
commit a9c33b1c14
6 changed files with 138 additions and 58 deletions

View File

@ -13,41 +13,19 @@ import { SettingsView } from '../../views/SettingsView';
export function AppShell() { export function AppShell() {
return ( return (
<div style={{ <div className="dashboard-shell">
display: 'flex',
minHeight: '100vh',
background: '#F3F4F6',
fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
}}>
{/* Fixed left sidebar */} {/* Fixed left sidebar */}
<Sidebar /> <Sidebar />
{/* Main area (right of sidebar) */} {/* Main area (right of sidebar) */}
<div style={{ <div className="dashboard-main">
marginLeft: 72,
flex: 1,
display: 'flex',
flexDirection: 'column',
minHeight: '100vh',
overflow: 'hidden',
}}>
{/* Sticky header */} {/* Sticky header */}
<Header /> <Header />
{/* Content row: main + right panel */} {/* Content row: main + right panel */}
<div style={{ <div className="dashboard-content-row">
flex: 1,
display: 'flex',
overflow: 'hidden',
minHeight: 0,
}}>
{/* Scrollable main content */} {/* Scrollable main content */}
<main style={{ <main className="dashboard-content">
flex: 1,
overflowY: 'auto',
padding: '24px 24px 32px',
minWidth: 0,
}}>
<Routes> <Routes>
<Route path="/" element={<HomeView />} /> <Route path="/" element={<HomeView />} />
<Route path="/portfolio" element={<PortfolioView />} /> <Route path="/portfolio" element={<PortfolioView />} />

View File

@ -227,8 +227,7 @@ function NewsFeed() {
export function RightPanel() { export function RightPanel() {
return ( return (
<aside style={{ <aside className="dashboard-right-panel" style={{
width: 308, minWidth: 308, maxWidth: 308,
background: '#ffffff', background: '#ffffff',
borderLeft: '1px solid #E5E7EB', borderLeft: '1px solid #E5E7EB',
display: 'flex', display: 'flex',

View File

@ -23,24 +23,9 @@ export function Sidebar() {
: 'US'; : 'US';
return ( return (
<aside style={{ <aside className="trading-sidebar">
width: 72,
minHeight: '100vh',
background: '#ffffff',
borderRight: '1px solid #E5E7EB',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
paddingTop: 16,
paddingBottom: 20,
position: 'fixed',
left: 0,
top: 0,
bottom: 0,
zIndex: 50,
}}>
{/* Logo */} {/* Logo */}
<div style={{ <div className="trading-sidebar-logo" style={{
width: 40, width: 40,
height: 40, height: 40,
borderRadius: 10, borderRadius: 10,
@ -58,25 +43,18 @@ export function Sidebar() {
</div> </div>
{/* Nav items */} {/* Nav items */}
<nav style={{ <nav className="trading-sidebar-nav">
flex: 1,
display: 'flex',
flexDirection: 'column',
width: '100%',
alignItems: 'center',
gap: 2,
}}>
{NAV.map(({ to, icon: Icon, label, end }) => ( {NAV.map(({ to, icon: Icon, label, end }) => (
<NavLink <NavLink
key={to} key={to}
to={to} to={to}
end={end} end={end}
className="trading-sidebar-link"
style={({ isActive }) => ({ style={({ isActive }) => ({
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
width: '100%',
padding: '10px 0 8px', padding: '10px 0 8px',
gap: 3, gap: 3,
borderLeft: isActive ? '3px solid #2563EB' : '3px solid transparent', borderLeft: isActive ? '3px solid #2563EB' : '3px solid transparent',
@ -105,6 +83,7 @@ export function Sidebar() {
{/* User avatar */} {/* User avatar */}
<div <div
className="trading-sidebar-avatar"
title={`${user?.email ?? ''} — click to sign out`} title={`${user?.email ?? ''} — click to sign out`}
onClick={handleSignOut} onClick={handleSignOut}
style={{ style={{

View File

@ -60,4 +60,128 @@ body {
@keyframes spin { @keyframes spin {
from { transform: rotate(0deg); } from { transform: rotate(0deg); }
to { transform: rotate(360deg); } to { transform: rotate(360deg); }
} }
.dashboard-shell {
display: flex;
min-height: 100vh;
background: #F3F4F6;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
.dashboard-main {
margin-left: 72px;
flex: 1;
display: flex;
flex-direction: column;
min-height: 100vh;
overflow: hidden;
}
.dashboard-content-row {
flex: 1;
display: flex;
overflow: hidden;
min-height: 0;
}
.dashboard-content {
flex: 1;
overflow-y: auto;
padding: 24px 24px 32px;
min-width: 0;
}
.dashboard-right-panel {
width: 308px;
min-width: 308px;
max-width: 308px;
}
.trading-sidebar {
width: 72px;
min-height: 100vh;
background: #ffffff;
border-right: 1px solid #E5E7EB;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 16px;
padding-bottom: 20px;
position: fixed;
left: 0;
top: 0;
bottom: 0;
z-index: 50;
}
.trading-sidebar-nav {
flex: 1;
display: flex;
flex-direction: column;
width: 100%;
align-items: center;
gap: 2px;
}
.trading-sidebar-link {
width: 100%;
}
@media (max-width: 1023px) {
.dashboard-shell {
padding-bottom: 68px;
}
.dashboard-main {
margin-left: 0;
min-width: 0;
}
.dashboard-content-row {
min-width: 0;
}
.dashboard-content {
padding: 16px 14px 24px;
}
.dashboard-right-panel {
display: none !important;
}
.trading-sidebar {
width: 100%;
min-height: 64px;
height: 64px;
top: auto;
right: 0;
bottom: 0;
flex-direction: row;
justify-content: center;
align-items: stretch;
padding: 0 8px;
border-right: 0;
border-top: 1px solid #E5E7EB;
overflow-x: auto;
}
.trading-sidebar-logo,
.trading-sidebar-avatar {
display: none !important;
}
.trading-sidebar-nav {
flex: 0 1 auto;
flex-direction: row;
width: auto;
max-width: 100%;
align-items: stretch;
gap: 0;
}
.trading-sidebar-link {
width: 68px;
min-width: 68px;
}
}

View File

@ -534,7 +534,7 @@ function QuickStats({ symbol }: { symbol: string }) {
]; ];
return ( return (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 12, marginBottom: 20 }}> <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))', gap: 12, marginBottom: 20 }}>
{stats.map(s => ( {stats.map(s => (
<div key={s.label} style={{ <div key={s.label} style={{
background: '#fff', background: '#fff',
@ -605,7 +605,7 @@ function ResearchCards({
]; ];
return ( return (
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 16 }}> <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 16 }}>
{/* Company Profile */} {/* Company Profile */}
<div style={{ background: '#fff', borderRadius: 12, border: '1px solid #E5E7EB', padding: 16 }}> <div style={{ background: '#fff', borderRadius: 12, border: '1px solid #E5E7EB', padding: 16 }}>
<div style={{ fontSize: 13, fontWeight: 700, color: '#111827', marginBottom: 10 }}> <div style={{ fontSize: 13, fontWeight: 700, color: '#111827', marginBottom: 10 }}>

View File

@ -265,7 +265,7 @@ export function ScreenerView() {
)} )}
{/* Results table */} {/* Results table */}
<div style={{ background: '#fff', borderRadius: 12, border: '1px solid #E5E7EB', overflow: 'hidden' }}> <div style={{ background: '#fff', borderRadius: 12, border: '1px solid #E5E7EB', overflowX: 'auto', overflowY: 'hidden' }}>
{/* Header */} {/* Header */}
<div style={{ <div style={{
display: 'grid', display: 'grid',