Search Apps Documentation Source Content File Folder Download Copy Actions Download

render.gno

6.75 Kb · 251 lines
  1package block
  2
  3import (
  4	"net/url"
  5
  6	"gno.land/p/demo/tokens/grc1155"
  7	"gno.land/p/jeronimoalbi/pager"
  8	"gno.land/p/nt/ufmt"
  9	"gno.land/r/akkadia/admin"
 10)
 11
 12func Render(iUrl string) string {
 13	u, err := url.Parse(iUrl)
 14	if err != nil {
 15		return "404\n"
 16	}
 17
 18	path := u.Path
 19	query := u.Query()
 20
 21	switch {
 22	case path == "":
 23		return renderHome()
 24	case path == "blocks":
 25		return renderBlocksList(iUrl)
 26	case path == "block":
 27		return renderBlock(query.Get("id"), query.Get("page"))
 28	case path == "inventory":
 29		return renderInventory(query.Get("owner"))
 30	case path == "grc1155":
 31		return renderGRC1155(query.Get("id"), query.Get("owner"))
 32	default:
 33		return "404\n"
 34	}
 35}
 36
 37func renderHome() string {
 38	output := `# Block
 39
 40Welcome to the Block management system on Akkadia.
 41
 42## What is Block?
 43
 44Block is a GRC1155-based multi-token system where each block type represents a unique item in the game:
 45
 46* **GRC1155 Token**: Each block type is a fungible token with supply limits
 47* **Mintable**: Users can mint blocks by paying the mint price
 48* **Tradeable**: Blocks can be transferred between users
 49* **Usable**: Blocks can be installed/uninstalled in chunks
 50
 51## How Blocks Work
 52
 531. **System Blocks**: Admin creates system blocks (ID < 100000)
 542. **User Blocks**: Users can create custom blocks (ID >= 100000)
 553. **Minting**: Pay mint price to receive block tokens
 564. **Usage**: Install blocks in chunks, uninstall to recover
 57
 58## Config
 59
 60`
 61	output += ufmt.Sprintf("* **List Limit**: %d\n", listLimit)
 62	output += ufmt.Sprintf("* **Creator BPS**: %d (%d.%02d%%)\n", creatorBPS, creatorBPS/100, creatorBPS%100)
 63
 64	output += `
 65## Stats
 66
 67`
 68	output += ufmt.Sprintf("* **Total Blocks**: %d\n", blocks.Size())
 69	output += ufmt.Sprintf("* **Next Block ID**: %d\n", nextBlockID)
 70
 71	output += `
 72## Quick Links
 73
 74* [Browse All Blocks](/r/akkadia/block:blocks)
 75
 76## Search Block by ID
 77
 78<gno-form path="block">
 79  <gno-input name="id" placeholder="Enter block ID" />
 80</gno-form>
 81
 82## Search Inventory by Owner
 83
 84<gno-form path="inventory">
 85  <gno-input name="owner" placeholder="Enter owner address" />
 86</gno-form>
 87
 88## Check GRC1155 Balance
 89
 90<gno-form path="grc1155">
 91  <gno-input name="id" placeholder="Enter block ID" />
 92  <gno-input name="owner" placeholder="Enter owner address" />
 93</gno-form>
 94`
 95
 96	return output
 97}
 98
 99// renderBlocksList renders a list of all blocks with pagination
100func renderBlocksList(iUrl string) string {
101	output := `# All Blocks
102
103[← Home](/r/akkadia/block:)
104
105`
106	if blocks.Size() == 0 {
107		output += "*No blocks created yet.*\n"
108		return output
109	}
110
111	pages, err := pager.New(iUrl, blocks.Size(), pager.WithPageSize(10))
112	if err != nil {
113		return output + "Invalid page"
114	}
115
116	// Get current page number for back links
117	currentPage := (pages.Offset() / pages.PageSize()) + 1
118
119	blocks.IterateByOffset(pages.Offset(), pages.PageSize(), func(key string, value interface{}) bool {
120		block := value.(map[string]string)
121		blockID := block["id"]
122		output += ufmt.Sprintf("### [%s - %s](/r/akkadia/block:block?id=%s&page=%d)\n\n", blockID, block["name"], blockID, currentPage)
123		output += ufmt.Sprintf("* **Type**: %s\n", block["blockType"])
124		output += ufmt.Sprintf("* **Max Supply**: %s\n", block["maxSupply"])
125		output += ufmt.Sprintf("* **Mint Price**: %s ugnot\n", block["mintPrice"])
126		output += "\n---\n\n"
127		return false
128	})
129
130	if pages.HasPages() {
131		output += pager.Picker(pages)
132	}
133
134	return output
135}
136
137func renderBlock(blockID string, page string) string {
138	output := "# Block Detail\n\n"
139	if page != "" {
140		output += ufmt.Sprintf("[← Back to List](/r/akkadia/block:blocks?page=%s) | [View on Explorer](%s/m/explorer/block?id=%s)\n\n", page, admin.GetExplorerURL(), blockID)
141	} else {
142		output += ufmt.Sprintf("[← Home](/r/akkadia/block:) | [View on Explorer](%s/m/explorer/block?id=%s)\n\n", admin.GetExplorerURL(), blockID)
143	}
144
145	bid := stringToBlockID(blockID)
146	blockIDKey := blockIDToKey(bid)
147	propertiesVal, found := blocks.Get(blockIDKey)
148	if !found {
149		return output + "Block not found"
150	}
151	properties := propertiesVal.(map[string]string)
152
153	textureURL := properties["textureURL"]
154	previewURL := properties["previewURL"]
155
156	output += ufmt.Sprintf("## %s\n\n", properties["name"])
157
158	output += `## Images
159<gno-columns>
160### Texture
161
162|||
163
164### Preview
165</gno-columns>
166<gno-columns>
167`
168	output += ufmt.Sprintf("![TextureURL](%s)\n\n|||\n\n![PreviewURL](%s192)\n", textureURL, previewURL)
169	output += "</gno-columns>\n\n"
170
171	output += "## Properties\n\n"
172
173	for key, value := range properties {
174		if key == "mintPrice" || key == "usePrice" {
175			output += ufmt.Sprintf("* **%s**: %s ugnot\n", key, value)
176		} else if key == "installerBps" {
177			bps := stringToBlockID(value)
178			output += ufmt.Sprintf("* **%s**: %s (%d.%02d%%)\n", key, value, bps/100, bps%100)
179		} else if key == "creator" {
180			output += ufmt.Sprintf("* **%s**: %s [[View on Explorer](%s/m/explorer/player?address=%s)]\n", key, value, admin.GetExplorerURL(), value)
181		} else if key == "textureURL" || key == "previewURL" {
182			output += ufmt.Sprintf("* **%s**: [%s](%s)\n", key, value, value)
183		} else {
184			output += ufmt.Sprintf("* **%s**: %s\n", key, value)
185		}
186	}
187
188	return output
189}
190
191func renderInventory(owner string) string {
192	output := ufmt.Sprintf("# Inventory of %s\n\n", owner)
193	output += "[← Home](/r/akkadia/block:)\n\n"
194
195	if owner == "" {
196		return output + "Owner address is required"
197	}
198
199	inventory := GetInventory(address(owner))
200
201	if len(inventory) == 0 {
202		output += "*No blocks found for this owner.*\n"
203		return output
204	}
205
206	output += ufmt.Sprintf("**Total Block Types**: %d\n\n", len(inventory))
207	output += "---\n\n"
208
209	for _, item := range inventory {
210		blockID := item["id"]
211		balance := item["balance"]
212
213		// Get block info
214		bid := stringToBlockID(blockID)
215		blockIDKey := blockIDToKey(bid)
216		blockVal, found := blocks.Get(blockIDKey)
217
218		if found {
219			block := blockVal.(map[string]string)
220			output += ufmt.Sprintf("### [%s - %s](/r/akkadia/block:block?id=%s)\n\n", blockID, block["name"], blockID)
221			output += ufmt.Sprintf("* **Balance**: %s\n", balance)
222			output += ufmt.Sprintf("* **Type**: %s\n", block["blockType"])
223		} else {
224			output += ufmt.Sprintf("### %s\n\n", blockID)
225			output += ufmt.Sprintf("* **Balance**: %s\n", balance)
226		}
227		output += "\n---\n\n"
228	}
229
230	return output
231}
232
233func renderGRC1155(blockID string, owner string) string {
234	output := "# GRC1155 Balance\n\n"
235	output += "[← Home](/r/akkadia/block:)\n\n"
236
237	if blockID == "" || owner == "" {
238		return output + "Block ID and owner address are required"
239	}
240
241	balance, err := token.BalanceOf(address(owner), grc1155.TokenID(blockID))
242	if err != nil {
243		return output + "Error getting balance"
244	}
245
246	output += ufmt.Sprintf("* **Block ID**: %s\n", blockID)
247	output += ufmt.Sprintf("* **Owner**: %s [[View on Explorer](%s/m/explorer/player?address=%s)]\n", owner, admin.GetExplorerURL(), owner)
248	output += ufmt.Sprintf("* **Balance**: %d\n\n", balance)
249
250	return output
251}