refactor(header): improve mobile header layout with responsive action controls
This commit is contained in:
107
src/app/page.tsx
107
src/app/page.tsx
@@ -15,7 +15,6 @@ import { DragDropContainer } from "@/components/drag-drop-container";
|
||||
import { EventDialog } from "@/components/event-dialog";
|
||||
import { EventsList } from "@/components/events-list";
|
||||
import { IcsFilePicker } from "@/components/ics-file-picker";
|
||||
import { ModeToggle } from "@/components/mode-toggle";
|
||||
import { SettingsPanel } from "@/components/settings-panel";
|
||||
import SignIn from "@/components/sign-in";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -432,12 +431,21 @@ export default function HomePage() {
|
||||
isMobile ? "px-4 pb-24 pt-4" : "px-8 py-4",
|
||||
);
|
||||
const appHeaderSurfaceClasses = getAppHeaderSurfaceClasses(isMobile);
|
||||
const headerLayoutClasses = cn(
|
||||
isMobile ? "flex-col items-start" : "items-center justify-between",
|
||||
);
|
||||
const appSectionSurfaceClasses = getAppSectionSurfaceClasses(isMobile);
|
||||
const appNavSurfaceClasses = getAppNavSurfaceClasses(isMobile);
|
||||
const mainContentClasses = cn(
|
||||
"grid items-start gap-4",
|
||||
isMobile ? "grid-cols-1" : "grid-cols-[minmax(0,0.75fr)_minmax(0,1.25fr)]",
|
||||
);
|
||||
const headerActionsClasses = isMobile
|
||||
? "flex w-full items-center justify-between gap-2"
|
||||
: "flex flex-wrap items-center justify-end gap-2";
|
||||
const mobileUtilityActionsClasses = "flex items-center gap-2";
|
||||
const desktopUtilityActionsClasses = "flex items-center gap-2";
|
||||
const moreTriggerLabel = isMobile ? null : "More";
|
||||
|
||||
return (
|
||||
<DragDropContainer
|
||||
@@ -447,8 +455,13 @@ export default function HomePage() {
|
||||
onImageDrop={(file) => handleImagesSelect([file])}
|
||||
>
|
||||
<div className={appFrameClasses}>
|
||||
<header className={appHeaderSurfaceClasses}>
|
||||
<div className="flex min-w-0 flex-col">
|
||||
<header className={cn(appHeaderSurfaceClasses, headerLayoutClasses)}>
|
||||
<div
|
||||
className={cn(
|
||||
"flex min-w-0 flex-col",
|
||||
isMobile ? "w-full" : undefined,
|
||||
)}
|
||||
>
|
||||
<p className="font-mono text-[11px] uppercase text-muted-foreground">
|
||||
Local Calendar
|
||||
</p>
|
||||
@@ -456,7 +469,7 @@ export default function HomePage() {
|
||||
Event timeline
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center justify-end gap-2">
|
||||
<div className={headerActionsClasses}>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={getConnectionBadgeClasses(isOnline)}
|
||||
@@ -468,41 +481,63 @@ export default function HomePage() {
|
||||
)}
|
||||
<span>{isOnline ? "Online ready" : "Offline mode"}</span>
|
||||
</Badge>
|
||||
<SignIn />
|
||||
<ModeToggle />
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleExport}
|
||||
disabled={events.length === 0}
|
||||
<div
|
||||
className={
|
||||
isMobile
|
||||
? mobileUtilityActionsClasses
|
||||
: desktopUtilityActionsClasses
|
||||
}
|
||||
>
|
||||
Export
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button type="button" variant="outline" size="sm">
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
More
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-48">
|
||||
<DropdownMenuItem onClick={openManualEventDialog}>
|
||||
Manual create
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setActiveView("settings")}>
|
||||
Settings
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
variant="destructive"
|
||||
onClick={handleClearAll}
|
||||
<SignIn />
|
||||
{!isMobile && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleExport}
|
||||
disabled={events.length === 0}
|
||||
>
|
||||
Clear all events
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
Export
|
||||
</Button>
|
||||
)}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size={isMobile ? "icon" : "sm"}
|
||||
aria-label="More actions"
|
||||
>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
{moreTriggerLabel}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-48">
|
||||
{isMobile && (
|
||||
<DropdownMenuItem
|
||||
onClick={handleExport}
|
||||
disabled={events.length === 0}
|
||||
>
|
||||
Export
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuItem onClick={openManualEventDialog}>
|
||||
Manual create
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setActiveView("settings")}>
|
||||
Settings
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
variant="destructive"
|
||||
onClick={handleClearAll}
|
||||
disabled={events.length === 0}
|
||||
>
|
||||
Clear all events
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user