Files
task-master/internal/ui/layout.go
T
skrueckenandCursor 79b0821837 Allow editing time entry start and end in TUI and web.
Duration is derived from the range so timer sessions can be corrected after the fact.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-27 22:59:40 +01:00

120 lines
3.3 KiB
Go

package ui
import (
"fmt"
"strings"
"github.com/charmbracelet/lipgloss"
"task/internal/config"
)
func (m Model) renderHeader() string {
brand := m.styles.HeaderBrand.Render(config.CliName)
project := m.styles.HeaderMeta.Render(fmt.Sprintf("project: %s", m.cfg.ActiveProject))
board := m.styles.FilterHint.Render(fmt.Sprintf("list: %s", m.boardFilter.Label()))
count := m.styles.HeaderMeta.Render(fmt.Sprintf("%d tickets", m.ticketCount()))
parts := []string{brand, project, board, count}
if label := m.timerHeaderLabel(); label != "" {
parts = append(parts, m.styles.FilterHint.Render(label))
}
if m.filter != "" {
parts = append(parts, m.styles.FilterHint.Render(fmt.Sprintf("filter: %q", m.filter)))
}
if m.status != "" {
style := m.styles.StatusMsg
if m.statusIsError {
style = m.styles.ErrorMsg
}
parts = append(parts, style.Render(m.status))
}
line := strings.Join(parts, m.styles.HeaderMeta.Render(" │ "))
return m.styles.Header.Width(m.width).Render(line)
}
func (m Model) renderBody(height int) string {
if height < 1 {
height = 1
}
switch m.mode {
case ModeCreate:
label := "New ticket:"
if m.creatingProject {
label = "New project:"
}
prompt := m.styles.InputPrompt.Render(label)
content := prompt + "\n" + m.input.View()
return lipgloss.NewStyle().Height(height).Width(m.width).Render(content)
case ModeSearch:
prompt := m.styles.InputPrompt.Render("Search:")
content := prompt + "\n" + m.input.View()
return lipgloss.NewStyle().Height(height).Width(m.width).Render(content)
case ModeTimeManual:
prompt := m.styles.InputPrompt.Render("Log time:")
content := prompt + "\n" + m.input.View()
return lipgloss.NewStyle().Height(height).Width(m.width).Render(content)
case ModeTimeEdit:
return lipgloss.NewStyle().Height(height).Width(m.width).Render(m.timeEdit.View())
case ModeTimeEntries:
m.timeEntries.SetSize(m.width, height)
return m.timeEntries.View()
case ModeReport:
m.report.SetSize(m.width, height)
return m.report.View()
case ModeReportGroup:
menu := m.groupByMenu.View()
return lipgloss.NewStyle().Height(height).Width(m.width).Render(menu)
case ModeProjects, ModeMoveTicket:
m.projectList.SetSize(m.width, height)
return m.projectList.View()
case ModeEditProject:
return lipgloss.NewStyle().Height(height).Width(m.width).Render(m.projectEdit.View())
case ModeStatus:
menu := m.statusMenu.View()
return lipgloss.NewStyle().Height(height).Width(m.width).Render(menu)
case ModeSync:
menu := m.syncMenu.View()
return lipgloss.NewStyle().Height(height).Width(m.width).Render(menu)
case ModeBoard:
menu := m.boardMenu.View()
return lipgloss.NewStyle().Height(height).Width(m.width).Render(menu)
case ModeConfirmDelete:
title := m.pendingDeleteTitle
if title == "" {
if m.pendingDeleteProject != "" {
title = "this project"
} else {
title = "this ticket"
}
}
var prompt string
if m.pendingDeleteProject != "" {
prompt = m.styles.ErrorMsg.Render(fmt.Sprintf("Delete %s?", title))
} else {
prompt = m.styles.ErrorMsg.Render(fmt.Sprintf("Delete %q?", title))
}
hint := m.styles.StatusMsg.Render("y/enter confirm · esc cancel")
content := prompt + "\n" + hint
return lipgloss.NewStyle().Height(height).Width(m.width).Render(content)
default:
m.tickets.SetSize(m.width, height)
return m.tickets.View()
}
}