render.gno
3.59 Kb · 143 lines
1package memba_collections
2
3import (
4 "strings"
5
6 "gno.land/p/nt/ufmt/v0"
7)
8
9const renderPageSize = 50
10
11// CollectionView is a structured read of a collection's public fields.
12type CollectionView struct {
13 ID string
14 Creator address
15 Admin address
16 Name string
17 Symbol string
18 RoyaltyBPS int64
19 RoyaltyRecip address
20 Phase int
21 MintPrice int64
22 PayDenom string
23 MaxSupply int64
24 MaxPerWallet int64
25 Minted int64
26 Paused bool
27}
28
29// CollectionInfo returns a structured view of a collection.
30func CollectionInfo(id string) CollectionView {
31 c := mustGet(id)
32 return CollectionView{
33 ID: id,
34 Creator: c.creator,
35 Admin: c.admin,
36 Name: c.nft.Name(),
37 Symbol: c.nft.Symbol(),
38 RoyaltyBPS: c.royaltyBPS,
39 RoyaltyRecip: c.royaltyRecip,
40 Phase: c.phase,
41 MintPrice: c.mintPrice,
42 PayDenom: denomKey(c.payDenom),
43 MaxSupply: c.maxSupply,
44 MaxPerWallet: c.maxPerWallet,
45 Minted: c.nextAutoTokenID,
46 Paused: c.paused,
47 }
48}
49
50// MintedBy returns how many tokens an address has minted in a collection.
51func MintedBy(id string, who address) int64 {
52 return walletCount(mustGet(id), who)
53}
54
55// Render mux:
56// "" → paginated collection list (?page=N)
57// "collection/<id>" → collection detail
58func Render(path string) string {
59 if path == "" || strings.HasPrefix(path, "?") {
60 return renderList(parsePage(path))
61 }
62 if strings.HasPrefix(path, "collection/") {
63 return renderCollection(strings.TrimPrefix(path, "collection/"))
64 }
65 return "# Not found\n\nUnknown path: " + path
66}
67
68func parsePage(path string) int {
69 idx := strings.Index(path, "page=")
70 if idx < 0 {
71 return 1
72 }
73 rest := path[idx+5:]
74 if amp := strings.IndexByte(rest, '&'); amp >= 0 {
75 rest = rest[:amp]
76 }
77 n := 0
78 for i := 0; i < len(rest); i++ {
79 c := rest[i]
80 if c < '0' || c > '9' {
81 break
82 }
83 n = n*10 + int(c-'0')
84 }
85 if n < 1 {
86 return 1
87 }
88 return n
89}
90
91func renderList(page int) string {
92 var b strings.Builder
93 b.WriteString("# Memba Collections\n\n")
94 if paused {
95 b.WriteString("> ⚠️ Registry is globally paused.\n\n")
96 }
97 total := collections.Size()
98 if total == 0 {
99 b.WriteString("_No collections yet._\n")
100 return b.String()
101 }
102 start := (page - 1) * renderPageSize
103 end := start + renderPageSize
104 i := 0
105 shown := 0
106 collections.Iterate("", "", func(key string, v any) bool {
107 if i >= start && i < end {
108 c := v.(*collection)
109 b.WriteString(ufmt.Sprintf("- **%s** (%s) — phase %d, minted %d\n",
110 c.nft.Name(), key, c.phase, c.nextAutoTokenID))
111 shown++
112 }
113 i++
114 return i >= end
115 })
116 b.WriteString(ufmt.Sprintf("\n_Page %d — %d of %d collections._\n", page, shown, total))
117 return b.String()
118}
119
120func renderCollection(id string) string {
121 v, ok := collections.Get(id)
122 if !ok {
123 return "# Not found\n\nNo collection: " + id
124 }
125 c := v.(*collection)
126 var b strings.Builder
127 b.WriteString(ufmt.Sprintf("# %s (%s)\n\n", c.nft.Name(), c.nft.Symbol()))
128 b.WriteString(ufmt.Sprintf("- ID: `%s`\n", id))
129 b.WriteString(ufmt.Sprintf("- Creator: %s\n", c.creator.String()))
130 b.WriteString(ufmt.Sprintf("- Admin: %s\n", c.admin.String()))
131 b.WriteString(ufmt.Sprintf("- Royalty: %d bps → %s\n", c.royaltyBPS, c.royaltyRecip.String()))
132 b.WriteString(ufmt.Sprintf("- Phase: %d\n", c.phase))
133 b.WriteString(ufmt.Sprintf("- Mint price: %d %s\n", c.mintPrice, denomKey(c.payDenom)))
134 b.WriteString(ufmt.Sprintf("- Supply: %d", c.nextAutoTokenID))
135 if c.maxSupply > 0 {
136 b.WriteString(ufmt.Sprintf(" / %d", c.maxSupply))
137 }
138 b.WriteString("\n")
139 if c.paused {
140 b.WriteString("- ⚠️ Paused\n")
141 }
142 return b.String()
143}