New Page
Create new pages in Chameleon
New Page
Learn how to create new pages in Chameleon using Next.js App Router and the project structure.
Overview
Chameleon uses Next.js App Router with internationalization support. New pages are created in the src/app/[locale]/ directory structure with proper routing, layouts, and component integration.
Page Structure
Directory Structure
src/app/[locale]/
├── (default)/ # Public pages
│ ├── page.tsx # Homepage
│ ├── about/
│ │ └── page.tsx # About page
│ └── contact/
│ └── page.tsx # Contact page
├── (console)/ # User dashboard pages
│ ├── my-orders/
│ │ └── page.tsx # User orders
│ └── ai-generator/
│ └── page.tsx # AI generator
├── (admin)/ # Admin pages
│ └── admin/
│ ├── users/
│ │ └── page.tsx # User management
│ └── posts/
│ └── page.tsx # Post management
└── layout.tsx # Root layout
Route Groups
(default)- Public pages accessible to all users(console)- User dashboard pages (requires authentication)(admin)- Admin pages (requires admin access)
Creating a New Page
Basic Page
// src/app/[locale]/(default)/about/page.tsx
import { Metadata } from "next";
import { useTranslations } from "next-intl";
export const metadata: Metadata = {
title: "About Us",
description: "Learn more about Chameleon",
};
export default function AboutPage() {
return (
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-4">About Chameleon</h1>
<p className="text-lg">
Chameleon is an AI-powered content generation platform.
</p>
</div>
);
}
Page with Translations
// src/app/[locale]/(default)/contact/page.tsx
import { useTranslations } from "next-intl";
export default function ContactPage() {
const t = useTranslations("contact");
return (
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-4">{t("title")}</h1>
<p className="text-lg mb-6">{t("description")}</p>
<form className="max-w-md">
<div className="mb-4">
<label className="block text-sm font-medium mb-2">
{t("form.name")}
</label>
<input
type="text"
className="w-full px-3 py-2 border rounded-md"
placeholder={t("form.name_placeholder")}
/>
</div>
<button
type="submit"
className="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600"
>
{t("form.submit")}
</button>
</form>
</div>
);
}
Protected Page
// src/app/[locale]/(console)/dashboard/page.tsx
import { auth } from "@/auth";
import { redirect } from "next/navigation";
export default async function DashboardPage() {
const session = await auth();
if (!session) {
redirect("/auth/signin");
}
return (
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-4">
Welcome, {session.user.name}!
</h1>
<p>This is your dashboard.</p>
</div>
);
}
Admin Page
// src/app/[locale]/(admin)/admin/settings/page.tsx
import { auth } from "@/auth";
import { redirect } from "next/navigation";
export default async function AdminSettingsPage() {
const session = await auth();
const adminEmails = process.env.ADMIN_EMAILS?.split(",");
if (!session || !adminEmails?.includes(session.user.email)) {
redirect("/");
}
return (
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-4">Admin Settings</h1>
<p>Configure system settings here.</p>
</div>
);
}
Dynamic Routes
Single Dynamic Route
// src/app/[locale]/(default)/posts/[slug]/page.tsx
import { Metadata } from "next";
interface PageProps {
params: { slug: string };
}
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const post = await getPostBySlug(params.slug);
return {
title: post.title,
description: post.description,
};
}
export default async function PostPage({ params }: PageProps) {
const post = await getPostBySlug(params.slug);
return (
<article className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-4">{post.title}</h1>
<div className="prose max-w-none">
{post.content}
</div>
</article>
);
}
Multiple Dynamic Routes
// src/app/[locale]/(default)/category/[category]/[slug]/page.tsx
interface PageProps {
params: {
category: string;
slug: string;
};
}
export default async function CategoryPostPage({ params }: PageProps) {
const { category, slug } = params;
const post = await getPostByCategoryAndSlug(category, slug);
return (
<div>
<nav className="text-sm text-gray-600 mb-4">
<a href="/">Home</a> /
<a href={`/category/${category}`}>{category}</a> /
{post.title}
</nav>
<article>
<h1>{post.title}</h1>
<div>{post.content}</div>
</article>
</div>
);
}
File Locations
src/app/[locale]/(default)/- Public pagessrc/app/[locale]/(console)/- User dashboard pagessrc/app/[locale]/(admin)/- Admin pagessrc/app/[locale]/layout.tsx- Root layoutsrc/i18n/pages/- Page-specific translations
Common Tasks
Create a New Public Page
- Create directory:
src/app/[locale]/(default)/your-page/ - Add
page.tsxfile - Add translations to
src/i18n/pages/your-page/ - Test page accessibility
Add Authentication Check
import { auth } from "@/auth";
import { redirect } from "next/navigation";
export default async function ProtectedPage() {
const session = await auth();
if (!session) {
redirect("/auth/signin");
}
// Page content
}
Add Admin Check
const adminEmails = process.env.ADMIN_EMAILS?.split(",");
if (!adminEmails?.includes(session.user.email)) {
redirect("/");
}
Add Metadata
export const metadata: Metadata = {
title: "Page Title",
description: "Page description",
openGraph: {
title: "Page Title",
description: "Page description",
},
};
Troubleshooting
Page not accessible
Problem: New page returns 404
Solution:
- Check file is named
page.tsx - Verify directory structure is correct
- Check for TypeScript errors
- Restart development server
Authentication not working
Problem: Protected page accessible without login
Solution:
- Check
auth()import is correct - Verify session check logic
- Check redirect path is valid
- Test with different user states
Translations not working
Problem: Page shows translation keys
Solution:
- Check translation files exist
- Verify
useTranslationsnamespace - Check translation key spelling
- Test with different locales
Next Steps
- New Component - Create reusable components
- API Calls - Add API integration
- Internationalization - Multi-language support