diff options
| author | Paul Buetow <paul@buetow.org> | 2025-06-28 11:22:55 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-06-28 11:22:55 +0300 |
| commit | b659b8cf87c86280f62cef0f499a60b999e6ce6b (patch) | |
| tree | 5c0dc0606a8bda997a3b25f4c8a51479c34bb51b /internal/ui/table.go | |
| parent | ab986c63c75a3114b409d171ab2aaf616c087554 (diff) | |
feat: add editing and visual feedback to task detail view
- Enable in-place editing of Priority, Tags, Due, and Recurrence fields
- Add blinking effect (bright yellow) after field changes
- Change all status message timeouts from 3 to 2 seconds
- Support disco mode in detail view (random theme on edit)
- Add showLabel parameter to view functions to hide redundant labels
- Temporarily clear input prompts in detail view for cleaner UI
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'internal/ui/table.go')
| -rw-r--r-- | internal/ui/table.go | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/internal/ui/table.go b/internal/ui/table.go index 281f3ba..cb9d13d 100644 --- a/internal/ui/table.go +++ b/internal/ui/table.go @@ -128,6 +128,9 @@ type Model struct { detailSearchInput textinput.Model detailSearchRegex *regexp.Regexp detailFieldIndex int // Current selected field in detail view + detailBlinkField int // Field that is currently blinking (-1 for none) + detailBlinkOn bool // Whether the blink is currently on + detailBlinkCount int // Number of blinks remaining } // editDoneMsg is emitted when the external editor process finishes. @@ -167,6 +170,21 @@ func (m *Model) clearEditingModes() { m.prioritySelecting = false } +// startDetailBlink starts blinking a field in the detail view +func (m *Model) startDetailBlink(fieldIndex int) tea.Cmd { + if !m.showTaskDetail { + return nil + } + if m.disco { + m.theme = RandomTheme() + m.applyTheme() + } + m.detailBlinkField = fieldIndex + m.detailBlinkOn = true + m.detailBlinkCount = blinkCycles + return blinkCmd() +} + func (m *Model) startBlink(id int, markDone bool) tea.Cmd { m.blinkID = id m.blinkMarkDone = markDone @@ -264,6 +282,11 @@ func (m *Model) reload() error { m.total = task.TotalTasks(tasks) m.inProgress = task.InProgressTasks(tasks) m.due = task.DueTasks(tasks, time.Now()) + + // Refresh current task detail if in detail view + if m.showTaskDetail { + m.refreshCurrentTaskDetail() + } m.computeColumnWidths() @@ -323,6 +346,18 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m.handleBlinkingState(msg) } + // Check if we're in detail view + if m.showTaskDetail { + // If we're editing in detail view, let editing modes handle it + if m.prioritySelecting || m.tagsEditing || m.dueEditing || m.recurEditing { + if handled, model, cmd := m.handleEditingModes(msg); handled { + return model, cmd + } + } + // Otherwise handle detail view navigation + return m.handleTaskDetailMode(msg) + } + // Check if we're in any editing mode if handled, model, cmd := m.handleEditingModes(msg); handled { return model, cmd @@ -364,6 +399,21 @@ func (m *Model) handleEditDone(msg editDoneMsg) (tea.Model, tea.Cmd) { // handleBlinkMsg handles the blinking animation timer func (m *Model) handleBlinkMsg() (tea.Model, tea.Cmd) { + // Handle detail view blinking + if m.showTaskDetail && m.detailBlinkField != -1 { + m.detailBlinkOn = !m.detailBlinkOn + m.detailBlinkCount++ + + if m.detailBlinkCount >= blinkCycles { + m.detailBlinkField = -1 + m.detailBlinkOn = false + m.detailBlinkCount = 0 + } else { + return m, blinkCmd() + } + return m, nil + } + if m.blinkID == 0 { return m, nil } @@ -427,13 +477,13 @@ func (m Model) View() string { if m.dueEditing { view = lipgloss.JoinVertical(lipgloss.Left, view, - m.dueView(), + m.dueView(true), ) } if m.prioritySelecting { view = lipgloss.JoinVertical(lipgloss.Left, view, - m.priorityView(), + m.priorityView(true), ) } if m.descEditing { @@ -667,11 +717,14 @@ func (m Model) formatUrgency(u string, width int) string { return u } -func (m Model) dueView() string { - return fmt.Sprintf("due: %s", m.dueDate.Format("2006-01-02")) +func (m Model) dueView(showLabel bool) string { + if showLabel { + return fmt.Sprintf("due: %s", m.dueDate.Format("2006-01-02")) + } + return m.dueDate.Format("2006-01-02") } -func (m Model) priorityView() string { +func (m Model) priorityView(showLabel bool) string { var parts []string for i, p := range priorityOptions { label := p @@ -684,7 +737,10 @@ func (m Model) priorityView() string { } parts = append(parts, style.Render(label)) } - return "priority: " + strings.Join(parts, " ") + if showLabel { + return "priority: " + strings.Join(parts, " ") + } + return strings.Join(parts, " ") } func (m Model) highlightCell(base lipgloss.Style, re *regexp.Regexp, raw string) string { |
