fix(grid): cursor marker follows active column; keep editable start/end last in add form
aae4bf89b081f84e73915e446559944da6c0b7e7
Kevin Kortum <kevinkortum@me.com> · 2026-07-07 22:04
parent bc8bdbcb
fix(grid): cursor marker follows active column; keep editable start/end last in add form - when the LOGGED column is active the cursor > sits to its left instead of staying pinned in the far-left TIME gutter - add form keeps start/end (prefilled from the selection) but places them last, so the cursor still lands on project while the times remain editable
2 files changed
internal/tui/form/form.go +4 −3
@@ -71,9 +71,8 @@ return huh.NewForm(huh.NewGroup(inputs(v)...))
}
// AddForm builds a form for a new entry whose start/end are already fixed by a
-// grid selection. It stores start/end/project into *v but shows only the
-// project/description/tags/note inputs, so the cursor lands on project instead
-// of tabbing through the pre-decided times.
+// grid selection. Start/end are prefilled and placed last so the cursor lands
+// on project, yet the times remain editable if the selection needs tweaking.
func AddForm(start, end, project string, v *Values) *huh.Form {
*v = Values{Start: start, End: end, Project: project}
return huh.NewForm(huh.NewGroup(
@@ -81,5 +80,7 @@ huh.NewInput().Title("project").Value(&v.Project),
huh.NewInput().Title("description").Value(&v.Desc),
huh.NewInput().Title("tags (comma-sep)").Value(&v.Tags),
huh.NewInput().Title("note").Value(&v.Note),
+ huh.NewInput().Title("start (HH:MM)").Value(&v.Start),
+ huh.NewInput().Title("end (HH:MM)").Value(&v.End),
))
}
internal/tui/grid/view.go +13 −8
@@ -53,10 +53,11 @@ }
return string(r[:w-1]) + "…"
}
-// gridRow renders one line with a fixed 1-col gutter so every row's separators
-// align: [gutter] time(5) │ activity(actWidth) │ logged.
-func gridRow(gutter, timeStr, actCell, logCell string) string {
- return fmt.Sprintf("%s %-5s │ %-*s │ %s", gutter, timeStr, actWidth, actCell, logCell)
+// gridRow renders one line with fixed 1-col gutters on both sides of the
+// dividers so separators align and the cursor marker can sit next to whichever
+// column is active: [gutterL] time(5) │ activity(actWidth) │[gutterR] logged.
+func gridRow(gutterL, timeStr, actCell, gutterR, logCell string) string {
+ return fmt.Sprintf("%s %-5s │ %-*s │%s %s", gutterL, timeStr, actWidth, actCell, gutterR, logCell)
}
// ruleLine draws the header underline with ┼ crossings at the │ columns.
@@ -83,7 +84,7 @@ }
var b strings.Builder
b.WriteString(gHeaderLine(m.date) + "\n\n")
- b.WriteString(gridRow(" ", "TIME", "ACTIVITY", "LOGGED → tock") + "\n")
+ b.WriteString(gridRow(" ", "TIME", "ACTIVITY", " ", "LOGGED → tock") + "\n")
b.WriteString(ruleLine() + "\n")
lo, hi, selecting := m.selectionRange()
@@ -118,12 +119,16 @@ logged = gDim.Render(logged)
}
}
- gutter := " "
+ gutterL, gutterR := " ", " "
if onCursor {
- gutter = gCursor.Render(">")
+ if m.col == ColActivity {
+ gutterL = gCursor.Render(">")
+ } else {
+ gutterR = gCursor.Render(">")
+ }
}
timeStr := gDim.Render(minuteLabel(m.grid.SlotMinute(row)))
- b.WriteString(gridRow(gutter, timeStr, act, logged) + "\n")
+ b.WriteString(gridRow(gutterL, timeStr, act, gutterR, logged) + "\n")
}
b.WriteString("\n")