fix: home sidebar flex column layout with independent scrolling sections
- Convert sidebar <aside> to flex column container (flex flex-col overflow-hidden min-h-0) - Remove sidebar-level scroll (overflow-y-auto → overflow-hidden) - Add min-h-0 to parent flex containers in both layout paths for proper height containment - Reorder sidebar sections: Clock → Projects → Drones → Recent Chats - Add shrink-0 to Clock component to keep it at intrinsic content size - Convert Projects, Drones, and Recent Chats sections to flex-1 min-h-0 flex-col with scrollable inner content - Pin section headers with shrink-0; list content scrolls independently via overflow-y-auto - Pin Recent Chats hint/footer with shrink-0 below its scrollable list - No logic changes — purely CSS/flexbox layout correction
This commit is contained in:
parent
c2028f45c5
commit
802184a487
@ -28,7 +28,7 @@ export default function Clock() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-3">
|
<div className="p-3 shrink-0">
|
||||||
<div className="text-xs font-semibold text-text-muted uppercase tracking-wider mb-2">
|
<div className="text-xs font-semibold text-text-muted uppercase tracking-wider mb-2">
|
||||||
Clock
|
Clock
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -269,53 +269,12 @@ function DashboardSidebar({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="w-64 border-l border-border-subtle bg-bg-secondary overflow-y-auto">
|
<aside className="w-64 border-l border-border-subtle bg-bg-secondary flex flex-col overflow-hidden min-h-0">
|
||||||
<Clock />
|
<Clock />
|
||||||
|
|
||||||
<div className="p-3 border-t border-border-subtle">
|
{/* Projects */}
|
||||||
<div className="text-xs font-semibold text-text-muted uppercase tracking-wider mb-2">
|
<div className="flex-1 min-h-0 flex flex-col border-t border-border-subtle">
|
||||||
Recent Chats
|
<div className="shrink-0 px-3 pt-3 pb-2 flex items-center justify-between text-xs font-semibold text-text-muted uppercase tracking-wider">
|
||||||
</div>
|
|
||||||
{loading ? (
|
|
||||||
<p className="text-sm text-text-muted px-2">Loading...</p>
|
|
||||||
) : recentChats.length === 0 ? (
|
|
||||||
<p className="text-sm text-text-muted px-2">No recent chats.</p>
|
|
||||||
) : (
|
|
||||||
<div className="space-y-1">
|
|
||||||
{recentChats.map((session) => (
|
|
||||||
<button
|
|
||||||
key={session._id}
|
|
||||||
onClick={() => handleOpenChat(session)}
|
|
||||||
className="w-full text-left px-2 py-1.5 text-sm text-text-secondary hover:bg-bg-tertiary hover:text-text-primary rounded transition-colors"
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-between gap-1">
|
|
||||||
<span className="truncate font-medium text-xs">{session.name || 'Untitled'}</span>
|
|
||||||
<span className={`text-[10px] px-1.5 py-0.5 rounded-full font-medium shrink-0 ${modeBadgeColors[session.mode] || 'bg-gray-500/20 text-gray-400'}`}>
|
|
||||||
{session.mode}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center justify-between gap-1 mt-0.5">
|
|
||||||
<span className="text-[11px] text-text-muted truncate">{getProjectName(session)}</span>
|
|
||||||
<span className="text-[10px] text-text-muted shrink-0">
|
|
||||||
{formatRelativeTime(session.lastMessageAt || session.createdAt)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{noDroneMessage && (
|
|
||||||
<p className="text-xs text-yellow-400 mt-2 px-2">{noDroneMessage}</p>
|
|
||||||
)}
|
|
||||||
{selectedDrone && (
|
|
||||||
<p className="text-[10px] text-text-muted mt-2 px-2 italic">
|
|
||||||
Select a chat to resume with {selectedDrone.hostname}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-3 border-t border-border-subtle">
|
|
||||||
<div className="flex items-center justify-between text-xs font-semibold text-text-muted uppercase tracking-wider mb-2">
|
|
||||||
<span>Projects</span>
|
<span>Projects</span>
|
||||||
<Link
|
<Link
|
||||||
to="/projects"
|
to="/projects"
|
||||||
@ -324,6 +283,7 @@ function DashboardSidebar({
|
|||||||
[+]
|
[+]
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex-1 min-h-0 overflow-y-auto px-3 pb-3">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<p className="text-sm text-text-muted px-2">Loading...</p>
|
<p className="text-sm text-text-muted px-2">Loading...</p>
|
||||||
) : projects.length === 0 ? (
|
) : projects.length === 0 ? (
|
||||||
@ -342,9 +302,11 @@ function DashboardSidebar({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="p-3 border-t border-border-subtle">
|
{/* Drones */}
|
||||||
<div className="flex items-center justify-between text-xs font-semibold text-text-muted uppercase tracking-wider mb-2">
|
<div className="flex-1 min-h-0 flex flex-col border-t border-border-subtle">
|
||||||
|
<div className="shrink-0 px-3 pt-3 pb-2 flex items-center justify-between text-xs font-semibold text-text-muted uppercase tracking-wider">
|
||||||
<span>Drones</span>
|
<span>Drones</span>
|
||||||
<Link
|
<Link
|
||||||
to="/drones"
|
to="/drones"
|
||||||
@ -372,6 +334,7 @@ function DashboardSidebar({
|
|||||||
</svg>
|
</svg>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex-1 min-h-0 overflow-y-auto px-3 pb-3">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<p className="text-sm text-text-muted px-2">Loading...</p>
|
<p className="text-sm text-text-muted px-2">Loading...</p>
|
||||||
) : drones.length === 0 ? (
|
) : drones.length === 0 ? (
|
||||||
@ -418,6 +381,54 @@ function DashboardSidebar({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Recent Chats */}
|
||||||
|
<div className="flex-1 min-h-0 flex flex-col border-t border-border-subtle">
|
||||||
|
<div className="shrink-0 px-3 pt-3 pb-2 text-xs font-semibold text-text-muted uppercase tracking-wider">
|
||||||
|
Recent Chats
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 min-h-0 overflow-y-auto px-3 pb-3">
|
||||||
|
{loading ? (
|
||||||
|
<p className="text-sm text-text-muted px-2">Loading...</p>
|
||||||
|
) : recentChats.length === 0 ? (
|
||||||
|
<p className="text-sm text-text-muted px-2">No recent chats.</p>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-1">
|
||||||
|
{recentChats.map((session) => (
|
||||||
|
<button
|
||||||
|
key={session._id}
|
||||||
|
onClick={() => handleOpenChat(session)}
|
||||||
|
className="w-full text-left px-2 py-1.5 text-sm text-text-secondary hover:bg-bg-tertiary hover:text-text-primary rounded transition-colors"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between gap-1">
|
||||||
|
<span className="truncate font-medium text-xs">{session.name || 'Untitled'}</span>
|
||||||
|
<span className={`text-[10px] px-1.5 py-0.5 rounded-full font-medium shrink-0 ${modeBadgeColors[session.mode] || 'bg-gray-500/20 text-gray-400'}`}>
|
||||||
|
{session.mode}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between gap-1 mt-0.5">
|
||||||
|
<span className="text-[11px] text-text-muted truncate">{getProjectName(session)}</span>
|
||||||
|
<span className="text-[10px] text-text-muted shrink-0">
|
||||||
|
{formatRelativeTime(session.lastMessageAt || session.createdAt)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="shrink-0 px-3 pb-3">
|
||||||
|
{noDroneMessage && (
|
||||||
|
<p className="text-xs text-yellow-400 mt-2 px-2">{noDroneMessage}</p>
|
||||||
|
)}
|
||||||
|
{selectedDrone && (
|
||||||
|
<p className="text-[10px] text-text-muted mt-2 px-2 italic">
|
||||||
|
Select a chat to resume with {selectedDrone.hostname}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
@ -447,7 +458,7 @@ export default function Home({ user }: HomeProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mainContent = selectedDrone ? (
|
const mainContent = selectedDrone ? (
|
||||||
<div className="relative z-10 flex-1 flex">
|
<div className="relative z-10 flex-1 flex min-h-0">
|
||||||
<DroneInspector
|
<DroneInspector
|
||||||
drone={selectedDrone}
|
drone={selectedDrone}
|
||||||
onClose={() => setSelectedDrone(null)}
|
onClose={() => setSelectedDrone(null)}
|
||||||
@ -463,8 +474,8 @@ export default function Home({ user }: HomeProps) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="relative z-10 flex-1 flex flex-col">
|
<div className="relative z-10 flex-1 flex flex-col min-h-0">
|
||||||
<div className="flex-1 flex">
|
<div className="flex-1 flex min-h-0">
|
||||||
<div className="flex-1 flex items-center justify-center p-8">
|
<div className="flex-1 flex items-center justify-center p-8">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<h1 className="text-2xl font-semibold mb-4">
|
<h1 className="text-2xl font-semibold mb-4">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user