Skip to content

Commit 3b3f8c8

Browse files
committed
Improve TUI with editable task view and better layout of task detail view
1 parent 3acf65e commit 3b3f8c8

4 files changed

Lines changed: 42 additions & 38 deletions

File tree

internal/tui/app.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,9 +463,12 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
463463
m.detail.commenting = false
464464
m.detail.postErr = ""
465465
return m, nil
466-
case "ctrl+d":
466+
case "enter":
467467
cmd := m.detail.submitComment(m.client)
468468
return m, cmd
469+
case "ctrl+j":
470+
m.detail.input.InsertString("\n")
471+
return m, nil
469472
default:
470473
cmd := m.detail.update(msg)
471474
return m, cmd

internal/tui/deptree.go

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -92,39 +92,38 @@ func buildDepTree(current model.Task, deps []model.Dependency, related map[strin
9292

9393
var b strings.Builder
9494

95-
// Parents (tasks that depend on current task).
96-
for i, p := range parents {
97-
prefix := "├── "
98-
if i == len(parents)-1 && len(children) == 0 && len(relatesTo) == 0 {
99-
prefix = "├── "
100-
}
101-
b.WriteString(renderDepNode(prefix, p) + "\n")
102-
b.WriteString("│\n")
95+
// Parents (tasks that depend on current task) — outer level.
96+
for _, p := range parents {
97+
b.WriteString(renderDepNode("◆ ", p) + "\n")
10398
}
10499

105-
// Current task (highlighted).
100+
// Current task (highlighted) — indented under parents.
106101
currentTitle := current.Title
107102
if len(currentTitle) > 50 {
108103
currentTitle = currentTitle[:47] + "..."
109104
}
110-
b.WriteString(depCurrentStyle.Render(fmt.Sprintf("◆ %s: %s", currentRef, currentTitle)) + " " + dimStyle.Render("["+current.State+"]") + "\n")
111-
112-
// Children (tasks that current depends on).
113-
for i, c := range children {
114-
connector := "├── "
115-
if i == len(children)-1 && len(relatesTo) == 0 {
116-
connector = "└── "
117-
}
118-
b.WriteString(renderDepNode(connector, c) + "\n")
105+
prefix := ""
106+
childIndent := ""
107+
if len(parents) > 0 {
108+
prefix = "└──"
109+
childIndent = " "
119110
}
111+
b.WriteString(prefix + depCurrentStyle.Render(fmt.Sprintf("◆ %s: %s", currentRef, currentTitle)) + " " + dimStyle.Render("["+current.State+"]") + "\n")
120112

121-
// Related tasks.
122-
for i, r := range relatesTo {
123-
connector := "├── "
124-
if i == len(relatesTo)-1 {
125-
connector = "└── "
113+
// Children and related — indented under current task.
114+
allBelow := make([]string, 0, len(children)+len(relatesTo))
115+
for _, c := range children {
116+
allBelow = append(allBelow, renderDepNode("◆ ", c))
117+
}
118+
for _, r := range relatesTo {
119+
allBelow = append(allBelow, renderRelated("◆ ", r))
120+
}
121+
for i, line := range allBelow {
122+
connector := "├──"
123+
if i == len(allBelow)-1 {
124+
connector = "└──"
126125
}
127-
b.WriteString(renderRelated(connector, r) + "\n")
126+
b.WriteString(childIndent + connector + line + "\n")
128127
}
129128

130129
return b.String()
@@ -140,7 +139,7 @@ func renderDepNode(prefix string, node depTreeNode) string {
140139
}
141140
ref := depRefStyle.Render(node.ref)
142141
state := dimStyle.Render("[" + node.state + "]")
143-
return fmt.Sprintf("%s%s: %s %s", prefix, ref, title, state)
142+
return prefix + fmt.Sprintf("%s: %s %s", ref, title, state)
144143
}
145144

146145
func renderRelated(prefix string, node depTreeNode) string {
@@ -154,5 +153,5 @@ func renderRelated(prefix string, node depTreeNode) string {
154153
ref := depRefStyle.Render(node.ref)
155154
state := dimStyle.Render("[" + node.state + "]")
156155
label := depTypeStyle.Render("relates to")
157-
return fmt.Sprintf("%s%s %s: %s %s", prefix, label, ref, title, state)
156+
return prefix + fmt.Sprintf("%s %s: %s %s", label, ref, title, state)
158157
}

internal/tui/detail.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ func (m detailModel) render(width, height int) string {
243243

244244
// Description.
245245
if t.Description != "" {
246-
b.WriteString(detailSectionStyle.Render("Description") + "\n")
246+
b.WriteString(detailSectionStyle.Render("Description") + "\n\n")
247247
descWidth := width - 2
248248
if descWidth < 20 {
249249
descWidth = 20
@@ -255,21 +255,21 @@ func (m detailModel) render(width, height int) string {
255255

256256
// Dependency tree.
257257
if len(d.dependencies) > 0 {
258-
b.WriteString(detailSectionStyle.Render("Dependencies") + "\n")
258+
b.WriteString(detailSectionStyle.Render("Dependencies") + "\n\n")
259259
b.WriteString(buildDepTree(t, d.dependencies, d.related))
260260
}
261261

262262
// Attachments.
263263
if len(d.attachments) > 0 {
264-
b.WriteString(detailSectionStyle.Render("Attachments") + "\n")
264+
b.WriteString(detailSectionStyle.Render("Attachments") + "\n\n")
265265
for _, att := range d.attachments {
266266
b.WriteString(fmt.Sprintf(" [%s] %s — %s\n", dimStyle.Render(string(att.RefType)), att.Label, att.Reference))
267267
}
268268
}
269269

270270
// Comments.
271271
if len(d.comments) > 0 {
272-
b.WriteString(detailSectionStyle.Render(fmt.Sprintf("Comments (%d)", len(d.comments))) + "\n")
272+
b.WriteString(detailSectionStyle.Render(fmt.Sprintf("Comments (%d)", len(d.comments))) + "\n\n")
273273
indentLen := 2 + 16 + 1 // " " + "YYYY-MM-DD HH:MM" + " "
274274
for _, c := range d.comments {
275275
ts := c.CreatedAt.Format("2006-01-02 15:04")
@@ -299,7 +299,7 @@ func (m detailModel) render(width, height int) string {
299299

300300
// Audit (last 10).
301301
if len(d.audit) > 0 {
302-
b.WriteString(detailSectionStyle.Render("Recent Activity") + "\n")
302+
b.WriteString(detailSectionStyle.Render("Recent Activity") + "\n\n")
303303
start := 0
304304
if len(d.audit) > 10 {
305305
start = len(d.audit) - 10

internal/tui/keymap.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -299,21 +299,23 @@ var detailKeyMap = detailKeys{
299299

300300
// commentKeys defines key bindings shown when the comment textarea is active.
301301
type commentKeys struct {
302-
Submit key.Binding
303-
Cancel key.Binding
302+
Submit key.Binding
303+
Newline key.Binding
304+
Cancel key.Binding
304305
}
305306

306307
func (k commentKeys) ShortHelp() []key.Binding {
307-
return []key.Binding{k.Submit, k.Cancel}
308+
return []key.Binding{k.Submit, k.Newline, k.Cancel}
308309
}
309310

310311
func (k commentKeys) FullHelp() [][]key.Binding {
311-
return [][]key.Binding{{k.Submit, k.Cancel}}
312+
return [][]key.Binding{{k.Submit, k.Newline, k.Cancel}}
312313
}
313314

314315
var commentKeyMap = commentKeys{
315-
Submit: key.NewBinding(key.WithKeys("ctrl+d"), key.WithHelp("ctrl+d", "submit")),
316-
Cancel: key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "cancel")),
316+
Submit: key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "submit")),
317+
Newline: key.NewBinding(key.WithKeys("ctrl+j"), key.WithHelp("ctrl+j", "newline")),
318+
Cancel: key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "cancel")),
317319
}
318320

319321
var keyHelp = key.NewBinding(key.WithKeys("?"), key.WithHelp("?", "help"))

0 commit comments

Comments
 (0)