|
|
@@ -0,0 +1,110 @@
|
|
|
+"use client";
|
|
|
+import React, {ReactNode, useState} from "react";
|
|
|
+
|
|
|
+interface HeaderProps {
|
|
|
+ children?: ReactNode;
|
|
|
+ renderFn?: () => ReactNode;
|
|
|
+ height?: number;
|
|
|
+ className?: string;
|
|
|
+ siteName?: string;
|
|
|
+ logo?: string;
|
|
|
+ menu?: any;
|
|
|
+}
|
|
|
+
|
|
|
+export const Header: React.FC<HeaderProps> = ({
|
|
|
+ height,
|
|
|
+ className = "",
|
|
|
+ siteName,
|
|
|
+ logo,
|
|
|
+ menu,
|
|
|
+ }) => {
|
|
|
+ const [open, setOpen] = useState(false);
|
|
|
+
|
|
|
+ return (
|
|
|
+ <header
|
|
|
+ className={`px-6 bg-gray-800 text-white ${className}`}
|
|
|
+ style={{height: height ? `${height}vh` : undefined}}
|
|
|
+ >
|
|
|
+ <div className="w-full max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-between">
|
|
|
+ <a href="#" className="flex items-center">
|
|
|
+ {logo && <img src={logo} alt="logo" className="w-5 h-5 mr-1"/>}
|
|
|
+ <strong className="ml-2">{siteName}</strong>
|
|
|
+ </a>
|
|
|
+
|
|
|
+ {/* Wrap button + menu in relative container */}
|
|
|
+ <div className="relative">
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ onClick={() => setOpen((v) => !v)}
|
|
|
+ className="inline-flex items-center justify-center p-2 rounded text-gray-200 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white"
|
|
|
+ aria-label="Toggle navigation"
|
|
|
+ aria-expanded={open}
|
|
|
+ >
|
|
|
+ {open ? (
|
|
|
+ <svg
|
|
|
+ xmlns="http://www.w3.org/2000/svg"
|
|
|
+ fill="none"
|
|
|
+ viewBox="0 0 24 24"
|
|
|
+ strokeWidth={1.5}
|
|
|
+ stroke="currentColor"
|
|
|
+ className="h-6 w-6"
|
|
|
+ >
|
|
|
+ <path strokeLinecap="round" strokeLinejoin="round" d="M6 18 18 6M6 6l12 12"/>
|
|
|
+ </svg>
|
|
|
+ ) : (
|
|
|
+ <svg
|
|
|
+ xmlns="http://www.w3.org/2000/svg"
|
|
|
+ fill="none"
|
|
|
+ viewBox="0 0 24 24"
|
|
|
+ strokeWidth={1.5}
|
|
|
+ stroke="currentColor"
|
|
|
+ className="h-6 w-6"
|
|
|
+ >
|
|
|
+ <path
|
|
|
+ strokeLinecap="round"
|
|
|
+ strokeLinejoin="round"
|
|
|
+ d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
|
|
+ />
|
|
|
+ </svg>
|
|
|
+ )}
|
|
|
+ </button>
|
|
|
+
|
|
|
+ {/* Small popup menu under button */}
|
|
|
+ {open && (
|
|
|
+ <nav
|
|
|
+ className="
|
|
|
+ absolute right-0 mt-2
|
|
|
+ w-40
|
|
|
+ rounded-md
|
|
|
+ bg-gray-800
|
|
|
+ shadow-lg
|
|
|
+ ring-1 ring-black/10
|
|
|
+ z-20
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <ul className="py-2 text-sm">
|
|
|
+ {menu.length > 0 && (
|
|
|
+ <nav>
|
|
|
+ <ul className="flex flex-col space-x-0 list-none m-0 p-0">
|
|
|
+ {menu.map((item: string, index: string) => (
|
|
|
+ <li key={index}>
|
|
|
+ <a
|
|
|
+ href={item.href}
|
|
|
+ className="block px-4 py-2 hover:bg-gray-700 transition-colors"
|
|
|
+ >
|
|
|
+ {item.name}
|
|
|
+ </a>
|
|
|
+ </li>
|
|
|
+ ))}
|
|
|
+ </ul>
|
|
|
+ </nav>
|
|
|
+ )}
|
|
|
+ </ul>
|
|
|
+ </nav>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </header>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|