Skip to content

Commit de7315c

Browse files
authored
Merge pull request #480 from bborn/task/1943-expand-task-details-field-to-fill-availa
Expand task details field to fill available space
2 parents 52958d1 + 73c1b34 commit de7315c

File tree

2 files changed

+49
-75
lines changed

2 files changed

+49
-75
lines changed

internal/ui/form.go

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,8 @@ func (m *FormModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
665665
m.focused = FieldTitle
666666
m.focusCurrent()
667667
}
668+
// Recalculate body height since available space changes with mode
669+
m.updateBodyHeight()
668670
return m, nil
669671

670672
case "ctrl+s":
@@ -1805,51 +1807,35 @@ func (m *FormModel) SetSize(width, height int) {
18051807
m.updateBodyHeight()
18061808
}
18071809

1808-
// calculateBodyHeight calculates the appropriate height for the body textarea based on content.
1809-
// Returns a height between minHeight (8) and maxHeight (50% of available screen height).
1810+
// calculateBodyHeight calculates the appropriate height for the body textarea.
1811+
// The body expands to fill all available screen space after accounting for other form elements.
18101812
func (m *FormModel) calculateBodyHeight() int {
1811-
content := m.bodyInput.Value()
1812-
1813-
// Minimum height - increased from 4 to 8 to display more content by default
18141813
minHeight := 8
18151814

1816-
// Maximum height is 50% of screen height
1817-
// Account for other form elements: header(2) + title(2) + body label(1) + project(2) +
1818-
// type(2) + schedule(2) + attachments(2) + help(1) + padding/borders(~6) = ~19 lines
1819-
formOverhead := 22
1820-
maxHeight := (m.height - formOverhead) / 2
1821-
if maxHeight < minHeight {
1822-
maxHeight = minHeight
1823-
}
1815+
// Box chrome: border(2) + padding(2) + Height offset(2) = 6
1816+
boxChrome := 6
18241817

1825-
// Count actual lines needed
1826-
lines := 1
1827-
if content != "" {
1828-
lines = strings.Count(content, "\n") + 1
1829-
}
1818+
// Non-body content lines common to both modes:
1819+
// header(1) + blank(1) + title(1) + blank(1) + details label(1) + help(1) = 6
1820+
commonOverhead := 6
18301821

1831-
// Account for line wrapping
1832-
textWidth := m.width - 24 // Same width as used in SetWidth
1833-
if textWidth > 0 {
1834-
for _, line := range strings.Split(content, "\n") {
1835-
// Each line might wrap based on character count
1836-
lineLen := len(line)
1837-
if lineLen > textWidth {
1838-
lines += lineLen / textWidth
1839-
}
1840-
}
1822+
var modeOverhead int
1823+
if m.showAdvanced {
1824+
// Advanced adds: project(1+blank) + attachments(blank+label+input+blank=4) +
1825+
// type(1+blank) + executor(1+blank) = 10
1826+
modeOverhead = 10
1827+
} else {
1828+
// Simple adds: blank + summary + blank(2) = 3
1829+
modeOverhead = 3
18411830
}
18421831

1843-
// Apply min/max bounds
1844-
height := lines
1845-
if height < minHeight {
1846-
height = minHeight
1847-
}
1848-
if height > maxHeight {
1849-
height = maxHeight
1832+
totalOverhead := boxChrome + commonOverhead + modeOverhead
1833+
availableHeight := m.height - totalOverhead
1834+
if availableHeight < minHeight {
1835+
availableHeight = minHeight
18501836
}
18511837

1852-
return height
1838+
return availableHeight
18531839
}
18541840

18551841
// updateBodyHeight updates the body textarea height based on content.

internal/ui/form_test.go

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,36 @@ func TestCalculateBodyHeight(t *testing.T) {
1818
wantMax int
1919
}{
2020
{
21-
name: "empty content returns minimum height",
21+
name: "empty content fills available space",
2222
content: "",
2323
screenHeight: 50,
2424
screenWidth: 100,
25-
wantMin: 8,
26-
wantMax: 8,
25+
wantMin: 20, // body fills available space (50 - overhead)
26+
wantMax: 50,
2727
},
2828
{
29-
name: "single line returns minimum height",
29+
name: "single line fills available space",
3030
content: "hello world",
3131
screenHeight: 50,
3232
screenWidth: 100,
33-
wantMin: 8,
34-
wantMax: 8,
33+
wantMin: 20,
34+
wantMax: 50,
3535
},
3636
{
37-
name: "multiple lines grows height",
38-
content: "line1\nline2\nline3\nline4\nline5\nline6",
39-
screenHeight: 50,
40-
screenWidth: 100,
41-
wantMin: 8,
42-
wantMax: 8,
43-
},
44-
{
45-
name: "many lines capped at max height (50% of screen)",
46-
content: strings.Repeat("line\n", 50),
47-
screenHeight: 50,
37+
name: "small screen uses minimum height",
38+
content: "",
39+
screenHeight: 20,
4840
screenWidth: 100,
49-
wantMin: 8, // at least minimum
50-
wantMax: 14, // (50-22)/2 = 14
41+
wantMin: 8, // minimum height enforced
42+
wantMax: 20,
5143
},
5244
{
53-
name: "long lines wrap and increase height",
54-
content: strings.Repeat("a", 200), // should wrap on ~76 char width
55-
screenHeight: 50,
45+
name: "large screen fills more space",
46+
content: "",
47+
screenHeight: 100,
5648
screenWidth: 100,
57-
wantMin: 8,
58-
wantMax: 8, // wrapped lines still within minimum
49+
wantMin: 50, // more screen = more body space
50+
wantMax: 100,
5951
},
6052
}
6153

@@ -79,41 +71,37 @@ func TestCalculateBodyHeight(t *testing.T) {
7971
func TestUpdateBodyHeightSetsHeight(t *testing.T) {
8072
m := NewFormModel(nil, 100, 50, "", nil)
8173

82-
// Initially should have minimum height of 8
74+
// Should fill available space regardless of content
8375
m.updateBodyHeight()
8476
// The textarea height is internal, so we just verify no panic
8577

86-
// Add content and update
78+
// Add content and update - height stays the same (fills available space)
8779
m.bodyInput.SetValue("line1\nline2\nline3\nline4\nline5")
8880
m.updateBodyHeight()
89-
// Verify no panic and height should be 5
9081

91-
// Verify that with large content, height is capped
82+
// Large content - height is the same (fills available space)
9283
m.bodyInput.SetValue(strings.Repeat("line\n", 100))
9384
m.updateBodyHeight()
94-
// Should be capped at max height (50% of screen)
9585
}
9686

97-
func TestMaxHeightIs50PercentOfScreen(t *testing.T) {
87+
func TestBodyHeightFillsAvailableSpace(t *testing.T) {
9888
screenHeights := []int{40, 60, 80, 100}
9989

10090
for _, screenHeight := range screenHeights {
10191
t.Run("screen_height_"+string(rune('0'+screenHeight/10)), func(t *testing.T) {
10292
m := NewFormModel(nil, 100, screenHeight, "", nil)
10393

104-
// Add lots of content to trigger max height
105-
m.bodyInput.SetValue(strings.Repeat("line\n", 100))
106-
10794
height := m.calculateBodyHeight()
10895

109-
// formOverhead is 22, so maxHeight = (screenHeight - 22) / 2
110-
expectedMax := (screenHeight - 22) / 2
111-
if expectedMax < 8 {
112-
expectedMax = 8
96+
// Body should fill available space (screen minus overhead)
97+
// In advanced mode: boxChrome(6) + common(6) + advanced(10) = 22
98+
expectedHeight := screenHeight - 22
99+
if expectedHeight < 8 {
100+
expectedHeight = 8
113101
}
114102

115-
if height > expectedMax {
116-
t.Errorf("height %d exceeds expected max %d for screen height %d", height, expectedMax, screenHeight)
103+
if height != expectedHeight {
104+
t.Errorf("height %d != expected %d for screen height %d", height, expectedHeight, screenHeight)
117105
}
118106
})
119107
}

0 commit comments

Comments
 (0)