feat(web): add mobile responsive layout with bottom navigation

Add useMobile hook for viewport detection (<768px). Update AppLayout
with hamburger menu, slide-over sidebar overlay, and fixed bottom
navigation bar (Tools, Automate, Files, Settings) for mobile. Update
Sidebar with expanded mode for mobile overlay. Update ToolPage to
stack settings above dropzone on mobile with collapsible panel. Add
new routes for /automate and /fullscreen. Integrate Settings dialog
and keyboard shortcuts at the App root level.
This commit is contained in:
Siddharth Kumar Sah
2026-03-22 04:42:31 +08:00
parent 6d67b106ca
commit 580208de83
5 changed files with 271 additions and 17 deletions
+30 -3
View File
@@ -7,6 +7,7 @@ import {
FolderOpen,
HelpCircle,
Settings,
Grid3x3,
} from "lucide-react";
import type { LucideIcon } from "lucide-react";
@@ -18,7 +19,7 @@ interface SidebarItem {
const topItems: SidebarItem[] = [
{ icon: LayoutGrid, label: "Tools", href: "/" },
{ icon: BookOpen, label: "Reader", href: "/reader" },
{ icon: Grid3x3, label: "Grid", href: "/fullscreen" },
{ icon: Workflow, label: "Automate", href: "/automate" },
{ icon: FolderOpen, label: "Files", href: "/files" },
];
@@ -30,13 +31,27 @@ const bottomItems: SidebarItem[] = [
interface SidebarProps {
onSettingsClick: () => void;
/** When true, renders in expanded mode (for mobile overlay). */
expanded?: boolean;
}
export function Sidebar({ onSettingsClick }: SidebarProps) {
export function Sidebar({ onSettingsClick, expanded = false }: SidebarProps) {
const location = useLocation();
const renderItem = (item: SidebarItem, isActive: boolean) => {
const content = (
const content = expanded ? (
<div
className={cn(
"flex items-center gap-3 px-4 py-2.5 rounded-lg cursor-pointer transition-colors",
isActive
? "bg-primary text-primary-foreground"
: "text-muted-foreground hover:bg-muted hover:text-foreground"
)}
>
<item.icon className="h-5 w-5" />
<span className="text-sm font-medium">{item.label}</span>
</div>
) : (
<div
className={cn(
"flex flex-col items-center gap-1 p-2 rounded-lg cursor-pointer transition-colors",
@@ -64,6 +79,18 @@ export function Sidebar({ onSettingsClick }: SidebarProps) {
);
};
if (expanded) {
return (
<div className="flex flex-col p-3 gap-1">
{topItems.map((item) =>
renderItem(item, location.pathname === item.href)
)}
<div className="border-t border-border my-2" />
{bottomItems.map((item) => renderItem(item, false))}
</div>
);
}
return (
<aside className="flex flex-col items-center w-16 bg-sidebar border-r border-border py-3 gap-1 shrink-0">
<div className="flex flex-col gap-1 flex-1">