diff options
Diffstat (limited to 'tui/post.go')
| -rw-r--r-- | tui/post.go | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/tui/post.go b/tui/post.go new file mode 100644 index 0000000..7762b56 --- /dev/null +++ b/tui/post.go @@ -0,0 +1,126 @@ +package tui + +// An example program demonstrating the pager component from the Bubbles +// component library. + +import ( + "fmt" + "strings" + + "github.com/charmbracelet/bubbles/viewport" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +// You generally won't need this unless you're processing stuff with +// complicated ANSI escape sequences. Turn it on if you notice flickering. +// +// Also keep in mind that high performance rendering only works for programs +// that use the full size of the terminal. We're enabling that below with +// tea.EnterAltScreen(). +const useHighPerformanceRenderer = false + +var ( + titleStyle = func() lipgloss.Style { + b := lipgloss.RoundedBorder() + b.Right = "├" + return lipgloss.NewStyle().BorderStyle(b).Padding(0, 1) + }() + + infoStyle = func() lipgloss.Style { + b := lipgloss.RoundedBorder() + b.Left = "┤" + return titleStyle.BorderStyle(b) + }() +) + +type PostModel struct { + content string + ready bool + viewport viewport.Model +} + +func (m PostModel) Init() tea.Cmd { + return nil +} + +func (m PostModel) Update(msg tea.Msg) (PostModel, tea.Cmd) { + var ( + cmd tea.Cmd + cmds []tea.Cmd + ) + + switch msg := msg.(type) { + case tea.KeyMsg: + if k := msg.String(); k == "ctrl+c" || k == "q" || k == "esc" { + return m, tea.Quit + } + + case tea.WindowSizeMsg: + headerHeight := lipgloss.Height(m.headerView()) + footerHeight := lipgloss.Height(m.footerView()) + verticalMarginHeight := headerHeight + footerHeight + + if !m.ready { + // Since this program is using the full size of the viewport we + // need to wait until we've received the window dimensions before + // we can initialize the viewport. The initial dimensions come in + // quickly, though asynchronously, which is why we wait for them + // here. + m.viewport = viewport.New(msg.Width, msg.Height-verticalMarginHeight) + m.viewport.YPosition = headerHeight + m.viewport.HighPerformanceRendering = useHighPerformanceRenderer + m.viewport.SetContent(m.content) + m.ready = true + + // This is only necessary for high performance rendering, which in + // most cases you won't need. + // + // Render the viewport one line below the header. + m.viewport.YPosition = headerHeight + 1 + } else { + m.viewport.Width = msg.Width + m.viewport.Height = msg.Height - verticalMarginHeight + } + + if useHighPerformanceRenderer { + // Render (or re-render) the whole viewport. Necessary both to + // initialize the viewport and when the window is resized. + // + // This is needed for high-performance rendering only. + cmds = append(cmds, viewport.Sync(m.viewport)) + } + } + + // Handle keyboard and mouse events in the viewport + m.viewport, cmd = m.viewport.Update(msg) + cmds = append(cmds, cmd) + + return m, tea.Batch(cmds...) +} + +func (m PostModel) View() string { + if !m.ready { + return "\n Initializing..." + } + return fmt.Sprintf("%s\n%s\n%s", m.headerView(), m.viewport.View(), m.footerView()) +} + +func (m PostModel) headerView() string { + title := titleStyle.Render("Mr. Pager") + line := strings.Repeat("─", max(0, m.viewport.Width-lipgloss.Width(title))) + return lipgloss.JoinHorizontal(lipgloss.Center, title, line) +} + +func (m PostModel) footerView() string { + info := infoStyle.Render(fmt.Sprintf("%3.f%%", m.viewport.ScrollPercent()*100)) + line := strings.Repeat("─", max(0, m.viewport.Width-lipgloss.Width(info))) + return lipgloss.JoinHorizontal(lipgloss.Center, line, info) +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} |
