This commit is contained in:
phaichayon
2026-06-11 12:46:57 +07:00
parent 1993d88306
commit 7a390cf0df
720 changed files with 100919 additions and 0 deletions

649
LAYOUT.md Normal file
View File

@@ -0,0 +1,649 @@
# ALLA OS CRM — Page Layout Templates
> **Rule**: No design tokens are embedded in this document.
> All colors, text content, icons, and brand-specific values are represented by **semantic placeholders** (`{placeholder}`).
> Use these templates as structural skeletons — inject your own design system, copy, and iconography.
---
## Table of Contents
1. [Shared Vocabulary](#1-shared-vocabulary)
2. [Template A — Entity Detail Page](#2-template-a--entity-detail-page)
3. [Template B — Entity List Page](#3-template-b--entity-list-page)
4. [Component Blueprints](#4-component-blueprints)
5. [Slot Reference](#5-slot-reference)
---
## 1. Shared Vocabulary
### Semantic Placeholders
| Category | Placeholder | Represents |
|---|---|---|
| Color | `{color.status-positive}` | approved / success / active |
| Color | `{color.status-negative}` | rejected / error / lost |
| Color | `{color.status-warning}` | pending / caution / awaiting |
| Color | `{color.status-neutral}` | draft / default / info |
| Color | `{color.accent}` | hot / highlight / urgent |
| Color | `{color.muted}` | secondary text / disabled |
| Color | `{color.surface}` | card background / subtle fill |
| Text | `{entity.code}` | business code (e.g. QT2606-001) |
| Text | `{entity.title}` | primary display name / project name |
| Text | `{label.fieldName}` | field label (locale-aware) |
| Text | `{action.verb}` | button label (locale-aware) |
| Text | `{value.field}` | field display value |
| Icon | `{icon.back}` | back / navigate-left icon |
| Icon | `{icon.status}` | contextual status icon |
| Icon | `{icon.field}` | field-specific icon |
| Link | `{route.list}` | parent list route |
| Link | `{route.detail}` | detail page route |
| Component | `<StatusBadge />` | status display component |
| Component | `<PreviewPanel />` | collapsible preview component |
| Data | `{data.summary}` | summary/computed values |
| Data | `{data.items}` | line items collection |
| Data | `{data.steps}` | approval/workflow steps |
| Data | `{data.related}` | related entities collection |
### Spacing Convention
| Token | Tailwind | Usage |
|---|---|---|
| `{gap-page}` | `gap-6` | between top-level sections |
| `{gap-card}` | `space-y-6` | between cards in a column |
| `{gap-inner}` | `gap-4` | between fields in a grid |
| `{gap-compact}` | `gap-2` / `gap-3` | between badges, inline items |
| `{pad-page}` | `p-4 md:p-6` | page outer padding |
| `{pad-card}` | default CardContent | card inner padding |
---
## 2. Template A — Entity Detail Page
**Used by**: Enquiry Detail, Quotation Detail, Approval Detail
### 2.1 Page Skeleton
```
┌─────────────────────────────────────────────────────────┐
│ [←] {entity.code} <StatusBadge> <Badge?> <Badge?> │ ← Header Bar
│ {entity.title} │
│ [Btn] [Btn] [Btn] │ ← Header Actions
├─────────────────────────────────────────────────────────┤
│ [Btn] [Btn] [Btn] │ ← Action Row (conditional)
├─────────────────────────────────────────────────────────┤
│ <CollapsiblePanel /> │ ← Optional Preview
├─────────────────────────────────────────────────────────┤
│ <ProgressBarCard /> │ ← Optional Progress
├──────────────────────────┬──────────────────────────────┤
│ │ │
│ Main Column (2/3) │ Side Column (1/3) │
│ │ │
│ ┌──────────────────┐ │ ┌────────────────────┐ │
│ │ Summary Card │ │ │ Key Metric Card │ │
│ └──────────────────┘ │ └────────────────────┘ │
│ ┌──────────────────┐ │ ┌────────────────────┐ │
│ │ Secondary Card │ │ │ Current State Card │ │
│ └──────────────────┘ │ └────────────────────┘ │
│ ┌──────────────────┐ │ ┌────────────────────┐ │
│ │ Table Card │ │ │ Progress Card │ │
│ └──────────────────┘ │ └────────────────────┘ │
│ ┌──────────────────┐ │ ┌────────────────────┐ │
│ │ Tabs Card │ │ │ Quick Links Card │ │
│ │ ┌─┬─┬─┬─┐ │ │ └────────────────────┘ │
│ │ │ │ │ │ │ │ │ │
│ │ └─┴─┴─┴─┘ │ │ │
│ │ Tab Content │ │ │
│ └──────────────────┘ │ │
│ │ │
└──────────────────────────┴──────────────────────────────┘
<Dialog /> (action confirmation)
```
### 2.2 Section Specifications
#### A. Header Bar
```
Container: flex items-center gap-{gap-inner}
─────────────────────────────────────────────
[BackButton] {entity.code} <StatusBadge> <Badge*>
{entity.title}
─────────────────────────────────────
flex-1 flex items-center gap-{gap-compact}
```
| Element | Structure | Notes |
|---|---|---|
| Back Button | `Button variant="ghost" size="icon"``Link` to `{route.list}` | Always present |
| Code | `h1` with `{font-size.heading}` | Monospace for business codes |
| Status Badge | `<StatusBadge status={status} />` | Maps status → `{color.status-*}` |
| Extra Badges | `Badge variant="outline"` or custom | Revision, Hot, Type — conditionally shown |
| Subtitle | `p text-muted-foreground` | `{entity.title}` or description |
| Header Actions | `Button variant="outline"` or `Button` | Preview, PDF, Navigate — aligned right |
#### B. Action Row (Conditional)
```
Container: flex flex-wrap items-center gap-{gap-compact}
─────────────────────────────────────────────────────
[Btn1] [Btn2] [Btn3] ...
```
- Only rendered when at least one action is available
- Actions are **status-driven**: show/hide based on `entity.status`
- Use consistent `size="sm"` for all action buttons
- Primary action uses default variant, destructive uses `variant="destructive"`, secondary uses `variant="outline"`
- Each button follows pattern: `<Icon className="h-4 w-4 mr-1" /> {action.verb}`
#### C. Collapsible Panel (Optional)
```
Container: Card → CardContent p-4 overflow-auto max-h-[{max-preview-height}]
──────────────────────────────────────────────────────────────────────────
<PreviewPanel />
```
- Toggled via state (`showPreview`)
- Rendered between Action Row and Grid
- Only present when entity supports preview (e.g. PDF preview for Quotation)
#### D. Progress Bar Card (Optional)
```
Container: Card → CardContent p-4
───────────────────────────────────
┌──────────────────────────────────────────────────┐
│ Progress Title ({completed}/{total}) Current │ ← flex justify-between
│ ▓▓▓▓▓▓▓▓░░░░░░░░░░░ │ ← step bars
│ ✓ Step1 ○ Step2 ○ Step3 │ ← step labels
└──────────────────────────────────────────────────┘
```
- Step bars: `flex items-center gap-1`, each step is `flex-1 h-2 rounded-full`
- Filled steps use `{color.status-positive}`, pending use `{color.muted}`
- Step labels: icon + role name per step
#### E. 3-Column Grid
```
Container: grid grid-cols-1 lg:grid-cols-3 gap-{gap-page}
─────────────────────────────────────────────────────────────
├── Main Column: lg:col-span-2 space-y-{gap-card}
└── Side Column: space-y-{gap-card}
```
---
### 2.3 Main Column — Card Types
#### Card Type 1: Summary Card (Always First)
```
┌─────────────────────────────────────────────┐
│ {label.summaryTitle} │ ← CardHeader pb-3, CardTitle text-base
├─────────────────────────────────────────────┤
│ ┌────────┬────────┬────────┬────────┐ │
│ │ Field1 │ Field2 │ Field3 │ Field4 │ │ ← grid 2cols md:4cols gap-{gap-inner}
│ │ label │ label │ label │ label │ │ ← text-xs text-muted-foreground
│ │ value │ value │ value │ value │ │ ← text-sm (or Badge for enum)
│ └────────┴────────┴────────┴────────┘ │
│ │
│ [Optional: description block] │ ← mt-3 / mt-4 if present
│ [Optional: location with icon] │ ← flex items-center gap-2
└─────────────────────────────────────────────┘
```
**Field cell pattern:**
```jsx
<div>
<p className="text-xs text-muted-foreground">{label.fieldName}</p>
<p className="text-sm">{value.field}</p> // plain value
// OR
<Badge variant="secondary">{value.field}</Badge> // enum value
// OR
<Link className="text-sm text-primary hover:underline">{value.field}</Link> // link value
</div>
```
#### Card Type 2: Entity List Card (e.g. Customer Roles)
```
┌─────────────────────────────────────────────┐
│ {label.cardTitle} │
├─────────────────────────────────────────────┤
│ ┌─────────────────┬─────────────────┐ │
│ │ [Icon] Name │ [Icon] Name │ │ ← grid 1col sm:2cols gap-3
│ │ Subtitle │ Subtitle │ │ ← each row: flex items-center gap-3 p-3 rounded-lg border
│ │ <Badge>│ <Badge>│ │
│ └─────────────────┴─────────────────┘ │
└─────────────────────────────────────────────┘
```
**Row pattern:**
```
[IconBox] [Content flex-1] [Badge]
p-2 Name (medium) variant="outline"
bg-muted Subtitle (xs)
rounded text-muted
```
#### Card Type 3: Table Card (e.g. Line Items)
```
┌─────────────────────────────────────────────┐
│ {label.tableTitle} │
├─────────────────────────────────────────────┤
│ ┌───┬──────────┬────┬────┬────────┬──────┐│
│ │ # │ Description│ Qty│Unit│ Price │Total ││ ← thead: border-b bg-muted/50
│ ├───┼──────────┼────┼────┼────────┼──────┤│
│ │ 1 │ Item A │ 2 │ ea │ 1,000 │2,000 ││ ← tbody: border-b last:border-0
│ │ │ spec... │ │ │ │ ││ ← specification: text-xs text-muted
│ └───┴──────────┴────┴────┴────────┴──────┘│
│ │
│ ┌─────────────────┐│
│ │ Subtotal val ││ ← Totals section: flex justify-end
│ │ Discount val ││ w-72 space-y-1 text-sm
│ │ Tax val ││
│ │ ────────────── ││ Separator
│ │ Grand val ││ font-bold text-base
│ └─────────────────┘│
└─────────────────────────────────────────────┘
```
#### Card Type 4: Topics Card (Optional — Key-Value List Groups)
```
┌─────────────────────────────────────────────┐
│ {label.topicsTitle} │
├─────────────────────────────────────────────┤
│ {icon.topicType} {topic.title} │ ← text-sm font-semibold
│ • Item 1 │ ← list-disc list-inside text-sm text-muted
│ • Item 2 │ ml-2 space-y-0.5
│ │
│ {icon.topicType} {topic.title} │ ← space-y-4 between topics
│ • Item 1 │
└─────────────────────────────────────────────┘
```
#### Card Type 5: Tabs Card (Always Last in Main Column)
```
┌─────────────────────────────────────────────┐
│ [Tab1 (n)] [Tab2 (n)] [Tab3] [Tab4] │ ← TabsList
├─────────────────────────────────────────────┤
│ <TabContent> │
│ ...varies per tab type (see below)... │
│ </TabContent> │
└─────────────────────────────────────────────┘
```
**Tab content variants:**
| Variant | Structure | Empty State |
|---|---|---|
| Step Timeline | Vertical: icon + step label + badge + meta + comment bubble | Centered text + create CTA |
| Related Items | Card list: each item is a linked card with code/status/amount | Icon + text + create CTA |
| Follow-ups | Icon-box + title + description + metadata | Centered text |
| Attachments | Upload area with drag-drop zone | Icon + text + upload button |
| Audit Log | Dot + action badge + description + timestamp | Centered text |
---
### 2.4 Side Column — Card Types
#### Side Card Type 1: Key Metric Summary
```
┌─────────────────────────────┐
│ {label.metricTitle} │ ← CardHeader pb-3, CardTitle text-base
├─────────────────────────────┤
│ Sub-amount {value} │ ← flex justify-between text-sm
│ Deduction {value} │ ← conditional, uses {color.status-negative}
│ Tax {value} │
│ ───────────────────────── │ ← Separator
│ Grand Total {value} │ ← flex justify-between font-bold
│ {label.currencyNote} │ ← text-xs text-muted-foreground
└─────────────────────────────┘
```
#### Side Card Type 2: Current State / Status Highlight
```
┌─────────────────────────────────────┐
│ {icon.state} {label.stateTitle} │ ← CardHeader with icon
├─────────────────────────────────────┤
│ ┌─────────────────────────────┐ │
│ │ [Icon] Step M/N │ │ ← Highlighted box: p-3 rounded-lg
│ │ {label.waitingFor} │ │ border uses {color.status-warning}
│ └─────────────────────────────┘ │ bg uses {color.status-warning} light
│ │
│ [Btn1] [Btn2] │ ← Inline action buttons (conditional)
│ OR │
│ ┌─────────────────────────────┐ │
│ │ [Icon] {label.completed} │ │ ← Completed state box
│ │ {label.subtext} │ │ uses {color.status-positive} or {color.status-negative}
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
```
#### Side Card Type 3: Progress Indicator
```
┌─────────────────────────────┐
│ {label.progressTitle} │ ← CardHeader pb-3
├─────────────────────────────┤
│ ████████░░░░░░ 70% │ ← flex items-center gap-3
│ │ bar: w-full bg-muted rounded-full h-3
│ │ fill: rounded-full h-3, width={percent}%
│ │ fill color: threshold-based from {color.status-*}
│ │ label: text-lg font-bold
└─────────────────────────────┘
```
#### Side Card Type 4: Quick Links / Metadata
```
┌─────────────────────────────┐
│ {label.infoTitle} │ ← CardHeader pb-3
├─────────────────────────────┤
│ {label.key1} {value1} │ ← flex justify-between text-sm
│ {label.key2} {value2} │ value can be: text | Link | Badge
│ {label.key3} <Badge> │
│ {label.key4} {value4} │
└─────────────────────────────┘
```
---
### 2.5 Dialog Pattern (Action Confirmation)
```
┌───────────────────────────────────────┐
│ {action.confirmTitle} │ ← DialogTitle
│ {entity.code} - {entity.title} │ ← DialogDescription
│ {label.metric}: {value} │
│ │
│ [Warning Box] (reject mode only) │ ← flex items-start gap-2 p-3 rounded-lg
│ {label.rejectWarning} │ uses {color.status-negative} light
│ │
│ {label.commentField} │ ← label text-sm font-medium
│ ┌─────────────────────────────────┐ │
│ │ {placeholder.comment} │ │ ← Textarea
│ └─────────────────────────────────┘ │
│ │
│ [Cancel] [Confirm] │ ← DialogFooter
└───────────────────────────────────────┘
```
---
## 3. Template B — Entity List Page
**Used by**: Approvals List (adaptable for any entity collection)
### 3.1 Page Skeleton
```
┌─────────────────────────────────────────────────────────┐
│ Page Title │ ← Page Header
│ {label.subtitle} ({count}) │
├─────────────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ ← Summary Row
│ │ Stat 1 │ │ Stat 2 │ │ Stat 3 │ │ grid 1col sm:3cols
│ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐│
│ │ Item Card 1 ││ ← Item Cards
│ │ Info | Metric | Progress + Actions ││ space-y-4
│ │ ───────────────────────────────── ││
│ │ Inline Timeline ││
│ └─────────────────────────────────────────────────────┘│
│ ┌─────────────────────────────────────────────────────┐│
│ │ Item Card 2 ││
│ │ ... ││
│ └─────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────┤
│ <Dialog /> │ ← Action Dialog
└─────────────────────────────────────────────────────────┘
```
### 3.2 Section Specifications
#### A. Page Header
```
Container: (no wrapper needed)
──────────────────────────────
<h1>{label.pageTitle}</h1> ← text-2xl font-bold tracking-tight
<p className="text-muted-foreground">
{label.subtitle} ({count})
</p>
```
#### B. Summary Row
```
Container: grid grid-cols-1 sm:grid-cols-3 gap-4
──────────────────────────────────────────────────
┌─────────────────────┐
│ [IconBox] {value} │ ← flex items-center gap-3
│ {label} │ ← value: text-2xl font-bold
└─────────────────────┘ label: text-xs text-muted-foreground
```
**Stat card pattern:**
```jsx
<Card>
<CardContent className="p-4 flex items-center gap-3">
<div className="p-2 rounded-lg {color.surface}">
<{icon.stat} className="h-5 w-5 {color.icon}" />
</div>
<div>
<p className="text-2xl font-bold">{value}</p>
<p className="text-xs text-muted-foreground">{label}</p>
</div>
</CardContent>
</Card>
```
#### C. Item Card
```
Container: Card hover:shadow-md transition-shadow
──────────────────────────────────────────────────
┌───────────────────────────────────────────────────────────────────┐
│ CardContent p-5 │
│ ┌─────────────────┬────────────┬───────────────────────────┐ │
│ │ Info (flex-1) │ Metric │ Progress + Actions │ │
│ │ │ (min-w-*) │ (min-w-*) flex-col items-end│ │
│ │ [Code] [Badge*] │ │ [Step Dots] │ │
│ │ Title │ {amount} │ {label.currentStep} │ │
│ │ [Meta items] │ {currency} │ [Btn] [Btn] [Btn] │ │
│ └─────────────────┴────────────┴───────────────────────────┘ │
│ │
│ ─── border-t ─── │
│ {label.timelineTitle} │
│ [Step1 icon + label] [Step2 icon + label] ... │
└──────────────────────────────────────────────────────────────────┘
```
**Responsive behavior:**
- Mobile: `flex-col items-start` — all sections stack vertically
- Desktop (`lg:`): `flex-row items-center` — sections align horizontally
**Info section pattern:**
```
Code link + Status Badge + Type Badge + Branch Badge ← flex items-center gap-2 mb-2
code: Link text-primary hover:underline font-mono
Title ← text-sm font-medium mb-1
Meta items: [Icon] value • [Icon] value • [Icon] value ← flex flex-wrap gap-3 text-xs text-muted
```
**Step dots pattern:**
```
Container: flex items-center gap-1
───────────────────────────────
[●]─[●]─[○]─[○]
1 2 3 4
Each dot: h-6 w-6 rounded-full flex items-center justify-center text-xs font-medium
approved → {color.status-positive}
rejected → {color.status-negative}
pending → {color.status-warning}
content: ✓ | ✗ | {stepNumber}
Connector: w-6 h-0.5 between dots
after approved → {color.status-positive}
otherwise → {color.muted}
```
**Inline timeline (collapsed):**
```
Container: mt-4 pt-4 border-t
───────────────────────────────
{label.timelineTitle}
flex items-start gap-3
[Icon] RoleName: ApproverName ← each step
timestamp
comment (italic)
```
---
## 4. Component Blueprints
### 4.1 Field Grid Cell
Reusable unit for Summary Card field grids.
```
┌──────────────┐
│ {label} │ ← text-xs text-muted-foreground
│ {value} │ ← text-sm (default) | text-sm font-medium (emphasized) | Badge (enum)
└──────────────┘
```
Grid: `grid grid-cols-2 md:grid-cols-4 gap-4`
### 4.2 Icon + Text Row (Metadata)
Used in side cards, info sections, and meta lines.
```
[{icon}] {text} ← flex items-center gap-2 text-sm
[{icon}] {label}: {value} ← icon: h-3.5 w-3.5 text-muted-foreground
```
### 4.3 Linked Entity Row
Used in tabs for related entities (Quotation in Enquiry, etc.).
```
┌─────────────────────────────────────────────────┐
│ Code [Badge] │ ← font-mono text-sm + Badge outline
│ Title Amount | Date │ ← text-sm + text-right values
└─────────────────────────────────────────────────┘
```
Wrapped in `Link``Card hover:shadow-md transition-shadow cursor-pointer mb-3`
### 4.4 Follow-up Row
```
[IconBox] Title ← icon: p-2 rounded-lg bg-muted
Description (optional) ← text-xs text-muted
{label.by} {person} • {label.due} {date} ← text-xs text-muted
```
### 4.5 Audit Timeline Entry
```
● [ActionBadge] Description ← dot: w-2 h-2 rounded-full bg-primary
{person} • {timestamp} ← text-xs text-muted
```
### 4.6 Approval Step Timeline (Vertical — Detail Page)
```
┌───┐
│ ✓ │ ← h-8 w-8 rounded-full, status-colored
└─┬─┘
│ ← w-0.5 flex-1 min-h-[24px], approved: {color.status-positive} light, else: {color.muted}
┌───┐
│ ○ │
└───┘
Step {n}: {role} [Status Badge] ← text-sm font-medium
{label.by} {approver} ← text-xs text-muted
{timestamp} ← text-xs text-muted
┌─────────────────────────────┐
│ {comment} │ ← text-sm mt-2 p-2.5 rounded-lg bg-muted
└─────────────────────────────┘
[Btn] [Btn] ← inline actions (if step is pending)
```
### 4.7 Empty State
```
[{icon}] ← h-8 w-8 mx-auto mb-2 opacity-50
{label.emptyMessage} ← text-sm text-muted-foreground text-center
[Btn] ← variant="outline" size="sm" mt-3
```
---
## 5. Slot Reference
Quick reference for what goes where when composing a new page from these templates.
### Detail Page Slots
| Slot | Location | Required | Content |
|---|---|---|---|
| `header.backLink` | Header left | ✅ | Link to list page |
| `header.code` | Header center-left | ✅ | Entity business code |
| `header.badges` | Header center-left | — | StatusBadge + 0..N extra badges |
| `header.subtitle` | Header center-left | ✅ | Entity display name / description |
| `header.actions` | Header right | — | 0..N outline/primary buttons |
| `actionRow` | Below header | — | Status-driven action buttons |
| `previewPanel` | Below actionRow | — | Collapsible preview (PDF, etc.) |
| `progressBar` | Below previewPanel | — | Step progress indicator |
| `main.summary` | Main col, 1st card | ✅ | Field grid with entity core data |
| `main.secondary*` | Main col, 2nd..Nth | — | Customer roles, table, topics |
| `main.tabs` | Main col, last | ✅ | Tabbed content area |
| `side.metric` | Side col, 1st card | — | Amount/quantity summary |
| `side.currentState` | Side col, 2nd card | — | Current workflow step + inline actions |
| `side.progress` | Side col, 3rd card | — | Progress bar (chance %, completion) |
| `side.quickInfo` | Side col, last card | — | Key-value pairs with optional links/badges |
| `dialog` | Overlay | — | Confirmation dialog for actions |
### List Page Slots
| Slot | Location | Required | Content |
|---|---|---|---|
| `pageHeader.title` | Top | ✅ | Page heading + subtitle |
| `summaryRow` | Below header | — | 3 stat cards |
| `itemCard.info` | Card left | ✅ | Code link, badges, title, metadata |
| `itemCard.metric` | Card center | — | Primary numeric value |
| `itemCard.progress` | Card right | — | Step dots + current step label |
| `itemCard.actions` | Card right | — | Action buttons (detail, approve, reject) |
| `itemCard.timeline` | Card bottom | — | Collapsed inline timeline |
| `dialog` | Overlay | — | Action confirmation dialog |
---
## Appendix: Page → Template Mapping
| Page | Template | Custom Slots Used |
|---|---|---|
| Enquiry Detail | A | summary, tabs (quotations, followups, timeline), side (customer, project, chance) |
| Quotation Detail | A | summary, customers, items table, topics, tabs (approval, followups, attachments, audit), side (amount, chance, quickInfo) + previewPanel + actionRow |
| Approval Detail | A | summary, linked-quotation, tabs (steps, followups, audit), side (amount, currentState, chance, quickInfo) + progressBar + actionRow + dialog |
| Approvals List | B | summaryRow, itemCards with stepDots + timeline, dialog |
---
*End of Layout Templates*