Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
.vscode/
.mypy_cache/
.idea
hostkey
hostkey.pub
.pub
ssh_dashboard
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- **Flex**: Mixed fixed/proportional layouts.
- **Grid**: 12-column dynamic grid system.
- **Absolutes**: Exact coordinates when needed.
- **🌐 SSH / Remote Apps**: Turn any TUI into a zero-install SSH accessible application (multi-tenant support).
- **📊 Rich Widgets**:
- **Charts**: BarChart, StackedBarChart, PieChart, DonutChart, RadarChart (Spider), FunnelChart, TreeMap, Sparkline, Plot (Scatter/Line).
- **Gauges**: Gauge, LineGauge (with pixel-perfect Braille/Block styles).
Expand All @@ -45,6 +46,7 @@
| **Pixel-Perfect** | **Yes** (Braille/Block/Space) | No |
| **Mouse Support** | **Full** (Wheel/Click/Drag) | Click |
| **TrueColor** | **Yes** | No |
| **SSH / Multi-User** | **Native** (Backend API) | No (Global State) |
| **Modern Terminal Support** | **All** (iterm, ghostty, etc.) | No |

## 📦 Installation
Expand Down Expand Up @@ -138,6 +140,7 @@ Run individual examples: `go run _examples/<name>/main.go`
| **Radarchart** | <img src="_examples/radarchart/screenshot.png" height="80" /> | [View Example Code](_examples/radarchart/main.go) |
| **Scrollbar** | <img src="_examples/scrollbar/screenshot.png" height="80" /> | [View Example Code](_examples/scrollbar/main.go) |
| **Sparkline** | <img src="_examples/sparkline/screenshot.png" height="80" /> | [View Example Code](_examples/sparkline/main.go) |
| **SSH Dashboard** | <img src="_examples/dashboard/screenshot.png" height="80" /> | [View Example Code](_examples/ssh-dashboard/main.go) |

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The image reference points to _examples/dashboard/screenshot.png but this is for the SSH Dashboard example. The path should likely be _examples/ssh-dashboard/screenshot.png to match the example's actual directory name.

Suggested change
| **SSH Dashboard** | <img src="_examples/dashboard/screenshot.png" height="80" /> | [View Example Code](_examples/ssh-dashboard/main.go) |
| **SSH Dashboard** | <img src="_examples/ssh-dashboard/screenshot.png" height="80" /> | [View Example Code](_examples/ssh-dashboard/main.go) |

Copilot uses AI. Check for mistakes.
| **Stacked Barchart** | <img src="_examples/stacked_barchart/screenshot.png" height="80" /> | [View Example Code](_examples/stacked_barchart/main.go) |
| **Table** | <img src="_examples/table/screenshot.png" height="80" /> | [View Example Code](_examples/table/main.go) |
| **Tabs** | <img src="_examples/tabs/screenshot.png" height="80" /> | [View Example Code](_examples/tabs/main.go) |
Expand Down Expand Up @@ -172,6 +175,29 @@ for e := range uiEvents {
}
```

### 🌐 Serving over SSH

You can easily serve your TUI over SSH (like standard CLI apps) using `ui.InitWithConfig` and a library like `gliderlabs/ssh`.

```go
func sshHandler(sess ssh.Session) {
// 1. Create a custom backend for this session
app, _ := ui.NewBackend(&ui.InitConfig{
CustomTTY: sess, // ssh.Session implements io.ReadWriter
})
Comment on lines +185 to +187

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code example shows error handling with _ (ignored errors) which is not a good practice to demonstrate in documentation. Consider showing proper error handling with return or log.Fatal to set a better example for users.

Suggested change
app, _ := ui.NewBackend(&ui.InitConfig{
CustomTTY: sess, // ssh.Session implements io.ReadWriter
})
app, err := ui.NewBackend(&ui.InitConfig{
CustomTTY: sess, // ssh.Session implements io.ReadWriter
})
if err != nil {
// handle error appropriately, e.g., log or return
return
}

Copilot uses AI. Check for mistakes.
defer app.Close()

// 2. Use the app instance instead of global ui.* functions
p := widgets.NewParagraph()
p.Text = "Hello SSH User!"
p.SetRect(0, 0, 20, 5)

app.Render(p) // Renders to the SSH client only!
}
```

Check `_examples/ssh-dashboard` for a full multi-user demo.

## 🤝 Contributing

Contributions are welcome! Please submit a Pull Request.
Expand Down
20 changes: 20 additions & 0 deletions _examples/ssh-dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SSH Dashboard Example

This example demonstrates the **SSH Dashboard** widget/feature.

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says "SSH Dashboard widget/feature" but this is not a widget, it's a complete example application demonstrating how to use gotui over SSH. Consider changing to "This example demonstrates serving a gotui dashboard over SSH" or similar to avoid confusion.

Suggested change
This example demonstrates the **SSH Dashboard** widget/feature.
This example demonstrates serving a gotui dashboard over SSH.

Copilot uses AI. Check for mistakes.

## 🚀 Run

```bash
$ ssh-keygen -t ed25519 -f hostkey -N "" # Generate sample host key
$ go run _examples/stacked_barchart/main.go

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command references the wrong example path. It should reference ssh-dashboard/main.go instead of stacked_barchart/main.go.

Suggested change
$ go run _examples/stacked_barchart/main.go
$ go run _examples/ssh-dashboard/main.go

Copilot uses AI. Check for mistakes.
```

In a separate window:

```bash
$ ssh 0.0.0.0 -p 2222
```

## 📝 Code

See [main.go](main.go) for the implementation.
Loading