diff options
-rw-r--r-- | internal/picker/defaults.go | 37 | ||||
-rw-r--r-- | internal/picker/picker.go | 17 | ||||
-rw-r--r-- | internal/quit/quit.go | 7 | ||||
-rw-r--r-- | internal/slider/slider.go | 16 | ||||
-rw-r--r-- | internal/switcher/switcher.go | 70 | ||||
-rw-r--r-- | internal/ui/style.go | 123 |
6 files changed, 200 insertions, 70 deletions
diff --git a/internal/picker/defaults.go b/internal/picker/defaults.go index a7a0d89..5500465 100644 --- a/internal/picker/defaults.go +++ b/internal/picker/defaults.go @@ -1,31 +1,34 @@ package picker import ( - "github.com/ChausseBenjamin/termpicker/internal/progress" "github.com/ChausseBenjamin/termpicker/internal/slider" + "github.com/ChausseBenjamin/termpicker/internal/ui" ) func RGB() *Model { - r := slider.New('R', 255, progress.WithGradient("#660000", "#ff0000")) - g := slider.New('G', 255, progress.WithGradient("#006600", "#00ff00")) - b := slider.New('B', 255, progress.WithGradient("#000066", "#0000ff")) - rgb := New([]slider.Model{r, g, b}, "RGB") - return rgb + return New( + []slider.Model{ + slider.New('R', 255, ui.Style().Sliders.R...), + slider.New('G', 255, ui.Style().Sliders.G...), + slider.New('B', 255, ui.Style().Sliders.B...), + }, "RGB") } func CMYK() *Model { - c := slider.New('C', 100, progress.WithGradient("#006666", "#00ffff")) - m := slider.New('M', 100, progress.WithGradient("#660066", "#ff00ff")) - y := slider.New('Y', 100, progress.WithGradient("#666600", "#ffff00")) - k := slider.New('K', 100, progress.WithSolidFill("#000000")) - cmyk := New([]slider.Model{c, m, y, k}, "CMYK") - return cmyk + return New( + []slider.Model{ + slider.New('C', 100, ui.Style().Sliders.C...), + slider.New('M', 100, ui.Style().Sliders.M...), + slider.New('Y', 100, ui.Style().Sliders.Y...), + slider.New('K', 100, ui.Style().Sliders.K...), + }, "CMYK") } func HSL() *Model { - h := slider.New('H', 360, progress.WithDefaultGradient()) - s := slider.New('S', 100, progress.WithGradient("#a68e59", "#ffae00")) - l := slider.New('L', 100, progress.WithGradient("#222222", "#ffffff")) - hsl := New([]slider.Model{h, s, l}, "HSL") - return hsl + return New( + []slider.Model{ + slider.New('H', 360, ui.Style().Sliders.H...), + slider.New('S', 100, ui.Style().Sliders.S...), + slider.New('L', 100, ui.Style().Sliders.L...), + }, "HSL") } diff --git a/internal/picker/picker.go b/internal/picker/picker.go index 5a7493d..3094396 100644 --- a/internal/picker/picker.go +++ b/internal/picker/picker.go @@ -5,14 +5,11 @@ import ( "github.com/ChausseBenjamin/termpicker/internal/colors" "github.com/ChausseBenjamin/termpicker/internal/slider" + "github.com/ChausseBenjamin/termpicker/internal/ui" "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" ) -const ( - activeRune = '>' -) - type Model struct { title string active int @@ -114,15 +111,19 @@ func (m Model) Init() tea.Cmd { func (m Model) View() string { var s string - carriageReturn := "" + newline := "" for i, slider := range m.sliders { if i > 0 { - carriageReturn = "\n" + newline = "\n" } if i == m.active { - s += fmt.Sprintf("%v%c %s", carriageReturn, activeRune, slider.View()) + s += fmt.Sprintf("%v%s %s", + newline, + ui.Style().PickerCursor.Render(ui.PickerSelRune), + slider.View(), + ) } else { - s += fmt.Sprintf("%v %s", carriageReturn, slider.View()) + s += fmt.Sprintf("%v %s", newline, slider.View()) } } return s diff --git a/internal/quit/quit.go b/internal/quit/quit.go index ac11abc..98c40a7 100644 --- a/internal/quit/quit.go +++ b/internal/quit/quit.go @@ -1,6 +1,9 @@ package quit -import tea "github.com/charmbracelet/bubbletea" +import ( + "github.com/ChausseBenjamin/termpicker/internal/ui" + tea "github.com/charmbracelet/bubbletea" +) const byeMsg = "Goodbye!\n" @@ -10,4 +13,4 @@ func (m Model) Init() tea.Cmd { return nil } func (m Model) Update(tea.Msg) (tea.Model, tea.Cmd) { return m, nil } -func (m Model) View() string { return byeMsg } +func (m Model) View() string { return ui.Style().Quit.Render(byeMsg) } diff --git a/internal/slider/slider.go b/internal/slider/slider.go index a6c6ee6..dbf4093 100644 --- a/internal/slider/slider.go +++ b/internal/slider/slider.go @@ -2,6 +2,7 @@ package slider import ( "fmt" + "strings" "github.com/ChausseBenjamin/termpicker/internal/progress" "github.com/ChausseBenjamin/termpicker/internal/ui" @@ -19,11 +20,8 @@ type Model struct { func New(label byte, maxVal int, opts ...progress.Option) Model { slider := Model{ - label: label, - progress: progress.New( - progress.WithoutPercentage(), - progress.WithColorProfile(ui.ColorProfile()), - ), + label: label, + progress: progress.New(), max: maxVal, current: maxVal / 2, mappings: newKeybinds(), @@ -34,7 +32,7 @@ func New(label byte, maxVal int, opts ...progress.Option) Model { return slider } -func (m Model) Title() string { return fmt.Sprintf("%c", m.label) } +func (m Model) Title() string { return fmt.Sprintf("%c:", m.label) } func (m Model) Init() tea.Cmd { // Triggering a frame message Update here will force the progress bar to @@ -81,5 +79,9 @@ func (m Model) ViewValue(current int) string { } func (m Model) View() string { - return fmt.Sprintf("%v: %v %v", m.Title(), m.progress.View(), m.ViewValue(m.current)) + return strings.Join([]string{ + ui.Style().SliderLabel.Render(m.Title()), + m.progress.View(), + ui.Style().SliderVal.Render(m.ViewValue(m.current)), + }, " ") } diff --git a/internal/switcher/switcher.go b/internal/switcher/switcher.go index f368224..91a46ef 100644 --- a/internal/switcher/switcher.go +++ b/internal/switcher/switcher.go @@ -10,6 +10,7 @@ import ( "github.com/ChausseBenjamin/termpicker/internal/picker" "github.com/ChausseBenjamin/termpicker/internal/preview" "github.com/ChausseBenjamin/termpicker/internal/quit" + "github.com/ChausseBenjamin/termpicker/internal/ui" "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/textinput" @@ -39,12 +40,19 @@ func New() Model { *picker.CMYK(), *picker.HSL(), } + + input := textinput.New() + input.PromptStyle = ui.Style().InputPrompt + input.TextStyle = ui.Style().InputText + input.Prompt = ui.PromptPrefix + input.Placeholder = ui.PromptPlaceholder + return Model{ active: 0, pickers: pickers, preview: *preview.New(colors.Hex(pickers[0].GetColor())), help: help.New(), - input: textinput.New(), + input: input, notices: notices.New(), fullHelp: false, } @@ -93,41 +101,27 @@ func (m Model) Init() tea.Cmd { } func (m Model) View() string { - norm := lipgloss.NewStyle().Faint(true) - bright := lipgloss.NewStyle().Faint(false) - - delims := [3]string{"[ ", " | ", "]"} - for i, d := range delims { - delims[i] = bright.Render(d) - } - - var sections []string + tabs := make([]string, len(m.pickers)) for i, p := range m.pickers { if i == m.active { - sections = append( - sections, - bright. - Underline(true). - Bold(true). - Render(p.Title()), - ) + tabs[i] = ui.Style().TabSel.Render(p.Title()) } else { - sections = append(sections, norm.Render(p.Title())) + tabs[i] = ui.Style().TabNorm.Render(p.Title()) } } - tabs := "[ " + strings.Join(sections, " | ") + " ]" + tabStr := strings.Join([]string{ + ui.Style().TabGeom.Render(ui.TabSepLeft), + strings.Join(tabs, ui.Style().TabGeom.Render(ui.TabSepMid)), + ui.Style().TabGeom.Render(ui.TabSepRight), + }, " ") - pickerView := m.pickers[m.active].View() - boxStyle := lipgloss.NewStyle().Border(lipgloss.RoundedBorder(), true, true, false, true) - w := lipgloss.Width(pickerView) - pickerView = boxStyle.Render(pickerView) + pickerStr := m.pickers[m.active].View() + w := lipgloss.Width(pickerStr) m.preview.SetWidth(w) - boxStyle = boxStyle.Border(lipgloss.RoundedBorder(), false, true, false, true) - previewStr := boxStyle.Render(m.preview.View()) + previewStr := m.preview.View() m.help.Styles.ShortKey.Width(w) - boxStyle = boxStyle.Border(lipgloss.RoundedBorder(), false, true, true, true).Width(w) var helpstr string if m.fullHelp { @@ -139,22 +133,26 @@ func (m Model) View() string { // helpstr = m.help.FullHelpView([][]key.Binding{m.AllKeys()[0]}) helpstr = m.help.FullHelpView(shortKeys()) } - helpstr = boxStyle.Render(helpstr) - inputStr := "" + var inputStr string if m.input.Focused() { - boxStyle = boxStyle.Border(lipgloss.RoundedBorder(), true, true, true, true).Width(w) - inputStr = boxStyle.Render(m.input.View()) + m.input.Width = w + inputStr = ui.Style().Boxed.Render(m.input.View()) } - return fmt.Sprintf("%s\n%s\n%s\n%v\n%v\n%v", - tabs, - pickerView, + mainArea := ui.Style().Boxed.Render(strings.Join([]string{ + pickerStr, previewStr, helpstr, - inputStr, - m.notices.View(), - ) + }, "\n")) + + return strings.Join( + []string{ + tabStr, + mainArea, + inputStr, + m.notices.View(), + }, "\n") } func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { diff --git a/internal/ui/style.go b/internal/ui/style.go new file mode 100644 index 0000000..71bff48 --- /dev/null +++ b/internal/ui/style.go @@ -0,0 +1,123 @@ +package ui + +import ( + "github.com/ChausseBenjamin/termpicker/internal/progress" + lg "github.com/charmbracelet/lipgloss" +) + +const ( + // Colors: + textSel = "#F2F1F0" + textNorm = "#A7AFB1" + textFaint = "#6F797B" + geomFg = "#ACB3B5" + + TabSepLeft = "[" + TabSepMid = " | " + TabSepRight = "]" + + PickerSelRune = ">" + + PromptPrefix = "> " + PromptPlaceholder = "Enter a color (ex: #b7416e)" + + SliderMinWidth = 22 // 1 ASCII change every 2.05 deg. avg + SliderMaxWidth = 90 // 2 ASCII change per deg. + +) + +type sliderOpts struct { + R, G, B []progress.Option + C, M, Y, K []progress.Option + H, S, L []progress.Option +} + +type StyleSheet struct { + TabSel lg.Style + TabNorm lg.Style + TabGeom lg.Style + SliderVal lg.Style + SliderLabel lg.Style + PickerCursor lg.Style + Preview lg.Style + InputPrompt lg.Style + InputText lg.Style + Notice lg.Style + Quit lg.Style + Boxed lg.Style + Sliders sliderOpts +} + +var style StyleSheet + +func Style() StyleSheet { + return style +} + +func init() { + baseStyle := lg.NewStyle(). + Foreground(lg.Color(textNorm)) + + baseSliderOpts := []progress.Option{ + progress.WithColorProfile(ColorProfile()), + progress.WithoutPercentage(), + // progress.WithFillCharacters(" ", "█"), // for legacy look + } + + style = StyleSheet{ + TabSel: baseStyle.Inherit(lg.NewStyle(). + Foreground(lg.Color(textSel)). + Underline(true). + Bold(true)), + + TabNorm: baseStyle.Inherit(lg.NewStyle(). + Foreground(lg.Color(textFaint)). + Underline(false). + Bold(false)), + + TabGeom: baseStyle.Inherit(lg.NewStyle(). + Foreground(lg.Color(geomFg))), + + SliderVal: baseStyle, + + SliderLabel: baseStyle, + + PickerCursor: baseStyle.Inherit(lg.NewStyle(). + Bold(true)), + + Preview: baseStyle, + + InputPrompt: baseStyle.Inherit(lg.NewStyle(). + Bold(true)), + + InputText: baseStyle, + + Notice: baseStyle.Inherit(lg.NewStyle(). + Bold(true)), + + Quit: baseStyle.Inherit(lg.NewStyle(). + Foreground(lg.Color(textSel)). + Bold(true)), + + Boxed: baseStyle.Inherit(lg.NewStyle(). + Border(lg.RoundedBorder())), + + Sliders: sliderOpts{ + // RGB + R: append(baseSliderOpts, progress.WithGradient("#660000", "#ff0000")), + G: append(baseSliderOpts, progress.WithGradient("#006600", "#00ff00")), + B: append(baseSliderOpts, progress.WithGradient("#000066", "#0000ff")), + + // CMYK + C: append(baseSliderOpts, progress.WithGradient("#006666", "#00ffff")), + M: append(baseSliderOpts, progress.WithGradient("#660066", "#ff00ff")), + Y: append(baseSliderOpts, progress.WithGradient("#666600", "#ffff00")), + K: append(baseSliderOpts, progress.WithSolidFill("#000000")), + + // HSL + H: append(baseSliderOpts, progress.WithDefaultGradient()), + S: append(baseSliderOpts, progress.WithGradient("#a68e59", "#ffae00")), + L: append(baseSliderOpts, progress.WithGradient("#222222", "#ffffff")), + }, + } +} |