summaryrefslogtreecommitdiff
path: root/tui/post.go
diff options
context:
space:
mode:
Diffstat (limited to 'tui/post.go')
-rw-r--r--tui/post.go126
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
+}