--- description: Creating new Pages in the app globs: apps/** alwaysApply: false --- # Creating Pages # Makerkit Page & Layout Guidelines ## Page Structure Overview Makerkit uses Next.js App Router architecture with a clear separation of concerns for layouts and pages. The application's structure reflects the multi-tenant approach with specific routing patterns: ``` - app - home # protected routes - (user) # user workspace (personal account context) - [account] # team workspace (team account context) - (marketing) # marketing pages - auth # auth pages ``` ## Key Components ### Layouts Layouts in Makerkit provide the structure for various parts of the application: 1. **Root Layout**: The base structure for the entire application 2. **Workspace Layouts**: - User Workspace Layout (`app/home/(user)/layout.tsx`): For personal account context - Team Workspace Layout (`app/home/[account]/layout.tsx`): For team account context Layouts handle: - Workspace context providers - Navigation components - Authentication requirements - UI structure (sidebar vs header style) ### Pages Pages represent the actual content for each route and follow a consistent pattern: 1. **Metadata Generation**: Using `generateMetadata()` for SEO and page titles 2. **Content Structure**: - Page headers with titles and descriptions - Page body containing the main content 3. **i18n Implementation**: Wrapped with `withI18n` HOC ## Creating a New Page ### 1. Define the Page Structure Create a new file within the appropriate route folder: ```tsx // app/home/(user)/my-feature/page.tsx import { PageBody } from '@kit/ui/page'; import { Trans } from '@kit/ui/trans'; import { createI18nServerInstance } from '~/lib/i18n/i18n.server'; import { withI18n } from '~/lib/i18n/with-i18n'; // Import components from the _components folder if needed import { MyFeatureHeader } from './_components/my-feature-header'; export const generateMetadata = async () => { const i18n = await createI18nServerInstance(); const title = i18n.t('account:myFeaturePage'); return { title, }; }; function MyFeaturePage() { return ( <> } description={} /> {/* Main page content */} ); } export default withI18n(MyFeaturePage); ``` - Authentication is enforced already in the middleware - Authorization is normally enforced by RLS at the database level - In the rare case you use the Supabase Admin client, you must enforce both authentication and authorization manually ### 2. Create a Loading State ```tsx // app/home/(user)/my-feature/loading.tsx import { GlobalLoader } from '@kit/ui/global-loader'; export default GlobalLoader; ``` ### 3. Create a Layout (if needed) If the feature requires a specific layout, create a layout file: ```tsx // app/home/(user)/my-feature/layout.tsx import { use } from 'react'; import { UserWorkspaceContextProvider } from '@kit/accounts/components'; import { Page, PageNavigation } from '@kit/ui/page'; import { withI18n } from '~/lib/i18n/with-i18n'; import { loadUserWorkspace } from '../_lib/server/load-user-workspace'; // Import components from the _components folder import { MyFeatureNavigation } from './_components/my-feature-navigation'; function MyFeatureLayout({ children }: React.PropsWithChildren) { const workspace = use(loadUserWorkspace()); return ( {children} ); } export default withI18n(MyFeatureLayout); ``` ## Layout Patterns ### 1. User Workspace Layout For pages in the personal account context, use the user workspace layout pattern: ```tsx import { use } from 'react'; import { UserWorkspaceContextProvider } from '@kit/accounts/components'; import { Page } from '@kit/ui/page'; import { withI18n } from '~/lib/i18n/with-i18n'; import { loadUserWorkspace } from './_lib/server/load-user-workspace'; function MyLayout({ children }: React.PropsWithChildren) { const workspace = use(loadUserWorkspace()); return ( {/* Navigation components */} {children} ); } export default withI18n(MyLayout); ``` ### 2. Team Workspace Layout For pages in the team account context, use the team workspace layout pattern: ```tsx import { use } from 'react'; import { TeamAccountWorkspaceContextProvider } from '@kit/team-accounts/components'; import { Page } from '@kit/ui/page'; import { withI18n } from '~/lib/i18n/with-i18n'; import { loadTeamWorkspace } from './_lib/server/load-team-workspace'; function TeamLayout({ children, params }: LayoutParams) { const workspace = use(loadTeamWorkspace(params.account)); return ( {/* Navigation components */} {children} ); } export default withI18n(TeamLayout); ``` ## UI Components Structure ### Page Components Break down pages into reusable components: 1. **Page Headers**: Create header components for consistent titling: ```tsx // _components/my-feature-header.tsx import { PageHeader } from '@kit/ui/page-header'; export function MyFeatureHeader({ title, description }: { title: React.ReactNode, description: React.ReactNode }) { return ( ); } ``` 2. **Feature Components**: Create components for feature-specific functionality: ```tsx // _components/my-feature-component.tsx 'use client'; import { useUserWorkspace } from '@kit/accounts/hooks/use-user-workspace'; export function MyFeatureComponent() { const { user } = useUserWorkspace(); return (
{/* Component content */}
); } ``` ### Navigation Components Create navigation components to handle sidebar or header navigation: ```tsx // _components/my-feature-navigation.tsx 'use client'; import { NavigationMenu } from '@kit/ui/navigation-menu'; export function MyFeatureNavigation({ workspace }: { workspace: UserWorkspace }) { return ( {/* Navigation items */} ); } ``` ## Layout Styles Makerkit supports different layout styles that can be toggled by the user: 1. **Sidebar Layout**: A vertical sidebar navigation 2. **Header Layout**: A horizontal header navigation The layout style is stored in cookies and can be accessed server-side: ```tsx async function getLayoutState() { const cookieStore = await cookies(); const layoutStyleCookie = cookieStore.get('layout-style'); return { style: layoutStyleCookie?.value ?? defaultStyle, // Other layout state properties }; } ``` ## Best Practices 1. **Server vs. Client Components**: - Use Server Components for data fetching and initial rendering - Use Client Components ('use client') for interactive elements 2. **Data Loading**: - Load workspace data in layouts using server functions - Pass data down to components that need it - Use React Query for client-side data fetching 3. **Component Organization**: - Place feature-specific components in a `_components` folder - Place feature-specific server utilities in a `_lib/server` folder - Place feature-specific client utilities in a `_lib/client` folder 4. **i18n Support**: - Always use `withI18n` HOC for pages and layouts - Use `` component for translated text - Define translation keys in the appropriate namespace in `apps/web/public/locales//.json` 5. **Metadata**: - Always include `generateMetadata` for SEO and UX - Use translations for page titles and descriptions 6. **Loading States**: - Always provide a loading state for each route - Use the `GlobalLoader` or custom loading components 7. **Error Handling**: - Implement error.tsx files for route error boundaries - Handle data fetching errors gracefully