# Common Page Patterns

Patterns shared across all screen types. Read for every page implementation.

## GraphQL Setup

All operations use gql.tada for type safety:

```ts
import { graphql, type FragmentOf, readFragment } from "@/graphql";
```

Built-in queries (`gqlOperations: "query"`) generate:

- `<Entity>(id: ID!)` — get by ID
- `<entities>` — list with connection pattern (`edges { node { ... } }`)

Mutations are defined by custom resolvers.

## Fragment Collocation

Each component defines and exports its own GraphQL fragment. The parent page imports it and includes it in the query:

```tsx
// components/user-card.tsx
export const UserCardFragment = graphql(`
  fragment UserCard on User {
    id
    name
    email
  }
`);

export const UserCard = ({ user }: { user: FragmentOf<typeof UserCardFragment> }) => {
  const data = readFragment(UserCardFragment, user);
  return <div>{data.name}</div>;
};

// page.tsx
const UserQuery = graphql(
  `
    query User($id: ID!) {
      user(id: $id) {
        ...UserCard
      }
    }
  `,
  [UserCardFragment],
);
```

## Page Conventions

Every page component must:

1. Be the **default export** of `page.tsx`
2. Set `appShellPageProps` with at least `meta.title`

## App.tsx

See [project-setup.md](project-setup.md) for authentication, sidebar, and Vite plugin configuration.

## Layout

Responsive column layout. Column count is auto-detected from `Layout.Column` children (1–3 get predefined widths; 4+ share equal width).

```tsx
<Layout>
  <Layout.Header
    title="Order #12345"
    actions={[
      <Button key="edit">Edit</Button>,
      <Button key="delete" variant="destructive">Delete</Button>,
    ]}
  />
  <Layout.Column>{/* main */}</Layout.Column>
  <Layout.Column>{/* sidebar */}</Layout.Column>
</Layout>
```

### Layout Props

| Prop | Type | Description |
|------|------|-------------|
| `className` | `string` | CSS classes for container (e.g. `"astw:gap-6"` for gap) |
| `style` | `CSSProperties` | Inline styles |
| `children` | `Layout.Header \| Layout.Column` | Direct children (other elements are filtered out) |

### Layout.Header Props

Place as a direct child of `<Layout>`, above any `<Layout.Column>`. Only the first `Layout.Header` is rendered if multiple are provided.

| Prop | Type | Description |
|------|------|-------------|
| `title` | `string` | Page title (left side, rendered as `<h1>`) |
| `actions` | `React.ReactNode[]` | Action buttons (right side) |
| `children` | `React.ReactNode` | Full-width content below title/actions row (e.g. tabs) |

Header with tabs:

```tsx
<Layout.Header title="Purchase Orders" actions={[<Button key="create">Create</Button>]}>
  <Tabs value={tab} onValueChange={setTab}>
    <TabsList>
      <TabsTrigger value="all">All</TabsTrigger>
      <TabsTrigger value="open">Open</TabsTrigger>
    </TabsList>
  </Tabs>
</Layout.Header>
```

### Layout.Column Props

| Prop | Type | Description |
|------|------|-------------|
| `className` | `string` | CSS classes |
| `style` | `CSSProperties` | Inline styles |
| `area` | `"left" \| "main" \| "right"` | Explicit width role (see Area Mode) |
| `children` | `React.ReactNode` | Column content |

### Column Widths

**2 Columns (≥ 1024px):** Column 1 flexible, Column 2 fixed 280px. Stacks on mobile.

**3 Columns (≥ 1280px):** Column 1 fixed 320px, Column 2 flexible, Column 3 fixed 280px. Stacks below breakpoint.

**4+ Columns (≥ 1280px):** Equal width (`repeat(N, 1fr)`).

### Area Mode (Advanced)

Most layouts should use the default position-based column widths (see Column Widths above) — just place `Layout.Column` children in order without `area`. Use `area` only when you need to override the default width assignment for a column position.

| Area | Width |
|------|-------|
| `"left"` | Fixed 320px |
| `"main"` | Flexible (1fr) |
| `"right"` | Fixed 280px |
| (unset) | Flexible (1fr) |

If any `Layout.Column` has `area`, all columns switch to area-based widths. Columns are rendered in source order.

```tsx
<Layout>
  <Layout.Column area="left"><nav>Sidebar</nav></Layout.Column>
  <Layout.Column area="main"><h2>Content</h2></Layout.Column>
</Layout>
```

For UI component references (Button, Badge, Table, Dialog, Menu, Sheet, Tooltip, etc.), see [components.md](components.md).
