fix(admin): make admin panel layout responsive on mobile
The permanent 224px sidebar in the admin layout had no responsive handling at all, leaving almost no width for content on a phone (Gitea #10). Sidebar is now hidden below md: and replaced by a topbar + slide-in Sheet drawer (AdminMobileNav) with the same nav links; content padding and the outer flex direction adapt per breakpoint.
This commit is contained in:
1 parent
707b0b6797
commit
f7049569e1
2 files changed
+91
-4
No files matched your search
@@ -3,6 +3,7 @@ import { auth } from "@clerk/nextjs/server";
|
||||
import Link from "next/link";
|
||||
import { createTRPCCaller } from "@/trpc/server";
|
||||
import { timingSafeStringEqual } from "@/lib/timing-safe-compare";
|
||||
import { AdminMobileNav } from "@/components/admin/AdminMobileNav";
|
||||
import {
|
||||
LayoutDashboard,
|
||||
Users,
|
||||
@@ -71,10 +72,19 @@ export default async function AdminLayout({ children, params }: AdminLayoutProps
|
||||
: []),
|
||||
];
|
||||
|
||||
const navForMobile = nav.map(({ href, label, Icon }) => ({
|
||||
href,
|
||||
label,
|
||||
icon: <Icon className="h-4 w-4 shrink-0" />,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen bg-zinc-950 text-zinc-100">
|
||||
{/* Sidebar */}
|
||||
<aside className="w-56 shrink-0 border-r border-zinc-800 flex flex-col py-6 px-4 gap-1 h-screen sticky top-0 overflow-y-auto">
|
||||
<div className="flex min-h-screen flex-col bg-zinc-950 text-zinc-100 md:flex-row">
|
||||
{/* Mobile topbar + drawer — hidden md: and up */}
|
||||
<AdminMobileNav nav={navForMobile} />
|
||||
|
||||
{/* Sidebar — hidden below md:, permanent from md: up */}
|
||||
<aside className="hidden md:flex w-56 shrink-0 border-r border-zinc-800 flex-col py-6 px-4 gap-1 h-screen sticky top-0 overflow-y-auto">
|
||||
<p className="text-xs font-semibold text-zinc-500 uppercase tracking-widest px-2 mb-3">
|
||||
PawFeed Admin
|
||||
</p>
|
||||
@@ -101,7 +111,7 @@ export default async function AdminLayout({ children, params }: AdminLayoutProps
|
||||
</aside>
|
||||
|
||||
{/* Content */}
|
||||
<main className="flex-1 overflow-auto p-8">{children}</main>
|
||||
<main className="min-w-0 flex-1 overflow-auto p-4 md:p-8">{children}</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { Menu, ArrowLeft } from "lucide-react";
|
||||
import {
|
||||
Sheet,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "@/components/ui/sheet";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
interface AdminMobileNavProps {
|
||||
nav: { href: string; label: string; icon: React.ReactNode }[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mobile topbar + slide-in nav drawer for the admin panel — the desktop
|
||||
* <aside> sidebar in layout.tsx is hidden below md: and replaced by this.
|
||||
*/
|
||||
export function AdminMobileNav({ nav }: AdminMobileNavProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="md:hidden sticky top-0 z-40 flex items-center justify-between gap-2 border-b border-zinc-800 bg-zinc-950 px-4 py-3">
|
||||
<p className="text-xs font-semibold text-zinc-500 uppercase tracking-widest">
|
||||
PawFeed Admin
|
||||
</p>
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetTrigger render={<Button variant="ghost" size="icon-sm" />}>
|
||||
<Menu className="h-5 w-5" />
|
||||
<span className="sr-only">Menü öffnen</span>
|
||||
</SheetTrigger>
|
||||
<SheetContent
|
||||
side="left"
|
||||
className="flex flex-col gap-1 border-zinc-800 bg-zinc-950 py-6 px-4 text-zinc-100"
|
||||
>
|
||||
<SheetHeader className="p-0 mb-3">
|
||||
<SheetTitle className="text-xs font-semibold text-zinc-500 uppercase tracking-widest">
|
||||
PawFeed Admin
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
{nav.map(({ href, label, icon }) => (
|
||||
<SheetClose
|
||||
key={href}
|
||||
render={
|
||||
<Link
|
||||
href={href}
|
||||
className="flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm text-zinc-300 hover:bg-zinc-800 hover:text-zinc-100 transition-colors"
|
||||
/>
|
||||
}
|
||||
>
|
||||
{icon}
|
||||
{label}
|
||||
</SheetClose>
|
||||
))}
|
||||
<div className="mt-auto pt-3 border-t border-zinc-800">
|
||||
<SheetClose
|
||||
render={
|
||||
<Link
|
||||
href="/feed"
|
||||
className="flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm text-zinc-400 hover:bg-zinc-800 hover:text-zinc-100 transition-colors"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4 shrink-0" />
|
||||
Zurück
|
||||
</SheetClose>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user