Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

format.gno

2.36 Kb · 98 lines
 1package boards2
 2
 3import (
 4	"strconv"
 5	"strings"
 6
 7	"gno.land/p/gnoland/boards/v0"
 8	"gno.land/p/moul/md/v0"
 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}