Eric Bower
·
2026-04-16
plus.go
1package tui
2
3import (
4 "fmt"
5 "math"
6 "net/url"
7
8 "git.sr.ht/~rockorager/vaxis"
9 "git.sr.ht/~rockorager/vaxis/vxfw"
10 "git.sr.ht/~rockorager/vaxis/vxfw/richtext"
11)
12
13type PlusPage struct {
14 shared *SharedModel
15
16 pager *Pager
17}
18
19func NewPlusPage(shrd *SharedModel) *PlusPage {
20 page := &PlusPage{
21 shared: shrd,
22 }
23 page.pager = NewPager()
24 return page
25}
26
27func (m *PlusPage) HandleEvent(ev vaxis.Event, phase vxfw.EventPhase) (vxfw.Command, error) {
28 switch ev.(type) {
29 case PageIn:
30 return vxfw.FocusWidgetCmd(m.pager), nil
31 }
32 return nil, nil
33}
34
35func (m *PlusPage) header(ctx vxfw.DrawContext) vxfw.Surface {
36 intro := richtext.New([]vaxis.Segment{
37 {
38 Text: "$2/mo\n",
39 Style: vaxis.Style{
40 UnderlineStyle: vaxis.UnderlineCurly,
41 UnderlineColor: oj,
42 Foreground: oj,
43 },
44 },
45 {
46 Text: "(billed yearly)\n\n",
47 },
48
49 {Text: "• tuns\n"},
50 {Text: " • per-site analytics\n"},
51 {Text: "• pgs\n"},
52 {Text: " • per-file max size 100mb\n"},
53 {Text: " • per-site analytics\n"},
54 {Text: "• prose\n"},
55 {Text: " • blog analytics\n"},
56 {Text: "• irc bouncer\n"},
57 {Text: "• 10GB total storage\n"},
58 })
59 brd := NewBorder(intro)
60 brd.Label = "pico+"
61 surf, _ := brd.Draw(ctx)
62 return surf
63}
64
65func (m *PlusPage) payment(ctx vxfw.DrawContext) vxfw.Surface {
66 paymentLink := "https://auth.pico.sh/checkout"
67 link := fmt.Sprintf("%s/%s", paymentLink, url.QueryEscape(m.shared.User.Name))
68 header := vaxis.Style{Foreground: oj, UnderlineColor: oj, UnderlineStyle: vaxis.UnderlineDashed}
69 pay := richtext.New([]vaxis.Segment{
70 {Text: "You can use this same flow to add additional years to your membership, including if you are already a pico+ user.\n\n", Style: vaxis.Style{Foreground: green}},
71
72 {Text: "There are a few ways to purchase a membership. We try our best to provide immediate access to pico+ regardless of payment method.\n"},
73
74 {Text: "\nOnline payment\n\n", Style: header},
75
76 {Text: link + "\n", Style: vaxis.Style{Hyperlink: link}},
77
78 {Text: "\nSnail mail\n\n", Style: header},
79
80 {Text: "Send cash (USD) or check to:\n\n"},
81 {Text: "• pico.sh LLC\n"},
82 {Text: "• 206 E Huron St\n"},
83 {Text: "• Ann Arbor MI 48104\n\n"},
84 {Text: "Have any questions? Feel free to reach out:\n\n"},
85 {Text: "• "}, {Text: "mailto:hello@pico.sh\n", Style: vaxis.Style{Hyperlink: "mailto:hello@pico.sh"}},
86 {Text: "• "}, {Text: "https://pico.sh/irc\n", Style: vaxis.Style{Hyperlink: "https://pico.sh/irc"}},
87 })
88 brd := NewBorder(pay)
89 brd.Label = "payment"
90 surf, _ := brd.Draw(vxfw.DrawContext{
91 Characters: ctx.Characters,
92 Max: vxfw.Size{Width: 50, Height: math.MaxUint16},
93 })
94 return surf
95}
96
97func (m *PlusPage) notes(ctx vxfw.DrawContext) vxfw.Surface {
98 wdgt := richtext.New([]vaxis.Segment{
99 {Text: "We do not maintain active subscriptions. "},
100 {Text: "Every year you must pay again. We do not take monthly payments, you must pay for a year up-front. Pricing is subject to change."},
101 })
102 brd := NewBorder(wdgt)
103 brd.Label = "notes"
104 surf, _ := brd.Draw(vxfw.DrawContext{
105 Characters: ctx.Characters,
106 Max: vxfw.Size{Width: 50, Height: math.MaxUint16},
107 })
108 return surf
109}
110
111func (m *PlusPage) Draw(ctx vxfw.DrawContext) (vxfw.Surface, error) {
112 stack := NewGroupStack([]vxfw.Surface{
113 m.header(ctx),
114 m.notes(ctx),
115 m.payment(ctx),
116 })
117 stack.Gap = 1
118 surf, _ := stack.Draw(createDrawCtx(ctx, math.MaxUint16))
119 m.pager.Surface = surf
120 return m.pager.Draw(ctx)
121}