Initial commit
This commit is contained in:
214
references/design-patterns.md
Normal file
214
references/design-patterns.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# Bubble Tea Design Patterns
|
||||
|
||||
Common architectural patterns for TUI development.
|
||||
|
||||
## Pattern 1: Single-View Application
|
||||
|
||||
**When**: Simple, focused TUIs with one main view
|
||||
**Components**: 1-3 components, single model struct
|
||||
**Complexity**: Low
|
||||
|
||||
```go
|
||||
type model struct {
|
||||
mainComponent component.Model
|
||||
ready bool
|
||||
}
|
||||
```
|
||||
|
||||
## Pattern 2: Multi-View State Machine
|
||||
|
||||
**When**: Multiple distinct screens (setup, main, done)
|
||||
**Components**: State enum + view-specific components
|
||||
**Complexity**: Medium
|
||||
|
||||
```go
|
||||
type view int
|
||||
const (
|
||||
setupView view = iota
|
||||
mainView
|
||||
doneView
|
||||
)
|
||||
|
||||
type model struct {
|
||||
currentView view
|
||||
// Components for each view
|
||||
}
|
||||
```
|
||||
|
||||
## Pattern 3: Composable Views
|
||||
|
||||
**When**: Complex UIs with reusable sub-components
|
||||
**Pattern**: Embed multiple bubble models
|
||||
**Example**: Dashboard with multiple panels
|
||||
|
||||
```go
|
||||
type model struct {
|
||||
panel1 Panel1Model
|
||||
panel2 Panel2Model
|
||||
panel3 Panel3Model
|
||||
}
|
||||
|
||||
// Each panel is itself a Bubble Tea model
|
||||
```
|
||||
|
||||
## Pattern 4: Master-Detail
|
||||
|
||||
**When**: Selection in one pane affects display in another
|
||||
**Example**: File list + preview, Email list + content
|
||||
**Layout**: Two-pane or three-pane
|
||||
|
||||
```go
|
||||
type model struct {
|
||||
list list.Model
|
||||
detail viewport.Model
|
||||
selectedItem int
|
||||
}
|
||||
```
|
||||
|
||||
## Pattern 5: Form Flow
|
||||
|
||||
**When**: Multi-step data collection
|
||||
**Pattern**: Array of inputs + focus management
|
||||
**Example**: Configuration wizard
|
||||
|
||||
```go
|
||||
type model struct {
|
||||
inputs []textinput.Model
|
||||
focusIndex int
|
||||
step int
|
||||
}
|
||||
```
|
||||
|
||||
## Pattern 6: Progress Tracker
|
||||
|
||||
**When**: Long-running sequential operations
|
||||
**Pattern**: Queue + progress per item
|
||||
**Example**: Installation, download manager
|
||||
|
||||
```go
|
||||
type model struct {
|
||||
items []Item
|
||||
currentIndex int
|
||||
progress progress.Model
|
||||
spinner spinner.Model
|
||||
}
|
||||
```
|
||||
|
||||
## Layout Patterns
|
||||
|
||||
### Vertical Stack
|
||||
```go
|
||||
lipgloss.JoinVertical(lipgloss.Left,
|
||||
header,
|
||||
content,
|
||||
footer,
|
||||
)
|
||||
```
|
||||
|
||||
### Horizontal Panels
|
||||
```go
|
||||
lipgloss.JoinHorizontal(lipgloss.Top,
|
||||
leftPanel,
|
||||
separator,
|
||||
rightPanel,
|
||||
)
|
||||
```
|
||||
|
||||
### Three-Column (File Manager Style)
|
||||
```go
|
||||
lipgloss.JoinHorizontal(lipgloss.Top,
|
||||
parentDir, // 25% width
|
||||
currentDir, // 35% width
|
||||
preview, // 40% width
|
||||
)
|
||||
```
|
||||
|
||||
## Message Passing Patterns
|
||||
|
||||
### Custom Messages
|
||||
```go
|
||||
type myCustomMsg struct {
|
||||
data string
|
||||
}
|
||||
|
||||
func doSomethingCmd() tea.Msg {
|
||||
return myCustomMsg{data: "result"}
|
||||
}
|
||||
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case myCustomMsg:
|
||||
// Handle custom message
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Async Operations
|
||||
```go
|
||||
func fetchDataCmd() tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
// Do async work
|
||||
data := fetchFromAPI()
|
||||
return dataFetchedMsg{data}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling Pattern
|
||||
|
||||
```go
|
||||
type errMsg struct{ err error }
|
||||
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case errMsg:
|
||||
m.err = msg.err
|
||||
m.errVisible = true
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Keyboard Navigation Pattern
|
||||
|
||||
```go
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "up", "k":
|
||||
m.cursor--
|
||||
case "down", "j":
|
||||
m.cursor++
|
||||
case "enter":
|
||||
m.selectCurrent()
|
||||
case "q", "ctrl+c":
|
||||
return m, tea.Quit
|
||||
}
|
||||
```
|
||||
|
||||
## Responsive Layout Pattern
|
||||
|
||||
```go
|
||||
case tea.WindowSizeMsg:
|
||||
m.width = msg.Width
|
||||
m.height = msg.Height
|
||||
|
||||
// Update component dimensions
|
||||
m.viewport.Width = msg.Width
|
||||
m.viewport.Height = msg.Height - 5 // Reserve space for header/footer
|
||||
```
|
||||
|
||||
## Help Overlay Pattern
|
||||
|
||||
```go
|
||||
type model struct {
|
||||
showHelp bool
|
||||
help help.Model
|
||||
}
|
||||
|
||||
func (m model) View() string {
|
||||
if m.showHelp {
|
||||
return m.help.View()
|
||||
}
|
||||
return m.mainView()
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user