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

render.gno

1.85 Kb · 73 lines
 1package memba_appstore_v3
 2
 3import (
 4	"chain/runtime"
 5
 6	"gno.land/p/nt/ufmt/v0"
 7)
 8
 9// RenderMaxRows bounds the Render() output so a large catalog can never make the
10// realm render-DoS (mirrors the feed's live-only bounded render).
11const RenderMaxRows = 100
12
13// Render shows the live catalog (bounded) — a read-only trust surface for gnoweb.
14// The frontend reads structured data via the getters, not this markdown.
15func Render(path string) string {
16	sb := ""
17	sb += "# Memba App Store\n\n"
18	sb += ufmt.Sprintf("Curated gno.land dApps. **Listing fee:** %d ugnot → treasury.\n\n", registrationFee)
19	if paused {
20		sb += "> ⏸️ Registration is paused.\n\n"
21	}
22
23	rows := 0
24	live := 0
25	sb += "| App | Package | Category |\n|---|---|---|\n"
26	listings.Iterate("", "", func(_ string, v any) bool {
27		l := v.(*Listing)
28		// Curated gnoweb view: live (Verified) + un-flag-hidden only — never pending/rejected.
29		if l.Status != StatusLive || l.FlagCount >= FlagHideThreshold {
30			return false
31		}
32		live++
33		if rows >= RenderMaxRows {
34			return false // stop appending, keep counting via the header below
35		}
36		rows++
37		sb += ufmt.Sprintf("| %s | `%s` | %s |\n", esc(l.Name), esc(l.PkgPath), esc(l.Category))
38		return false
39	})
40
41	if live == 0 {
42		sb += "\n*No live apps yet.*\n"
43	} else {
44		sb += ufmt.Sprintf("\n*%d live app(s)%s. Block %d.*\n", live, moreNote(live), runtime.ChainHeight())
45	}
46	return sb
47}
48
49func moreNote(live int) string {
50	if live > RenderMaxRows {
51		return ufmt.Sprintf(" (showing first %d)", RenderMaxRows)
52	}
53	return ""
54}
55
56// esc neutralizes the markdown/table metachars that could break the table or inject
57// layout from an attacker-supplied listing field.
58func esc(s string) string {
59	out := ""
60	for _, r := range s {
61		switch r {
62		case '|':
63			out += "\\|"
64		case '\n', '\r':
65			out += " "
66		case '`':
67			out += "'"
68		default:
69			out += string(r)
70		}
71	}
72	return out
73}