90 lines
2.5 KiB
TypeScript
90 lines
2.5 KiB
TypeScript
"use client";
|
|
|
|
import { ReactNode, useEffect, useState } 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";
|
|
|
|
interface PageHeaderProps {
|
|
title: string;
|
|
description?: string | ReactNode;
|
|
actions?: ReactNode;
|
|
rightContent?: ReactNode;
|
|
}
|
|
|
|
export function PageHeader({
|
|
title,
|
|
description,
|
|
actions,
|
|
rightContent,
|
|
}: PageHeaderProps) {
|
|
const { setOpen } = useSidebarContext();
|
|
const isMobile = useIsMobile();
|
|
const [textColor, setTextColor] = useState("var(--foreground)");
|
|
|
|
useEffect(() => {
|
|
const checkDarkBackground = () => {
|
|
const pageBackground = document.querySelector(".page-background");
|
|
if (pageBackground?.classList.contains("bg-solid-dark")) {
|
|
setTextColor("#f5f5f5");
|
|
} else {
|
|
setTextColor("var(--foreground)");
|
|
}
|
|
};
|
|
|
|
checkDarkBackground();
|
|
const observer = new MutationObserver(checkDarkBackground);
|
|
const pageBackground = document.querySelector(".page-background");
|
|
if (pageBackground) {
|
|
observer.observe(pageBackground, {
|
|
attributes: true,
|
|
attributeFilter: ["class"],
|
|
});
|
|
}
|
|
|
|
return () => observer.disconnect();
|
|
}, []);
|
|
|
|
return (
|
|
<div className="flex flex-col gap-4 mb-2">
|
|
<div className="flex items-start gap-4 flex-1 min-w-0">
|
|
{isMobile && (
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => setOpen(true)}
|
|
className="shrink-0 rounded-xl hover:bg-muted/60 mt-1"
|
|
>
|
|
<Menu className="w-5 h-5" />
|
|
</Button>
|
|
)}
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-start justify-between gap-2 mb-2">
|
|
<h1
|
|
className="text-2xl md:text-4xl lg:text-5xl font-black tracking-tight leading-tight flex-1 min-w-0"
|
|
style={{
|
|
color: textColor,
|
|
WebkitTextFillColor: textColor,
|
|
}}
|
|
>
|
|
{title}
|
|
</h1>
|
|
{rightContent && <div className="shrink-0">{rightContent}</div>}
|
|
</div>
|
|
{description && (
|
|
<div className="text-base md:text-lg text-muted-foreground/70 font-semibold">
|
|
{description}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
{actions && (
|
|
<div className="flex items-center gap-3 flex-wrap justify-end">
|
|
{actions}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|