package block
import (
"net/url"
"gno.land/p/demo/tokens/grc1155"
"gno.land/p/jeronimoalbi/pager"
"gno.land/p/nt/ufmt"
"gno.land/r/akkadia/admin"
)
func Render(iUrl string) string {
u, err := url.Parse(iUrl)
if err != nil {
return "404\n"
}
path := u.Path
query := u.Query()
switch {
case path == "":
return renderHome()
case path == "blocks":
return renderBlocksList(iUrl)
case path == "block":
return renderBlock(query.Get("id"), query.Get("page"))
case path == "inventory":
return renderInventory(query.Get("owner"))
case path == "grc1155":
return renderGRC1155(query.Get("id"), query.Get("owner"))
default:
return "404\n"
}
}
func renderHome() string {
output := `# Block
Welcome to the Block management system on Akkadia.
## What is Block?
Block is a GRC1155-based multi-token system where each block type represents a unique item in the game:
* **GRC1155 Token**: Each block type is a fungible token with supply limits
* **Mintable**: Users can mint blocks by paying the mint price
* **Tradeable**: Blocks can be transferred between users
* **Usable**: Blocks can be installed/uninstalled in chunks
## How Blocks Work
1. **System Blocks**: Admin creates system blocks (ID < 100000)
2. **User Blocks**: Users can create custom blocks (ID >= 100000)
3. **Minting**: Pay mint price to receive block tokens
4. **Usage**: Install blocks in chunks, uninstall to recover
## Config
`
output += ufmt.Sprintf("* **List Limit**: %d\n", listLimit)
output += ufmt.Sprintf("* **Creator BPS**: %d (%d.%02d%%)\n", creatorBPS, creatorBPS/100, creatorBPS%100)
output += `
## Stats
`
output += ufmt.Sprintf("* **Total Blocks**: %d\n", blocks.Size())
output += ufmt.Sprintf("* **Next Block ID**: %d\n", nextBlockID)
output += `
## Quick Links
* [Browse All Blocks](/r/akkadia/block:blocks)
## Search Block by ID
## Search Inventory by Owner
## Check GRC1155 Balance
`
return output
}
// renderBlocksList renders a list of all blocks with pagination
func renderBlocksList(iUrl string) string {
output := `# All Blocks
[← Home](/r/akkadia/block:)
`
if blocks.Size() == 0 {
output += "*No blocks created yet.*\n"
return output
}
pages, err := pager.New(iUrl, blocks.Size(), pager.WithPageSize(10))
if err != nil {
return output + "Invalid page"
}
// Get current page number for back links
currentPage := (pages.Offset() / pages.PageSize()) + 1
blocks.IterateByOffset(pages.Offset(), pages.PageSize(), func(key string, value interface{}) bool {
block := value.(map[string]string)
blockID := block["id"]
output += ufmt.Sprintf("### [%s - %s](/r/akkadia/block:block?id=%s&page=%d)\n\n", blockID, block["name"], blockID, currentPage)
output += ufmt.Sprintf("* **Type**: %s\n", block["blockType"])
output += ufmt.Sprintf("* **Max Supply**: %s\n", block["maxSupply"])
output += ufmt.Sprintf("* **Mint Price**: %s ugnot\n", block["mintPrice"])
output += "\n---\n\n"
return false
})
if pages.HasPages() {
output += pager.Picker(pages)
}
return output
}
func renderBlock(blockID string, page string) string {
output := "# Block Detail\n\n"
if page != "" {
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)
} else {
output += ufmt.Sprintf("[← Home](/r/akkadia/block:) | [View on Explorer](%s/m/explorer/block?id=%s)\n\n", admin.GetExplorerURL(), blockID)
}
bid := stringToBlockID(blockID)
blockIDKey := blockIDToKey(bid)
propertiesVal, found := blocks.Get(blockIDKey)
if !found {
return output + "Block not found"
}
properties := propertiesVal.(map[string]string)
textureURL := properties["textureURL"]
previewURL := properties["previewURL"]
output += ufmt.Sprintf("## %s\n\n", properties["name"])
output += `## Images
### Texture
|||
### Preview
`
output += ufmt.Sprintf("\n\n|||\n\n\n", textureURL, previewURL)
output += "\n\n"
output += "## Properties\n\n"
for key, value := range properties {
if key == "mintPrice" || key == "usePrice" {
output += ufmt.Sprintf("* **%s**: %s ugnot\n", key, value)
} else if key == "installerBps" {
bps := stringToBlockID(value)
output += ufmt.Sprintf("* **%s**: %s (%d.%02d%%)\n", key, value, bps/100, bps%100)
} else if key == "creator" {
output += ufmt.Sprintf("* **%s**: %s [[View on Explorer](%s/m/explorer/player?address=%s)]\n", key, value, admin.GetExplorerURL(), value)
} else if key == "textureURL" || key == "previewURL" {
output += ufmt.Sprintf("* **%s**: [%s](%s)\n", key, value, value)
} else {
output += ufmt.Sprintf("* **%s**: %s\n", key, value)
}
}
return output
}
func renderInventory(owner string) string {
output := ufmt.Sprintf("# Inventory of %s\n\n", owner)
output += "[← Home](/r/akkadia/block:)\n\n"
if owner == "" {
return output + "Owner address is required"
}
inventory := GetInventory(address(owner))
if len(inventory) == 0 {
output += "*No blocks found for this owner.*\n"
return output
}
output += ufmt.Sprintf("**Total Block Types**: %d\n\n", len(inventory))
output += "---\n\n"
for _, item := range inventory {
blockID := item["id"]
balance := item["balance"]
// Get block info
bid := stringToBlockID(blockID)
blockIDKey := blockIDToKey(bid)
blockVal, found := blocks.Get(blockIDKey)
if found {
block := blockVal.(map[string]string)
output += ufmt.Sprintf("### [%s - %s](/r/akkadia/block:block?id=%s)\n\n", blockID, block["name"], blockID)
output += ufmt.Sprintf("* **Balance**: %s\n", balance)
output += ufmt.Sprintf("* **Type**: %s\n", block["blockType"])
} else {
output += ufmt.Sprintf("### %s\n\n", blockID)
output += ufmt.Sprintf("* **Balance**: %s\n", balance)
}
output += "\n---\n\n"
}
return output
}
func renderGRC1155(blockID string, owner string) string {
output := "# GRC1155 Balance\n\n"
output += "[← Home](/r/akkadia/block:)\n\n"
if blockID == "" || owner == "" {
return output + "Block ID and owner address are required"
}
balance, err := token.BalanceOf(address(owner), grc1155.TokenID(blockID))
if err != nil {
return output + "Error getting balance"
}
output += ufmt.Sprintf("* **Block ID**: %s\n", blockID)
output += ufmt.Sprintf("* **Owner**: %s [[View on Explorer](%s/m/explorer/player?address=%s)]\n", owner, admin.GetExplorerURL(), owner)
output += ufmt.Sprintf("* **Balance**: %d\n\n", balance)
return output
}