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.13 Kb · 167 lines
  1package avatar
  2
  3import (
  4	"strconv"
  5
  6	"gno.land/p/moul/md/v0"
  7	"gno.land/p/moul/mdtable/v0"
  8	"gno.land/p/nt/grc721/v0"
  9	"gno.land/p/nt/mdalert/v0"
 10	"gno.land/p/nt/mux/v0"
 11	settlers "gno.land/r/g17khqpukees4237dtn3astzapmp462vjhsz6st4/settlers/nft"
 12)
 13
 14const (
 15	// Sample size is the size in pixels of the avatars in the pages.
 16	sampleSize = 48
 17
 18	// Samples is how many avatars the home page shows.
 19	samples = 6
 20)
 21
 22// Render renders the realm.
 23//
 24// By default renders what this realm is, how to use it, and some avatars.
 25//
 26// Paths:
 27//   - `svg/{address}`: The SVG of the Settler of an address.
 28//   - `md/{address}`: The Markdown that Markdown returns for an address, rendered, with the same parameters.
 29func Render(path string) string {
 30	router := mux.NewRouter()
 31	router.NotFoundHandler = func(res *mux.ResponseWriter, _ *mux.Request) {
 32		res.Write("Path not found")
 33	}
 34
 35	router.HandleFunc("", renderHome)
 36	router.HandleFunc("svg/{addr}", renderSVG)
 37	router.HandleFunc("md/{addr}", renderMarkdown)
 38
 39	return router.Render(path)
 40}
 41
 42func renderHome(res *mux.ResponseWriter, _ *mux.Request) {
 43	res.Write(md.H1("Settler avatars"))
 44
 45	if Notice != "" {
 46		res.Write(mdalert.New(NoticeType, "Message", Notice, false).String() + "\n\n")
 47	}
 48
 49	res.Write(md.Paragraph("This realm draws a Settler as a picture give an address."))
 50	res.Write(md.Paragraph(
 51		"It doesn't own the Settler, or store anything about it, it just looks one up and draws it, " +
 52			"fresh, every time it's asked. That's on purpose, keeping the drawing separate from the main " +
 53			"collection means any other realm or web app on Gno.land, a forum, a leaderboard, a profile " +
 54			"page, can show a Settler next to an address without needing to understand pixel art, traits, " +
 55			"or how any of it's put together.",
 56	))
 57
 58	res.Write(md.Paragraph(
 59		"The " + md.Link("Settlers nft", settlers.RealmPath) + " realm is still the one that actually mints " +
 60			"the Settlers and keeps track of who owns what.",
 61	))
 62
 63	res.Write(md.Paragraph("Realm paths:"))
 64	pathsTable := mdtable.Table{Headers: []string{"Path", "Description"}}
 65	pathsTable.Append([]string{
 66		md.InlineCode("svg/{address}"),
 67		"The SVG of the Settler of an address.",
 68	})
 69	pathsTable.Append([]string{
 70		md.InlineCode("md/{address}"),
 71		"The Markdown that Markdown returns for an address, rendered, with the same parameters.",
 72	})
 73	res.Write(pathsTable.String() + "\n")
 74
 75	res.Write(md.H2("From a realm"))
 76	res.Write(md.Paragraph(
 77		"Call it directly from another realm, for example to show a Settler " +
 78			"next to an address in your own " + md.InlineCode("Render") + " function:",
 79	))
 80	res.Write(md.LanguageCodeBlock("go", goSnippet))
 81
 82	table := mdtable.Table{Headers: []string{"Function", "Description"}}
 83	table.Append([]string{
 84		"Markdown(addr, size, transparent)",
 85		"The image, or an empty text if there is none",
 86	})
 87	table.Append([]string{
 88		"SVG(addr, size, transparent)",
 89		"The SVG document, or an empty text if there is none",
 90	})
 91	table.Append([]string{
 92		"URI(addr, size, transparent)",
 93		"The same image as a data URI",
 94	})
 95	res.Write(table.String() + "\n")
 96
 97	res.Write(md.Paragraph(
 98		"The size is in pixels, from 32 to 2048, and 0 leaves it to the container. " +
 99			"With transparent the image has no background. Every call draws the image again and " +
100			"costs gas (about 6 to 8 million), so use it in `Render` and not in a transaction.",
101	))
102
103	res.Write(md.H2("From a web app"))
104	res.Write(md.Paragraph(
105		"Ask the node for the page of an address, with `vm/qrender`, and use what it returns as an image: " +
106			md.InlineCode(RealmPath+":svg/{address}?size=64&transparent=1") +
107			". It is empty if the address has no Settler.",
108	))
109	res.Write(md.Paragraph("With gnokey, from a terminal, save it straight to a file:"))
110	res.Write(md.LanguageCodeBlock("sh", gnokeySnippet))
111
112	if n := settlers.TotalSupply(); n > 0 {
113		res.Write(md.H2("Last Settlers"))
114
115		for id := n; id > 0 && id > n-samples; id-- {
116			tid := grc721.TokenID(strconv.FormatInt(id, 10))
117			owner, err := settlers.OwnerOf(tid)
118			if err != nil {
119				continue
120			}
121
122			tokenPath := settlers.RealmPath + ":token/" + string(tid)
123			table := mdtable.Table{Headers: []string{"", ""}}
124			table.Append([]string{
125				Markdown(owner, sampleSize, false),
126				md.Link(owner.String(), tokenPath),
127			})
128			res.Write(table.String() + "\n")
129		}
130	}
131}
132
133func renderSVG(res *mux.ResponseWriter, req *mux.Request) {
134	svg := SVG(address(req.GetVar("addr")), sizeParam(req), transparentParam(req))
135	res.Write(svg)
136}
137
138func renderMarkdown(res *mux.ResponseWriter, req *mux.Request) {
139	size := sizeParam(req)
140	if size == 0 {
141		size = sampleSize
142	}
143
144	addr := req.GetVar("addr")
145	if !address(addr).IsValid() {
146		res.Write(md.Paragraph("Not a valid address."))
147		res.Write(md.Paragraph(md.Link("< Home", RealmPath)))
148		return
149	}
150
151	res.Write(md.H1("Avatar of " + md.InlineCode(addr)))
152	res.Write(md.Paragraph(Markdown(address(addr), size, transparentParam(req))))
153	res.Write(md.Paragraph(md.Link("< Home", RealmPath)))
154}
155
156func sizeParam(req *mux.Request) int {
157	size, err := strconv.Atoi(req.Query.Get("size"))
158	if err != nil {
159		return 0
160	}
161	return size
162}
163
164func transparentParam(req *mux.Request) bool {
165	v := req.Query.Get("transparent")
166	return v == "1" || v == "true"
167}