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

render.gno

4.21 Kb · 144 lines
  1package namereg
  2
  3import (
  4	"gno.land/p/moul/md/v0"
  5	"gno.land/p/moul/realmpath/v0"
  6	"gno.land/p/moul/txlink/v0"
  7	"gno.land/p/nt/ufmt/v0"
  8
  9	"gno.land/r/demo/profile"
 10	susers "gno.land/r/sys/users"
 11)
 12
 13func Render(path string) string {
 14	req := realmpath.Parse(path)
 15
 16	if req.Path == "" {
 17		return renderHomePage()
 18	}
 19
 20	// Otherwise, render the user page
 21	return renderUserPage(req.Path)
 22}
 23
 24func renderHomePage() string {
 25	var out string
 26
 27	out += "# Gno.land User Registry\n"
 28
 29	if paused {
 30		out += md.HorizontalRule()
 31		out += md.H2("This realm is paused.")
 32		out += md.Paragraph("Check out [`gno.land/r/sys/users`](/r/sys/users) for the current user registry.")
 33		out += md.HorizontalRule()
 34	}
 35
 36	out += renderIntroParagraph()
 37
 38	out += md.H2("Latest registrations")
 39	out += RenderLatestUsersWidget(-1)
 40
 41	return out
 42}
 43
 44func renderIntroParagraph() string {
 45	out := md.Paragraph("Welcome to the Gno.land User Registry (v0). Please register a username.")
 46	out += md.Paragraph(`Registering a username grants the registering address the right to deploy packages and realms
 47under that username’s namespace. For example, if an address registers the username ` + md.InlineCode("nym-alice123") + `, it
 48will gain permission to deploy packages and realms to package paths with the pattern ` + md.InlineCode("gno.land/{p,r}/nym-alice123/*") + `.`)
 49
 50	out += md.Paragraph("In V0, usernames must match `nym-<stem><digits>`, where:")
 51	items := []string{
 52		"`<stem>` is 5 to 13 lowercase ASCII letters",
 53		"`<digits>` is exactly 3 decimal digits",
 54		"The stem must NOT start with `gno`, `gl`, `atom`, `atone`, `photon`, or `cosmos` (reserved prefixes)",
 55		"The stem must NOT match a reserved role name (admin, root, support, ...)",
 56		"Confusable variants (e.g. `vitaiik` vs `vitalik` via `l↔i`) are blocked via canonical-form collision detection",
 57		"Total username length: 12–20 chars (distinct from `g1...` addresses, which are always 40 chars)",
 58	}
 59	out += md.BulletList(items)
 60
 61	out += "\n\n"
 62	out += md.Paragraph("Vanity names outside this format may be allocated by GovDAO governance through `ProposeNewName`.")
 63
 64	if !paused {
 65		amount := ufmt.Sprintf("%dugnot", registerPrice)
 66		link := txlink.NewLink("Register")
 67		if registerPrice > 0 {
 68			link = link.SetSend(amount)
 69		}
 70
 71		out += md.H3(ufmt.Sprintf(" [[Click here to register]](%s)", link.URL()))
 72		// XXX: Display registration price adjusting for dynamic GNOT price when it becomes possible.
 73		out += ufmt.Sprintf("Registration price: %f GNOT (%s)\n\n", float64(registerPrice)/1_000_000, amount)
 74	}
 75
 76	out += md.HorizontalRule()
 77	out += "\n\n"
 78
 79	return out
 80}
 81
 82// resolveUser resolves the user based on the path, determining if it's a name or address
 83func resolveUser(path string) (*susers.UserData, bool, bool) {
 84	if address(path).IsValid() {
 85		return susers.ResolveAddress(address(path)), false, false
 86	}
 87
 88	data, isLatest := susers.ResolveName(path)
 89	return data, isLatest, true
 90}
 91
 92// renderUserPage generates the user page based on user data and path
 93func renderUserPage(path string) string {
 94	var out string
 95
 96	// Render single user page
 97	data, isLatest, isName := resolveUser(path)
 98	if data == nil {
 99		out += md.H1("User not found.")
100		out += "This user does not exist or has been deleted.\n"
101		return out
102	}
103
104	out += md.H1("User - " + md.InlineCode(data.Name()))
105
106	if isName && !isLatest {
107		out += md.Paragraph(ufmt.Sprintf(
108			"Note: You searched for `%s`, which is a previous name of [`%s`](/u/%s).",
109			path, data.Name(), data.Name()))
110	} else {
111		out += ufmt.Sprintf("Address: %s\n\n", data.Addr().String())
112
113		out += md.H2("Bio")
114		out += profile.GetStringField(data.Addr(), "Bio", "No bio defined.")
115		out += "\n\n"
116		out += ufmt.Sprintf("[Update bio](%s)", txlink.Realm("gno.land/r/demo/profile").Call("SetStringField", "field", "Bio"))
117		out += "\n\n"
118	}
119
120	return out
121}
122
123// RenderLatestUsersWidget renders the latest num registered users.
124// For num = -1, the maximum number (100) will be displayed.
125func RenderLatestUsersWidget(num int) string {
126	size := latestUsers.Size()
127	if size == 0 {
128		return "No registered users."
129	}
130
131	if num > size || num < 0 {
132		num = size
133	}
134
135	entries := latestUsers.Entries()
136	var out string
137
138	for i := size - 1; i >= size-num; i-- {
139		user := entries[i].(string)
140		out += md.BulletItem(md.UserLink(user))
141	}
142
143	return out
144}