Skip to content

Commit

Permalink
Add calendar view
Browse files Browse the repository at this point in the history
  • Loading branch information
anirudhaCodes committed Feb 21, 2024
1 parent b25d131 commit 1e25556
Showing 1 changed file with 193 additions and 19 deletions.
212 changes: 193 additions & 19 deletions datetimepicker/datetimepicker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package datetimepicker

import (
"fmt"
"strings"
"time"

"github.com/charmbracelet/bubbles/key"
Expand Down Expand Up @@ -71,35 +72,100 @@ const (

// TimeOnly represents the picker type for selecting only the time.
TimeOnly

// Calendar

Check failure on line 76 in datetimepicker/datetimepicker.go

View workflow job for this annotation

GitHub Actions / lint-soft

Comment should end in a period (godot)
Calendar
)

// Model is the Bubble Tea model for the date input element.
type Model struct {
Err error
Prompt string
TextStyle lipgloss.Style
Date time.Time
PromptStyle lipgloss.Style
TextStyle lipgloss.Style
CursorStyle lipgloss.Style
Pos PositionType
TimeFormat TimeFormat
PickerType PickerType
// expanded view / calendar style
CalendarBorderColor lipgloss.Color
MonthYearStyle lipgloss.Style
WeekDayStyle lipgloss.Style
DateStyle lipgloss.Style
CurrentDateColor lipgloss.Color // current date in calander view

Check failure on line 93 in datetimepicker/datetimepicker.go

View workflow job for this annotation

GitHub Actions / lint-soft

`calander` is a misspelling of `calendar` (misspell)
Pos PositionType
TimeFormat TimeFormat
PickerType PickerType
// KeyMap encodes the keybindings.
KeyMap KeyMap
}

// New creates a new model with default settings.
func New() Model {
dayStyle := lipgloss.Border{
Top: "─",
Bottom: "─",
Left: "β”‚",
Right: "β”‚",
TopLeft: "β”Œ",
TopRight: "┐",
BottomLeft: "β”œ",
BottomRight: "─",
MiddleLeft: "β”œ",
MiddleRight: "─",
Middle: "β”Ό",
MiddleTop: "┬",
MiddleBottom: "β”΄",
}
monthYearBorder := lipgloss.Border{
Top: "─",
Bottom: "─",
Left: "β”‚",
Right: "β”‚",
TopLeft: "β”Œ",
TopRight: "┐",
BottomLeft: "β”œ",
BottomRight: "─",
MiddleLeft: "β”œ",
MiddleRight: "─",
Middle: "β”Ό",
MiddleTop: "┬",
MiddleBottom: "β”΄",
}

CalendarBorderColor := lipgloss.Color("212")
monthYearStyle := lipgloss.NewStyle().BorderStyle(monthYearBorder).Padding(0, 6).Width(20).
BorderBottom(false).
BorderLeft(true).
BorderTop(true).
BorderRight(true).
BorderForeground(CalendarBorderColor).
Background(lipgloss.Color("212")).
Bold(true)

weekDayStyle := lipgloss.NewStyle().
BorderStyle(dayStyle).
BorderLeft(true).
BorderForeground(CalendarBorderColor).
Foreground(CalendarBorderColor)
dateStyle := lipgloss.NewStyle().
BorderStyle(dayStyle).
BorderLeft(true).
BorderForeground(CalendarBorderColor)

return Model{
Prompt: "> ",
PromptStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("212")),
TextStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("255")),
CursorStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("212")),
Pos: Date,
Date: time.Now(),
TimeFormat: Hour12,
PickerType: DateTime,
KeyMap: DefaultKeyMap,
Prompt: "> ",
PromptStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("212")),
TextStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("255")),
CursorStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("212")),
CalendarBorderColor: CalendarBorderColor,
MonthYearStyle: monthYearStyle,
WeekDayStyle: weekDayStyle,
DateStyle: dateStyle,
CurrentDateColor: lipgloss.Color("#7D56F4"),
Pos: Date,
Date: time.Now(),
TimeFormat: Hour12,
PickerType: DateTime,
KeyMap: DefaultKeyMap,
}
}

Expand Down Expand Up @@ -170,6 +236,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

case key.Matches(msg, m.KeyMap.Forward):
if m.PickerType == Calendar {
break
}
lastPos := Minute
if m.PickerType == DateOnly {
lastPos = Year
Expand All @@ -179,6 +248,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

case key.Matches(msg, m.KeyMap.Backward):
if m.PickerType == Calendar {
break
}
firstPos := Date
if m.PickerType == TimeOnly {
firstPos = Hour
Expand All @@ -200,16 +272,21 @@ func (m Model) View() string {

text := ""
if m.PickerType == DateTime {
text += prompt
text += m.dateView()
text += " | "
text += m.timeView()
} else if m.PickerType == DateOnly {
text += prompt
text += m.dateView()
} else {
} else if m.PickerType == TimeOnly {
text += prompt
text += m.timeView()
} else { // Calendar
text += m.calendarView()
}

return prompt + text
return text
}

func (m Model) dateView() string {
Expand Down Expand Up @@ -281,11 +358,11 @@ func (m *Model) SetTimeFormat(format TimeFormat) {
func (m *Model) SetPickerType(pickerType PickerType) {
if pickerType < 0 {
pickerType = 0
} else if pickerType > 2 {
pickerType = 2
} else if pickerType > 3 {
pickerType = 3
}
m.PickerType = pickerType
if pickerType == DateTime || pickerType == DateOnly {
if pickerType == DateTime || pickerType == DateOnly || pickerType == Calendar {
m.Pos = Date
} else {
m.Pos = Hour
Expand All @@ -296,7 +373,7 @@ func (m *Model) SetPickerType(pickerType PickerType) {
func (m Model) Value() string {
if m.PickerType <= DateTime {
return m.Date.Format("02 January 2006 03:04 PM")
} else if m.PickerType >= TimeOnly {
} else if m.PickerType == TimeOnly {
if m.TimeFormat <= 0 {
return m.Date.Format("03:04 PM")
} else if m.TimeFormat >= 1 {
Expand All @@ -306,6 +383,103 @@ func (m Model) Value() string {
return m.Date.Format("02 January 2006")
}

// SetMonthYearStyle sets the style of MonthYear part of calendar.
func (m *Model) SetMonthYearStyle(style lipgloss.Style) {
m.MonthYearStyle = style
}

// SetCalendarBorderColor sets the color of the calendar border.
func (m *Model) SetCalendarBorderColor(color lipgloss.Color) {
m.CalendarBorderColor = color
}

// SetWeekDayStyle sets the style of the weekday part of the calendar.
func (m *Model) SetWeekDayStyle(style lipgloss.Style) {
m.WeekDayStyle = style
}

// SetDateStyle sets the style of the date part of the calendar.
func (m *Model) SetDateStyle(style lipgloss.Style) {
m.DateStyle = style
}

// SetCurrentDateColor sets the color of the current date in the calendar.
func (m *Model) SetCurrentDateColor(color lipgloss.Color) {
m.CurrentDateColor = color
}

func (m Model) calendarView() string {
// Get the current date
now := m.Date
// Get the first day of the month
firstDay := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
// Get the last day of the month
lastDay := firstDay.AddDate(0, 1, -1)
// Get the total number of days in the month
totalDays := lastDay.Day()

// Print the month and year
t := ""
divider := lipgloss.NewStyle().Foreground(m.CalendarBorderColor).Render("β”œβ”€β”€β”¬β”€β”€β”¬β”€β”€β”¬β”€β”€β”¬β”€β”€β”¬β”€β”€β”¬β”€β”€β”€")
yearStr := fmt.Sprintf("%d", now.Year())
t += m.MonthYearStyle.Render(strings.ToUpper(now.Month().String()[:3]) + " " + yearStr)
t += "\n" + divider + "\n"

// Print weekdays
lastWeekDayBorder := m.WeekDayStyle.Copy().BorderRight(true)

days := []string{"MO", "TU", "WE", "TH", "FR", "SA", "SU"}

for _, day := range days {
if day == "SU" {
t += lastWeekDayBorder.Render(day)
} else {
t += m.WeekDayStyle.Render(day)
}
}
t += "\n" + lipgloss.NewStyle().Foreground(m.CalendarBorderColor).Render("β”œβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”Όβ”€β”€β”€") + "\n"

// Get the weekday of the first day of the month
lastDayBorder := m.DateStyle.Copy().BorderRight(true)
firstDayWeekday := firstDay.Weekday()

// Print leading spaces for the first day
for i := 0; i < int(firstDayWeekday); i++ {
t += m.DateStyle.Render(" ")
}

// Print the dates
for day := 1; day <= totalDays; day++ {
val := fmt.Sprintf("%2d", day)

if day == now.Day() {
val = lipgloss.NewStyle().Background(m.CurrentDateColor).Render(val)
}

if (int(firstDayWeekday)+day)%7 == 0 {
t += lastDayBorder.Render(val)
t += "\n"
} else {
t += m.DateStyle.Render(val)
}
}

// Get the weekday of the last day of the month
lastDayWeekday := lastDay.Weekday()

// Print leading spaces for the first day
for i := int(lastDayWeekday) + 1; i < 7; i++ {
if i == 6 {
t += lastDayBorder.Render(" ") + "\n"
} else {
t += m.DateStyle.Render(" ")
}
}
t += lipgloss.NewStyle().Foreground(m.CalendarBorderColor).Render("β””β”€β”€β”΄β”€β”€β”΄β”€β”€β”΄β”€β”€β”΄β”€β”€β”΄β”€β”€β”΄β”€β”€β”˜") + "\n"

return t
}

// bubbletea Init function.
func (m Model) Init() tea.Cmd {
return nil
Expand Down

0 comments on commit 1e25556

Please sign in to comment.