format.gno
2.35 Kb · 98 lines
1package boards2
2
3import (
4 "strconv"
5 "strings"
6
7 "gno.land/p/gnoland/boards"
8 "gno.land/p/moul/md"
9 "gno.land/p/nt/markdown/foreign/v0"
10
11 "gno.land/r/sys/users"
12)
13
14const dateFormat = "2006-01-02 3:04pm MST"
15
16func padLeft(s string, length int) string {
17 if len(s) >= length {
18 return s
19 }
20 return strings.Repeat(" ", length-len(s)) + s
21}
22
23func padZero(u64 uint64, length int) string {
24 s := strconv.Itoa(int(u64))
25 if len(s) >= length {
26 return s
27 }
28 return strings.Repeat("0", length-len(s)) + s
29}
30
31func indentBody(indent string, body string) string {
32 var (
33 res string
34 lines = strings.Split(body, "\n")
35 )
36 for i, line := range lines {
37 if i > 0 {
38 // Add two spaces to keep newlines within Markdown
39 res += " \n"
40 }
41 res += indent + line
42 }
43 return res
44}
45
46// indentForeignBody is the single "render a user body" operation: it
47// sandboxes the body in a <gno-foreign> block, indents it like
48// indentBody, AND charges one unit against the per-render budget — so
49// wrapping and budget-accounting can't drift apart (the *int signals
50// the mutation). The body renders inside the sandbox: its block
51// structure (headings, blockquotes, lists, columns, alerts) is
52// contained and cannot hijack realm chrome, so boards no longer needs
53// the write-time markdown blacklist. The opener survives the "> "
54// comment indentation at any depth (goldmark strips the "> " prefix
55// before the block parser runs).
56func indentForeignBody(indent, body string, budget *int) string {
57 *budget-- // one <gno-foreign> block
58 return indentBody(indent, foreign.Foreign(body))
59}
60
61func summaryOf(text string, length int) string {
62 lines := strings.SplitN(text, "\n", 2)
63 line := lines[0]
64 if len(line) > length {
65 line = line[:(length-3)] + "..."
66 } else if len(lines) > 1 {
67 line = line + "..."
68 }
69 return line
70}
71
72func userLink(addr address) string {
73 if u := users.ResolveAddress(addr); u != nil {
74 return md.UserLink(u.Name())
75 }
76 return md.UserLink(addr.String())
77}
78
79func getRoleBadge(post *boards.Post) string {
80 if post == nil || post.Board == nil || post.Board.Permissions == nil {
81 return ""
82 }
83
84 perms := post.Board.Permissions
85 creator := post.Creator
86
87 // Check roles in order of priority
88 if perms.HasRole(creator, RoleOwner) {
89 return " `owner`"
90 }
91 if perms.HasRole(creator, RoleAdmin) {
92 return " `admin`"
93 }
94 if perms.HasRole(creator, RoleModerator) {
95 return " `mod`"
96 }
97 return ""
98}