Files

179 lines
7.5 KiB
TypeScript

import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import { useState } from "react";
import styles from "@/styles/Layout.module.css";
export interface SiteLayoutProps {
title?: string;
description?: string;
keywords?: string;
canonical?: string;
children: React.ReactNode;
}
const WORLD_LINKS = [
{ href: "/world/lore", label: "Lore" },
{ href: "/world/world", label: "World" },
{ href: "/world/characters", label: "Characters" },
{ href: "/world/music", label: "Music" },
{ href: "/world/gallery", label: "Gallery" },
];
export default function SiteLayout({
title = "Bone Lord Bob — American Anime",
description = "Bone Lord Bob is an original American Anime series — dark, brutal, beautiful.",
keywords = "Bone Lord Bob, American Anime, indie animation, dark fantasy",
canonical,
children,
}: SiteLayoutProps) {
const router = useRouter();
const [worldOpen, setWorldOpen] = useState(false);
const [mobileOpen, setMobileOpen] = useState(false);
const canonicalUrl = canonical
? `https://www.bonelordbob.com${canonical}`
: `https://www.bonelordbob.com${router.asPath.split("?")[0]}`;
const isActive = (href: string) =>
href === "/" ? router.pathname === "/" : router.pathname.startsWith(href);
const isWorldActive = WORLD_LINKS.some((l) => router.pathname.startsWith(l.href));
return (
<>
<Head>
<title>{title === "Bone Lord Bob — American Anime" ? title : `${title} | Bone Lord Bob`}</title>
<meta name="description" content={description} />
<meta name="keywords" content={keywords} />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="canonical" href={canonicalUrl} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:image" content="https://www.bonelordbob.com/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
</Head>
<div className={styles.site}>
{/* ── Nav ── */}
<nav className={styles.nav}>
<Link href="/" className={styles.navLogo}>
Bone Lord <span>Bob</span>
</Link>
{/* Desktop nav */}
<ul className={styles.navLinks}>
<li className={styles.navItem}>
<Link
href="/"
className={`${styles.navLink} ${isActive("/") ? styles.navLinkActive : ""}`}
>
Home
</Link>
</li>
{/* World dropdown */}
<li
className={styles.navItem}
onMouseEnter={() => setWorldOpen(true)}
onMouseLeave={() => setWorldOpen(false)}
>
<button
className={`${styles.navLink} ${styles.navDropdownTrigger} ${isWorldActive ? styles.navLinkActive : ""}`}
aria-haspopup="true"
aria-expanded={worldOpen}
>
World <span className={styles.chevron}></span>
</button>
{worldOpen && (
<div className={styles.dropdown}>
{WORLD_LINKS.map((l) => (
<Link
key={l.href}
href={l.href}
className={`${styles.dropdownItem} ${router.pathname === l.href ? styles.dropdownItemActive : ""}`}
onClick={() => setWorldOpen(false)}
>
{l.label}
</Link>
))}
</div>
)}
</li>
<li className={styles.navItem}>
<Link href="/#follow" className={styles.navLink}>
Follow
</Link>
</li>
</ul>
{/* Mobile hamburger */}
<button
className={styles.hamburger}
onClick={() => setMobileOpen(!mobileOpen)}
aria-label="Toggle menu"
>
<span /><span /><span />
</button>
</nav>
{/* Mobile drawer */}
{mobileOpen && (
<div className={styles.mobileDrawer}>
<Link href="/" className={styles.mobileLink} onClick={() => setMobileOpen(false)}>Home</Link>
<div className={styles.mobileSectionLabel}>World</div>
{WORLD_LINKS.map((l) => (
<Link key={l.href} href={l.href} className={styles.mobileLinkIndent} onClick={() => setMobileOpen(false)}>
{l.label}
</Link>
))}
<Link href="/#follow" className={styles.mobileLink} onClick={() => setMobileOpen(false)}>Follow</Link>
</div>
)}
{/* ── Page content ── */}
<main className={styles.main}>{children}</main>
{/* ── Footer ── */}
<footer className={styles.footer}>
<div className={styles.footerTop}>
<div className={styles.footerBrand}>
<span className={styles.footerLogo}>Bone Lord <span>Bob</span></span>
<p className={styles.footerTagline}>American Anime. Dark. Brutal. Beautiful.</p>
</div>
<div className={styles.footerColumns}>
<div className={styles.footerCol}>
<span className={styles.footerColTitle}>World</span>
{WORLD_LINKS.map((l) => (
<Link key={l.href} href={l.href} className={styles.footerLink}>{l.label}</Link>
))}
</div>
<div className={styles.footerCol}>
<span className={styles.footerColTitle}>Follow</span>
<a href="https://www.youtube.com/@bonelordbob" target="_blank" rel="noopener noreferrer" className={styles.footerLink}>YouTube</a>
<a href="https://x.com/bonelordbob" target="_blank" rel="noopener noreferrer" className={styles.footerLink}>X / Twitter</a>
<a href="https://www.instagram.com/bonelordbob" target="_blank" rel="noopener noreferrer" className={styles.footerLink}>Instagram</a>
<a href="https://www.facebook.com/profile.php?id=61580718487639" target="_blank" rel="noopener noreferrer" className={styles.footerLink}>Facebook</a>
<a href="https://www.tiktok.com/@bonelordbob" target="_blank" rel="noopener noreferrer" className={styles.footerLink}>TikTok</a>
<a href="https://www.patreon.com/BoneLordBob" target="_blank" rel="noopener noreferrer" className={styles.footerLink}>Patreon</a>
</div>
<div className={styles.footerCol}>
<span className={styles.footerColTitle}>Legal</span>
<Link href="/privacy" className={styles.footerLink}>Privacy Policy</Link>
<Link href="/terms" className={styles.footerLink}>Terms &amp; Conditions</Link>
</div>
</div>
</div>
<div className={styles.footerBottom}>
<span>© {new Date().getFullYear()} Mathison Projects Inc. All rights reserved. &nbsp;·&nbsp; Powered by <a href="https://www.silmaai.com" target="_blank" rel="noopener noreferrer" style={{ color: "#e8dcc8", textDecoration: "underline", opacity: 0.7 }}>Silma AI</a></span>
</div>
</footer>
</div>
</>
);
}