Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}