Skip to content

Commit 39ff715

Browse files
polish tiny mode centering, help menu, processes panel, demo tape
tiny: center vertically and horizontally via centerFrame instead of only horizontal centerInline; wraps output in full terminal frame help: only ? toggles help now; removed default key handler that closed help on any keypress; text updated to press ? to return processes: redesigned with rounded indigo border matching help menu aesthetic, consistent padding, muted separators, cleaner table layout tape: add n key demo for network processes panel; bump curl max-time values by 10s to compensate; tighten some sleep durations mod: go mod tidy adds indirect deps for gopsutil process pkg
1 parent 9341a5f commit 39ff715

6 files changed

Lines changed: 89 additions & 61 deletions

File tree

docs/demo.gif

-2.14 MB
Loading

flow.tape

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,31 +49,30 @@ Ctrl+L
4949
Sleep 300ms
5050

5151
# Steady medium-contention traffic — long-running throttled downloads
52-
# All --max-time values are generous to cover the full demo duration
53-
Type "curl -L --limit-rate 4M --max-time 65 -o /dev/null https://speed.hetzner.de/100MB.bin &>/dev/null &"
52+
Type "curl -L --limit-rate 4M --max-time 75 -o /dev/null https://speed.hetzner.de/100MB.bin &>/dev/null &"
5453
Enter
5554
Sleep 400ms
56-
Type "curl -L --limit-rate 3M --max-time 60 -o /dev/null https://proof.ovh.net/files/100Mb.dat &>/dev/null &"
55+
Type "curl -L --limit-rate 3M --max-time 70 -o /dev/null https://proof.ovh.net/files/100Mb.dat &>/dev/null &"
5756
Enter
5857
Sleep 400ms
59-
Type "curl -L --limit-rate 5M --max-time 62 -o /dev/null https://speed.hetzner.de/100MB.bin &>/dev/null &"
58+
Type "curl -L --limit-rate 5M --max-time 72 -o /dev/null https://speed.hetzner.de/100MB.bin &>/dev/null &"
6059
Enter
6160
Sleep 400ms
62-
Type "curl -L --limit-rate 2M --max-time 55 -o /dev/null https://proof.ovh.net/files/100Mb.dat &>/dev/null &"
61+
Type "curl -L --limit-rate 2M --max-time 65 -o /dev/null https://proof.ovh.net/files/100Mb.dat &>/dev/null &"
6362
Enter
6463
Sleep 400ms
65-
Type "curl -L --limit-rate 3M --max-time 68 -o /dev/null https://speed.hetzner.de/100MB.bin &>/dev/null &"
64+
Type "curl -L --limit-rate 3M --max-time 78 -o /dev/null https://speed.hetzner.de/100MB.bin &>/dev/null &"
6665
Enter
6766
Sleep 400ms
68-
Type "curl -X POST --limit-rate 3M --max-time 58 -o /dev/null https://httpbin.org/post &>/dev/null &"
67+
Type "curl -X POST --limit-rate 3M --max-time 68 -o /dev/null https://httpbin.org/post &>/dev/null &"
6968
Enter
7069
Sleep 400ms
7170

7271
# Small delayed bumps for visual texture on the steady baseline
73-
Type "(sleep 6; curl -L --limit-rate 4M --max-time 45 -o /dev/null https://speed.hetzner.de/100MB.bin &>/dev/null) &"
72+
Type "(sleep 6; curl -L --limit-rate 4M --max-time 55 -o /dev/null https://speed.hetzner.de/100MB.bin &>/dev/null) &"
7473
Enter
7574
Sleep 400ms
76-
Type "(sleep 12; curl -L --limit-rate 3M --max-time 40 -o /dev/null https://proof.ovh.net/files/100Mb.dat &>/dev/null) &"
75+
Type "(sleep 12; curl -L --limit-rate 3M --max-time 50 -o /dev/null https://proof.ovh.net/files/100Mb.dat &>/dev/null) &"
7776
Enter
7877
Sleep 400ms
7978

@@ -89,7 +88,7 @@ Sleep 3s
8988

9089
# Reveal — hero logo, breathing dot, subtitle, traffic flowing
9190
Show
92-
Sleep 6s
91+
Sleep 5s
9392

9493
# Reset peaks
9594
Type "r"
@@ -111,22 +110,28 @@ Sleep 2s
111110
Type "c"
112111
Sleep 2s
113112

114-
# Pause — hold longer to show the frozen state
113+
# Pause — hold to show the frozen state
115114
Type "p"
116-
Sleep 4s
115+
Sleep 3s
117116

118117
# Resume
119118
Type "p"
120119
Sleep 2s
121120

122121
# Show the help overlay
123122
Type "?"
124-
Sleep 4s
123+
Sleep 3s
125124
Type "?"
126125
Sleep 2s
127126

128-
# Let the fresh burst animate through
127+
# Show the network processes panel
128+
Type "n"
129129
Sleep 4s
130+
Type "n"
131+
Sleep 2s
132+
133+
# Let the traffic animate through
134+
Sleep 3s
130135

131136
# Hide before quitting so the GIF ends on the clean TUI screen
132137
Hide

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ require (
2323
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
2424
github.com/go-ole/go-ole v1.2.6 // indirect
2525
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
26+
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
2627
github.com/mattn/go-isatty v0.0.20 // indirect
2728
github.com/mattn/go-localereader v0.0.1 // indirect
2829
github.com/mattn/go-runewidth v0.0.19 // indirect
@@ -31,6 +32,9 @@ require (
3132
github.com/muesli/termenv v0.16.0 // indirect
3233
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
3334
github.com/rivo/uniseg v0.4.7 // indirect
35+
github.com/shoenig/go-m1cpu v0.1.6 // indirect
36+
github.com/tklauser/go-sysconf v0.3.12 // indirect
37+
github.com/tklauser/numcpus v0.6.1 // indirect
3438
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
3539
github.com/yusufpapurcu/wmi v1.2.4 // indirect
3640
golang.org/x/sys v0.38.0 // indirect

go.sum

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,13 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6
2828
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
2929
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
3030
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
31+
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
32+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
33+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
3134
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
3235
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
36+
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
37+
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
3338
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
3439
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
3540
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
@@ -50,8 +55,16 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
5055
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
5156
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
5257
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
58+
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
59+
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
60+
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
61+
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
5362
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
5463
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
64+
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
65+
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
66+
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
67+
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
5568
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
5669
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
5770
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
@@ -62,9 +75,12 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w
6275
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
6376
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
6477
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
78+
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
79+
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
6580
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
6681
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
6782
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
6883
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
84+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
6985
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
7086
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/ui/model.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,6 @@ func (m Model) handleKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
237237
}
238238

239239
default:
240-
if m.showHelp {
241-
m.showHelp = false
242-
}
243240
}
244241

245242
return m, nil

internal/ui/views.go

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@ func renderTiny(m Model) string {
2828
left := lbl.Render("↓ download") + " " + theme.ValuePrimary(downRatio, true).Render(m.FormatBps(m.dispDown))
2929
right := lbl.Render("↑ upload") + " " + theme.ValuePrimary(upRatio, false).Render(m.FormatBps(m.dispUp))
3030
line := left + " " + right
31-
if m.width > 0 {
32-
return centerInline(line, m.width)
31+
w := m.width
32+
if w <= 0 {
33+
w = 80
3334
}
34-
return line
35+
h := m.height
36+
if h <= 0 {
37+
h = 24
38+
}
39+
return centerFrame(line, w, h)
3540
}
3641

3742
func renderProcesses(m Model) string {
@@ -49,25 +54,21 @@ func renderProcesses(m Model) string {
4954
contentW = max(termW-2, 40)
5055
}
5156

52-
title := lipgloss.NewStyle().
57+
titleStyle := lipgloss.NewStyle().
5358
Foreground(lipgloss.Color("#f8fafc")).
54-
Bold(true).
55-
Render("network processes")
59+
Bold(true)
5660

57-
var lines []string
58-
lines = append(lines, " "+title)
59-
lines = append(lines, "")
61+
title := titleStyle.Render("network processes")
62+
63+
var block []string
64+
block = append(block, "")
65+
block = append(block, " "+title)
66+
block = append(block, "")
6067

6168
if len(m.procs) == 0 {
62-
muted := theme.Muted().Render("no active network processes detected")
63-
pad := (contentW - lipgloss.Width(muted)) / 2
64-
if pad < 0 {
65-
pad = 0
66-
}
67-
lines = append(lines, strings.Repeat(" ", pad)+muted)
69+
block = append(block, " "+theme.Muted().Render("no active network processes detected"))
6870
} else {
69-
// Truncate to top entries that fit the terminal height
70-
maxRows := termH - 8
71+
maxRows := termH - 10
7172
if maxRows < 5 {
7273
maxRows = 5
7374
}
@@ -76,47 +77,52 @@ func renderProcesses(m Model) string {
7677
list = list[:maxRows]
7778
}
7879

79-
// Column widths
80+
innerW := contentW - 8
81+
if innerW < 30 {
82+
innerW = 30
83+
}
8084
pidW := 7
81-
nameW := contentW - pidW - 16
85+
nameW := innerW - pidW - 10
8286
if nameW < 10 {
8387
nameW = 10
8488
}
8589

86-
headerKey := lipgloss.NewStyle().
90+
keyStyle := lipgloss.NewStyle().
8791
Foreground(lipgloss.Color("#a5b4fc")).
8892
Bold(true)
89-
headerMuted := theme.Muted()
93+
muted := theme.Muted()
9094

91-
header := fmt.Sprintf(" %s %s %s",
92-
headerKey.Render(fmt.Sprintf("%-*s", pidW, "PID")),
93-
headerKey.Render(fmt.Sprintf("%-*s", nameW, "Process")),
94-
headerKey.Render(fmt.Sprintf("%*s", 7, "Conns")))
95+
pidH := keyStyle.Render(fmt.Sprintf("%-*s", pidW, "PID"))
96+
nameH := keyStyle.Render(fmt.Sprintf("%-*s", nameW, "Process"))
97+
connH := keyStyle.Render(fmt.Sprintf("%*s", 7, "Conns"))
98+
header := fmt.Sprintf(" %s %s %s", pidH, nameH, connH)
9599

96-
sep := theme.Dim().Render(strings.Repeat("─", contentW-2))
97-
lines = append(lines, " "+sep)
98-
lines = append(lines, header)
99-
lines = append(lines, " "+sep)
100+
sep := muted.Render(strings.Repeat("─", innerW+6))
101+
102+
block = append(block, " "+sep)
103+
block = append(block, header)
104+
block = append(block, " "+sep)
100105

101106
for _, p := range list {
102-
pidStr := fmt.Sprintf("%-*d", pidW, p.PID)
103-
nameStr := fmt.Sprintf("%-*s", nameW, truncate(p.Name, nameW))
104-
connStr := fmt.Sprintf("%*d", 7, p.Connections)
105-
106-
row := fmt.Sprintf(" %s %s %s",
107-
headerMuted.Render(pidStr),
108-
theme.Accent().Render(nameStr),
109-
headerKey.Render(connStr))
110-
lines = append(lines, row)
107+
pidS := muted.Render(fmt.Sprintf("%-*d", pidW, p.PID))
108+
nameS := theme.Accent().Render(fmt.Sprintf("%-*s", nameW, truncate(p.Name, nameW)))
109+
connS := keyStyle.Render(fmt.Sprintf("%*d", 7, p.Connections))
110+
block = append(block, fmt.Sprintf(" %s %s %s", pidS, nameS, connS))
111111
}
112-
lines = append(lines, " "+sep)
112+
block = append(block, " "+sep)
113113
}
114114

115-
lines = append(lines, "")
116-
lines = append(lines, " "+theme.Dim().Render("press n to return"))
115+
block = append(block, "")
116+
block = append(block, " "+theme.Dim().Render("press n to return"))
117+
block = append(block, "")
117118

118-
content := strings.Join(lines, "\n")
119-
return centerFrame(content, termW, termH)
119+
box := lipgloss.NewStyle().
120+
Border(lipgloss.RoundedBorder()).
121+
BorderForeground(lipgloss.Color("#6366f1")).
122+
Padding(0, 2).
123+
Render(strings.Join(block, "\n"))
124+
125+
return centerFrame(box, termW, termH)
120126
}
121127

122128
func truncate(s string, max int) string {
@@ -176,7 +182,7 @@ func renderHelp(m Model) string {
176182
block = append(block, "")
177183
block = append(block, keyLines...)
178184
block = append(block, "")
179-
block = append(block, " "+theme.Dim().Render("press any key to return"))
185+
block = append(block, " "+theme.Dim().Render("press ? to return"))
180186
block = append(block, "")
181187

182188
helpBox := lipgloss.NewStyle().

0 commit comments

Comments
 (0)