feat: SiteLayout template + World menu with 5 new pages (Lore, World, Characters, Music, Gallery)

- SiteLayout.tsx: shared layout component with nav dropdown, mobile hamburger drawer, full footer
- Nav: World dropdown menu (Lore, World, Characters, Music, Gallery) + Follow link
- Footer: 3-column (World links, Social links, Legal links) + tagline
- pages/lore.tsx: lore entry grid with placeholder canon entries
- pages/world.tsx: location/setting cards with worldbuilding teaser
- pages/characters.tsx: character roster with locked/revealed states
- pages/music.tsx: soundtrack page with Patreon CTA (inspired by silmaai.com music page)
- pages/gallery.tsx: tabbed Official / Fan Art gallery with empty states and social tag CTAs
- styles/Layout.module.css: shared nav, dropdown, footer, page hero, coming-soon styles
- styles/World.module.css: lore, location, character, music styles
- styles/Gallery.module.css: tabs, grid, card, empty state styles
- All pages: SEO meta, canonical URLs, OG tags
This commit is contained in:
2026-04-11 10:46:24 -05:00
parent b04d65f062
commit 8afb112eee
14 changed files with 2070 additions and 710 deletions
+182
View File
@@ -0,0 +1,182 @@
import SiteLayout from "@/pages/components/SiteLayout";
const s = {
page: {
maxWidth: "860px",
margin: "0 auto",
padding: "64px 32px 96px",
} as React.CSSProperties,
hero: {
marginBottom: "64px",
textAlign: "center" as const,
} as React.CSSProperties,
eyebrow: {
display: "block",
fontSize: "0.75rem",
fontWeight: 700,
letterSpacing: "0.18em",
textTransform: "uppercase" as const,
color: "#c0392b",
marginBottom: "16px",
} as React.CSSProperties,
h1: {
fontFamily: "'Georgia', 'Times New Roman', serif",
fontSize: "clamp(2.4rem, 6vw, 4rem)",
fontWeight: 700,
color: "#e8dcc8",
lineHeight: 1.1,
marginBottom: "20px",
} as React.CSSProperties,
heroSub: {
fontSize: "1.05rem",
color: "#9e9080",
maxWidth: "560px",
margin: "0 auto",
lineHeight: 1.7,
} as React.CSSProperties,
divider: {
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: "12px",
margin: "48px 0",
fontSize: "1.2rem",
opacity: 0.4,
} as React.CSSProperties,
section: {
marginBottom: "56px",
} as React.CSSProperties,
sectionLabel: {
display: "block",
fontSize: "0.72rem",
fontWeight: 700,
letterSpacing: "0.14em",
textTransform: "uppercase" as const,
color: "#c0392b",
marginBottom: "12px",
} as React.CSSProperties,
h2: {
fontFamily: "'Georgia', 'Times New Roman', serif",
fontSize: "clamp(1.6rem, 3vw, 2.2rem)",
fontWeight: 700,
color: "#e8dcc8",
marginBottom: "20px",
lineHeight: 1.2,
} as React.CSSProperties,
p: {
fontSize: "1rem",
color: "#c8bfae",
lineHeight: 1.8,
marginBottom: "16px",
maxWidth: "680px",
} as React.CSSProperties,
comingSoon: {
background: "#1a1510",
border: "1px solid rgba(232,220,200,0.1)",
borderRadius: "8px",
padding: "40px 32px",
textAlign: "center" as const,
marginTop: "16px",
} as React.CSSProperties,
comingSoonIcon: {
fontSize: "2rem",
marginBottom: "12px",
display: "block",
opacity: 0.4,
} as React.CSSProperties,
comingSoonText: {
fontSize: "0.88rem",
color: "#9e9080",
letterSpacing: "0.08em",
textTransform: "uppercase" as const,
fontWeight: 600,
} as React.CSSProperties,
};
export default function Lore() {
return (
<SiteLayout
title="Lore"
description="The mythology and history of the Bone Kingdom — the world of Bone Lord Bob."
keywords="Bone Lord Bob, lore, mythology, bone kingdom, dark fantasy, American Anime, worldbuilding"
>
<div style={s.page}>
{/* Hero */}
<div style={s.hero}>
<span style={s.eyebrow}>The Mythology</span>
<h1 style={s.h1}>The Lore</h1>
<p style={s.heroSub}>
Death is not the end in this world. It is the beginning of debt.
</p>
</div>
{/* Section: Bone Kingdom */}
<div style={s.section}>
<span style={s.sectionLabel}>Foundation</span>
<h2 style={s.h2}>The Bone Kingdom</h2>
<p style={s.p}>
A land where death is currency and the living are guests. The Bone
Kingdom does not welcome the breathing it merely tolerates them,
for now, until their ledger comes due. Every step taken on its soil
is a transaction. Every breath drawn is borrowed.
</p>
<p style={s.p}>
Its borders are not marked by walls or rivers, but by a feeling: the
moment the air turns cold and the light goes gray, you have arrived.
The dead know. The living learn too late.
</p>
</div>
<div style={s.divider}>
<span>💀</span><span>💀</span><span>💀</span>
</div>
{/* Section: The Ledger */}
<div style={s.section}>
<span style={s.sectionLabel}>The Accounting</span>
<h2 style={s.h2}>The Ledger</h2>
<p style={s.p}>
Every soul has a price. The Bone Lord keeps the account. From the
moment of first breath, your name is inscribed not in ink, but in
marrow. The record does not forget. It does not forgive. It only
waits.
</p>
<p style={s.p}>
Heroes have tried to destroy the Ledger. Warlords have tried to
steal it. Gods have tried to rewrite it. None have succeeded. The
book endures because it is not made of paper. It is made of
consequence.
</p>
</div>
<div style={s.divider}>
<span>💀</span><span>💀</span><span>💀</span>
</div>
{/* Section: Origins — coming soon */}
<div style={s.section}>
<span style={s.sectionLabel}>History</span>
<h2 style={s.h2}>Origins</h2>
<div style={s.comingSoon}>
<span style={s.comingSoonIcon}>💀</span>
<p style={s.comingSoonText}>Coming Soon</p>
</div>
</div>
<div style={s.divider}>
<span>💀</span><span>💀</span><span>💀</span>
</div>
{/* Section: Prophecy — coming soon */}
<div style={s.section}>
<span style={s.sectionLabel}>The Foretelling</span>
<h2 style={s.h2}>Prophecy</h2>
<div style={s.comingSoon}>
<span style={s.comingSoonIcon}>💀</span>
<p style={s.comingSoonText}>Coming Soon</p>
</div>
</div>
</div>
</SiteLayout>
);
}
+146
View File
@@ -0,0 +1,146 @@
import SiteLayout from "@/pages/components/SiteLayout";
const s = {
page: {
maxWidth: "1000px",
margin: "0 auto",
padding: "64px 32px 96px",
} as React.CSSProperties,
hero: {
marginBottom: "64px",
textAlign: "center" as const,
} as React.CSSProperties,
eyebrow: {
display: "block",
fontSize: "0.75rem",
fontWeight: 700,
letterSpacing: "0.18em",
textTransform: "uppercase" as const,
color: "#c0392b",
marginBottom: "16px",
} as React.CSSProperties,
h1: {
fontFamily: "'Georgia', 'Times New Roman', serif",
fontSize: "clamp(2.4rem, 6vw, 4rem)",
fontWeight: 700,
color: "#e8dcc8",
lineHeight: 1.1,
marginBottom: "20px",
} as React.CSSProperties,
heroSub: {
fontSize: "1.05rem",
color: "#9e9080",
maxWidth: "520px",
margin: "0 auto",
lineHeight: 1.7,
} as React.CSSProperties,
sectionLabel: {
display: "block",
fontSize: "0.72rem",
fontWeight: 700,
letterSpacing: "0.14em",
textTransform: "uppercase" as const,
color: "#c0392b",
marginBottom: "12px",
textAlign: "center" as const,
} as React.CSSProperties,
grid: {
display: "grid",
gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))",
gap: "20px",
marginTop: "32px",
marginBottom: "48px",
} as React.CSSProperties,
card: {
background: "#1a1510",
border: "1px solid rgba(232,220,200,0.12)",
borderRadius: "8px",
padding: "32px 28px",
transition: "border-color 0.2s",
} as React.CSSProperties,
cardIcon: {
fontSize: "2rem",
marginBottom: "16px",
display: "block",
} as React.CSSProperties,
cardName: {
fontFamily: "'Georgia', 'Times New Roman', serif",
fontSize: "1.25rem",
fontWeight: 700,
color: "#e8dcc8",
marginBottom: "12px",
} as React.CSSProperties,
cardDesc: {
fontSize: "0.92rem",
color: "#9e9080",
lineHeight: 1.65,
} as React.CSSProperties,
more: {
textAlign: "center" as const,
padding: "32px",
background: "#120f0a",
border: "1px solid rgba(232,220,200,0.08)",
borderRadius: "8px",
fontSize: "0.9rem",
color: "#9e9080",
fontStyle: "italic",
letterSpacing: "0.04em",
} as React.CSSProperties,
};
const REGIONS = [
{
icon: "🏴",
name: "The Bone Kingdom",
desc: "Where the dead outnumber the living. The seat of the Bone Lord's power — a realm that does not distinguish between conqueror and conquered. All serve, eventually.",
},
{
icon: "🌑",
name: "The Bonefield",
desc: "An endless plain of ash and silence. Nothing grows. Nothing dies. Those who wander into the Bonefield are neither living nor dead — just lost.",
},
{
icon: "🔥",
name: "The Pyre Gates",
desc: "The boundary between worlds. Cross it once. You won't cross back. The Gates do not open for the living — but they have been known to open for the desperate.",
},
];
export default function WorldPage() {
return (
<SiteLayout
title="The World"
description="Explore the world of Bone Lord Bob — the Bone Kingdom, the Bonefield, the Pyre Gates, and beyond."
keywords="Bone Lord Bob, world, bone kingdom, bonefield, pyre gates, dark fantasy, geography, factions, American Anime"
>
<div style={s.page}>
{/* Hero */}
<div style={s.hero}>
<span style={s.eyebrow}>Geography &amp; Factions</span>
<h1 style={s.h1}>The World</h1>
<p style={s.heroSub}>
Every territory has a cost. Every border is written in bone. Know
where you are before it&apos;s too late.
</p>
</div>
{/* Region cards */}
<span style={s.sectionLabel}>Regions</span>
<div style={s.grid}>
{REGIONS.map((r) => (
<div key={r.name} style={s.card}>
<span style={s.cardIcon}>{r.icon}</span>
<div style={s.cardName}>{r.name}</div>
<p style={s.cardDesc}>{r.desc}</p>
</div>
))}
</div>
{/* Placeholder */}
<div style={s.more}>
More regions revealed as the story unfolds...
</div>
</div>
</SiteLayout>
);
}