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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

render.gno

5.07 Kb · 180 lines
  1package nft
  2
  3import (
  4	"strconv"
  5
  6	"gno.land/p/g17khqpukees4237dtn3astzapmp462vjhsz6st4/settlers/nft/v0"
  7	"gno.land/p/moul/md/v0"
  8	"gno.land/p/moul/mdtable/v0"
  9	"gno.land/p/nt/grc721/v0"
 10	"gno.land/p/nt/markdown/sanitize/v0"
 11	"gno.land/p/nt/mdalert/v0"
 12	"gno.land/p/nt/mux/v0"
 13)
 14
 15const (
 16	// Gallery width is the width/height of gallery Settler images.
 17	galleryWidth = 96
 18
 19	// Detail width is the width/height of Settler the image for detail views.
 20	detailWidth = 256
 21
 22	// Gallery length is the number of last minted Settlers of the home page.
 23	galleryLen = 5
 24)
 25
 26// Render renders the realm.
 27//
 28// By default renders the state of the mint and the last minted Settlers.
 29//
 30// Paths:
 31//   - `token/{id}`: A Settler with its traits and its owner.
 32//   - `addr/{address}`: The Settler of an account.
 33func Render(path string) string {
 34	router := mux.NewRouter()
 35	router.NotFoundHandler = func(res *mux.ResponseWriter, _ *mux.Request) {
 36		res.Write("Path not found")
 37	}
 38
 39	router.HandleFunc("", renderHome)
 40	router.HandleFunc("token/{id}", renderToken)
 41	router.HandleFunc("addr/{addr}", renderAddr)
 42
 43	return router.Render(path)
 44}
 45
 46func renderHome(res *mux.ResponseWriter, _ *mux.Request) {
 47	res.Write(md.H1("Settlers"))
 48
 49	if Notice != "" {
 50		res.Write(mdalert.New(NoticeType, "Message", Notice, false).String() + "\n\n")
 51	}
 52
 53	res.Write(md.Paragraph(
 54		"Soulbound pixel-art gnomes for the early settlers of Gno.land. " +
 55			"Every account that had at least 15 GNOT at the launch of `gnoland-1` can mint one, " +
 56			"first come first served. A Settler can't be transferred, it's soulbound",
 57	))
 58
 59	res.Write(md.Paragraph("Realm paths:"))
 60	pathsTable := mdtable.Table{Headers: []string{"Path", "Description"}}
 61	pathsTable.Append([]string{
 62		md.InlineCode("token/{id}"),
 63		"A Settler with its traits and its owner.",
 64	})
 65	pathsTable.Append([]string{
 66		md.InlineCode("addr/{address}"),
 67		"The Settler of an account.",
 68	})
 69	res.Write(pathsTable.String() + "\n")
 70
 71	minted := tokens.Size()
 72	if len(root) == 0 {
 73		res.Write(md.Paragraph("The mint is not open yet."))
 74	} else {
 75		res.Write(md.Paragraph(
 76			md.BulletItem(md.Bold("Minted:")+" "+strconv.Itoa(minted)+" of "+strconv.Itoa(supplyCap)) +
 77				md.BulletItem(md.Bold("Eligible accounts:")+" "+strconv.Itoa(total)) +
 78				md.BulletItem(md.Bold("Merkle root:")+" "+md.InlineCode(MerkleRoot())),
 79		))
 80
 81		res.Write(md.Paragraph(
 82			"To mint, get your proof from the list of eligible accounts and call " +
 83				md.Link("Mint", RealmPath+"$help&func=Mint") + " with it; the account that " +
 84				"signs the transaction is the one that gets the Settler.",
 85		))
 86		res.Write(md.Paragraph(
 87			"Check the " + md.Link("README", RealmPath+"$source&file=README.md") + " for the full instructions.",
 88		))
 89	}
 90
 91	if minted > 0 {
 92		res.Write(md.H2("Last Settlers"))
 93		tokens.ReverseIterateByOffset(0, galleryLen, func(key string, value any) bool {
 94			settlerID, _ := strconv.Atoi(key)
 95			img := image(settlerID, nft.Unpack(value.(uint32)), galleryWidth)
 96			res.Write("[" + img + "](" + tokenPath(settlerID) + ") ")
 97			return false
 98		})
 99		res.Write("\n\n")
100	}
101
102	res.Write(footer())
103}
104
105func renderToken(res *mux.ResponseWriter, req *mux.Request) {
106	tid := grc721.TokenID(req.GetVar("id"))
107	settlerID, _ := parseTokenID(tid)
108	packed, ok := traitsOf(tid)
109	if !ok {
110		res.Write(md.Paragraph("Settler not found."))
111		res.Write(md.Paragraph(backHomeLink()))
112		return
113	}
114
115	res.Write(md.H1(settlerName(settlerID)))
116	t := nft.Unpack(packed)
117	res.Write(image(settlerID, t, detailWidth) + "\n\n")
118
119	ownerAddr, _ := OwnerOf(tid)
120	owner := ownerAddr.String()
121	res.Write(md.Paragraph(
122		"Owner: " + md.Link(owner, RealmPath+":addr/"+owner) +
123			" · soulbound, it can't be transferred",
124	))
125
126	res.Write("| Trait | Value |\n| --- | --- |\n")
127	for _, attr := range t.Attributes() {
128		res.Write("| " + attr.Type + " | " + attr.Value + " |\n")
129	}
130	res.Write("\n")
131
132	res.Write(md.Paragraph(backHomeLink()))
133	res.Write(footer())
134}
135
136func renderAddr(res *mux.ResponseWriter, req *mux.Request) {
137	addr := sanitize.BechString(req.GetVar("addr"), "g")
138	if addr == "" {
139		res.Write(md.Paragraph("Not a valid address."))
140		res.Write(md.Paragraph(backHomeLink()))
141		return
142	}
143
144	tid := TokenOf(address(addr))
145	if tid == "" {
146		res.Write(md.H1("Settler of " + md.InlineCode(addr)))
147		res.Write(md.Paragraph("This account has not minted a Settler."))
148		res.Write(md.Paragraph(backHomeLink()))
149		return
150	}
151
152	settlerID, _ := parseTokenID(tid)
153	packed, _ := traitsOf(tid)
154	img := image(settlerID, nft.Unpack(packed), detailWidth)
155	res.Write(md.H1("Settler of " + md.InlineCode(addr)))
156	res.Write("[" + img + "](" + tokenPath(settlerID) + ")\n\n")
157	res.Write(md.Paragraph(backHomeLink()))
158	res.Write(footer())
159}
160
161func image(settlerID int, t nft.Traits, width int) string {
162	alt := settlerName(settlerID)
163	return "![" + alt + "](" + nft.RenderDataURI(t, nft.Options{Size: width}) + ")"
164}
165
166func tokenPath(settlerID int) string {
167	return RealmPath + ":token/" + strconv.Itoa(settlerID)
168}
169
170func backHomeLink() string {
171	return md.Link("< Home", RealmPath)
172}
173
174func settlerName(settlerID int) string {
175	return "Settler #" + strconv.Itoa(settlerID)
176}
177
178func footer() string {
179	return md.Blockquote(nft.Credits)
180}