Skip to content

Commit

Permalink
feat: status bar
Browse files Browse the repository at this point in the history
  • Loading branch information
bilguun0203 committed Aug 26, 2024
1 parent e6cf4e4 commit a8b86a6
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 14 deletions.
3 changes: 3 additions & 0 deletions internal/tui/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package constants

import "github.com/charmbracelet/lipgloss"

var ColorBW = lipgloss.AdaptiveColor{Light: "#000", Dark: "#FFF"}
var ColorNormal = lipgloss.AdaptiveColor{Light: "#1A1A1A", Dark: "#DDDDDD"}
var ColorNormalInv = lipgloss.AdaptiveColor{Light: "#DDDDDD", Dark: "#1A1A1A"}
var ColorDanger = lipgloss.AdaptiveColor{Light: "197", Dark: "197"}
var ColorSuccess = lipgloss.AdaptiveColor{Light: "034", Dark: "049"}
var ColorWarning = lipgloss.AdaptiveColor{Light: "214", Dark: "214"}
Expand All @@ -13,6 +15,7 @@ var ColorSecondary = lipgloss.AdaptiveColor{Light: "#05EAFF", Dark: "#00E5FA"}

var PrimaryTitleStyle = lipgloss.NewStyle().Padding(0, 1).Background(lipgloss.Color(ColorPrimary.Dark)).Foreground(lipgloss.Color("#000000"))
var SecondaryTitleStyle = lipgloss.NewStyle().Padding(0, 1).Background(lipgloss.Color(ColorSecondary.Light)).Foreground(lipgloss.Color("#000000"))
var WarningTitleStyle = lipgloss.NewStyle().Padding(0, 1).Background(lipgloss.Color(ColorWarning.Light)).Foreground(lipgloss.Color("#000000"))
var NormalTextStyle = lipgloss.NewStyle().Foreground(ColorNormal)
var DangerTextStyle = lipgloss.NewStyle().Foreground(ColorDanger)
var SuccessTextStyle = lipgloss.NewStyle().Foreground(ColorSuccess)
Expand Down
7 changes: 7 additions & 0 deletions internal/tui/node_details/node_details.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package nodedetails

import (
"fmt"

"github.com/atotto/clipboard"
"github.com/bilguun0203/tailscale-tui/internal/tui/constants"
"github.com/bilguun0203/tailscale-tui/internal/tui/keymap"
"github.com/bilguun0203/tailscale-tui/internal/tui/types"
"github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
Expand Down Expand Up @@ -54,6 +58,9 @@ func (m Model) keyBindingsHandler(msg tea.KeyMsg) (Model, []tea.Cmd) {
}
if copyStr != "" {
clipboard.WriteAll(copyStr)
status := fmt.Sprintf("Copied \"%s\"!", constants.PrimaryTextStyle.Underline(true).Render(copyStr))
cmd = func() tea.Msg { return types.StatusMsg(status) }
cmds = append(cmds, cmd)
}
}
}
Expand Down
20 changes: 14 additions & 6 deletions internal/tui/node_list/node_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/bilguun0203/tailscale-tui/internal/tui/constants"
"github.com/bilguun0203/tailscale-tui/internal/tui/keymap"
nodedetails "github.com/bilguun0203/tailscale-tui/internal/tui/node_details"
"github.com/bilguun0203/tailscale-tui/internal/tui/types"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/spinner"
Expand Down Expand Up @@ -46,7 +47,6 @@ func (m *Model) SetSize(w int, h int) {
}

type NodeSelectedMsg tsKey.NodePublic
type RefreshMsg bool

func (m *Model) updateKeybindings() {
if m.list.SelectedItem() != nil {
Expand Down Expand Up @@ -84,13 +84,21 @@ func (m Model) keyBindingsHandler(msg tea.KeyMsg) (Model, []tea.Cmd) {
}
if copyStr == "" {
m.list.NewStatusMessage("Sorry, nothing to copy.")
cmd = func() tea.Msg { return types.StatusMsg("Sorry, nothing to copy.") }
cmds = append(cmds, cmd)
} else {
clipboard.WriteAll(copyStr)
m.list.NewStatusMessage(fmt.Sprintf("Copied \"%s\"!", constants.PrimaryTextStyle.Underline(true).Render(copyStr)))
err := clipboard.WriteAll(copyStr)
status := fmt.Sprintf("Copied \"%s\"!", constants.PrimaryTextStyle.Underline(true).Render(copyStr))
if err != nil {
status = fmt.Sprintf("Sorry, error occured: %s", err)
}
m.list.NewStatusMessage(status)
cmd = func() tea.Msg { return types.StatusMsg(status) }
cmds = append(cmds, cmd)
}
}
if key.Matches(msg, m.keyMap.Refresh) {
cmd = func() tea.Msg { return RefreshMsg(true) }
cmd = func() tea.Msg { return types.RefreshMsg(true) }
cmds = append(cmds, cmd)
}
if key.Matches(msg, m.keyMap.Enter) {
Expand All @@ -99,12 +107,12 @@ func (m Model) keyBindingsHandler(msg tea.KeyMsg) (Model, []tea.Cmd) {
}
if key.Matches(msg, m.keyMap.TSUp) {
ts.SetTSStatus(true)
cmd = func() tea.Msg { return RefreshMsg(true) }
cmd = func() tea.Msg { return types.RefreshMsg(true) }
cmds = append(cmds, cmd)
}
if key.Matches(msg, m.keyMap.TSDown) {
ts.SetTSStatus(false)
cmd = func() tea.Msg { return RefreshMsg(true) }
cmd = func() tea.Msg { return types.RefreshMsg(true) }
cmds = append(cmds, cmd)
}
return m, cmds
Expand Down
76 changes: 76 additions & 0 deletions internal/tui/status_bar/status_bar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package statusbar

import (
"github.com/bilguun0203/tailscale-tui/internal/tui/constants"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)

type Model struct {
barStyle lipgloss.Style
prefix string
prefixStyle lipgloss.Style
msg string
msgStyle lipgloss.Style
suffix string
suffixStyle lipgloss.Style
w int
h int
}

func (m *Model) UpdatePrefix(v string) {
m.prefix = v
}

func (m *Model) UpdateMessage(v string) {
m.msg = v
}

func (m *Model) UpdateSuffix(v string) {
m.suffix = v
}

func (m *Model) UpdatePrefixStyle(style lipgloss.Style) {
m.prefixStyle = style
}

func (m *Model) UpdateMessageStyle(style lipgloss.Style) {
m.msgStyle = style
}

func (m *Model) UpdateSuffixStyle(style lipgloss.Style) {
m.suffixStyle = style
}

func (m Model) Init() tea.Cmd {
return nil
}
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.w, m.h = msg.Width, msg.Height
m.barStyle = m.barStyle.Width(m.w)
}
return m, nil
}

func (m Model) View() string {
prefixView := m.prefixStyle.Render(m.prefix)
suffixView := m.suffixStyle.Render(m.suffix)
msgW := m.w - lipgloss.Width(prefixView) - lipgloss.Width(suffixView)
msgView := m.msgStyle.Padding(0, 1).Width(msgW).Render(m.msg)
return m.barStyle.Render(prefixView + msgView + suffixView)
}

func New() Model {
barStyle := lipgloss.NewStyle().Background(constants.ColorNormalInv).Margin(1, 0).Height(1)
return Model{
barStyle: barStyle,
prefix: "TAILSCALE-TUI",
prefixStyle: constants.PrimaryTitleStyle,
msg: "",
msgStyle: lipgloss.NewStyle().Background(barStyle.GetBackground()).Foreground(constants.ColorBW),
suffix: "",
suffixStyle: constants.SecondaryTitleStyle,
}
}
35 changes: 27 additions & 8 deletions internal/tui/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import (
"github.com/bilguun0203/tailscale-tui/internal/tui/constants"
nodedetails "github.com/bilguun0203/tailscale-tui/internal/tui/node_details"
nodelist "github.com/bilguun0203/tailscale-tui/internal/tui/node_list"
statusbar "github.com/bilguun0203/tailscale-tui/internal/tui/status_bar"
"github.com/bilguun0203/tailscale-tui/internal/tui/types"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"tailscale.com/ipn/ipnstate"
tsKey "tailscale.com/types/key"
)
Expand All @@ -35,6 +38,7 @@ type Model struct {
Err error
nodelist nodelist.Model
nodedetails nodedetails.Model
statusbar statusbar.Model
spinner spinner.Model
w, h int
}
Expand Down Expand Up @@ -67,30 +71,42 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.Err = nil
m.tsStatus = msg
m.viewState = viewStateList
m.statusbar.UpdateMessage("Showing all network devices")
case ts.StatusErrorMsg:
m.isLoading = false
m.Err = msg
m.statusbar.UpdateMessage(fmt.Sprintf("Error: %s", msg))
return m, tea.Quit
case nodedetails.BackMsg:
m.viewState = viewStateList
case nodelist.RefreshMsg:
m.statusbar.UpdateMessage("Showing all network devices")
case types.RefreshMsg:
m.isLoading = true
cmds = append(cmds, m.getTsStatus())
cmds = append(cmds, m.spinner.Tick)
case types.StatusMsg:
m.statusbar.UpdateMessage(string(msg))
case nodelist.NodeSelectedMsg:
m.selectedNodeID = tsKey.NodePublic(msg)
m.nodedetails = nodedetails.New(m.tsStatus, m.selectedNodeID, m.w, m.h)
m.viewState = viewStateDetails
m.statusbar.UpdateMessage("Showing device details")
case tea.WindowSizeMsg:
m.w, m.h = msg.Width, msg.Height
m.nodelist.SetSize(msg.Width, msg.Height)
m.w, m.h = msg.Width, msg.Height-3
m.nodelist.SetSize(m.w, m.h)
case spinner.TickMsg:
if m.isLoading {
m.spinner, tmpCmd = m.spinner.Update(msg)
cmds = append(cmds, tmpCmd)
}
}

if m.isLoading {
m.statusbar.UpdatePrefixStyle(constants.WarningTitleStyle)
} else {
m.statusbar.UpdatePrefixStyle(constants.PrimaryTitleStyle)
}

switch m.viewState {
case viewStateDetails:
m.nodedetails, tmpCmd = m.nodedetails.Update(msg)
Expand All @@ -104,18 +120,20 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds = append(cmds, tmpCmd)
}
}
m.statusbar, tmpCmd = m.statusbar.Update(msg)
cmds = append(cmds, tmpCmd)
return m, tea.Batch(cmds...)
}

func (m Model) View() string {
switch m.viewState {
case viewStateDetails:
return m.nodedetails.View()
return lipgloss.JoinVertical(lipgloss.Left, m.nodedetails.View(), m.statusbar.View())
case viewStateList:
if m.isLoading {
return fmt.Sprintf("\n\n %s Loading...\n\n", m.spinner.View())
m.statusbar.UpdateMessage(fmt.Sprintf("%s Loading...", m.spinner.View()))
}
return m.nodelist.View()
return lipgloss.JoinVertical(lipgloss.Left, m.nodelist.View(), m.statusbar.View())
default:
return "*_*"
}
Expand All @@ -126,10 +144,11 @@ func New() Model {
viewState: viewStateList,
isLoading: true,
spinner: spinner.New(),
statusbar: statusbar.New(),
}
m.spinner.Spinner = spinner.Dot
m.spinner.Spinner = spinner.Line
m.spinner.Style = constants.SpinnerStyle

m.nodelist = nodelist.New(nil, m.w, m.h)
m.nodelist = nodelist.New(nil, m.w, m.h-lipgloss.Height(m.statusbar.View()))
return m
}
4 changes: 4 additions & 0 deletions internal/tui/types/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package types

type RefreshMsg bool
type StatusMsg string

0 comments on commit a8b86a6

Please sign in to comment.