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

avatar.gno

5.03 Kb · 173 lines
  1package avatar
  2
  3import (
  4	"chain"
  5	"chain/runtime"
  6	"strings"
  7
  8	"gno.land/p/g17khqpukees4237dtn3astzapmp462vjhsz6st4/settlers/nft/v0"
  9	"gno.land/p/nt/grc721/v0"
 10	"gno.land/p/nt/mdalert/v0"
 11	"gno.land/p/nt/ownable/v0"
 12	settlers "gno.land/r/g17khqpukees4237dtn3astzapmp462vjhsz6st4/settlers/nft"
 13)
 14
 15const (
 16	// MinSize is the minimum size allowed for an avatar in pixels.
 17	MinSize = 32
 18
 19	// MaxSize is the maximum size allowed for an avatar in pixels.
 20	MaxSize = 2048
 21)
 22
 23var (
 24	// Notice is a realm-wide message the admin can post at any time, shown at the top of the page.
 25	// It never affects SVG, URI or Markdown, it is purely informational.
 26	Notice string
 27
 28	// NoticeType is the style Notice is shown as.
 29	NoticeType mdalert.Type
 30
 31	// Realm path is the path of this realm.
 32	RealmPath string
 33
 34	// Admin account for the realm, only valid to post or clear realm-wide notices.
 35	admin *ownable.Ownable
 36
 37	// Go snippet is the Go usage example.
 38	goSnippet string
 39
 40	// Gnokey snippet is the gnokey example.
 41	gnokeySnippet string
 42)
 43
 44func init(cur realm) {
 45	RealmPath = strings.TrimPrefix(cur.PkgPath(), runtime.ChainDomain())
 46	admin = ownable.NewWithAddress(cur.Previous().Address())
 47	pkgPath := runtime.ChainDomain() + RealmPath
 48
 49	goSnippet = "import \"" + pkgPath + "\"\n\n" +
 50		"func RenderUser(addr address) string {\n\treturn avatar.Markdown(addr, 32, true) " +
 51		"+ \" \" + addr.String()\n}\n"
 52
 53	gnokeySnippet = "gnokey query vm/qrender \\\n" +
 54		"  -remote <remote> \\\n" +
 55		"  -data \"" + pkgPath + ":svg/{address}?size=256\" \\\n" +
 56		"  | tail -n +2 | sed '1s/^data: //' > settler.svg\n"
 57}
 58
 59// Admin returns the address of the admin account.
 60func Admin() address { return admin.Owner() }
 61
 62// TransferAdmin makes another account the admin. Only the admin can call it.
 63func TransferAdmin(cur realm, newAdmin address) {
 64	assertIsCurrent(cur)
 65	if err := admin.TransferOwnership(0, cur, newAdmin); err != nil {
 66		panic(err)
 67	}
 68}
 69
 70// SetNotice posts a realm-wide message, shown at the top of the page.
 71func SetNotice(cur realm, alertType mdalert.Type, msg string) {
 72	assertIsCurrent(cur)
 73	admin.AssertOwnedBy(cur.Previous().Address())
 74	assertIsValidAlertType(alertType)
 75
 76	NoticeType = alertType
 77	Notice = msg
 78	chain.Emit("NoticeSet", "type", string(alertType))
 79}
 80
 81// ClearNotice removes the current notice.
 82func ClearNotice(cur realm) {
 83	assertIsCurrent(cur)
 84	admin.AssertOwnedBy(cur.Previous().Address())
 85
 86	NoticeType = ""
 87	Notice = ""
 88	chain.Emit("NoticeCleared")
 89}
 90
 91// SVG returns the SVG document of the Settler of an address, or an empty text if it has none.
 92//
 93// The size is the width and height in pixels of the square image, from 32 to 2048 (multiples of 32 keep
 94// every art pixel as a whole number of screen pixels). A size of 0 or less leaves out the width and the
 95// height, so that the image scales to its container. If transparent is true, the image has no background.
 96func SVG(addr address, size int, transparent bool) string {
 97	if tid, traits := lookup(addr); tid != "" {
 98		return nft.RenderSVG(traits, options(size, transparent))
 99	}
100	return ""
101}
102
103// URI returns the image of the Settler of an address as a "data:image/svg+xml;charset=utf-8," URI, that can
104// be used as the source of an image or as the address of a Markdown image, or an empty text if it has none.
105// The size and transparent are the same as in SVG.
106func URI(addr address, size int, transparent bool) string {
107	if tid, traits := lookup(addr); tid != "" {
108		return nft.RenderDataURI(traits, options(size, transparent))
109	}
110	return ""
111}
112
113// Markdown returns the avatar of an address as a Markdown image, or an empty text if it has none:
114//
115//	![Settler #12](data:image/svg+xml;charset=utf-8,...)
116//
117// The size and transparent are the same as in SVG.
118func Markdown(addr address, size int, transparent bool) string {
119	if tid, traits := lookup(addr); tid != "" {
120		uri := nft.RenderDataURI(traits, options(size, transparent))
121		return "![Settler #" + string(tid) + "](" + uri + ")"
122	}
123	return ""
124}
125
126// lookup returns the ID and traits of the Settler of an address, or an empty ID and a zero-value Traits if it
127// has none.
128func lookup(addr address) (grc721.TokenID, nft.Traits) {
129	tid := settlers.TokenOf(addr)
130	if tid == "" {
131		return "", nft.Traits{}
132	}
133
134	traits, err := settlers.TraitsOf(tid)
135	if err != nil {
136		return "", nft.Traits{}
137	}
138	return tid, traits
139}
140
141// options builds the nft.Options for an image; size is clamped between MinSize and MaxSize (0 or less is
142// left as 0, so the image has no fixed size and scales to its container), and transparent controls whether
143// the background is drawn.
144func options(size int, transparent bool) nft.Options {
145	switch {
146	case size <= 0:
147		size = 0
148	case size < MinSize:
149		size = MinSize
150	case size > MaxSize:
151		size = MaxSize
152	}
153
154	return nft.Options{
155		Size:         size,
156		NoBackground: transparent,
157	}
158}
159
160func assertIsCurrent(cur realm) {
161	if !cur.IsCurrent() {
162		panic("unauthorized")
163	}
164}
165
166func assertIsValidAlertType(t mdalert.Type) {
167	switch t {
168	case mdalert.TypeCaution, mdalert.TypeInfo, mdalert.TypeNote,
169		mdalert.TypeSuccess, mdalert.TypeTip, mdalert.TypeWarning:
170		return
171	}
172	panic("invalid notice type")
173}