repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

pico / tui / plus
Eric Bower · 17 May 24

plus.go

  1package plus
  2
  3import (
  4	"fmt"
  5	"net/url"
  6
  7	"github.com/charmbracelet/bubbles/viewport"
  8	tea "github.com/charmbracelet/bubbletea"
  9	"github.com/charmbracelet/glamour"
 10	"github.com/picosh/pico/tui/common"
 11	"github.com/picosh/pico/tui/pages"
 12)
 13
 14func PlusView(username string, w int) string {
 15	paymentLink := "https://auth.pico.sh/checkout"
 16	url := fmt.Sprintf("%s/%s", paymentLink, url.QueryEscape(username))
 17	md := fmt.Sprintf(`Signup to get premium access
 18
 19## $2/month (billed annually)
 20
 21- tuns
 22  - full access
 23- pages
 24  - full access
 25  - per-site analytics
 26- prose
 27  - increased storage limits
 28  - blog analytics
 29- docker registry
 30  - full access
 31- 20GB total storage
 32
 33There are a few ways to purchase a membership. We try our best to
 34provide immediate access to <code>pico+</code> regardless of payment
 35method.
 36
 37## Online Payment (credit card, paypal)
 38
 39%s
 40
 41## Snail Mail
 42
 43Send cash (USD) or check to:
 44- pico.sh LLC
 45- 206 E Huron St STE 103
 46- Ann Arbor MI 48104
 47
 48## Notes
 49
 50Have any questions not covered here? [Email](mailto:hello@pico.sh)
 51us or join [IRC](https://pico.sh/irc), we will promptly respond.
 52
 53We do not maintain active subscriptions for pico+.
 54Every year you must pay again. We do not take monthly payments, you
 55must pay for a year up-front. Pricing is subject to change because
 56we plan on continuing to include more services as we build them.`, url)
 57
 58	r, _ := glamour.NewTermRenderer(
 59		// detect background color and pick either the default dark or light theme
 60		glamour.WithAutoStyle(),
 61		glamour.WithWordWrap(w-20),
 62	)
 63	out, _ := r.Render(md)
 64	return out
 65}
 66
 67// Model holds the state of the username UI.
 68type Model struct {
 69	shared   common.SharedModel
 70	viewport viewport.Model
 71}
 72
 73func headerHeight(shrd common.SharedModel) int {
 74	return shrd.HeaderHeight
 75}
 76
 77func headerWidth(w int) int {
 78	return w - 2
 79}
 80
 81// NewModel returns a new username model in its initial state.
 82func NewModel(shared common.SharedModel) Model {
 83	hh := headerHeight(shared)
 84	ww := headerWidth(shared.Width)
 85	viewport := viewport.New(ww, shared.Height-hh)
 86	if shared.User != nil {
 87		viewport.SetContent(PlusView(shared.User.Name, ww))
 88	}
 89
 90	return Model{
 91		shared:   shared,
 92		viewport: viewport,
 93	}
 94}
 95
 96func (m Model) Init() tea.Cmd {
 97	return nil
 98}
 99
100// Update is the Bubble Tea update loop.
101func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
102	switch msg := msg.(type) {
103	case tea.WindowSizeMsg:
104		m.viewport.Width = headerWidth(msg.Width)
105		hh := headerHeight(m.shared)
106		m.viewport.Height = msg.Height - hh
107	case tea.KeyMsg:
108		switch msg.String() {
109		case "q", "esc":
110			return m, pages.Navigate(pages.MenuPage)
111		}
112	}
113
114	var cmd tea.Cmd
115	m.viewport, cmd = m.viewport.Update(msg)
116	return m, cmd
117}
118
119// View renders current view from the model.
120func (m Model) View() string {
121	return m.viewport.View()
122}