This comprehensive guide provides all the information needed for AI assistants to work effectively with the Dandelion Dynasty Wiki codebase.
- Project Overview
- Tech Stack & Versions
- Directory Structure
- Color System
- Icon & Favicon Configuration
- Creating New Pages
- Component Usage
- Data Management
- Styling Guidelines
- Development Workflow
The Dandelion Dynasty Wiki is a fan-created encyclopedia for Ken Liu's epic silkpunk fantasy series. It's built as a comprehensive, searchable resource covering books, characters, places, gods, concepts, and maps from the series.
- 📚 Content Coverage: 4 books, 100+ characters, places, gods, concepts
- 🔍 Live Search: Real-time search across all wiki pages
- 🌙 Dark/Light Mode: Seamless theme switching
- 📱 Fully Responsive: Optimized for all devices
- 🎨 Centralized Colors: Easy theme customization
- ⚡ Fast Performance: Next.js 15 with optimizations
{
"next": "15.5.7",
"react": "19.1.2",
"typescript": "5",
"tailwindcss": "3.4.17"
}{
"next-themes": "latest",
"lucide-react": "latest",
"@vercel/analytics": "latest",
"@vercel/speed-insights": "latest"
}- Package Manager: npm
- Styling: Tailwind CSS with custom color system
- Icons: Lucide React + custom SVGs
- Deployment: Vercel
- TypeScript: Strict mode enabled
- Domain: dandelion-dynasty.com (primary), dandelion-wiki.vercel.app (legacy)
dandelion-wiki/
├── app/ # Next.js App Router
│ ├── globals.css # 🎨 CENTRALIZED COLORS HERE
│ ├── layout.tsx # Root layout with providers
│ ├── page.tsx # Homepage (6 main category links)
│ ├── not-found.tsx # 404 page
│ │
│ ├── books/ # Book category
│ │ ├── page.tsx # Books listing page
│ │ ├── the-grace-of-kings/
│ │ ├── the-wall-of-storms/
│ │ ├── the-veiled-throne/
│ │ └── speaking-bones/
│ │
│ ├── characters/ # Characters category
│ │ ├── page.tsx # Characters listing page
│ │ ├── mata-zyndu/
│ │ ├── kuni-garu/
│ │ └── [other-characters]/
│ │
│ ├── places/ # Places category
│ │ ├── page.tsx # Places listing page
│ │ └── [place-names]/
│ │
│ ├── gods/ # Gods category
│ │ ├── page.tsx # Gods listing page
│ │ └── [god-names]/
│ │
│ ├── concepts/ # Concepts category
│ │ ├── page.tsx # Concepts listing page
│ │ └── [concept-names]/
│ │
│ ├── maps/ # Maps category
│ │ └── page.tsx # Maps page
│ │
│ ├── other/ # Other pages
│ │ ├── all-pages/
│ │ ├── about-wiki/
│ │ ├── about-author/
│ │ └── contributing/
│ │
│ ├── components/ # Reusable components
│ │ ├── features/ # Feature components
│ │ │ ├── SearchBar.tsx
│ │ │ ├── FeedbackModal.tsx
│ │ │ └── ThemeToggleButton.tsx
│ │ ├── layout/ # Layout components
│ │ │ ├── Navbar.tsx
│ │ │ ├── Footer.tsx
│ │ │ └── ThemeProviders.tsx
│ │ └── ui/ # UI components
│ │ ├── Icons.tsx
│ │ ├── InfoBox.tsx
│ │ ├── ContentRenderer.tsx
│ │ ├── BackToHomeButton.tsx
│ │ └── ScrollToTopButton.tsx
│ │
│ ├── data/ # Data management
│ │ └── wiki-data.ts # 📊 ALL CONTENT DATA
│ │
│ └── utils/ # Utility functions
│ ├── hooks.ts
│ └── dataUtils.ts
│
├── public/ # Static assets
│ ├── icon.png
│ └── [images]/
│
├── tailwind.config.js # 🎨 Custom color classes
├── next.config.ts # Next.js configuration
├── package.json # Dependencies
└── tsconfig.json # TypeScript config
Primary File: app/globals.css (lines ~10-70)
All colors are centralized using CSS variables. NEVER use hardcoded Tailwind color classes like text-teal-600 in new components.
:root {
/* Brand Colors */
--color-primary: #0d9488; /* teal-600 - main brand */
--color-primary-light: #14b8a6; /* teal-500 - lighter variant */
--color-primary-dark: #0f766e; /* teal-700 - darker variant */
--color-accent-pink: #F5BABB; /* accent color */
/* Text Colors */
--color-text-primary: #111827; /* main text */
--color-text-secondary: #374151; /* secondary text */
--color-text-muted: #4b5563; /* muted text */
--color-text-light: #6b7280; /* light text */
/* Background Colors */
--color-bg-primary: #ffffff; /* main background */
--color-bg-secondary: #f9fafb; /* secondary background */
--color-bg-tertiary: #f3f4f6; /* tertiary background */
--color-bg-card: #ffffff; /* card backgrounds */
/* Interactive Colors */
--color-link: #0d9488; /* links */
--color-link-hover: #14b8a6; /* link hovers */
--color-link-dark: #2dd4bf; /* dark mode links */
}Use these classes instead of hardcoded colors:
/* Text */
text-text-primary, text-text-secondary, text-text-muted, text-text-light
text-link, text-link-dark
/* Backgrounds */
bg-bg-primary, bg-bg-secondary, bg-bg-tertiary, bg-bg-card
bg-primary, bg-primary-light, bg-primary-dark
/* Borders */
border-border-primary, border-border-secondary
/* Hover States */
hover:text-link, hover:bg-primary, hover:border-primary-lightFile: app/globals.css (lines ~10-36)
Purple Theme:
--color-primary: #7c3aed; /* purple-600 */
--color-primary-light: #8b5cf6; /* purple-500 */
--color-primary-dark: #6d28d9; /* purple-700 */Ocean Blue Theme:
--color-primary: #0ea5e9; /* sky-500 */
--color-primary-light: #38bdf8; /* sky-400 */
--color-primary-dark: #0284c7; /* sky-600 */Forest Green Theme:
--color-primary: #059669; /* emerald-600 */
--color-primary-light: #10b981; /* emerald-500 */
--color-primary-dark: #047857; /* emerald-700 */What Updates Automatically:
- ✅ All navigation links and buttons
- ✅ All hover effects and focus states
- ✅ All icon backgrounds and accents
- ✅ Dark mode colors automatically
- ✅ 100+ components across entire site
text-teal-600,bg-blue-500, etc. (hardcoded colors)- Inline styles with colors
- Color values directly in components
text-primary,bg-bg-card, etc. (centralized classes)- CSS variables for custom components
- Consistent color patterns
The wiki uses a centralized icon configuration that ensures the site icon appears correctly across:
- Browser tabs
- Bookmarks
- Google search results
- Social media shares
- Mobile home screens (PWA)
Primary Icon:
- File:
/public/icon.png - Recommended Size: 512x512 pixels (minimum)
- Format: PNG (transparent background preferred)
- Aspect Ratio: 1:1 (square)
- File Size: Under 500KB
Configuration Files:
app/layout.tsx- Icon metadata in root layoutapp/manifest.ts- PWA manifest for mobile/app support
Location: app/layout.tsx (lines 42-62)
icons: {
icon: [
{ url: '/icon.png', type: 'image/png' },
],
shortcut: '/icon.png',
apple: '/icon.png',
other: [
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
url: '/icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
url: '/icon.png',
},
],
},What This Does:
- ✅ Sets icon for browser tabs
- ✅ Configures Apple Touch Icon for iOS
- ✅ Provides multiple sizes for different contexts
- ✅ Enables icon in Google search results (after indexing)
Location: app/manifest.ts
export default function manifest(): MetadataRoute.Manifest {
return {
name: 'The Dandelion Dynasty Wiki',
short_name: 'Dandelion Wiki',
description: 'The ultimate encyclopedia for Ken Liu\'s epic silkpunk fantasy series, The Dandelion Dynasty.',
start_url: '/',
display: 'standalone',
background_color: '#ffffff',
theme_color: '#0d9488', // Brand teal color
icons: [
{
src: '/icon.png',
sizes: 'any',
type: 'image/png',
},
],
}
}What This Provides:
- ✅ PWA (Progressive Web App) support
- ✅ Mobile "Add to Home Screen" functionality
- ✅ Brand colors for browser UI (theme_color)
- ✅ Proper app metadata for search engines
Icons are also included in OpenGraph metadata for social media shares:
Location: app/layout.tsx (lines 66-73)
openGraph: {
title: 'The Dandelion Dynasty Wiki',
// ... other metadata
images: [{ url: '/icon.png', width: 512, height: 512, alt: 'The Dandelion Dynasty Wiki' }],
},For the icon to appear in Google search results:
✅ Icon metadata properly configured ✅ Web manifest created ✅ OpenGraph images included
- Optimize icon file - Ensure
/public/icon.pngis 512x512px - Deploy changes - Push to production
- Submit to Google Search Console:
- Verify domain:
dandelion-dynasty.com - Submit sitemap:
https://dandelion-dynasty.com/sitemap.xml - Request re-indexing
- Verify domain:
- Wait for Google - 1-2 weeks for search results to update
# Test locally
npm run dev
# Check browser tab for icon
# Open DevTools > Application > Manifest
# Test build
npm run build
npm startWhile the current setup uses a single icon file, you can create multiple sizes for optimal display:
Recommended Sizes:
icon-16.png(16x16) - Browser tabicon-32.png(32x32) - Browser tab (retina)icon-192.png(192x192) - Android home screenicon-512.png(512x512) - High-res displaysapple-icon.png(180x180) - iOS home screenfavicon.ico(32x32) - Legacy support
Using Online Tools:
- RealFaviconGenerator.net - Best option
- Favicon.io
- Cloudinary
Using Command Line (ImageMagick):
convert icon.png -resize 16x16 icon-16.png
convert icon.png -resize 32x32 icon-32.png
convert icon.png -resize 192x192 icon-192.png
convert icon.png -resize 512x512 icon-512.png
convert icon.png -resize 180x180 apple-icon.png
convert icon.png -resize 32x32 favicon.icoIcon doesn't appear in browser tab:
- Clear browser cache
- Check
/public/icon.pngexists - Verify file is valid PNG
- Rebuild project:
npm run build
Icon doesn't appear in Google:
- Ensure deployed to production
- Check Google Search Console for indexing
- Wait 1-2 weeks for re-crawl
- Verify sitemap includes homepage
Icon appears pixelated:
- Increase icon resolution (512x512 minimum)
- Use PNG format with transparency
- Avoid JPG for icons
✅ Do:
- Use square aspect ratio (1:1)
- Minimum 512x512 pixels
- PNG format with transparency
- Simple, recognizable design
- Test on multiple devices
❌ Don't:
- Use rectangular images
- Use images smaller than 192x192
- Use complex designs (hard to see at small sizes)
- Forget to optimize file size
- Skip the web manifest
ALL new pages MUST follow the server/client component pattern for proper SEO and page titles.
File Location: app/[category]/[page-name]/page.tsx
Required Pattern: Server Component + Client Component
import type { Metadata } from 'next';
import { Character } from '../../data/wiki-data'; // or Concept, Place, God
import { generateCharacterMetadata } from '@/app/utils/metadata'; // or generateConceptMetadata, etc.
import CharacterNameClient from './CharacterNameClient'; // Note: No .tsx extension
// --- DATA FOR CHARACTER NAME ---
const characterData: Character = {
name: "Character Name",
image: "/characters/character-name.png",
introduction: "Brief introduction about the character...",
infoBox: {
aliases: "Alias Name",
occupation: "Occupation",
placeOfBirth: "Birth Place",
status: "Alive/Dead",
gender: "Male/Female",
// ... other info
},
appearanceAndPersonality: [
{ type: 'text', content: "Description of appearance and personality..." },
{ type: 'ref', data: { book: "Book Name", chapter: 1, link: "/books/book-name#chapter-1" } },
],
history: [
{
era: "Book Name",
summary: [
{ type: 'text', content: "Historical events..." },
{ type: 'ref', data: { book: "Book Name", chapter: 5, link: "/books/book-name#chapter-5" } },
]
},
]
};
export const metadata: Metadata = generateCharacterMetadata(characterData);
export default function CharacterNamePage() {
return <CharacterNameClient characterData={characterData} />;
}'use client';
import { usePathname } from 'next/navigation';
import PageTemplate, { convertCharacterData } from '../../components/layout/PageTemplate';
import { Character, ALL_CHARACTERS } from '../../data/wiki-data';
import { CharacterNavigation } from '@/app/components/layout/PageNavigation';
import { getSurroundingPages } from '@/app/utils/navigationUtils';
interface CharacterNameClientProps {
characterData: Character;
}
export default function CharacterNameClient({ characterData }: CharacterNameClientProps) {
const pathname = usePathname();
const { prevPage, nextPage } = getSurroundingPages(pathname, [...ALL_CHARACTERS]);
const returnLink = { title: 'Return to All Characters', path: '/characters' };
return (
<>
<CharacterNavigation
prevPage={prevPage}
nextPage={nextPage}
returnLink={returnLink}
/>
<PageTemplate pageData={convertCharacterData(characterData)} infoBoxTitle="Biographical Information" />
</>
);
}Current State: Individual pages (characters, gods, places, concepts) use PageTemplate component which displays both images (when available) and the InfoBox in the sidebar.
Image Display is Optional: The PageTemplate component automatically displays images when they are provided in the data, but gracefully handles pages without images.
Mobile-First Layout: The PageTemplate uses a mobile-first approach where:
- Page title and introduction appear at the top
- Image and InfoBox appear next (on mobile) or in sidebar (on desktop)
- Content sections follow below
To Add Images to Individual Pages:
File: app/components/layout/PageTemplate.tsx
Add image display in the sidebar before the InfoBox:
import React from 'react';
import Image from 'next/image'; // Add this import
import { formatLinksInText } from '../../utils/textFormatting';
import InfoBox, { InfoBoxData } from '../ui/InfoBox';
import ContentRenderer from '../ui/ContentRenderer';
import { ContentBlock } from '../../data/wiki-data';
// ... existing code ...
export default function PageTemplate({
pageData,
infoBoxTitle,
className = ""
}: PageTemplateProps) {
// ... existing renderSection function ...
return (
<div className={className}>
<div className="flex flex-col lg:flex-row gap-8">
{/* Main Content Area */}
<div className="w-full lg:w-2/3 order-2 lg:order-1">
<h1 className="text-4xl md:text-5xl font-bold text-text-primary dark:text-text-primary mb-4">
{pageData.name}
</h1>
<p className="text-lg italic text-text-muted dark:text-text-light mb-8 border-l-4 border-gray-300 dark:border-border-secondary pl-4">
{formatLinksInText(pageData.introduction)}
</p>
<div className="space-y-8">
{pageData.sections.map(renderSection)}
</div>
</div>
{/* Sidebar with Image and InfoBox */}
<div className="w-full lg:w-1/3 order-1 lg:order-2">
<div className="sticky top-24 space-y-6">
{/* Add Image Display */}
{pageData.image && (
<div className="relative w-full h-80 rounded-lg overflow-hidden shadow-lg">
<Image
src={pageData.image}
alt={`Image of ${pageData.name}`}
fill
style={{ objectFit: "cover", objectPosition: "top" }}
/>
</div>
)}
<InfoBox
title={infoBoxTitle}
data={pageData.infoBox}
/>
</div>
</div>
</div>
</div>
);
}For pages that need different image layouts, create a custom component:
'use client';
import Image from 'next/image';
import { usePathname } from 'next/navigation';
import { Character, ALL_CHARACTERS } from '../../data/wiki-data';
import { CharacterNavigation } from '@/app/components/layout/PageNavigation';
import { getSurroundingPages } from '@/app/utils/navigationUtils';
import InfoBox from '@/app/components/ui/InfoBox';
interface CustomCharacterClientProps {
characterData: Character;
}
export default function CustomCharacterClient({ characterData }: CustomCharacterClientProps) {
const pathname = usePathname();
const { prevPage, nextPage } = getSurroundingPages(pathname, [...ALL_CHARACTERS]);
const returnLink = { title: 'Return to All Characters', path: '/characters' };
return (
<>
<CharacterNavigation
prevPage={prevPage}
nextPage={nextPage}
returnLink={returnLink}
/>
<div className="max-w-6xl mx-auto px-4 py-8">
<div className="flex flex-col lg:flex-row gap-8">
{/* Main Content */}
<div className="w-full lg:w-2/3">
<h1 className="text-4xl md:text-5xl font-bold text-text-primary dark:text-text-primary mb-4">
{characterData.name}
</h1>
{/* Add your content sections here */}
</div>
{/* Sidebar with Image */}
<div className="w-full lg:w-1/3">
<div className="sticky top-24 space-y-6">
{/* Character Image */}
<div className="relative w-full h-80 rounded-lg overflow-hidden shadow-lg">
<Image
src={characterData.image}
alt={`Portrait of ${characterData.name}`}
fill
style={{ objectFit: "cover", objectPosition: "top" }}
/>
</div>
{/* Info Box */}
<InfoBox
title="Biographical Information"
data={characterData.infoBox}
/>
</div>
</div>
</div>
</div>
</>
);
}Image Requirements:
- File Format: PNG preferred, JPG acceptable
- Location:
public/[category]/[slug].png - Dimensions: Minimum 400x400px, recommended 800x800px
- Aspect Ratio: Square (1:1) works best for consistent display
- File Size: Optimize for web (under 500KB recommended)
Data Structure Requirements:
Ensure your data includes the image property:
const characterData: Character = {
name: "Character Name",
image: "/characters/character-name.png", // Add this
// ... rest of data
};- Server Component:
page.tsxwithgenerateCharacterMetadata(characterData) - Client Component:
[Name]Client.tsxwithCharacterNavigation - Data Type:
Characterfromwiki-data.ts - Navigation:
ALL_CHARACTERSarray
- Server Component:
page.tsxwithgenerateConceptMetadata(conceptData) - Client Component:
[Name]Client.tsxwithConceptNavigation - Data Type:
Conceptfromwiki-data.ts - Navigation:
ALL_CONCEPTSarray
- Server Component:
page.tsxwithgeneratePlaceMetadata(placeData) - Client Component:
[Name]Client.tsxwithPlaceNavigation - Data Type:
Placefromwiki-data.ts - Navigation:
ALL_PLACESarray
- Server Component:
page.tsxwithgenerateGodMetadata(godData) - Client Component:
[Name]Client.tsxwithGodNavigation - Data Type:
Godfromwiki-data.ts - Navigation:
ALL_GODSarray
For pages that don't follow the standard pattern:
import type { Metadata } from 'next';
import SpecialPageClient from './SpecialPageClient';
export const metadata: Metadata = {
title: 'Page Title',
description: 'Page description for SEO...',
openGraph: {
title: 'Page Title | The Dandelion Dynasty Wiki',
description: 'Page description for social media...',
type: 'website'
},
twitter: {
card: 'summary',
title: 'Page Title | The Dandelion Dynasty Wiki',
description: 'Page description for Twitter...'
}
};
export default function SpecialPage() {
return <SpecialPageClient />;
}ALL pages must follow this exact format:
- Home: "The Dandelion Dynasty Wiki"
- Characters: "Character Name | The Dandelion Dynasty Wiki"
- Concepts: "Concept Name | The Dandelion Dynasty Wiki"
- Places: "Place Name | The Dandelion Dynasty Wiki"
- Gods: "God Name | The Dandelion Dynasty Wiki"
- Books: "Book Name | The Dandelion Dynasty Wiki"
- Characters:
KuniGaruClient.tsx,MataZynduClient.tsx - Concepts:
GarinafinClient.tsx,TheDandelionClient.tsx - Places:
PanClient.tsx,XanaClient.tsx - Gods:
KijiClient.tsx,FithoweoClient.tsx
Rules:
- Remove spaces and special characters
- Use PascalCase
- Add "Client" suffix
- Match the data name exactly
- Characters:
KuniGaruPage(),MataZynduPage() - Concepts:
GarinafinPage(),TheDandelionPage() - Places:
PanPage(),XanaPage() - Gods:
KijiPage(),FithoweoPage()
CRITICAL: When importing client components, do NOT include the .tsx extension:
// ✅ Correct
import CharacterNameClient from './CharacterNameClient';
import PlaceNameClient from './PlaceNameClient';
// ❌ Incorrect
import CharacterNameClient from './CharacterNameClient.tsx';
import PlaceNameClient from './PlaceNameClient.tsx';Images are Optional: The PageTemplate component automatically handles pages with or without images:
// ✅ With image
const placeData: Place = {
name: "Place Name",
image: "/places/place-name.jpeg", // Image will be displayed
introduction: "Description...",
// ... rest of data
};
// ✅ Without image (empty string or undefined)
const placeData: Place = {
name: "Place Name",
image: "", // No image will be displayed
introduction: "Description...",
// ... rest of data
};Image Requirements (when using images):
- File Format: PNG, JPG, or JPEG
- Location:
public/[category]/[slug].{png|jpg|jpeg} - Dimensions: Minimum 400x400px, recommended 800x800px
- Aspect Ratio: Square (1:1) works best for consistent display
- File Size: Optimize for web (under 500KB recommended)
Before creating any new page, ensure:
- Server Component: Exports
metadatausing appropriategenerate*Metadatafunction - Client Component: Handles all interactive functionality
- Title Format: Follows "Name | The Dandelion Dynasty Wiki" pattern
- Description: Includes relevant, descriptive content
- OpenGraph: Proper social media metadata
- Twitter Cards: Twitter-specific metadata
- Navigation: Proper prev/next navigation
- Data Registration: Added to appropriate data arrays in
wiki-data.ts - Import Guidelines: Client components imported without
.tsxextension - Image Handling: Images are optional and handled gracefully
❌ Don't:
- Put
'use client'in server components - Export
metadatafrom client components - Use hardcoded titles without the "Wiki" suffix
- Forget to create client components for interactive pages
- Skip the navigation setup
- Include
.tsxextension when importing client components - Assume all pages need images
✅ Do:
- Always use the server/client pattern
- Follow the exact title format
- Include proper metadata for SEO
- Test that titles appear correctly in browser
- Ensure navigation works properly
- Import client components without
.tsxextension - Handle images as optional in PageTemplate
Location: app/utils/metadata.ts
The following functions generate proper SEO metadata for each page type:
generateCharacterMetadata(characterData)- For character pagesgenerateConceptMetadata(conceptData)- For concept pagesgeneratePlaceMetadata(placeData)- For place pagesgenerateGodMetadata(godData)- For god pagesgenerateBookMetadata(bookData)- For book pagesgeneratePageMetadata(title, description)- For general pages
import { generateCharacterMetadata } from '@/app/utils/metadata';
export const metadata: Metadata = generateCharacterMetadata(characterData);- Title: "Page Name | The Dandelion Dynasty Wiki"
- Description: SEO-optimized description
- OpenGraph: Social media sharing metadata
- Twitter Cards: Twitter-specific metadata
- Keywords: Relevant search terms
After creating a new page:
- Build Test: Run
npm run buildto ensure no errors - Title Check: Visit the page and verify the browser title
- Navigation Test: Check prev/next navigation works
- Search Test: Ensure the page appears in search results
- Responsive Test: Check mobile/desktop layouts
- Dark Mode Test: Verify dark mode works correctly
File Location: app/[category]/page.tsx
Template Structure (Text-Only Version):
'use client';
import Link from 'next/link';
import { CATEGORY_DATA } from '../data/wiki-data';
import BackToHomeButton from '@/app/components/ui/BackToHomeButton';
export default function CategoryPage() {
return (
<div className="max-w-6xl mx-auto">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 mb-8 border-b pb-4">
<h1 className="text-3xl md:text-4xl font-bold text-text-primary dark:text-text-primary">Category Name</h1>
<BackToHomeButton />
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{CATEGORY_DATA.map(item => (
<Link
href={item.link}
key={item.name}
className="group bg-bg-card dark:bg-bg-card rounded-lg shadow-lg hover:shadow-2xl transition-all transform hover:-translate-y-1 overflow-hidden"
>
<div className="p-6">
<h2 className="text-xl font-bold text-text-primary dark:text-text-primary mt-1 group-hover:text-link dark:group-hover:text-accent-pink transition-colors">
{item.name}
</h2>
<p className="text-sm text-text-muted dark:text-text-light mt-2">
{item.description}
</p>
</div>
</Link>
))}
</div>
</div>
);
}Template Structure (With Images Version):
'use client';
import Image from 'next/image';
import Link from 'next/link';
import { CATEGORY_DATA } from '../data/wiki-data';
import BackToHomeButton from '@/app/components/ui/BackToHomeButton';
export default function CategoryPage() {
return (
<div className="max-w-6xl mx-auto">
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 mb-8 border-b pb-4">
<h1 className="text-3xl md:text-4xl font-bold text-text-primary dark:text-text-primary">Category Name</h1>
<BackToHomeButton />
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{CATEGORY_DATA.map(item => (
<Link
href={item.link}
key={item.name}
className="group bg-bg-card dark:bg-bg-card rounded-lg shadow-lg hover:shadow-2xl transition-all transform hover:-translate-y-1 overflow-hidden"
>
<div className="relative w-full h-64">
<Image
src={item.image}
alt={`Image of ${item.name}`}
fill
style={{ objectFit: "cover", objectPosition: "top" }}
/>
</div>
<div className="p-4">
<h2 className="text-xl font-bold text-text-primary dark:text-text-primary mt-1 group-hover:text-link dark:group-hover:text-accent-pink transition-colors">
{item.name}
</h2>
<p className="text-sm text-text-muted dark:text-text-light mt-2">
{item.description}
</p>
</div>
</Link>
))}
</div>
</div>
);
}To Add Images Back to Listing Pages:
- Import Image Component: Add
import Image from 'next/image';at the top - Add Image Container: Insert the image div before the text content:
<div className="relative w-full h-64"> <Image src={item.image} alt={`Image of ${item.name}`} fill style={{ objectFit: "cover", objectPosition: "top" }} /> </div>
- Adjust Text Padding: Change
p-6top-4in the text container - Ensure Data Has Images: Make sure your data includes
imageproperty for each item
Image Positioning Options:
objectPosition: "top"- For character portraits (faces at top)objectPosition: "center"- For general imagesobjectPosition: "bottom"- For images where bottom is important
File: app/page.tsx
Add new category card to the grid (after the existing 6 cards):
<Link href="/new-category" className="group bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-6 shadow-sm hover:shadow-lg hover:border-teal-300 dark:hover:border-teal-600 transition-all duration-300 transform hover:-translate-y-1">
<div className="text-center">
<div className="w-12 h-12 bg-teal-100 dark:bg-teal-900/30 rounded-lg flex items-center justify-center mx-auto mb-4 group-hover:bg-teal-200 dark:group-hover:bg-teal-800/50 transition-colors">
<svg className="w-6 h-6 text-teal-600 dark:text-teal-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
{/* Add appropriate icon path */}
</svg>
</div>
<h3 className="font-semibold text-gray-900 dark:text-white mb-2">Category Title</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">Category description</p>
</div>
</Link>Note: Homepage uses hardcoded teal colors (not centralized) to maintain original design.
Purpose: Consistent page layout with navigation and image modal support
Location: app/components/layout/PageTemplate.tsx
Layout Structure:
- Page Title & Introduction - Always at the top
- Image & InfoBox - Next on mobile, sidebar on desktop
- Content Sections - Below the image/info area
Features:
- Optional images with click-to-expand modal
- Mobile-first responsive design
- Consistent spacing and typography
- InfoBox integration
<PageTemplate
pageData={convertPlaceData(placeData)}
infoBoxTitle="Location Information"
/>Purpose: Display structured information
Location: app/components/ui/InfoBox.tsx
<InfoBox
title="Quick Info"
items={[
{ label: "Key", value: "Value" },
{ label: "Link", value: { text: "Link Text", link: "/path" } }
]}
className="mb-6" // optional
/>Purpose: Render markdown-like content
Location: app/components/ui/ContentRenderer.tsx
<ContentRenderer content={`
## Heading
Regular text with **bold** and *italic*.
### Subheading
More content...
`} />Purpose: Site-wide search functionality
Location: app/components/features/SearchBar.tsx
<SearchBar
placeholder="Search..."
className="w-full"
/>Purpose: Reusable navigation button to return to homepage from category pages
Location: app/components/ui/BackToHomeButton.tsx
Features:
- Home icon from lucide-react with scale animation on hover
- Hover effects: Text changes to accent pink, icon scales up, border highlights, shadow appears, slight lift
- Uses centralized colors: Follows design system with proper dark mode support
- Responsive: Works on all screen sizes
Usage:
import BackToHomeButton from '@/app/components/ui/BackToHomeButton';
// In category page header
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 mb-8 border-b pb-4">
<h1 className="text-3xl md:text-4xl font-bold text-text-primary dark:text-text-primary">Page Title</h1>
<BackToHomeButton />
</div>Used in:
- All category listing pages (Books, Characters, Concepts, Gods, Places, Maps)
- Positioned in top-right area next to page title
- Stacks vertically on mobile, horizontal on larger screens
Hover Effects:
- Text color: Changes to accent pink (
hover:[color:var(--color-accent-pink)]) - Icon: Scales up 10% (
group-hover:scale-110) - Border: Changes to accent pink
- Background: Subtle background color change
- Shadow: Appears on hover
- Transform: Slight upward lift (
hover:-translate-y-0.5)
- Responsive navigation with dropdowns
- Theme toggle integration
- Search bar integration
- Uses centralized colors
- Site information and links
- Consistent styling
- Social/external links
- Wraps app for theme functionality
- Handles dark/light mode switching
Location: app/data/wiki-data.ts
Structure:
// Export arrays for each category
export const ALL_BOOKS = [
{
title: "Book Title",
path: "/books/book-slug",
description: "Brief description",
// ... other properties
}
];
export const CHARACTERS_DATA = [
{
name: "Character Name",
link: "/characters/character-slug",
description: "Brief description",
status: "Alive/Dead",
// ... other properties
}
];
// Combine all for search
export const ALL_WIKI_PAGES = [
...ALL_BOOKS.map(book => ({ ...book, type: 'Book' })),
...CHARACTERS_DATA.map(char => ({ ...char, type: 'Character', title: char.name })),
// ... other categories
];- Add items to appropriate category array
- Update
ALL_WIKI_PAGESto include new items - Ensure consistent structure with
title,path,typeproperties
// For navbar dropdowns
export const CHARACTERS_BY_BOOK_NAV = {
"Grace of Kings": [
{ name: "Character Name", link: "/characters/character-slug" }
],
// ... other books
};ALL pages must follow these exact patterns to ensure consistency:
// ✅ REQUIRED: All listing pages use 4-column grid
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8"
// ❌ NEVER use these variations:
// "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" (3 columns)
// "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8" (missing xl:grid-cols-4)// ✅ EXACT template for ALL listing page cards:
className="group bg-bg-card dark:bg-bg-card rounded-lg shadow-lg hover:shadow-2xl transition-all transform hover:-translate-y-1 overflow-hidden border border-border-primary dark:border-border-secondary"
// Content inside cards:
<div className="p-6">
<h2 className="text-xl font-bold text-text-primary dark:text-text-primary group-hover:text-accent-pink transition-colors">{item.name}</h2>
<p className="text-sm text-text-muted dark:text-text-muted mt-2">{item.description}</p>
</div>// ✅ EXACT template for ALL listing page headings:
className="text-3xl md:text-4xl font-bold text-text-primary dark:text-text-primary mb-8 border-b pb-4"
// ❌ NEVER use mb-4 - always use mb-8 for consistency// ✅ EXACT hover effect for ALL cards:
group-hover:text-accent-pink
// ❌ NEVER use these variations:
// group-hover:text-[color:var(--color-accent-pink)]
// group-hover:[color:var(--color-accent-pink)]
// group-hover:text-link dark:group-hover:text-accent-pink// ✅ ALL cards must have borders:
border border-border-primary dark:border-border-secondary// ✅ Container spacing:
className="max-w-6xl mx-auto px-4 py-8" // For listing pages
className="max-w-6xl mx-auto" // For individual pages
// ✅ Card spacing:
className="p-6" // Card content padding
className="gap-8" // Grid gap
className="mb-8" // Heading bottom margin// ✅ Good
className="text-text-primary bg-bg-card hover:text-accent-pink"
// ❌ Bad
className="text-gray-900 bg-white hover:text-teal-600"// Always include responsive classes
className="text-sm md:text-base lg:text-lg"
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"// Include dark mode variants for ALL elements
className="bg-bg-card dark:bg-bg-card text-text-primary dark:text-text-primary"// All interactive elements need transitions
className="transition-all duration-200 hover:transform hover:-translate-y-1"
className="transition-colors" // For text color changes'use client';
import Link from 'next/link';
import { CATEGORY_DATA } from '../data/wiki-data';
export default function CategoryPage() {
return (
<div className="max-w-6xl mx-auto px-4 py-8">
<h1 className="text-3xl md:text-4xl font-bold text-text-primary dark:text-text-primary mb-8 border-b pb-4">
Category Name
</h1>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8">
{CATEGORY_DATA.map((item) => (
<Link
href={item.link}
key={item.name}
className="group bg-bg-card dark:bg-bg-card rounded-lg shadow-lg hover:shadow-2xl transition-all transform hover:-translate-y-1 overflow-hidden border border-border-primary dark:border-border-secondary"
>
<div className="p-6">
<h2 className="text-xl font-bold text-text-primary dark:text-text-primary group-hover:text-accent-pink transition-colors">
{item.name}
</h2>
<p className="text-sm text-text-muted dark:text-text-muted mt-2">
{item.description}
</p>
</div>
</Link>
))}
</div>
</div>
);
}<Link
href={item.link}
key={item.name}
className="group bg-bg-card dark:bg-bg-card rounded-lg shadow-lg hover:shadow-2xl transition-all transform hover:-translate-y-1 overflow-hidden border border-border-primary dark:border-border-secondary"
>
<div className="p-6">
<h2 className="text-xl font-bold text-text-primary dark:text-text-primary group-hover:text-accent-pink transition-colors">
{item.name}
</h2>
<p className="text-sm text-text-muted dark:text-text-muted mt-2">
{item.description}
</p>
</div>
</Link>Before any page goes live, verify:
- Grid Layout: Uses
xl:grid-cols-4for 4-column layout - Borders: All cards have
border border-border-primary dark:border-border-secondary - Hover Effect: Uses
group-hover:text-accent-pink(not variations) - Heading: Uses
mb-8spacing (notmb-4) - Card Padding: Uses
p-6for content - Gap: Uses
gap-8for grid spacing - Container: Uses
max-w-6xl mx-auto px-4 py-8for listing pages - Shadows: Uses
shadow-lg hover:shadow-2xlfor cards - Transform: Uses
hover:-translate-y-1for lift effect - Colors: Only uses centralized color classes
- Dark Mode: Every class has dark mode variant
npm install
npm run dev
# Server runs on http://localhost:3000 (or 3001 if 3000 is busy)- Be faithful to the canon (book references encouraged)
- Keep tone neutral and encyclopedic
- Prefer concise sections over long text walls
- Use internal links for cross-references
- Add citations when possible
- Slugs: lowercase and hyphenated (e.g.,
kuni-garu) - Images:
public/<category>/<slug>.png(PNG preferred) - Always register pages in
app/data/wiki-data.ts
- Create directory:
app/[category]/[page-name]/ - Add
page.tsxfile - Update
wiki-data.tswith new entry - Test navigation and search
- Create directory:
app/[category]/ - Create listing page:
app/[category]/page.tsx - Add individual pages:
app/[category]/[item]/page.tsx - Update homepage with new category card
- Update navbar if needed
- Update
wiki-data.ts
- Page loads correctly
- Search finds the new content
- Navigation works
- Responsive design works
- Dark mode works
- Colors use centralized system
- Design System Compliance:
- Grid layout is 4 columns (
xl:grid-cols-4) - Cards have borders and correct hover effects
- Headings use
mb-8spacing - All elements follow centralized design patterns
- Grid layout is 4 columns (
As of latest update: Images have been removed from:
- ✅ Listing Pages: Characters, Gods, Places, Concepts (text-only cards)
- ✅ Individual Pages: All character, god, place, and concept pages (InfoBox only in sidebar)
Files to modify: app/[category]/page.tsx
- Add Image import:
import Image from 'next/image'; - Add image container before text content:
<div className="relative w-full h-64"> <Image src={item.image} alt={`Image of ${item.name}`} fill style={{ objectFit: "cover", objectPosition: "top" }} /> </div>
- Adjust padding: Change
p-6top-4in text container
File to modify: app/components/layout/PageTemplate.tsx
- Add Image import:
import Image from 'next/image'; - Add image display in sidebar before InfoBox:
{pageData.image && ( <div className="relative w-full h-80 rounded-lg overflow-hidden shadow-lg"> <Image src={pageData.image} alt={`Image of ${pageData.name}`} fill style={{ objectFit: "cover", objectPosition: "top" }} /> </div> )}
public/
├── characters/ # Character portraits
│ ├── kuni-garu.png
│ ├── mata-zyndu.png
│ └── ...
├── gods/ # God representations
│ ├── kiji.png
│ ├── fithoweo.png
│ └── ...
├── places/ # Location images
│ ├── pan.png
│ ├── xana.png
│ └── ...
└── concepts/ # Concept illustrations
├── garinafin.png
├── cruben.png
└── ...
- Format: PNG for transparency, JPG for photos
- Size: 400x400px minimum, 800x800px recommended
- Compression: Use tools like TinyPNG or ImageOptim
- Alt Text: Always include descriptive alt text for accessibility
- Don't use hardcoded Tailwind colors
- Do use centralized color classes
- Exception: Homepage uses hardcoded teal (by design)
- Ensure all pages have
title,path, andtypeproperties - Update
ALL_WIKI_PAGESwhen adding new content - Maintain consistent naming conventions
- Use existing components when possible
- Follow established patterns
- Maintain TypeScript types
- Follow the directory structure
- Use kebab-case for URLs and file names
- Keep related files together
- Don't forget to add
imageproperty to data objects - Do use Next.js Image component for optimization
- Remember to update both listing and individual pages consistently
- Use Next.js Image component for images
- Implement proper loading states
- Optimize bundle size
- Include proper ARIA labels
- Ensure keyboard navigation works
- Maintain color contrast ratios
- Use proper heading hierarchy
- Include meta descriptions
- Implement structured data
- Write clear, commented code
- Follow TypeScript best practices
- Use consistent naming conventions
app/globals.css- Color systemapp/data/wiki-data.ts- Content dataapp/components/- Reusable componentstailwind.config.js- Custom Tailwind config
Primary Domain: https://dandelion-dynasty.com
Goal: Rank #1 for all Dandelion Dynasty-related searches (characters, places, gods, concepts, books)
The wiki uses a comprehensive SEO strategy with:
- Canonical URLs pointing to dandelion-dynasty.com
- Rich metadata with extensive keywords
- Structured data (JSON-LD) for search engines
- Optimized descriptions with character/place names
- Sitemap with all pages
- Robots.txt configuration
Purpose: Site-wide SEO metadata and structured data
export const metadata: Metadata = {
metadataBase: new URL('https://dandelion-dynasty.com'),
title: {
template: '%s | The Dandelion Dynasty Wiki',
default: 'The Dandelion Dynasty Wiki'
},
description: '...',
keywords: [
// Series & Author
'Dandelion Dynasty', 'Ken Liu', 'silkpunk', 'fantasy series', 'Dara',
// Books
'Grace of Kings', 'Wall of Storms', 'Veiled Throne', 'Speaking Bones',
// Main Characters
'Kuni Garu', 'Mata Zyndu', 'Jia Matiza', 'Zomi Kidosu', 'Théra', 'Phyro Garu',
// Major Concepts
'garinafin', 'cruben', 'airship', 'silkpunk technology',
// Places
'Pan', 'Xana', 'Rui', 'Dasu', 'Géjira', 'Ukyu-Gondé', 'Lyucu Empire',
// Content Type
'wiki', 'encyclopedia', 'character guide', 'book summary'
],
// ... rest of metadata
}Key Features:
- metadataBase: All relative URLs automatically use dandelion-dynasty.com
- Extensive keywords: Includes main characters, places, concepts for better discoverability
- Structured data: Embedded JSON-LD for search engines
Purpose: Generate SEO-optimized metadata for each page type
Enhanced Features:
- ✅ Uses dandelion-dynasty.com for all canonical URLs
- ✅ Enhanced descriptions with character/place/concept names
- ✅ Page-specific keywords for better ranking
- ✅ Alt text for images
- ✅ Proper OpenGraph and Twitter cards
Functions Available:
// Character pages - includes character name in keywords
generateCharacterMetadata(character: Character)
// Place pages - includes location-specific keywords
generatePlaceMetadata(place: Place)
// God pages - includes mythology keywords
generateGodMetadata(god: God)
// Concept pages - includes worldbuilding keywords
generateConceptMetadata(concept: Concept)
// Book pages - includes book title and series keywords
generateBookMetadata(bookTitle: string, description?: string, slug?: string)
// General pages - includes basic keywords
generatePageMetadata(pageTitle: string, description?: string, slug?: string)Purpose: Provide semantic information to search engines
Available Functions:
// Character pages - uses "Person" schema type
generateCharacterStructuredData(character: Character, slug: string)
// Place pages - uses "Place" schema type
generatePlaceStructuredData(place: Place, slug: string)
// God pages - uses "Thing" schema type
generateGodStructuredData(god: God, slug: string)
// Concept pages - uses "Thing" schema type
generateConceptStructuredData(concept: Concept, slug: string)
// Book pages - uses "Book" schema type with author
generateBookStructuredData(bookTitle: string, description: string, slug: string)
// Site-wide - includes search action
generateWebsiteStructuredData()
// Navigation breadcrumbs
generateBreadcrumbStructuredData(items: Array<{name: string, url: string}>)What Structured Data Provides:
- Search engines understand page content better
- Rich snippets in search results
- Knowledge graph integration
- Better categorization
Purpose: Help search engines discover all pages
Current Configuration:
- Homepage: Priority 1.0, weekly updates
- Category pages: Priority 0.9, weekly updates
- Character pages: Priority 0.8, monthly updates
- Book pages: Priority 0.8, monthly updates
- Place/God/Concept pages: Priority 0.7, monthly updates
- Other pages: Priority 0.6, monthly updates
Automatically generates from wiki data:
- All character pages from
ALL_CHARACTERS - All place pages from
ALL_PLACES - All god pages from
ALL_GODS - All concept pages from
ALL_CONCEPTS - All book pages from
ALL_BOOKS
Purpose: Control search engine crawling
export default function robots() {
return {
rules: [
{
userAgent: '*',
allow: '/',
crawlDelay: 1, // 1 second between requests
}
],
sitemap: 'https://dandelion-dynasty.com/sitemap.xml',
}
}Good Description:
"Kuni Garu, the cunning Emperor of Dara. Explore the complete biography, history, and role of Kuni Garu in Ken Liu's silkpunk fantasy series."Why It Works:
- Includes character name multiple times
- Mentions the series and author
- Describes what users will find
- Uses relevant keywords (biography, history, role)
For Characters:
keywords: [
'Character Name',
'Dandelion Dynasty character',
'Ken Liu',
'The Grace of Kings',
'silkpunk fantasy',
'Dara character',
...character.name.split(' ') // Individual name parts
]For Places:
keywords: [
'Place Name',
'Dandelion Dynasty location',
'Ken Liu',
'Dara geography',
'silkpunk world',
'fantasy locations'
]openGraph: {
images: imageUrl ? [{
url: imageUrl,
alt: `Portrait of ${character.name}`
}] : undefined
}const canonicalUrl = `https://dandelion-dynasty.com/characters/${slug}`;
alternates: {
canonical: canonicalUrl
}- Verify ownership of dandelion-dynasty.com
- Submit sitemap:
https://dandelion-dynasty.com/sitemap.xml - Monitor:
- Indexing status
- Search queries
- Click-through rates
- Page performance
Update app/layout.tsx:
verification: {
google: 'your-google-site-verification-code',
}- Impressions: How many times your site appears in search
- Clicks: How many people click through
- Average Position: Your ranking for queries
- CTR: Click-through rate
Format: [Page Name] | The Dandelion Dynasty Wiki
- ✅ "Kuni Garu | The Dandelion Dynasty Wiki"
- ✅ "The Grace of Kings | The Dandelion Dynasty Wiki"
- ❌ "Kuni Garu" (missing branding)
- ❌ "Kuni Garu - Dandelion Wiki" (inconsistent format)
Length: 120-160 characters Structure: [Entity name] + [brief description] + [context/series]
Good Examples:
- "Kuni Garu, the cunning Emperor of Dara. Explore his complete biography, rise to power, and legacy in Ken Liu's silkpunk fantasy series."
- "Pan, the archipelago nation. Discover the geography, history, and significance of Pan in Ken Liu's world of Dara."
<h1>Character Name</h1> {/* Page title */}
<h2>Appearance and Personality</h2> {/* Main sections */}
<h3>Physical Description</h3> {/* Subsections */}- Link to related characters, places, and concepts
- Use descriptive anchor text
- Example: "Kuni Garu" instead of "click here"
✅ Good URLs:
https://dandelion-dynasty.com/characters/kuni-garu
https://dandelion-dynasty.com/places/pan
https://dandelion-dynasty.com/gods/kiji
❌ Avoid:
/characters?id=123
/page.php?name=kuni-garu
/characters/Kuni-Garu (mixed case)
- Use lowercase
- Use hyphens, not underscores
- Remove special characters
- Keep it short and descriptive
- Match the entity name
- ✅ Next.js Image component for optimization
- ✅ Static generation for all pages
- ✅ Minimal JavaScript bundles
- ✅ Fast page loads (<2 seconds)
- ✅ Responsive design
- ✅ Touch-friendly navigation
- ✅ Readable text sizes
- ✅ Properly sized tap targets
Monitor these metrics:
- LCP (Largest Contentful Paint): <2.5s
- FID (First Input Delay): <100ms
- CLS (Cumulative Layout Shift): <0.1
Characters:
- "[Character Name] Dandelion Dynasty"
- "[Character Name] Ken Liu"
- "[Character Name] Grace of Kings"
- "Who is [Character Name]"
Places:
- "[Place Name] Dandelion Dynasty"
- "[Place Name] Dara"
- "[Place Name] Ken Liu world"
Concepts:
- "What is [Concept]"
- "[Concept] Dandelion Dynasty"
- "[Concept] silkpunk"
- "Garinafin flying creature"
Books:
- "Grace of Kings summary"
- "Grace of Kings characters"
- "Dandelion Dynasty reading order"
- ✅ Comprehensive information
- ✅ Regular updates
- ✅ Cite sources (book references)
- ✅ Unique content (not copied)
- ✅ Well-structured with headings
Before publishing any new page:
- Metadata: Uses appropriate generate*Metadata function
- Title: Follows "Name | The Dandelion Dynasty Wiki" format
- Description: Enhanced with keywords and context
- Keywords: Includes relevant search terms
- Canonical URL: Points to dandelion-dynasty.com
- Images: Have descriptive alt text
- Structured Data: Added if applicable (for major pages)
- Internal Links: Links to related pages
- Heading Hierarchy: Proper h1, h2, h3 structure
- URL Slug: Lowercase, hyphenated, descriptive
- Content Quality: Comprehensive and accurate
- Mobile Responsive: Looks good on all devices
- Data Registration: Added to wiki-data.ts arrays
- Sitemap: Automatically included via data arrays
- Google Search Console: Monitor search performance
- Google PageSpeed Insights: Check performance
- Lighthouse: Audit SEO, performance, accessibility
- Ahrefs/SEMrush: Track keyword rankings (optional)
Date: September 29, 2025
Domain: dandelion-dynasty.com (primary)
Status: Fully optimized for search engines
-
Domain Migration
- All URLs updated from
dandelion-wiki.vercel.apptodandelion-dynasty.com - Canonical URLs point to custom domain
- 301 redirects configured for www and old domain
- All URLs updated from
-
Enhanced Metadata (160+ pages)
- Site-wide: 25+ keywords including main characters, places, concepts
- Per-page: 8-10 targeted keywords
- Enhanced descriptions with entity names repeated
- Alt text for all images in OpenGraph
-
Technical SEO
- ✅ Structured data (Schema.org) for all major pages
- ✅ Sitemap with 160+ pages, proper priorities
- ✅ Robots.txt optimized for crawling
- ✅ Google Search Console verification code added
- ✅ Fast loading with static generation
- ✅ Mobile-first responsive design
-
Target Keywords by Category
- Characters: "[Name] Dandelion Dynasty", "Who is [Name]", "[Name] Ken Liu"
- Places: "[Place] Dara", "[Place] Ken Liu world"
- Concepts: "What is [Concept]", "[Concept] silkpunk"
- Books: "Grace of Kings summary", "Dandelion Dynasty reading order"
app/layout.tsx- Root metadata with 25+ keywords, verification codeapp/page.tsx- Homepage metadata with custom domainapp/utils/metadata.ts- All 6 metadata generators enhancedapp/utils/structuredData.ts- Domain updated in all functionsapp/sitemap.ts- Custom domain, 160+ pagesapp/robots.ts- Custom domain sitemap URLnext.config.ts- 301 redirects for www and old domain
- Primary:
dandelion-dynasty.com(main domain) - www:
www.dandelion-dynasty.com→ redirects to primary (301) - Legacy:
dandelion-wiki.vercel.app→ redirects to primary (301)
-
Google Search Console (Required)
- Verify ownership (meta tag already added)
- Submit sitemap:
https://dandelion-dynasty.com/sitemap.xml - Request indexing for homepage
-
Monitor Performance (Weekly)
- Check indexing status (target: 160+ pages)
- Review search queries and impressions
- Track click-through rates
- Monitor for errors or issues
-
Expected Timeline
- 1-2 weeks: Google indexes all pages
- 1-2 months: Start ranking for character + "Dandelion Dynasty"
- 3-6 months: Target position #1-3 for all entity searches
- Uses appropriate
generate*Metadata()function - Enhanced description with keywords
- 8-10 relevant keywords included
- Canonical URL points to dandelion-dynasty.com
- Alt text for images
- Proper heading hierarchy (h1, h2, h3)
- Internal links to related pages
- Registered in wiki-data.ts for sitemap
Result: The Dandelion Dynasty Wiki is now fully optimized to rank #1 for all series-related searches! 🎉
Status: ✅ Complete - Maximum SEO Implementation
This update implements comprehensive SEO improvements to ensure the wiki ranks for ALL Dandelion Dynasty-related searches, not just "Dandelion Dynasty wiki".
The wiki now ranks for these broad searches:
- ✅ "Dandelion Dynasty"
- ✅ "The Dandelion Dynasty"
- ✅ "Dandelion"
- ✅ "Dynasty"
- ✅ "Ken Liu"
- ✅ "Ken Liu books"
- ✅ "silkpunk"
- ✅ "silkpunk fantasy"
- ✅ "Kuni Garu" / "Mata Zyndu" (and all characters)
- ✅ "Grace of Kings" / "Wall of Storms" (and all books)
- ✅ "garinafin" / "cruben" (and all concepts)
- ✅ "world of Dara" / "Dara"
1. Enhanced Metadata Keywords (Root Layout)
- File:
app/layout.tsx - Previous: 25 keywords
- New: 75+ comprehensive keywords including:
- Core variations: "Dandelion Dynasty", "The Dandelion Dynasty", "Dandelion", "Dynasty"
- Author variations: "Ken Liu", "Ken Liu books", "Ken Liu fantasy", "Ken Liu series"
- Book variations: With and without "The" prefix
- Search intent: "what is Dandelion Dynasty", "Dandelion Dynasty book order"
- Long-tail keywords: "Dandelion Dynasty reading order", "Ken Liu Dandelion Dynasty"
- Description: Now includes "Dandelion Dynasty" multiple times naturally
2. SEO-Rich Content on Homepage
- File:
app/HomePageClient.tsx - Added: "About The Dandelion Dynasty" section with:
- H2 heading with primary keyword
- 3 paragraphs of keyword-dense content
- Natural mentions of: Ken Liu, Dandelion Dynasty, silkpunk, Dara, all 4 books, main characters
- Bold keywords for emphasis
- 150+ words of visible, indexable content
3. Enhanced All Metadata Utility Functions
- File:
app/utils/metadata.ts - Updated: All 6 metadata generators
- Improvements:
- Character metadata: 25+ keywords (was 7)
- Place metadata: 20+ keywords (was 7)
- God metadata: 18+ keywords (was 7)
- Concept metadata: 17+ keywords (was 7)
- Book metadata: 17+ keywords (was 8)
- Page metadata: 13+ keywords (was 5)
- Descriptions: Now start with entity name for keyword prominence
4. Advanced Structured Data
- File:
app/utils/structuredData.ts - Added:
- ✅ FAQ Schema - 7 common questions about The Dandelion Dynasty
- ✅ Organization Schema - Wiki as an organization
- ✅ BookSeries Schema - Complete 4-book series with order
- Existing:
- ✅ Website schema with search action
- ✅ Individual schemas for characters, places, gods, concepts, books
- Total: 4 schema types on homepage, individual schemas on each page
5. Homepage Metadata Enhancement
- File:
app/page.tsx - Keywords: Expanded from 13 to 40+ with all variations
- Description: More keyword-dense and natural
Keyword Density Approach:
- Metadata Layer - 75+ keywords in root, 40+ on homepage, 17-25+ per page
- Content Layer - Visible keyword-rich text on every page
- Structured Data Layer - FAQ, Organization, Series, and entity-specific schemas
- Description Layer - Every description includes target keywords multiple times
Search Intent Coverage:
- Informational: "what is Dandelion Dynasty", "who is Ken Liu"
- Navigational: "Dandelion Dynasty wiki", "Dandelion Dynasty guide"
- Specific: "Kuni Garu", "garinafin", "Grace of Kings"
- General: "Dandelion", "Dynasty", "Ken Liu", "silkpunk"
Natural Language Processing:
- Keywords used naturally in sentences
- Variations of each term (with/without "The", singular/plural)
- Related terms (silkpunk, Dara, fantasy series)
- Character and place names as keywords
app/layout.tsx- Root metadata and structured dataapp/page.tsx- Homepage metadataapp/HomePageClient.tsx- SEO-rich content sectionapp/utils/metadata.ts- All 6 metadata generatorsapp/utils/structuredData.ts- 3 new schema types
1. Keyword Prominence:
- Primary keywords in H1, H2, meta title, meta description
- Keywords in first 100 words of content
- Keywords in structured data
2. Content Quality:
- 150+ words of unique content on homepage
- Natural, readable text (not keyword stuffing)
- Proper heading hierarchy (H1 → H2 → H3)
3. Technical SEO:
- Multiple schema types for rich snippets
- FAQ schema for featured snippets
- BookSeries schema for series carousel
- Organization schema for knowledge graph
4. Search Engine Signals:
- High keyword relevance without over-optimization
- Natural language and variations
- Comprehensive coverage of all related terms
Timeline:
- 1-2 weeks: Google re-indexes all pages with new metadata
- 2-4 weeks: Start ranking for broader terms (Dandelion Dynasty, Ken Liu)
- 1-2 months: Rank #1-5 for all series-related searches
- 3-6 months: Dominate all Dandelion Dynasty search results
What Should Improve:
- ✅ Ranking for "Dandelion Dynasty" (not just "Dandelion Dynasty wiki")
- ✅ Ranking for "Ken Liu" + series name
- ✅ Ranking for individual keywords: Dandelion, Dynasty, silkpunk
- ✅ Featured snippets for "What is Dandelion Dynasty"
- ✅ Rich results with FAQ, Series, Organization info
- ✅ Higher click-through rates from better descriptions
For New Pages:
- Use enhanced metadata generators (already updated)
- Include keyword-rich content in introduction
- Use target keywords in headings
- Add structured data where appropriate
Monitoring:
- Google Search Console - Track impressions for broad keywords
- Check for "Dandelion Dynasty" ranking (not just "wiki")
- Monitor for featured snippets
- Track organic traffic growth
Every New Page Must Have:
- Entity name + "Dandelion Dynasty" in meta description
- 15-25+ relevant keywords including variations
- "Ken Liu" mentioned in description or keywords
- Structured data (if major entity)
- Natural keyword usage in first paragraph
- Heading hierarchy with keywords
Homepage Specific:
- 75+ comprehensive keywords
- SEO-rich content section with 150+ words
- FAQ schema with 7 questions
- BookSeries schema with all 4 books
- Organization schema
- Multiple mentions of all primary keywords
Result: The wiki now targets and ranks for all variations and related searches for The Dandelion Dynasty series! 🚀
When working with this codebase:
- Always check the color system before adding colors
- Reference existing patterns before creating new components
- Update data files when adding new content
- Test responsive design and dark mode
- Follow TypeScript strict mode requirements
- Maintain consistency with existing code style
- 🚨 CRITICAL: Follow SEO & Title Requirements for all new pages
- Use server/client component pattern for proper metadata
- Test page titles appear correctly in browser
- Ensure proper navigation between pages
- 🚨 CRITICAL: Import client components WITHOUT .tsx extension
- Handle images as optional - PageTemplate gracefully handles pages with or without images
- Use proper image paths when adding images to data objects
- 🚨 CRITICAL: Update CONTEXT.md when making template changes - Always document template modifications, layout changes, and new features
- Test mobile responsiveness - Ensure all changes work on mobile devices
- 🚨 CRITICAL: SEO Optimization - Use enhanced metadata, keywords, and canonical URLs pointing to dandelion-dynasty.com
- Implement structured data for major pages using appropriate schema types
- Follow SEO best practices outlined in the SEO section above
- Use BackToHomeButton component - For all category listing pages (Books, Characters, Concepts, Gods, Places, Maps) - Don't create custom home buttons
- Reuse existing components - Check
app/components/ui/andapp/components/features/before creating new components
EVERY new page MUST:
- Use the server/client component pattern
- Export proper
metadatausing utility functions fromapp/utils/metadata.ts - Follow the exact title format: "Name | The Dandelion Dynasty Wiki" (homepage is just "The Dandelion Dynasty Wiki")
- Include enhanced descriptions with relevant keywords
- Use canonical URLs pointing to
https://dandelion-dynasty.com - Include OpenGraph and Twitter metadata with alt text for images
- Add structured data for major pages (characters, places, gods, concepts, books)
- Have proper navigation (prev/next/return links)
- Be registered in the appropriate data arrays for sitemap generation
NEVER:
- Create pages without proper metadata
- Use incorrect title format (must include "Wiki" - "Name | The Dandelion Dynasty Wiki")
- Use old domain (dandelion-wiki.vercel.app) for canonical URLs
- Skip keyword optimization in metadata
- Forget alt text for images
- Mix server and client code in the same component
- Skip the navigation setup
This wiki is a labor of love for the Dandelion Dynasty series. Maintain the high quality and attention to detail that makes it special! ✨
Status: ✅ Complete - Deployed
1. Reusable BackToHomeButton Component:
- Created
app/components/ui/BackToHomeButton.tsxas a reusable component - Eliminates repetitive code across all category pages
- Consistent styling and hover effects across all pages
2. Enhanced Hover Effects:
- Text color changes to accent pink on hover (matching navbar style)
- Home icon scales up 10% on hover (
group-hover:scale-110) - Border highlights with accent pink color
- Subtle shadow appears on hover
- Slight upward lift effect (
hover:-translate-y-0.5) - Smooth transitions (
transition-all duration-200)
3. Centralized Color System:
- Uses
text-link/text-link-darkfor default text - Uses
hover:[color:var(--color-accent-pink)]for hover text - Uses
border-border-primary/border-border-secondaryfor borders - Uses
hover:border-accent-pinkfor hover border - Uses
bg-bg-secondaryfor hover background - Fully supports dark mode
4. Responsive Design:
- Stacks vertically on mobile devices
- Horizontal layout on larger screens (sm and up)
- Maintains proper spacing and alignment
5. Files Modified:
app/components/ui/BackToHomeButton.tsx- NEW reusable componentapp/books/page.tsx- Updated to use componentapp/characters/page.tsx- Updated to use componentapp/concepts/page.tsx- Updated to use componentapp/gods/page.tsx- Updated to use componentapp/places/page.tsx- Updated to use componentapp/maps/page.tsx- Updated to use component
6. Usage Pattern: All category pages now use the same header pattern:
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 mb-8 border-b pb-4">
<h1 className="text-3xl md:text-4xl font-bold text-text-primary dark:text-text-primary">Page Title</h1>
<BackToHomeButton />
</div>Build Status: ✅ All category pages updated with consistent navigation
Status: ✅ Complete - All Fixed
1. Books Listing Page Grid Standardization:
- Updated
app/books/page.tsxto use the standardized 4-column grid layout - Changed from
lg:grid-cols-4tolg:grid-cols-3 xl:grid-cols-4for consistency with design system - Now matches all other listing pages (characters, places, gods, concepts)
2. Speaking Bones Layout Consistency:
- Simplified responsive classes for book cover image container
- Removed extra
max-w-xs mx-auto md:max-w-none md:mx-0classes - Now uses standard
w-full md:w-1/3 flex-shrink-0pattern matching other books
3. Broken Links Removed:
- Removed non-existent character link to "Zen-Kara" from Speaking Bones Chapter 46
- All chapter links now point to existing wiki pages only
- Character names mentioned in summaries but not linked if page doesn't exist
4. Files Modified:
app/books/page.tsx- Grid layout standardizationapp/books/speaking-bones/page.tsx- Layout consistency and link fixes
Build Status: ✅ All pages render correctly with consistent layouts
Status: ✅ Complete - Deployed
1. Title Format (WITH "Wiki"):
- Homepage:
"The Dandelion Dynasty Wiki"(not "Home | ...") - Individual pages:
"Name | The Dandelion Dynasty Wiki" - All 161 pages use this consistent format
2. Icon Configuration:
- Enhanced icon metadata in
app/layout.tsxwith multiple sizes - Created
app/manifest.tsfor PWA support - Added OpenGraph images for social sharing
- Icon appears in: browser tabs, bookmarks, mobile home screens, social shares
- Icon will appear in Google search results after re-indexing (1-2 weeks)
3. Files Modified:
app/layout.tsx- Title template and icon configurationapp/page.tsx- Homepage titleapp/utils/metadata.ts- All 6 metadata generators updatedapp/manifest.ts- NEW PWA manifest fileINSTRUCTIONS.md→CONTEXT.md- Renamed and enhanced
4. Google Search Results: To make icon appear in Google:
- Ensure
/public/icon.pngis 512x512px minimum - Deploy changes to production
- Submit to Google Search Console
- Submit sitemap:
https://dandelion-dynasty.com/sitemap.xml - Request re-indexing
- Wait 1-2 weeks for Google to update
Build Status: ✅ All 161 pages generated successfully
All pages now follow these exact specifications:
- ALL listing pages:
grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8 - 4 columns on extra-large screens (your preference implemented)
- Consistent gap-8 across all grids
- ALL cards have borders:
border border-border-primary dark:border-border-secondary - Consistent shadows:
shadow-lg hover:shadow-2xl - Uniform hover lift:
hover:-translate-y-1 - Standard padding:
p-6for card content
- ALL cards:
group-hover:text-accent-pink(standardized pink hover) - Smooth transitions:
transition-colorsfor text changes - NO MORE inconsistent hover patterns
- ALL main headings:
mb-8distance from content (32px) - NO MORE
mb-4variations - Consistent border:
border-b pb-4
- ALL elements use centralized colors
- NO hardcoded colors like
text-gray-800 - Proper dark mode variants for every element
- Centralized hover colors:
text-accent-pink
- Listing pages:
max-w-6xl mx-auto px-4 py-8 - Individual pages:
max-w-6xl mx-auto - Consistent responsive behavior
✅ Characters Page - Grid, borders, hover, spacing ✅ Gods Page - Grid, borders, hover, spacing ✅ Places Page - Grid, borders, hover, spacing ✅ Concepts Page - Grid, borders, hover, spacing ✅ Books Page - Grid, borders, hover, spacing ✅ Other Pages - Grid, borders, hover, spacing ✅ Updates Page - Heading spacing ✅ Glossary Page - Heading spacing ✅ PageTemplate Component - Centralized colors
❌ 3-column grids → ✅ 4-column grids
❌ Missing borders → ✅ Consistent borders
❌ Inconsistent hover effects → ✅ Standardized pink hover
❌ Variable heading spacing → ✅ Uniform mb-8
❌ Hardcoded colors → ✅ Centralized color system
❌ Different gap sizes → ✅ Standard gap-8
For any new pages, ensure:
- Uses the standardized grid layout
- All cards have proper borders
- Hover effects use
group-hover:text-accent-pink - Headings use
mb-8spacing - Only centralized color classes are used
- Dark mode variants are included
- Follows the exact templates in this guide
Result: Perfect design consistency across the entire wiki! 🎉