feat: enhance responsive design and layout consistency across various components, including dashboard, statistics, and rules pages
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Menu } from "lucide-react";
|
||||
import { useSidebarContext } from "@/components/layout/sidebar-context";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface PageHeaderProps {
|
||||
title: string;
|
||||
@@ -15,16 +20,39 @@ export function PageHeader({
|
||||
actions,
|
||||
rightContent,
|
||||
}: PageHeaderProps) {
|
||||
const { setOpen } = useSidebarContext();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-foreground">{title}</h1>
|
||||
{description && (
|
||||
<div className="text-muted-foreground">{description}</div>
|
||||
<div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
{isMobile && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setOpen(true)}
|
||||
className="shrink-0"
|
||||
>
|
||||
<Menu className="w-5 h-5" />
|
||||
</Button>
|
||||
)}
|
||||
<div>
|
||||
<h1 className="text-lg md:text-2xl font-bold text-foreground">{title}</h1>
|
||||
{description && (
|
||||
<div className="text-xs md:text-base text-muted-foreground mt-1">{description}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{rightContent}
|
||||
{actions && <div className="flex gap-2">{actions}</div>}
|
||||
{(rightContent || actions) && (
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
{rightContent}
|
||||
{actions && (
|
||||
<div className={cn("flex gap-2", isMobile && "flex-wrap")}>
|
||||
{actions}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
"use client";
|
||||
|
||||
import { Sidebar } from "@/components/dashboard/sidebar";
|
||||
import { ReactNode } from "react";
|
||||
import { ReactNode, useState } from "react";
|
||||
import { SidebarContext } from "@/components/layout/sidebar-context";
|
||||
|
||||
interface PageLayoutProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function PageLayout({ children }: PageLayoutProps) {
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-background">
|
||||
<Sidebar />
|
||||
<main className="flex-1 overflow-auto">
|
||||
<div className="p-6 space-y-6">{children}</div>
|
||||
</main>
|
||||
</div>
|
||||
<SidebarContext.Provider value={{ open: sidebarOpen, setOpen: setSidebarOpen }}>
|
||||
<div className="flex h-screen bg-background overflow-hidden">
|
||||
<Sidebar open={sidebarOpen} onOpenChange={setSidebarOpen} />
|
||||
<main className="flex-1 overflow-auto overflow-x-hidden">
|
||||
<div className="p-4 md:p-6 space-y-4 md:space-y-6 max-w-full">{children}</div>
|
||||
</main>
|
||||
</div>
|
||||
</SidebarContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
18
components/layout/sidebar-context.tsx
Normal file
18
components/layout/sidebar-context.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
interface SidebarContextType {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
}
|
||||
|
||||
export const SidebarContext = createContext<SidebarContextType>({
|
||||
open: false,
|
||||
setOpen: () => {},
|
||||
});
|
||||
|
||||
export function useSidebarContext() {
|
||||
return useContext(SidebarContext);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user