Pages

In Chidori, pages are the building blocks of your application. Based on Rasengan.js's file-based routing system, creating pages is as simple as creating files in the _routes directory.

Creating Pages

Basic Page Structure

Pages in Chidori can be created using two main file types:

  • .page.mdx - For pages with Markdown content and React components
  • .page.tsx - For pure React components

MDX Pages

MDX pages are perfect for documentation, blog posts, or content-heavy pages:

src/app/_routes/about.page.mdx
--- metadata: title: About Us description: Learn more about our company toc: true --- # About Us Welcome to our about page! Here you can use **Markdown** syntax and also embed React components. <Note title="info"> This is a custom React component embedded in MDX! </Note> ## Our Mission We're building amazing things with Chidori and Rasengan.js.

React Component Pages

For interactive pages or complex UI, use .page.tsx:

src/app/_routes/dashboard.page.tsx
import React from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; export default function Dashboard() { return ( <div className="container mx-auto p-6"> <h1 className="text-3xl font-bold mb-6">Dashboard</h1> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <Card> <CardHeader> <CardTitle>Analytics</CardTitle> </CardHeader> <CardContent> <p>View your application analytics here.</p> </CardContent> </Card> <Card> <CardHeader> <CardTitle>Users</CardTitle> </CardHeader> <CardContent> <p>Manage your application users.</p> </CardContent> </Card> </div> </div> ); }

Page Metadata

Pages can include metadata in the frontmatter:

--- metadata: title: Page Title description: Page description for SEO openGraph: title: Chidori description: Chidori Documentation image: https://example.com/image.jpg url: https://example.com twitter: title: Chidori description: Chidori Documentation image: https://example.com/image.jpg card: summary_large_image ---

Route Structure

The file structure in _routes directly maps to your URL structure:

_routes/ ├── index.page.mdx # → / ├── about.page.mdx # → /about ├── contact.page.tsx # → /contact ├── docs/ │ ├── index.page.mdx # → /docs │ ├── getting-started.page.mdx # → /docs/getting-started │ └── advanced/ │ ├── index.page.mdx # → /docs/advanced │ └── api.page.mdx # → /docs/advanced/api └── blog/ ├── [slug].page.mdx # → /blog/:slug (dynamic) └── [category]/ └── [slug].page.mdx # → /blog/:category/:slug

Dynamic Routes

Create dynamic routes using square brackets [param]:

src/app/_routes/blog/[slug].page.tsx
import React from 'react'; import { useParams } from 'rasengan'; export default function BlogPost() { const { slug } = useParams<{ slug: string }>(); return ( <div className="container mx-auto p-6"> <h1 className="text-3xl font-bold mb-6"> Blog Post: {slug} </h1> <p>This is a dynamic blog post page.</p> </div> ); }

Page Components

Using Custom Components

You can use any React component in your pages:

src/app/_routes/home.page.tsx
import React from 'react'; import { Hero } from '@/components/Hero'; import { Features } from '@/components/Features'; import { Testimonials } from '@/components/Testimonials'; export default function Home() { return ( <> <Hero /> <Features /> <Testimonials /> </> ); }

Page Layouts

Pages automatically inherit layouts from parent directories. You can also create page-specific layouts:

src/app/_routes/dashboard.page.tsx
import React from 'react'; import { DashboardLayout } from '@/layouts/DashboardLayout'; import { DashboardContent } from '@/components/DashboardContent'; export default function Dashboard() { return ( <DashboardLayout> <DashboardContent /> </DashboardLayout> ); }

Data Fetching

Static Data

For static data, import directly or use top-level imports:

src/app/_routes/products.page.tsx
import React from 'react'; import { products } from '@/data/products'; export default function Products() { return ( <div className="container mx-auto p-6"> <h1 className="text-3xl font-bold mb-6">Products</h1> <div className="grid grid-cols-1 md:grid-cols-3 gap-6"> {products.map((product) => ( <div key={product.id} className="border rounded-lg p-4"> <h3>{product.name}</h3> <p>{product.description}</p> </div> ))} </div> </div> ); }

Client-Side Data Fetching

For dynamic data, use React hooks:

src/app/_routes/posts.page.tsx
import React, { useState, useEffect } from 'react'; interface Post { id: number; title: string; body: string; } export default function Posts() { const [posts, setPosts] = useState<Post[]>([]); const [loading, setLoading] = useState(true); useEffect(() => { fetch('https://jsonplaceholder.typicode.com/posts') .then((response) => response.json()) .then((data) => { setPosts(data); setLoading(false); }); }, []); if (loading) return <div>Loading...</div>; return ( <div className="container mx-auto p-6"> <h1 className="text-3xl font-bold mb-6">Posts</h1> <div className="space-y-4"> {posts.map((post) => ( <div key={post.id} className="border rounded-lg p-4"> <h3 className="font-bold">{post.title}</h3> <p>{post.body}</p> </div> ))} </div> </div> ); }

Page Styling

Using CSS Modules

src/app/_routes/about.page.tsx
import React from 'react'; import styles from './about.module.css'; export default function About() { return ( <div className={styles.container}> <h1 className={styles.title}>About Us</h1> <p className={styles.description}> Learn more about our amazing company. </p> </div> ); }

Using Tailwind CSS

src/app/_routes/contact.page.tsx
import React from 'react'; export default function Contact() { return ( <div className="min-h-screen bg-gray-50 py-12 px-4"> <div className="max-w-2xl mx-auto"> <h1 className="text-4xl font-bold text-center mb-8"> Contact Us </h1> <form className="space-y-6"> <div> <label className="block text-sm font-medium mb-2"> Name </label> <input type="text" className="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500" /> </div> </form> </div> </div> ); }

Best Practices

1. File Naming

  • Use kebab-case for file names: getting-started.page.mdx
  • Keep names descriptive and concise
  • Use index files for directory roots

2. Component Organization

  • Keep page components focused on layout and composition
  • Extract reusable logic into custom hooks
  • Use shared components for common UI patterns

3. Performance

  • Use lazy loading for heavy components
  • Optimize images and assets
  • Implement proper error boundaries

4. SEO

  • Always include descriptive metadata
  • Use semantic HTML elements
  • Implement proper heading hierarchy

Advanced Features

Route Guards

Protect pages with authentication:

src/app/_routes/admin/dashboard.page.tsx
import React from 'react'; import { useAuth } from '@/hooks/useAuth'; import { useNavigate } from 'rasengan'; export default function AdminDashboard() { const { user } = useAuth(); const navigate = useNavigate(); React.useEffect(() => { if (!user || !user.isAdmin) { navigate('/login'); } }, [user, router]); if (!user || !user.isAdmin) { return <div>Redirecting...</div>; } return ( <div className="container mx-auto p-6"> <h1 className="text-3xl font-bold mb-6">Admin Dashboard</h1> {/* Admin content */} </div> ); }

Page Transitions

Add smooth transitions between pages:

src/app/_routes/_layout.tsx
import React from 'react'; import { AnimatePresence, motion } from 'framer-motion'; import { useLocation } from 'rasengan'; export default function Layout({ children }: { children: React.ReactNode }) { const location = useLocation(); return ( <AnimatePresence mode="wait"> <motion.div key={location.pathname} initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -20 }} transition={{ duration: 0.3 }} > {children} </motion.div> </AnimatePresence> ); }