Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}