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:
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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 & 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'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user