package render import ( "fmt" "strings" "github.com/charmbracelet/lipgloss" "github.com/humdrum-tiv/dots-cli/internal/api" "github.com/humdrum-tiv/dots-cli/internal/day" ) // Grid renders the day as rows of colored dots with a legend. // Logged = ● in type color; planned-only = ○ in type color; empty = dim ·. // currentIndex (−1 to disable) gets an underline marker. func Grid(d *api.DayData, currentIndex int) string { blocksPerDay := 1440 / d.BlockSize perRow := blocksPerDay / 6 // 6 rows → 4h per row at any blockSize colorOf := make(map[string]string, len(d.Types)) for _, t := range d.Types { colorOf[t.ID] = t.Color } var b strings.Builder for row := 0; row < 6; row++ { start := row * perRow b.WriteString(fmt.Sprintf("%-6s", day.SlotLabel(start, d.BlockSize))) for i := start; i < start+perRow; i++ { style := lipgloss.NewStyle() var glyph string if id, ok := d.Blocks[i]; ok { style = style.Foreground(lipgloss.Color(colorOf[id])) glyph = "●" } else if id, ok := d.PlanBlocks[i]; ok { style = style.Foreground(lipgloss.Color(colorOf[id])) glyph = "○" } else { style = style.Foreground(lipgloss.Color("240")) glyph = "·" } if i == currentIndex { style = style.Underline(true) } b.WriteString(style.Render(glyph) + " ") } b.WriteString("\n") } b.WriteString("\n") for _, t := range d.Types { sw := lipgloss.NewStyle().Foreground(lipgloss.Color(t.Color)).Render("●") b.WriteString(fmt.Sprintf("%s %s ", sw, t.Name)) } b.WriteString("\n") return b.String() }