# 3.1 — Tab Bar & Document Lifecycle

**Next Step:** → [Sidebar](../../04-file-organization/4.1-sidebar/4.1-sidebar.md)

---

## Page Metadata

| Property | Value |
|----------|-------|
| **Scenario** | 03 — Document Management |
| **Page Number** | 3.1 |
| **Platform** | Web (PWA), portable to macOS/Windows |
| **Page Type** | Embedded Strip (within App Shell, between header and editor) |

---

## Overview

**Page Purpose:** Enable multi-document workflow. Users can open, create, close, reorder, and rename documents via tabs. The tab bar is the primary navigation between open documents.

**Success Criteria:**
- Switching tabs feels instant (< 50ms)
- Users never lose work (auto-save before switch)
- Tab state survives page reload
- 15+ tabs remain usable (horizontal scroll)

---

## Layout Structure

```
┌──────────────────────────────────────────────────────────┐
│ [● Budget ×] [  Invoice ×] [  Unit Conv ×]  [+]    ··· │  36px
└──────────────────────────────────────────────────────────┘
  ● = unsaved changes dot
  Active tab: connected to editor (no bottom border)
  [+] = new document button
  ··· = overflow gradient when scrollable
```

---

## Spacing

| Property | Token | Pixels |
|----------|-------|--------|
| Tab bar height | — | 36px |
| Tab padding horizontal | space-sm | 8px |
| Tab gap | — | 0px (tabs are flush, separated by 1px border) |
| Tab min width | — | 100px |
| Tab max width | — | 200px |
| Close button size | — | 16px × 16px |
| Close button margin-left | space-xs | 6px |
| Modified dot size | — | 6px |
| Modified dot margin-right | space-2xs | 4px |
| New tab button width | — | 36px (square) |

---

## Typography

| Element | Size | Weight | Color |
|---------|------|--------|-------|
| Tab label (active) | text-xs | 500 | var(--text-h) |
| Tab label (inactive) | text-xs | 400 | var(--text) |
| Close × | text-xs | 400 | var(--text) at 50%, hover → var(--text) |
| New + icon | text-sm | 300 | var(--text), hover → var(--accent) |

---

## Tab States

### Active Tab

| Property | Value |
|----------|-------|
| Background | var(--bg) — same as editor, creates visual connection |
| Border bottom | None — tab "opens into" the editor |
| Border left/right | 1px solid var(--border) |
| Border top | 2px solid var(--accent) — active indicator |
| Label | Weight 500, var(--text-h) |
| Close button | Always visible |

### Inactive Tab

| Property | Value |
|----------|-------|
| Background | var(--bg-secondary) |
| Border bottom | 1px solid var(--border) — closed off from editor |
| Border left/right | 1px solid var(--border) |
| Border top | 2px solid transparent |
| Label | Weight 400, var(--text) |
| Close button | Visible on hover only |

### Hover (Inactive)

| Property | Value |
|----------|-------|
| Background | Blend between bg-secondary and bg (subtle lighten) |
| Transition | background 0.1s |

### Dragging

| Property | Value |
|----------|-------|
| Appearance | Tab lifts with subtle shadow (0 2px 8px rgba(0,0,0,0.15)) |
| Opacity | 90% |
| Placeholder | 2px var(--accent) vertical line at insertion point |
| Cursor | grabbing |

---

## Interactions

| Action | Behavior |
|--------|----------|
| **Click tab** | Switch to document. Auto-save current. Restore editor state (content, cursor, scroll, undo). |
| **Click +** | Create "Untitled" doc, open in new tab, focus editor. |
| **Click ×** | Close tab. If unsaved and modified, no prompt (auto-saved). Remove from openTabIds. |
| **Middle-click tab** | Close tab (same as ×). |
| **Double-click tab** | Inline rename — label becomes input field, Enter confirms, Esc cancels. |
| **Drag tab** | Reorder. Drop position shown by accent line indicator. |
| **Ctrl/Cmd+Tab** | Next tab (wraps). |
| **Ctrl/Cmd+Shift+Tab** | Previous tab (wraps). |
| **Ctrl/Cmd+W** | Close active tab. If last tab, create new "Untitled". |
| **Ctrl/Cmd+N** | New document + tab. |
| **Ctrl/Cmd+1–9** | Jump to tab by position. |
| **Mouse wheel on tab bar** | Horizontal scroll when tabs overflow. |

---

## Tab Overflow

| Property | Value |
|----------|-------|
| Trigger | Total tab width > container width |
| Scroll | Horizontal, smooth, via mouse wheel or trackpad |
| Indicators | 16px fade gradient on left/right edges when scrollable |
| Active tab | Auto-scrolls into view when selected via keyboard |
| New tab button | Sticky right — always visible outside scroll area |

---

## Document Lifecycle

### Create

| Trigger | Behavior |
|---------|----------|
| Click [+] | New doc: `{ id: uuid(), title: "Untitled", content: "", folderId: null }` |
| Sidebar template click | New doc with template content and suggested title |
| Ctrl/Cmd+N | Same as [+] |

Title auto-increments: "Untitled", "Untitled 2", "Untitled 3"...

### Rename

| Trigger | Behavior |
|---------|----------|
| Double-click tab | Label becomes `<input>`, pre-selected text, 200px max width |
| Sidebar right-click → Rename | Same inline editing in sidebar |
| Enter | Confirm rename, update document and sidebar |
| Esc | Cancel, revert to previous name |
| Blur | Confirm (same as Enter) |
| Empty name | Revert to "Untitled" |

### Delete

| Trigger | Behavior |
|---------|----------|
| Sidebar right-click → Delete | Confirmation: "Delete '{title}'? This cannot be undone." |
| Confirm | Remove from documents[], close tab if open, remove from folder |
| Cancel | No action |
| Undo | 5-second toast: "Document deleted. [Undo]" — restores document if clicked |

### Duplicate

| Trigger | Behavior |
|---------|----------|
| Sidebar right-click → Duplicate | New doc: same content, title = "{original} (copy)", same folder |
| Opens in new tab automatically |

### Auto-Save

| Property | Value |
|----------|-------|
| Trigger | Document content change |
| Debounce | 500ms after last keystroke |
| Storage | localStorage (calctext-documents) |
| Indicator | Modified dot (●) appears immediately on change, disappears on save |
| Manual save | Ctrl/Cmd+S shows brief checkmark animation in tab (visual confirmation) |

---

## Modified Indicator

| Property | Value |
|----------|-------|
| Shape | Filled circle, 6px |
| Color | var(--text) at 60% |
| Position | Before tab label, 4px gap |
| Appears | On first character change |
| Disappears | On auto-save completion (500ms debounce) |
| Animation | Fade in 0.2s |

---

## Context Menu (Right-Click Tab)

| Item | Action |
|------|--------|
| Close | Close this tab |
| Close Others | Close all tabs except this one |
| Close to the Right | Close all tabs to the right |
| — | (separator) |
| Rename | Inline rename |
| Duplicate | Duplicate document |
| — | (separator) |
| Reveal in Sidebar | Scroll sidebar to show this file |

---

## Mobile Adaptations

| Property | Value |
|----------|-------|
| Tab bar | Horizontal scroll, touch-friendly |
| Tab height | 40px (larger touch target) |
| Close button | Hidden — swipe left on tab to reveal close |
| New tab | [+] button at far right |
| Rename | Long-press → context menu → Rename |
| Reorder | Long-press + drag |

---

## Page States

| State | When | Behavior |
|-------|------|----------|
| **Single tab** | Only one document open | Tab still shown (establishes pattern). Close creates new "Untitled". |
| **Many tabs (>10)** | Heavy usage | Horizontal scroll. Active tab auto-scrolls into view. |
| **All tabs closed** | User closed everything | Auto-create "Untitled" tab (workspace never empty). |
| **First launch** | No localStorage | Single "Welcome" tab with demo content. |

---

## Technical Notes

- **Tab switching performance:** Store `EditorState` per tab in memory. On switch: destroy current EditorView, create new with stored state. Content swap < 20ms.
- **Tab order persistence:** `openTabIds: string[]` in localStorage maintains order.
- **Cross-platform:** Maps to native tab bars. macOS: NSTabView or custom tab strip. Windows: iced tabs widget.
- **Max tabs:** Soft limit at 20 with performance hint in status bar. No hard limit.

---

_Created using Whiteport Design Studio (WDS) methodology_
