Files
alla-allaos-fullstack/LAYOUT.md
phaichayon 7a390cf0df init
2026-06-11 12:46:57 +07:00

34 KiB

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
  2. Template A — Entity Detail Page
  3. Template B — Entity List Page
  4. Component Blueprints
  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:

<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
└─────────────────────────────┘
┌─────────────────────────────┐
│  {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:

<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 LinkCard 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