From 65ee7a5366cfea06deee2172a2abce797104ba98 Mon Sep 17 00:00:00 2001
From: Leon Hudak <33522493+leohhhn@users.noreply.github.com>
Date: Tue, 3 Sep 2024 18:17:37 +0200
Subject: [PATCH] feat(examples): add `r/leon` (#2740)
## Description
This PR adds v1 of `r/leon` to the examples folder. It contains
`r/leon/home` & `r/leon/config`.
For context - this is meant to be a personal realm (or set of realms)
that every gno.land user should have at some point. Later, the idea is
to have a [special user
page](https://github.com/gnolang/gno/issues/2189) which will fetch the
`Render()` of `r/username/home`. This will serve like the profile of the
user; and the home realm will most likely be upgradeable down the line.
The reason I am making this a PR and not simply publishing it to the
Portal Loop is that it allows for further code changes down the line.
`examples/` get loaded into genesis first, and all other replayed addpkg
transactions after that, making it possible to have "upgradeable" realms
on Portal Loop.
Contributors' checklist...
- [x] Added new tests, or not needed, or not feasible
- [x] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [x] Updated the official documentation or not needed
- [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [x] Added references to related issues and PRs
- [x] Provided any useful hints for running manual tests
- [x] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
---
examples/gno.land/r/leon/config/config.gno | 65 +++++++++++
examples/gno.land/r/leon/config/gno.mod | 1 +
examples/gno.land/r/leon/home/gno.mod | 8 ++
examples/gno.land/r/leon/home/home.gno | 121 +++++++++++++++++++++
4 files changed, 195 insertions(+)
create mode 100644 examples/gno.land/r/leon/config/config.gno
create mode 100644 examples/gno.land/r/leon/config/gno.mod
create mode 100644 examples/gno.land/r/leon/home/gno.mod
create mode 100644 examples/gno.land/r/leon/home/home.gno
diff --git a/examples/gno.land/r/leon/config/config.gno b/examples/gno.land/r/leon/config/config.gno
new file mode 100644
index 00000000000..cbc1e537e3f
--- /dev/null
+++ b/examples/gno.land/r/leon/config/config.gno
@@ -0,0 +1,65 @@
+package config
+
+import (
+ "errors"
+ "std"
+)
+
+var (
+ main std.Address // leon's main address
+ backup std.Address // backup address
+)
+
+func init() {
+ main = "g125em6arxsnj49vx35f0n0z34putv5ty3376fg5"
+}
+
+func Address() std.Address {
+ return main
+}
+
+func Backup() std.Address {
+ return backup
+}
+
+func SetAddress(a std.Address) error {
+ if !a.IsValid() {
+ return errors.New("config: invalid address")
+ }
+
+ if err := checkAuthorized(); err != nil {
+ return err
+ }
+
+ main = a
+ return nil
+}
+
+func SetBackup(a std.Address) error {
+ if !a.IsValid() {
+ return errors.New("config: invalid address")
+ }
+
+ if err := checkAuthorized(); err != nil {
+ return err
+ }
+
+ backup = a
+ return nil
+}
+
+func checkAuthorized() error {
+ caller := std.PrevRealm().Addr()
+ if caller != main || caller != backup {
+ return errors.New("config: unauthorized")
+ }
+
+ return nil
+}
+
+func AssertAuthorized() {
+ caller := std.PrevRealm().Addr()
+ if caller != main || caller != backup {
+ panic("config: unauthorized")
+ }
+}
diff --git a/examples/gno.land/r/leon/config/gno.mod b/examples/gno.land/r/leon/config/gno.mod
new file mode 100644
index 00000000000..e8cd5cd85b7
--- /dev/null
+++ b/examples/gno.land/r/leon/config/gno.mod
@@ -0,0 +1 @@
+module gno.land/r/leon/config
diff --git a/examples/gno.land/r/leon/home/gno.mod b/examples/gno.land/r/leon/home/gno.mod
new file mode 100644
index 00000000000..48cf64a9d0a
--- /dev/null
+++ b/examples/gno.land/r/leon/home/gno.mod
@@ -0,0 +1,8 @@
+module gno.land/r/leon/home
+
+require (
+ gno.land/p/demo/ufmt v0.0.0-latest
+ gno.land/r/demo/art/gnoface v0.0.0-latest
+ gno.land/r/demo/art/millipede v0.0.0-latest
+ gno.land/r/leon/config v0.0.0-latest
+)
diff --git a/examples/gno.land/r/leon/home/home.gno b/examples/gno.land/r/leon/home/home.gno
new file mode 100644
index 00000000000..1f6a07e8959
--- /dev/null
+++ b/examples/gno.land/r/leon/home/home.gno
@@ -0,0 +1,121 @@
+package home
+
+import (
+ "std"
+ "strconv"
+
+ "gno.land/p/demo/ufmt"
+
+ "gno.land/r/demo/art/gnoface"
+ "gno.land/r/demo/art/millipede"
+ "gno.land/r/leon/config"
+)
+
+var (
+ pfp string // link to profile picture
+ pfpCaption string // profile picture caption
+ abtMe [2]string
+)
+
+func init() {
+ pfp = "https://i.imgflip.com/91vskx.jpg"
+ pfpCaption = "[My favourite painting & pfp](https://en.wikipedia.org/wiki/Wanderer_above_the_Sea_of_Fog)"
+ abtMe = [2]string{
+ `### About me
+Hi, I'm Leon, a DevRel Engineer at gno.land. I am a tech enthusiast,
+life-long learner, and sharer of knowledge.`,
+ `### Contributions
+My contributions to gno.land can mainly be found
+[here](https://github.com/gnolang/gno/issues?q=sort:updated-desc+author:leohhhn).
+
+TODO import r/gh
+`,
+ }
+}
+
+func UpdatePFP(url, caption string) {
+ config.AssertAuthorized()
+ pfp = url
+ pfpCaption = caption
+}
+
+func UpdateAboutMe(col1, col2 string) {
+ config.AssertAuthorized()
+ abtMe[0] = col1
+ abtMe[1] = col2
+}
+
+func Render(path string) string {
+ out := "# Leon's Homepage\n\n"
+
+ out += renderAboutMe()
+ out += renderBlogPosts()
+ out += "\n\n"
+ out += renderArt()
+
+ return out
+}
+
+func renderBlogPosts() string {
+ out := ""
+ //out += "## Leon's Blog Posts"
+
+ // todo fetch blog posts authored by @leohhhn
+ // and render them
+ return out
+}
+
+func renderAboutMe() string {
+ out := "
"
+
+ out += "
\n\n"
+ out += ufmt.Sprintf("![my profile pic](%s)\n\n%s\n\n", pfp, pfpCaption)
+ out += "
\n\n"
+
+ out += "
\n\n"
+ out += abtMe[0] + "\n\n"
+ out += "
\n\n"
+
+ out += "
\n\n"
+ out += abtMe[1] + "\n\n"
+ out += "
\n\n"
+
+ out += "
\n\n"
+
+ return out
+}
+
+func renderArt() string {
+ out := `` + "\n\n"
+ out += "# Gno Art\n\n"
+
+ out += "
"
+
+ out += renderGnoFace()
+ out += renderMillipede()
+ out += "Empty spot :/"
+
+ out += "
\n\n"
+
+ out += "This art is dynamic; it will change with every new block.\n\n"
+ out += `
` + "\n"
+
+ return out
+}
+
+func renderGnoFace() string {
+ out := "\n\n"
+ out += gnoface.Render(strconv.Itoa(int(std.GetHeight())))
+ out += "
\n\n"
+
+ return out
+}
+
+func renderMillipede() string {
+ out := "\n\n"
+ out += "Millipede\n\n"
+ out += "```\n" + millipede.Draw(int(std.GetHeight())%10+1) + "```\n"
+ out += "
\n\n"
+
+ return out
+}