From 4646ae677578ae2848f9df84a4ec3d2dfba0bb29 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Wed, 20 Nov 2024 08:31:02 +0100 Subject: [PATCH] feat: add r/docs/home (#3160) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introducing the `r/docs` namespace, where the homepage currently lists subrealms manually. In the future, we may implement a registry, but for now, we’re keeping the source code as lean as possible. The namespace includes several interactive examples to guide users through key concepts. The `r/docs/hello` example provides a simple Render function and invites users to click on "view source" to understand the basics of customization. The `r/docs/avl_pager` example demonstrates path-based interactions, allowing users to explore an avl tree structure with pagination links to navigate between items. Users are encouraged to click on these links for inspiration before manually adjusting parameters in the URL. The added `r/docs/add` example introduces interactivity through transactions, allowing users to adjust a number by submitting transactions, and see the updated result with each interaction. These examples are designed to engage users with Render-based UI interactions, path handling, and transaction-based updates. Once we have more content in r/docs, this section could serve as the main documentation link in the navbar, providing a comprehensive, hands-on introduction to Gno. Addresses #3084 Addresses https://github.com/gnolang/docs-v2/pull/27#discussion_r1848481556 Addresses #2953 --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/r/demo/hello_world/gno.mod | 1 - .../gno.land/r/demo/hello_world/hello.gno | 17 ------ examples/gno.land/r/docs/add/add.gno | 42 ++++++++++++++ examples/gno.land/r/docs/add/add_test.gno | 44 +++++++++++++++ examples/gno.land/r/docs/add/gno.mod | 3 + .../gno.land/r/docs/avl_pager/avl_pager.gno | 40 ++++++++++++++ .../r/docs/avl_pager/avl_pager_test.gno | 55 +++++++++++++++++++ examples/gno.land/r/docs/avl_pager/gno.mod | 6 ++ examples/gno.land/r/docs/hello/gno.mod | 1 + examples/gno.land/r/docs/hello/hello.gno | 11 ++++ .../hello_world => docs/hello}/hello_test.gno | 2 +- examples/gno.land/r/docs/home/gno.mod | 1 + examples/gno.land/r/docs/home/home.gno | 20 +++++++ examples/gno.land/r/docs/home/home_test.gno | 22 ++++++++ 14 files changed, 246 insertions(+), 19 deletions(-) delete mode 100644 examples/gno.land/r/demo/hello_world/gno.mod delete mode 100644 examples/gno.land/r/demo/hello_world/hello.gno create mode 100644 examples/gno.land/r/docs/add/add.gno create mode 100644 examples/gno.land/r/docs/add/add_test.gno create mode 100644 examples/gno.land/r/docs/add/gno.mod create mode 100644 examples/gno.land/r/docs/avl_pager/avl_pager.gno create mode 100644 examples/gno.land/r/docs/avl_pager/avl_pager_test.gno create mode 100644 examples/gno.land/r/docs/avl_pager/gno.mod create mode 100644 examples/gno.land/r/docs/hello/gno.mod create mode 100644 examples/gno.land/r/docs/hello/hello.gno rename examples/gno.land/r/{demo/hello_world => docs/hello}/hello_test.gno (93%) create mode 100644 examples/gno.land/r/docs/home/gno.mod create mode 100644 examples/gno.land/r/docs/home/home.gno create mode 100644 examples/gno.land/r/docs/home/home_test.gno diff --git a/examples/gno.land/r/demo/hello_world/gno.mod b/examples/gno.land/r/demo/hello_world/gno.mod deleted file mode 100644 index 9561cd4f077..00000000000 --- a/examples/gno.land/r/demo/hello_world/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/r/demo/hello_world diff --git a/examples/gno.land/r/demo/hello_world/hello.gno b/examples/gno.land/r/demo/hello_world/hello.gno deleted file mode 100644 index 312520de44d..00000000000 --- a/examples/gno.land/r/demo/hello_world/hello.gno +++ /dev/null @@ -1,17 +0,0 @@ -// Package hello_world demonstrates the usage of the Render() function. -// Render() can be called via the vm/qrender ABCI query off-chain to -// retrieve realm state or any other custom data defined by the realm -// developer. The vm/qrender query allows for additional data to be -// passed in with the call, which can be utilized as the path argument -// to the Render() function. This allows developers to create different -// "renders" of their realms depending on the data which is passed in, -// such as pagination, admin dashboards, and more. -package hello_world - -func Render(path string) string { - if path == "" { - return "# Hello, 世界!" - } - - return "# Hello, " + path + "!" -} diff --git a/examples/gno.land/r/docs/add/add.gno b/examples/gno.land/r/docs/add/add.gno new file mode 100644 index 00000000000..ffc8f9c6877 --- /dev/null +++ b/examples/gno.land/r/docs/add/add.gno @@ -0,0 +1,42 @@ +package add + +import ( + "strconv" + "time" + + "gno.land/p/moul/txlink" +) + +// Global variables to store the current number and last update timestamp +var ( + number int + lastUpdate time.Time +) + +// Add function to update the number and timestamp +func Add(n int) { + number += n + lastUpdate = time.Now() +} + +// Render displays the current number value, last update timestamp, and a link to call Add with 42 +func Render(path string) string { + // Display the current number and formatted last update time + result := "# Add Example\n\n" + result += "Current Number: " + strconv.Itoa(number) + "\n\n" + result += "Last Updated: " + formatTimestamp(lastUpdate) + "\n\n" + + // Generate a transaction link to call Add with 42 as the default parameter + txLink := txlink.URL("Add", "n", "42") + result += "[Increase Number](" + txLink + ")\n" + + return result +} + +// Helper function to format the timestamp for readability +func formatTimestamp(timestamp time.Time) string { + if timestamp.IsZero() { + return "Never" + } + return timestamp.Format("2006-01-02 15:04:05") +} diff --git a/examples/gno.land/r/docs/add/add_test.gno b/examples/gno.land/r/docs/add/add_test.gno new file mode 100644 index 00000000000..8994b895f7e --- /dev/null +++ b/examples/gno.land/r/docs/add/add_test.gno @@ -0,0 +1,44 @@ +package add + +import ( + "testing" +) + +func TestRenderAndAdd(t *testing.T) { + // Initial Render output + output := Render("") + expected := `# Add Example + +Current Number: 0 + +Last Updated: Never + +[Increase Number](/r/docs/add$help&func=Add&n=42) +` + if output != expected { + t.Errorf("Initial Render failed, got:\n%s", output) + } + + // Call Add with a value of 10 + Add(10) + + // Call Add again with a value of -5 + Add(-5) + + // Render after two Add calls + finalOutput := Render("") + + // Initial Render output + output = Render("") + expected = `# Add Example + +Current Number: 5 + +Last Updated: 2009-02-13 23:31:30 + +[Increase Number](/r/docs/add$help&func=Add&n=42) +` + if output != expected { + t.Errorf("Final Render failed, got:\n%s", output) + } +} diff --git a/examples/gno.land/r/docs/add/gno.mod b/examples/gno.land/r/docs/add/gno.mod new file mode 100644 index 00000000000..a66c63e0910 --- /dev/null +++ b/examples/gno.land/r/docs/add/gno.mod @@ -0,0 +1,3 @@ +module gno.land/r/docs/add + +require gno.land/p/moul/txlink v0.0.0-latest diff --git a/examples/gno.land/r/docs/avl_pager/avl_pager.gno b/examples/gno.land/r/docs/avl_pager/avl_pager.gno new file mode 100644 index 00000000000..75807b71981 --- /dev/null +++ b/examples/gno.land/r/docs/avl_pager/avl_pager.gno @@ -0,0 +1,40 @@ +package avl_pager + +import ( + "strconv" + + "gno.land/p/demo/avl" + "gno.land/p/demo/avl/pager" +) + +// Tree instance for 100 items +var tree *avl.Tree + +// Initialize a tree with 100 items. +func init() { + tree = avl.NewTree() + for i := 1; i <= 100; i++ { + key := "Item" + strconv.Itoa(i) + tree.Set(key, "Value of "+key) + } +} + +// Render paginated content based on the given URL path. +// URL format: `...?page=&size=` (default is page 1 and size 10). +func Render(path string) string { + p := pager.NewPager(tree, 10) // Default page size is 10 + page := p.MustGetPageByPath(path) + + // Header and pagination info + result := "# Paginated Items\n" + result += "Page " + strconv.Itoa(page.PageNumber) + " of " + strconv.Itoa(page.TotalPages) + "\n\n" + result += page.Selector() + "\n\n" + + // Display items on the current page + for _, item := range page.Items { + result += "- " + item.Key + ": " + item.Value.(string) + "\n" + } + + result += "\n" + page.Selector() // Repeat selector for ease of navigation + return result +} diff --git a/examples/gno.land/r/docs/avl_pager/avl_pager_test.gno b/examples/gno.land/r/docs/avl_pager/avl_pager_test.gno new file mode 100644 index 00000000000..1ffc9a0c3ba --- /dev/null +++ b/examples/gno.land/r/docs/avl_pager/avl_pager_test.gno @@ -0,0 +1,55 @@ +package avl_pager + +import ( + "testing" +) + +func TestRender(t *testing.T) { + // Test default Render output (first page) + output := Render("") + expected := `# Paginated Items +Page 1 of 10 + +**1** | [2](?page=2) | [3](?page=3) | … | [10](?page=10) + +- Item1: Value of Item1 +- Item10: Value of Item10 +- Item100: Value of Item100 +- Item11: Value of Item11 +- Item12: Value of Item12 +- Item13: Value of Item13 +- Item14: Value of Item14 +- Item15: Value of Item15 +- Item16: Value of Item16 +- Item17: Value of Item17 + +**1** | [2](?page=2) | [3](?page=3) | … | [10](?page=10)` + if output != expected { + t.Errorf("Render(\"\") failed, got:\n%s", output) + } +} + +func TestRender_page2(t *testing.T) { + // Test Render output for a custom page (page 2) + output := Render("?page=2&size=10") + expected := `# Paginated Items +Page 2 of 10 + +[1](?page=1) | **2** | [3](?page=3) | [4](?page=4) | … | [10](?page=10) + +- Item18: Value of Item18 +- Item19: Value of Item19 +- Item2: Value of Item2 +- Item20: Value of Item20 +- Item21: Value of Item21 +- Item22: Value of Item22 +- Item23: Value of Item23 +- Item24: Value of Item24 +- Item25: Value of Item25 +- Item26: Value of Item26 + +[1](?page=1) | **2** | [3](?page=3) | [4](?page=4) | … | [10](?page=10)` + if output != expected { + t.Errorf("Render(\"\") failed, got:\n%s", output) + } +} diff --git a/examples/gno.land/r/docs/avl_pager/gno.mod b/examples/gno.land/r/docs/avl_pager/gno.mod new file mode 100644 index 00000000000..0d05b24bcd0 --- /dev/null +++ b/examples/gno.land/r/docs/avl_pager/gno.mod @@ -0,0 +1,6 @@ +module gno.land/r/docs/avl_pager + +require ( + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/avl/pager v0.0.0-latest +) diff --git a/examples/gno.land/r/docs/hello/gno.mod b/examples/gno.land/r/docs/hello/gno.mod new file mode 100644 index 00000000000..25ddf30051f --- /dev/null +++ b/examples/gno.land/r/docs/hello/gno.mod @@ -0,0 +1 @@ +module gno.land/r/docs/hello diff --git a/examples/gno.land/r/docs/hello/hello.gno b/examples/gno.land/r/docs/hello/hello.gno new file mode 100644 index 00000000000..e881c155cdd --- /dev/null +++ b/examples/gno.land/r/docs/hello/hello.gno @@ -0,0 +1,11 @@ +// Package hello_world demonstrates basic usage of Render(). +// Try adding `:World` at the end of the URL, like `.../hello:World`. +package hello + +// Render outputs a greeting. It customizes the message based on the provided path. +func Render(path string) string { + if path == "" { + return "# Hello, 世界!" + } + return "# Hello, " + path + "!" +} diff --git a/examples/gno.land/r/demo/hello_world/hello_test.gno b/examples/gno.land/r/docs/hello/hello_test.gno similarity index 93% rename from examples/gno.land/r/demo/hello_world/hello_test.gno rename to examples/gno.land/r/docs/hello/hello_test.gno index 4c3d86c556a..8159fb1341c 100644 --- a/examples/gno.land/r/demo/hello_world/hello_test.gno +++ b/examples/gno.land/r/docs/hello/hello_test.gno @@ -1,4 +1,4 @@ -package hello_world +package hello import ( "testing" diff --git a/examples/gno.land/r/docs/home/gno.mod b/examples/gno.land/r/docs/home/gno.mod new file mode 100644 index 00000000000..b9f8d060f75 --- /dev/null +++ b/examples/gno.land/r/docs/home/gno.mod @@ -0,0 +1 @@ +module gno.land/r/docs/home diff --git a/examples/gno.land/r/docs/home/home.gno b/examples/gno.land/r/docs/home/home.gno new file mode 100644 index 00000000000..2c581019380 --- /dev/null +++ b/examples/gno.land/r/docs/home/home.gno @@ -0,0 +1,20 @@ +package home + +func Render(_ string) string { + return `# Gno Examples Documentation + +Welcome to the Gno examples documentation index. +Explore various examples to learn more about Gno functionality and usage. + +## Examples + +- [Hello World](/r/docs/hello) - A simple introductory example. +- [Add](/r/docs/add) - An interactive example to update a number with transactions. +- [AVL Pager](/r/docs/avl_pager) - Paginate through AVL tree items. +- ... + +## Other resources + +- [Official documentation](https://github.com/gnolang/gno/tree/master/docs) +` +} diff --git a/examples/gno.land/r/docs/home/home_test.gno b/examples/gno.land/r/docs/home/home_test.gno new file mode 100644 index 00000000000..98dc999e005 --- /dev/null +++ b/examples/gno.land/r/docs/home/home_test.gno @@ -0,0 +1,22 @@ +package home + +import ( + "strings" + "testing" +) + +func TestRenderHome(t *testing.T) { + output := Render("") + + // Check for the presence of key sections + if !contains(output, "# Gno Examples Documentation") { + t.Errorf("Render output is missing the title.") + } + if !contains(output, "Official documentation") { + t.Errorf("Render output is missing the official documentation link.") + } +} + +func contains(s, substr string) bool { + return strings.Index(s, substr) >= 0 +}