diff --git a/docs/requirements.md b/docs/requirements.md index c5c1a74..59c588f 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -42,7 +42,8 @@ commit hashes. It doesn't answer the questions users actually have: ### State per submodule - **F10** Each submodule shows at most **one** state word: the most severe - issue, plus `+n` if there are more. Submodules without issues show no word. + issue, plus `+n` if there are more. Submodules without issues show a + muted `in sync`. See [state-model.md](state-model.md) for the full rules. - **F11** Each submodule shows its pin as a ref (`origin/main`, a tag, or a short SHA as a fallback) and the distance to that ref (`↑n`, `↓n`, `↑n↓m`). diff --git a/docs/ux-guide.md b/docs/ux-guide.md index a6448b4..d0c1ade 100644 --- a/docs/ux-guide.md +++ b/docs/ux-guide.md @@ -47,13 +47,15 @@ indent ▸ name [n] status ref delta | indent | 2 per depth | | | toggle | 3 | `▸` collapsed, `▾` expanded, blank for leaves | | name | fits the widest visible name | name, `[n]` = direct children (collapsed only) | -| status | 14 | issue word, `+n`, `·k` hidden issues; spinner while loading | +| status | 14 | issue word, `+n`, `·k` hidden issues; muted `in sync` without issues; spinner while loading | | ref | widest ref, max 22 | resolved ref; muted short SHA if unresolved | | delta | 6 | `↑n`, `↓n`, `↑n↓m` | - The name column is only as wide as needed, so states stay close to names. - Directory headers (`src/`, `modules/`) are muted and not selectable. -- Rows without issues: name and ref muted (except the selected row). +- Rows without issues: name and ref muted (except the selected row), status + `in sync` in muted grey. An empty status cell would look like missing + data; the muted word confirms the check ran without drawing attention. ### Detail pane diff --git a/internal/tui/detail/detail.go b/internal/tui/detail/detail.go index ae44621..49fd382 100644 --- a/internal/tui/detail/detail.go +++ b/internal/tui/detail/detail.go @@ -74,7 +74,7 @@ func (m Model) lines(s *submodule.Submodule) []string { out = append(out, t.LevelStyle(is.Level, lipgloss.NewStyle()).Width(labelWidth).Render(theme.IssueWord(is.Kind))+text.Render(is.Detail)) } if len(issues) == 0 { - out = append(out, label("in sync")+muted.Render("nothing to do")) + out = append(out, label(theme.InSync)+muted.Render("nothing to do")) } if st.PinStaged { out = append(out, theme.Fg(t.Info).Width(labelWidth).Render("staged")+text.Render("pin change staged, not committed")) diff --git a/internal/tui/theme/issues.go b/internal/tui/theme/issues.go index 2aa0c7b..7287435 100644 --- a/internal/tui/theme/issues.go +++ b/internal/tui/theme/issues.go @@ -9,6 +9,9 @@ import ( "submarine/internal/submodule" ) +// InSync is the word for a submodule without issues. +const InSync = "in sync" + // IssueWord is the short label for an issue kind shown in the tree. func IssueWord(k submodule.IssueKind) string { switch k { diff --git a/internal/tui/tree/tree.go b/internal/tui/tree/tree.go index 92b2ded..7e81868 100644 --- a/internal/tui/tree/tree.go +++ b/internal/tui/tree/tree.go @@ -398,7 +398,8 @@ func (m Model) nodeLine(r row, nameColW, refW int) string { name := ansi.Truncate(s.Name, max(nameW-len(count), 1), "…") nameCell := seg(textColor, name) + seg(t.Muted, count) + pad(nameW-lipgloss.Width(name+count)) - // status: the most severe issue as a word, "+n" for further issues + // status: the most severe issue as a word, "+n" for further issues; + // a muted "in sync" without issues, so an empty cell never looks broken var status string switch { case s.Err != nil: @@ -410,6 +411,8 @@ func (m Model) nodeLine(r row, nameColW, refW int) string { if len(issues) > 1 { status += seg(t.Muted, fmt.Sprintf(" +%d", len(issues)-1)) } + default: + status = seg(t.Muted, theme.InSync) } if k, worst := s.HiddenIssues(); collapsed && k > 0 { if status != "" {