Files
myeasycms-v2/.cursor/rules/page-creation.mdc
Giancarlo Buomprisco 22f78b9a86 Cursor rules v2 (#200)
* Add new Cursor rules based on new format
2025-03-03 12:38:32 +08:00

322 lines
8.3 KiB
Plaintext

---
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 (
<>
<MyFeatureHeader
title={<Trans i18nKey={'common:routes.myFeature'} />}
description={<Trans i18nKey={'common:myFeatureDescription'} />}
/>
<PageBody>
{/* Main page content */}
</PageBody>
</>
);
}
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 (
<UserWorkspaceContextProvider value={workspace}>
<Page>
<PageNavigation>
<MyFeatureNavigation workspace={workspace} />
</PageNavigation>
{children}
</Page>
</UserWorkspaceContextProvider>
);
}
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 (
<UserWorkspaceContextProvider value={workspace}>
<Page>
{/* Navigation components */}
{children}
</Page>
</UserWorkspaceContextProvider>
);
}
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 (
<TeamAccountWorkspaceContextProvider value={workspace}>
<Page>
{/* Navigation components */}
{children}
</Page>
</TeamAccountWorkspaceContextProvider>
);
}
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 (
<PageHeader
title={title}
description={description}
/>
);
}
```
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 (
<div>
{/* Component content */}
</div>
);
}
```
### 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 (
<NavigationMenu>
{/* Navigation items */}
</NavigationMenu>
);
}
```
## 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 `<Trans>` component for translated text
- Define translation keys in the appropriate namespace in `apps/web/public/locales/<locale>/<namespace>.json`
5. **Metadata**:
- Always include `generateMetadata` for SEO
- 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