Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}