diff --git a/gno.land/pkg/gnoweb/Makefile b/gno.land/pkg/gnoweb/Makefile
index 8e8b6bf1a2ce..c8d662ec3b5a 100644
--- a/gno.land/pkg/gnoweb/Makefile
+++ b/gno.land/pkg/gnoweb/Makefile
@@ -13,7 +13,7 @@ input_css := frontend/css/input.css
output_css := $(PUBLIC_DIR)/styles.css
tw_version := 3.4.14
tw_config_path := frontend/css/tx.config.js
-templates_files := $(shell find . -iname '*.gohtml')
+templates_files := $(shell find . -iname '*.html')
# static config
src_dir_static := frontend/static
@@ -79,7 +79,7 @@ dev:
# Go server in development mode
dev.gnoweb: generate
- $(run_reflex) -s -r '.*\.go(html)?' -- \
+ $(run_reflex) -s -r '.*\.(go|html)' -- \
go run ../../cmd/gnoweb -assets-dir=${PUBLIC_DIR} -chainid=${CHAIN_ID} -remote=${DEV_REMOTE} \
2>&1 | $(run_logname) gnoweb
diff --git a/gno.land/pkg/gnoweb/alias.go b/gno.land/pkg/gnoweb/alias.go
index 06bb3941e41a..a837a2dcb49a 100644
--- a/gno.land/pkg/gnoweb/alias.go
+++ b/gno.land/pkg/gnoweb/alias.go
@@ -39,10 +39,10 @@ func AliasAndRedirectMiddleware(next http.Handler, analytics bool) http.Handler
// Check if the request path matches a redirect
if newPath, ok := Redirects[r.URL.Path]; ok {
http.Redirect(w, r, newPath, http.StatusFound)
- components.RenderRedirectComponent(w, components.RedirectData{
+ components.RedirectView(components.RedirectData{
To: newPath,
WithAnalytics: analytics,
- })
+ }).Render(w)
return
}
diff --git a/gno.land/pkg/gnoweb/app.go b/gno.land/pkg/gnoweb/app.go
index 455a9aafaf12..61773ef39af2 100644
--- a/gno.land/pkg/gnoweb/app.go
+++ b/gno.land/pkg/gnoweb/app.go
@@ -95,10 +95,10 @@ func NewRouter(logger *slog.Logger, cfg *AppConfig) (http.Handler, error) {
if cfg.FaucetURL != "" {
mux.Handle("/faucet", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, cfg.FaucetURL, http.StatusFound)
- components.RenderRedirectComponent(w, components.RedirectData{
+ components.RedirectView(components.RedirectData{
To: cfg.FaucetURL,
WithAnalytics: cfg.Analytics,
- })
+ }).Render(w)
}))
}
diff --git a/gno.land/pkg/gnoweb/components/breadcrumb.gohtml b/gno.land/pkg/gnoweb/components/breadcrumb.gohtml
deleted file mode 100644
index 3824eb5894fe..000000000000
--- a/gno.land/pkg/gnoweb/components/breadcrumb.gohtml
+++ /dev/null
@@ -1,18 +0,0 @@
-{{ define "breadcrumb" }}
-
- {{- range $index, $part := .Parts }}
- {{- if $index }}
- -
- {{- else }}
-
-
- {{- end }}
- {{ $part.Name }}
-
- {{- end }}
- {{- if .Args }}
- -
- {{ .Args }}
-
- {{- end }}
-
-{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/component.go b/gno.land/pkg/gnoweb/components/component.go
new file mode 100644
index 000000000000..7a7c8a3d160e
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/component.go
@@ -0,0 +1,35 @@
+package components
+
+import (
+ "io"
+)
+
+type Component interface {
+ Render(w io.Writer) error
+}
+
+type TemplateComponent struct {
+ name string
+ data any
+}
+
+func (c *TemplateComponent) Render(w io.Writer) error {
+ return tmpl.ExecuteTemplate(w, c.name, c.data)
+}
+
+func NewTemplateComponent(name string, data any) Component {
+ return &TemplateComponent{name: name, data: data}
+}
+
+type readerComponent struct {
+ io.Reader
+}
+
+func NewReaderComponent(reader io.Reader) Component {
+ return &readerComponent{reader}
+}
+
+func (c *readerComponent) Render(w io.Writer) (err error) {
+ _, err = io.Copy(w, c)
+ return err
+}
diff --git a/gno.land/pkg/gnoweb/components/directory.go b/gno.land/pkg/gnoweb/components/directory.go
deleted file mode 100644
index 6e47db3b2c40..000000000000
--- a/gno.land/pkg/gnoweb/components/directory.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package components
-
-import (
- "io"
-)
-
-type DirData struct {
- PkgPath string
- Files []string
- FileCounter int
-}
-
-func RenderDirectoryComponent(w io.Writer, data DirData) error {
- return tmpl.ExecuteTemplate(w, "renderDir", data)
-}
diff --git a/gno.land/pkg/gnoweb/components/help.go b/gno.land/pkg/gnoweb/components/help.go
deleted file mode 100644
index e819705006be..000000000000
--- a/gno.land/pkg/gnoweb/components/help.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package components
-
-import (
- "html/template"
- "io"
- "strings"
-
- "github.com/gnolang/gno/gno.land/pkg/sdk/vm" // for error types
-)
-
-type HelpData struct {
- // Selected function
- SelectedFunc string
- SelectedArgs map[string]string
-
- RealmName string
- Functions []vm.FunctionSignature
- ChainId string
- Remote string
- PkgPath string
-}
-
-func registerHelpFuncs(funcs template.FuncMap) {
- funcs["helpFuncSignature"] = func(fsig vm.FunctionSignature) (string, error) {
- var fsigStr strings.Builder
-
- fsigStr.WriteString(fsig.FuncName)
- fsigStr.WriteRune('(')
- for i, param := range fsig.Params {
- if i > 0 {
- fsigStr.WriteString(", ")
- }
- fsigStr.WriteString(param.Name)
- }
- fsigStr.WriteRune(')')
-
- return fsigStr.String(), nil
- }
-
- funcs["getSelectedArgValue"] = func(data HelpData, param vm.NamedType) (string, error) {
- if data.SelectedArgs == nil {
- return "", nil
- }
-
- return data.SelectedArgs[param.Name], nil
- }
-}
-
-func RenderHelpComponent(w io.Writer, data HelpData) error {
- return tmpl.ExecuteTemplate(w, "renderHelp", data)
-}
diff --git a/gno.land/pkg/gnoweb/components/help.gohtml b/gno.land/pkg/gnoweb/components/help.gohtml
deleted file mode 100644
index 535cb56e9d61..000000000000
--- a/gno.land/pkg/gnoweb/components/help.gohtml
+++ /dev/null
@@ -1,110 +0,0 @@
-{{ define "renderHelp" }}
- {{ $data := . }}
-
-
-
-
-
-
- {{ range .Functions }}
-
- {{ .FuncName }}
-
-
-
Command
-
-
-
gnokey maketx call -pkgpath "{{ $.PkgPath }}" -func "{{ .FuncName }}" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid "{{ $.ChainId }}"{{ range .Params }} -args ""{{ end }} -remote "{{ $.Remote }}" ADDRESSgnokey query -remote "{{ $.Remote }}" auth/accounts/ADDRESS
-gnokey maketx call -pkgpath "{{ $.PkgPath }}" -func "{{ .FuncName }}" -gas-fee 1000000ugnot -gas-wanted 2000000 -send "" {{ range .Params }} -args ""{{ end }} ADDRESS > call.tx
-gnokey sign -tx-path call.tx -chainid "{{ $.ChainId }}" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
-gnokey broadcast -remote "{{ $.Remote }}" call.tx
-
-
-
- {{ end }}
-
-
-
-
-{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/index.go b/gno.land/pkg/gnoweb/components/index.go
deleted file mode 100644
index 0cc020ae2619..000000000000
--- a/gno.land/pkg/gnoweb/components/index.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package components
-
-import (
- "context"
- "html/template"
- "io"
- "net/url"
-)
-
-type HeadData struct {
- Title string
- Description string
- Canonical string
- Image string
- URL string
- ChromaPath string
- AssetsPath string
- Analytics bool
-}
-
-type HeaderData struct {
- RealmPath string
- Breadcrumb BreadcrumbData
- WebQuery url.Values
-}
-
-type FooterData struct {
- Analytics bool
- AssetsPath string
-}
-
-type IndexData struct {
- HeadData
- HeaderData
- FooterData
- Body template.HTML
-}
-
-func IndexComponent(data IndexData) Component {
- return func(ctx context.Context, tmpl *template.Template, w io.Writer) error {
- return tmpl.ExecuteTemplate(w, "index", data)
- }
-}
-
-func RenderIndexComponent(w io.Writer, data IndexData) error {
- return tmpl.ExecuteTemplate(w, "index", data)
-}
diff --git a/gno.land/pkg/gnoweb/components/index.gohtml b/gno.land/pkg/gnoweb/components/index.gohtml
deleted file mode 100644
index a87decc14bfd..000000000000
--- a/gno.land/pkg/gnoweb/components/index.gohtml
+++ /dev/null
@@ -1,159 +0,0 @@
-{{ define "index" }}
-
-
- {{ template "head" .HeadData }}
-
- {{ template "spritesvg" }}
-
-
- {{ template "header" .HeaderData }}
-
-
- {{ template "main" .Body }}
-
-
- {{ template "footer" .FooterData }}
-
-
-{{ end }}
-
-{{ define "head" }}
-
-
-
- {{ .Title }}
-
-
-
-
-
-
-
-
-
-
- {{ if .Canonical }}
-
- {{ end }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{ end }}
-
-{{ define "header" }}
-
-
-
-{{ end }}
-
-{{ define "main" }}
- {{ . }}
-{{ end }}
-
-{{ define "footer" }}
-
-
-{{- if .Analytics -}} {{- template "analytics" }} {{- end -}}
-
-{{- end }}
-
-{{- define "analytics" -}}
-
-
-
-{{- end -}}
diff --git a/gno.land/pkg/gnoweb/components/layout_footer.go b/gno.land/pkg/gnoweb/components/layout_footer.go
new file mode 100644
index 000000000000..05c83ba130be
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/layout_footer.go
@@ -0,0 +1,50 @@
+package components
+
+type FooterData struct {
+ Analytics bool
+ AssetsPath string
+ Sections []FooterSection
+}
+
+type FooterLink struct {
+ Label string
+ URL string
+}
+
+type FooterSection struct {
+ Title string
+ Links []FooterLink
+}
+
+func EnrichFooterData(data FooterData) FooterData {
+ data.Sections = []FooterSection{
+ {
+ Title: "Footer navigation",
+ Links: []FooterLink{
+ {Label: "About", URL: "/about"},
+ {Label: "Docs", URL: "https://docs.gno.land/"},
+ {Label: "Faucet", URL: "https://faucet.gno.land/"},
+ {Label: "Blog", URL: "https://gno.land/r/gnoland/blog"},
+ {Label: "Status", URL: "https://status.gnoteam.com/"},
+ },
+ },
+ {
+ Title: "Social media",
+ Links: []FooterLink{
+ {Label: "GitHub", URL: "https://github.com/gnolang/gno"},
+ {Label: "X", URL: "https://twitter.com/_gnoland"},
+ {Label: "Discord", URL: "https://discord.gg/S8nKUqwkPn"},
+ {Label: "YouTube", URL: "https://www.youtube.com/@_gnoland"},
+ },
+ },
+ {
+ Title: "Legal",
+ Links: []FooterLink{
+ {Label: "Terms", URL: "https://github.com/gnolang/gno/blob/master/LICENSE.md"},
+ {Label: "Privacy", URL: "https://github.com/gnolang/gno/blob/master/LICENSE.md"},
+ },
+ },
+ }
+
+ return data
+}
diff --git a/gno.land/pkg/gnoweb/components/layout_header.go b/gno.land/pkg/gnoweb/components/layout_header.go
new file mode 100644
index 000000000000..b85efde5f852
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/layout_header.go
@@ -0,0 +1,60 @@
+package components
+
+import (
+ "net/url"
+)
+
+type HeaderLink struct {
+ Label string
+ URL string
+ Icon string
+ IsActive bool
+}
+
+type HeaderData struct {
+ RealmPath string
+ Breadcrumb BreadcrumbData
+ WebQuery url.Values
+ Links []HeaderLink
+}
+
+func StaticHeaderLinks(realmPath string, webQuery url.Values) []HeaderLink {
+ return []HeaderLink{
+ {
+ Label: "Content",
+ URL: realmPath,
+ Icon: "ico-info",
+ IsActive: isActive(webQuery, "Content"),
+ },
+ {
+ Label: "Source",
+ URL: realmPath + "$source",
+ Icon: "ico-code",
+ IsActive: isActive(webQuery, "Source"),
+ },
+ {
+ Label: "Docs",
+ URL: realmPath + "$help",
+ Icon: "ico-docs",
+ IsActive: isActive(webQuery, "Docs"),
+ },
+ }
+}
+
+func EnrichHeaderData(data HeaderData) HeaderData {
+ data.Links = StaticHeaderLinks(data.RealmPath, data.WebQuery)
+ return data
+}
+
+func isActive(webQuery url.Values, label string) bool {
+ switch label {
+ case "Content":
+ return !(webQuery.Has("source") || webQuery.Has("help"))
+ case "Source":
+ return webQuery.Has("source")
+ case "Docs":
+ return webQuery.Has("help")
+ default:
+ return false
+ }
+}
diff --git a/gno.land/pkg/gnoweb/components/layout_index.go b/gno.land/pkg/gnoweb/components/layout_index.go
new file mode 100644
index 000000000000..8b49e8f8adac
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/layout_index.go
@@ -0,0 +1,67 @@
+package components
+
+// Layout
+const (
+ SidebarLayout = "sidebar"
+ FullLayout = "full"
+)
+
+type HeadData struct {
+ Title string
+ Description string
+ Canonical string
+ Image string
+ URL string
+ ChromaPath string
+ AssetsPath string
+ Analytics bool
+}
+
+type IndexData struct {
+ HeadData
+ HeaderData
+ FooterData
+ BodyView *View
+}
+
+type indexLayoutParams struct {
+ IndexData
+
+ // Additional data
+ IsDevmodView bool
+ Layout string
+ ViewType string
+}
+
+func IndexLayout(data IndexData) Component {
+ data.FooterData = EnrichFooterData(data.FooterData)
+ data.HeaderData = EnrichHeaderData(data.HeaderData)
+
+ dataLayout := indexLayoutParams{
+ IndexData: data,
+ // Set default value
+ Layout: FullLayout,
+ ViewType: data.BodyView.String(),
+ }
+
+ switch data.BodyView.Type {
+ case RealmViewType:
+ dataLayout.Layout = SidebarLayout
+
+ case HelpViewType:
+ dataLayout.IsDevmodView = true
+ dataLayout.Layout = SidebarLayout
+
+ case SourceViewType:
+ dataLayout.IsDevmodView = true
+ dataLayout.Layout = SidebarLayout
+
+ case DirectoryViewType:
+ dataLayout.IsDevmodView = true
+
+ case StatusViewType:
+ dataLayout.IsDevmodView = true
+ }
+
+ return NewTemplateComponent("index", dataLayout)
+}
diff --git a/gno.land/pkg/gnoweb/components/layouts/analytics.html b/gno.land/pkg/gnoweb/components/layouts/analytics.html
new file mode 100644
index 000000000000..8782c80d7ae2
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/layouts/analytics.html
@@ -0,0 +1,7 @@
+{{- define "layout/analytics" -}}
+
+
+
+{{- end -}}
diff --git a/gno.land/pkg/gnoweb/components/layouts/article.html b/gno.land/pkg/gnoweb/components/layouts/article.html
new file mode 100644
index 000000000000..63862e9a4dc7
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/layouts/article.html
@@ -0,0 +1,3 @@
+{{ define "layout/article" }}
+{{ render .ComponentContent }}
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/layouts/aside.html b/gno.land/pkg/gnoweb/components/layouts/aside.html
new file mode 100644
index 000000000000..2b33d7a8e2be
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/layouts/aside.html
@@ -0,0 +1,10 @@
+{{- define "layout/aside" }}
+
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/layouts/footer.html b/gno.land/pkg/gnoweb/components/layouts/footer.html
new file mode 100644
index 000000000000..1ae51add9953
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/layouts/footer.html
@@ -0,0 +1,23 @@
+{{ define "layouts/footer" }}
+
+
+
+
+
+{{- if .Analytics -}} {{- template "layout/analytics" }}{{- end -}} {{ end }}
\ No newline at end of file
diff --git a/gno.land/pkg/gnoweb/components/layouts/head.html b/gno.land/pkg/gnoweb/components/layouts/head.html
new file mode 100644
index 000000000000..1b78eeeb3242
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/layouts/head.html
@@ -0,0 +1,44 @@
+{{ define "layouts/head" }}
+
+
+
+ {{ .Title }}
+
+
+
+
+
+
+
+
+
+ {{ if .Canonical }}
+
+ {{ end }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/layouts/header.html b/gno.land/pkg/gnoweb/components/layouts/header.html
new file mode 100644
index 000000000000..8a1433ccd1c3
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/layouts/header.html
@@ -0,0 +1,24 @@
+{{ define "layouts/header" }}
+
+
+
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/layouts/index.html b/gno.land/pkg/gnoweb/components/layouts/index.html
new file mode 100644
index 000000000000..c42a868e6faf
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/layouts/index.html
@@ -0,0 +1,29 @@
+{{ define "index" -}}
+
+
+
+ {{ template "layouts/head" .IndexData.HeadData -}}
+
+ {{ template "ui/icons" -}}
+
+
+ {{ template "layouts/header" .IndexData.HeaderData -}}
+
+
+
+
+ {{ render .IndexData.BodyView -}}
+
+
+
+
+ {{ template "layouts/footer" .FooterData -}}
+
+
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/logosvg.gohtml b/gno.land/pkg/gnoweb/components/logosvg.gohtml
deleted file mode 100644
index 5ebe6460ee30..000000000000
--- a/gno.land/pkg/gnoweb/components/logosvg.gohtml
+++ /dev/null
@@ -1,21 +0,0 @@
-{{ define "logosvg" }}
-
-{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/realm.go b/gno.land/pkg/gnoweb/components/realm.go
deleted file mode 100644
index 027760bb3822..000000000000
--- a/gno.land/pkg/gnoweb/components/realm.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package components
-
-import (
- "context"
- "html/template"
- "io"
-
- "github.com/gnolang/gno/gno.land/pkg/gnoweb/markdown"
-)
-
-type RealmTOCData struct {
- Items []*markdown.TocItem
-}
-
-func RealmTOCComponent(data *RealmTOCData) Component {
- return func(ctx context.Context, tmpl *template.Template, w io.Writer) error {
- return tmpl.ExecuteTemplate(w, "renderRealmToc", data)
- }
-}
-
-func RenderRealmTOCComponent(w io.Writer, data *RealmTOCData) error {
- return tmpl.ExecuteTemplate(w, "renderRealmToc", data)
-}
-
-type RealmData struct {
- Content template.HTML
- TocItems *RealmTOCData
-}
-
-func RenderRealmComponent(w io.Writer, data RealmData) error {
- return tmpl.ExecuteTemplate(w, "renderRealm", data)
-}
diff --git a/gno.land/pkg/gnoweb/components/realm.gohtml b/gno.land/pkg/gnoweb/components/realm.gohtml
deleted file mode 100644
index 55f39ef36d77..000000000000
--- a/gno.land/pkg/gnoweb/components/realm.gohtml
+++ /dev/null
@@ -1,41 +0,0 @@
-{{ define "renderRealmToc" }}
-
-{{ end }}
-
-{{ define "renderRealm" }}
-
-
-
-
-
- {{ .Content }}
-
-
-
-{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/redirect.go b/gno.land/pkg/gnoweb/components/redirect.go
deleted file mode 100644
index 873ddf56ff5a..000000000000
--- a/gno.land/pkg/gnoweb/components/redirect.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package components
-
-import "io"
-
-type RedirectData struct {
- To string
- WithAnalytics bool
-}
-
-func RenderRedirectComponent(w io.Writer, data RedirectData) error {
- return tmpl.ExecuteTemplate(w, "renderRedirect", data)
-}
diff --git a/gno.land/pkg/gnoweb/components/source.go b/gno.land/pkg/gnoweb/components/source.go
deleted file mode 100644
index 231707766576..000000000000
--- a/gno.land/pkg/gnoweb/components/source.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package components
-
-import (
- "html/template"
- "io"
-)
-
-type SourceData struct {
- PkgPath string
- Files []string
- FileName string
- FileSize string
- FileLines int
- FileCounter int
- FileSource template.HTML
-}
-
-func RenderSourceComponent(w io.Writer, data SourceData) error {
- return tmpl.ExecuteTemplate(w, "renderSource", data)
-}
diff --git a/gno.land/pkg/gnoweb/components/source.gohtml b/gno.land/pkg/gnoweb/components/source.gohtml
deleted file mode 100644
index cb2430b504ad..000000000000
--- a/gno.land/pkg/gnoweb/components/source.gohtml
+++ /dev/null
@@ -1,57 +0,0 @@
-{{ define "renderSource" }}
-
-
-
-
-
-
-
- {{ .FileSource }}
-
-
-
-
-{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/spritesvg.gohtml b/gno.land/pkg/gnoweb/components/spritesvg.gohtml
deleted file mode 100644
index c061e97bf58f..000000000000
--- a/gno.land/pkg/gnoweb/components/spritesvg.gohtml
+++ /dev/null
@@ -1,125 +0,0 @@
-{{ define "spritesvg" }}
-
-{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/status.gohtml b/gno.land/pkg/gnoweb/components/status.gohtml
deleted file mode 100644
index 2321d1110bd0..000000000000
--- a/gno.land/pkg/gnoweb/components/status.gohtml
+++ /dev/null
@@ -1,12 +0,0 @@
-{{ define "status" }}
-
-
-
-

-
Error: {{ .Message }}
-
Something went wrong. Let’s find our way back!
-
Go Back Home
-
-
-
-{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/template.go b/gno.land/pkg/gnoweb/components/template.go
index 9c08703f4603..ee2605d14367 100644
--- a/gno.land/pkg/gnoweb/components/template.go
+++ b/gno.land/pkg/gnoweb/components/template.go
@@ -2,76 +2,57 @@ package components
import (
"bytes"
- "context"
"embed"
+ "fmt"
"html/template"
- "io"
"net/url"
)
-//go:embed *.gohtml
-var gohtml embed.FS
+//go:embed ui/*.html views/*.html layouts/*.html
+var html embed.FS
-var funcMap = template.FuncMap{
+var funcMap = template.FuncMap{}
+
+var tmpl = template.New("web")
+
+func registerCommonFuncs(funcs template.FuncMap) {
// NOTE: this method does NOT escape HTML, use with caution
- "noescape_string": func(in string) template.HTML {
+ funcs["noescape_string"] = func(in string) template.HTML {
return template.HTML(in) //nolint:gosec
- },
+ }
// NOTE: this method does NOT escape HTML, use with caution
- "noescape_bytes": func(in []byte) template.HTML {
+ funcs["noescape_bytes"] = func(in []byte) template.HTML {
return template.HTML(in) //nolint:gosec
- },
- "queryHas": func(vals url.Values, key string) bool {
+ }
+ // NOTE: this method does NOT escape HTML, use with caution
+ // Render Component element into raw html element
+ funcs["render"] = func(comp Component) (template.HTML, error) {
+ var buf bytes.Buffer
+ if err := comp.Render(&buf); err != nil {
+ return "", fmt.Errorf("unable to render component: %w", err)
+ }
+
+ return template.HTML(buf.String()), nil //nolint:gosec
+ }
+ funcs["queryHas"] = func(vals url.Values, key string) bool {
if vals == nil {
return false
}
return vals.Has(key)
- },
+ }
}
-var tmpl = template.New("web").Funcs(funcMap)
-
func init() {
+ // Register templates functions
+ registerCommonFuncs(funcMap)
registerHelpFuncs(funcMap)
tmpl.Funcs(funcMap)
+ // Parse templates
var err error
- tmpl, err = tmpl.ParseFS(gohtml, "*.gohtml")
+ tmpl, err = tmpl.ParseFS(html, "layouts/*.html", "ui/*.html", "views/*.html")
if err != nil {
panic("unable to parse embed tempalates: " + err.Error())
}
}
-
-type Component func(ctx context.Context, tmpl *template.Template, w io.Writer) error
-
-func (c Component) Render(ctx context.Context, w io.Writer) error {
- return RenderComponent(ctx, w, c)
-}
-
-func RenderComponent(ctx context.Context, w io.Writer, c Component) error {
- var render *template.Template
- funcmap := template.FuncMap{
- "render": func(cf Component) (string, error) {
- var buf bytes.Buffer
- if err := cf(ctx, render, &buf); err != nil {
- return "", err
- }
-
- return buf.String(), nil
- },
- }
-
- render = tmpl.Funcs(funcmap)
- return c(ctx, render, w)
-}
-
-type StatusData struct {
- Message string
-}
-
-func RenderStatusComponent(w io.Writer, message string) error {
- return tmpl.ExecuteTemplate(w, "status", StatusData{
- Message: message,
- })
-}
diff --git a/gno.land/pkg/gnoweb/components/ui/breadcrumb.html b/gno.land/pkg/gnoweb/components/ui/breadcrumb.html
new file mode 100644
index 000000000000..42f3186a4760
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/ui/breadcrumb.html
@@ -0,0 +1,19 @@
+{{ define "ui/breadcrumb" }}
+
+ {{- range $index, $part := .Parts }} {{- if $index }}
+ - {{- else }}
+
+ -
+ {{- end }}
+ {{ $part.Name }}
+
+ {{- end }} {{- if .Args }}
+ -
+ {{ .Args }}
+
+ {{- end }}
+
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/ui/btn_copy.html b/gno.land/pkg/gnoweb/components/ui/btn_copy.html
new file mode 100644
index 000000000000..5f6e7c6f7a82
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/ui/btn_copy.html
@@ -0,0 +1,6 @@
+{{ define "ui/copy" }}
+
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/ui/code_wrapper.html b/gno.land/pkg/gnoweb/components/ui/code_wrapper.html
new file mode 100644
index 000000000000..b05adb0532de
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/ui/code_wrapper.html
@@ -0,0 +1,3 @@
+{{ define "ui/code_wrapper" }}
+{{ render . }}
+{{ end }}
\ No newline at end of file
diff --git a/gno.land/pkg/gnoweb/components/ui/expend_label.html b/gno.land/pkg/gnoweb/components/ui/expend_label.html
new file mode 100644
index 000000000000..53b92721c07f
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/ui/expend_label.html
@@ -0,0 +1,14 @@
+{{ define "ui/expend_label" }}
+
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/ui/header_link.html b/gno.land/pkg/gnoweb/components/ui/header_link.html
new file mode 100644
index 000000000000..e70c6a7f733c
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/ui/header_link.html
@@ -0,0 +1,14 @@
+
+{{ define "ui/header_link" }}
+
+
+
+
+ {{ .Label }}
+
+
+{{ end }}
\ No newline at end of file
diff --git a/gno.land/pkg/gnoweb/components/ui/help_function.html b/gno.land/pkg/gnoweb/components/ui/help_function.html
new file mode 100644
index 000000000000..59c5286b0934
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/ui/help_function.html
@@ -0,0 +1,43 @@
+{{ define "ui/help_function" }}
+{{ $data := . }}
+{{ range .Functions }}
+
+ {{ .FuncName }}
+
+
+
Command
+
+
+
gnokey maketx call -pkgpath "{{ $.PkgPath }}" -func "{{ .FuncName }}" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid "{{ $.ChainId }}"{{ range .Params }} -args ""{{ end }} -remote "{{ $.Remote }}" ADDRESSgnokey query -remote "{{ $.Remote }}" auth/accounts/ADDRESS
+gnokey maketx call -pkgpath "{{ $.PkgPath }}" -func "{{ .FuncName }}" -gas-fee 1000000ugnot -gas-wanted 2000000 -send "" {{ range .Params }} -args ""{{ end }} ADDRESS > call.tx
+gnokey sign -tx-path call.tx -chainid "{{ $.ChainId }}" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
+gnokey broadcast -remote "{{ $.Remote }}" call.tx
+
+
+
+{{ end }}
+{{ end }}
\ No newline at end of file
diff --git a/gno.land/pkg/gnoweb/components/ui/icons.html b/gno.land/pkg/gnoweb/components/ui/icons.html
new file mode 100644
index 000000000000..feef8226be72
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/ui/icons.html
@@ -0,0 +1,124 @@
+{{ define "ui/icons" }}
+
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/ui/logo.html b/gno.land/pkg/gnoweb/components/ui/logo.html
new file mode 100644
index 000000000000..a61beafd3cd6
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/ui/logo.html
@@ -0,0 +1,51 @@
+{{ define "ui/logo" }}
+
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/ui/toc_generic.html b/gno.land/pkg/gnoweb/components/ui/toc_generic.html
new file mode 100644
index 000000000000..3cd027f2a0cb
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/ui/toc_generic.html
@@ -0,0 +1,14 @@
+{{- define "ui/toc_generic" }}
+
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/ui/toc_realm.html b/gno.land/pkg/gnoweb/components/ui/toc_realm.html
new file mode 100644
index 000000000000..dc09db4d0e66
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/ui/toc_realm.html
@@ -0,0 +1,10 @@
+{{ define "ui/toc_realm" }}
+
+{{ end }}
\ No newline at end of file
diff --git a/gno.land/pkg/gnoweb/components/breadcrumb.go b/gno.land/pkg/gnoweb/components/ui_breadcrumb.go
similarity index 100%
rename from gno.land/pkg/gnoweb/components/breadcrumb.go
rename to gno.land/pkg/gnoweb/components/ui_breadcrumb.go
diff --git a/gno.land/pkg/gnoweb/components/view.go b/gno.land/pkg/gnoweb/components/view.go
new file mode 100644
index 000000000000..f2da05b4b907
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/view.go
@@ -0,0 +1,32 @@
+package components
+
+import (
+ "fmt"
+ "io"
+)
+
+type ViewType string
+
+type View struct {
+ Type ViewType
+ Component
+}
+
+func (v *View) String() string {
+ return string(v.Type)
+}
+
+func (v *View) Render(w io.Writer) error {
+ if err := v.Component.Render(w); err != nil {
+ return fmt.Errorf("view %q error: %w", string(v.Type), err)
+ }
+
+ return nil
+}
+
+func NewTemplateView(typ ViewType, name string, data any) *View {
+ return &View{
+ Type: typ,
+ Component: NewTemplateComponent(name, data),
+ }
+}
diff --git a/gno.land/pkg/gnoweb/components/view_directory.go b/gno.land/pkg/gnoweb/components/view_directory.go
new file mode 100644
index 000000000000..a105291a4ddc
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/view_directory.go
@@ -0,0 +1,13 @@
+package components
+
+const DirectoryViewType ViewType = "dir-view"
+
+type DirData struct {
+ PkgPath string
+ Files []string
+ FileCounter int
+}
+
+func DirectoryView(data DirData) *View {
+ return NewTemplateView(DirectoryViewType, "renderDir", data)
+}
diff --git a/gno.land/pkg/gnoweb/components/view_help.go b/gno.land/pkg/gnoweb/components/view_help.go
new file mode 100644
index 000000000000..3473f5a3f420
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/view_help.go
@@ -0,0 +1,83 @@
+package components
+
+import (
+ "html/template"
+
+ "github.com/gnolang/gno/gno.land/pkg/sdk/vm" // for error types
+)
+
+const HelpViewType ViewType = "help-view"
+
+type HelpData struct {
+ // Selected function
+ SelectedFunc string
+ SelectedArgs map[string]string
+
+ RealmName string
+ Functions []vm.FunctionSignature
+ ChainId string
+ Remote string
+ PkgPath string
+}
+
+type HelpTocData struct {
+ Icon string
+ Items []HelpTocItem
+}
+
+type HelpTocItem struct {
+ Link string
+ Text string
+}
+
+type helpViewParams struct {
+ HelpData
+ Article ArticleData
+ ComponentTOC Component
+}
+
+func registerHelpFuncs(funcs template.FuncMap) {
+ funcs["getSelectedArgValue"] = func(data HelpData, param vm.NamedType) (string, error) {
+ if data.SelectedArgs == nil {
+ return "", nil
+ }
+
+ return data.SelectedArgs[param.Name], nil
+ }
+}
+
+func HelpView(data HelpData) *View {
+ tocData := HelpTocData{
+ Icon: "code",
+ Items: make([]HelpTocItem, len(data.Functions)),
+ }
+
+ for i, fn := range data.Functions {
+ sig := fn.FuncName + "("
+ for j, param := range fn.Params {
+ if j > 0 {
+ sig += ", "
+ }
+ sig += param.Name
+ }
+ sig += ")"
+
+ tocData.Items[i] = HelpTocItem{
+ Link: "#func-" + fn.FuncName,
+ Text: sig,
+ }
+ }
+
+ toc := NewTemplateComponent("ui/toc_generic", tocData)
+ content := NewTemplateComponent("ui/help_function", data)
+ viewData := helpViewParams{
+ HelpData: data,
+ Article: ArticleData{
+ ComponentContent: content,
+ Classes: "",
+ },
+ ComponentTOC: toc,
+ }
+
+ return NewTemplateView(HelpViewType, "renderHelp", viewData)
+}
diff --git a/gno.land/pkg/gnoweb/components/view_realm.go b/gno.land/pkg/gnoweb/components/view_realm.go
new file mode 100644
index 000000000000..49372244fd42
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/view_realm.go
@@ -0,0 +1,38 @@
+package components
+
+import (
+ "github.com/gnolang/gno/gno.land/pkg/gnoweb/markdown"
+)
+
+const RealmViewType ViewType = "realm-view"
+
+type RealmTOCData struct {
+ Items []*markdown.TocItem
+}
+
+type RealmData struct {
+ ComponentContent Component
+ TocItems *RealmTOCData
+}
+
+type ArticleData struct {
+ ComponentContent Component
+ Classes string
+}
+
+type realmViewParams struct {
+ Article ArticleData
+ ComponentTOC Component
+}
+
+func RealmView(data RealmData) *View {
+ viewData := realmViewParams{
+ Article: ArticleData{
+ ComponentContent: data.ComponentContent,
+ Classes: "realm-view lg:row-start-1",
+ },
+ ComponentTOC: NewTemplateComponent("ui/toc_realm", data.TocItems),
+ }
+
+ return NewTemplateView(RealmViewType, "renderRealm", viewData)
+}
diff --git a/gno.land/pkg/gnoweb/components/view_redirect.go b/gno.land/pkg/gnoweb/components/view_redirect.go
new file mode 100644
index 000000000000..57d2f59e20ab
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/view_redirect.go
@@ -0,0 +1,12 @@
+package components
+
+const RedirectViewType = "redirect-view"
+
+type RedirectData struct {
+ To string
+ WithAnalytics bool
+}
+
+func RedirectView(data RedirectData) *View {
+ return NewTemplateView(RedirectViewType, "renderRedirect", data)
+}
diff --git a/gno.land/pkg/gnoweb/components/view_source.go b/gno.land/pkg/gnoweb/components/view_source.go
new file mode 100644
index 000000000000..7eb5227dea19
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/view_source.go
@@ -0,0 +1,66 @@
+package components
+
+const SourceViewType ViewType = "source-view"
+
+type SourceData struct {
+ PkgPath string
+ Files []string
+ FileName string
+ FileSize string
+ FileLines int
+ FileCounter int
+ FileSource Component
+}
+
+type SourceTocData struct {
+ Icon string
+ Items []SourceTocItem
+}
+
+type SourceTocItem struct {
+ Link string
+ Text string
+}
+
+type sourceViewParams struct {
+ Article ArticleData
+ Files []string
+ FileName string
+ FileSize string
+ FileLines int
+ FileCounter int
+ PkgPath string
+ ComponentTOC Component
+}
+
+func SourceView(data SourceData) *View {
+ tocData := SourceTocData{
+ Icon: "file",
+ Items: make([]SourceTocItem, len(data.Files)),
+ }
+
+ for i, file := range data.Files {
+ tocData.Items[i] = SourceTocItem{
+ Link: data.PkgPath + "$source&file=" + file,
+ Text: file,
+ }
+ }
+
+ toc := NewTemplateComponent("ui/toc_generic", tocData)
+ content := NewTemplateComponent("ui/code_wrapper", data.FileSource)
+ viewData := sourceViewParams{
+ Article: ArticleData{
+ ComponentContent: content,
+ Classes: "source-view col-span-1 lg:col-span-7 lg:row-start-2 pb-24 text-gray-900",
+ },
+ ComponentTOC: toc,
+ Files: data.Files,
+ FileName: data.FileName,
+ FileSize: data.FileSize,
+ FileLines: data.FileLines,
+ FileCounter: data.FileCounter,
+ PkgPath: data.PkgPath,
+ }
+
+ return NewTemplateView(SourceViewType, "renderSource", viewData)
+}
diff --git a/gno.land/pkg/gnoweb/components/view_status.go b/gno.land/pkg/gnoweb/components/view_status.go
new file mode 100644
index 000000000000..46f998c45cb8
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/view_status.go
@@ -0,0 +1,11 @@
+package components
+
+const StatusViewType ViewType = "status-view"
+
+type StatusData struct {
+ Message string
+}
+
+func StatusComponent(message string) *View {
+ return NewTemplateView(StatusViewType, "status", StatusData{message})
+}
diff --git a/gno.land/pkg/gnoweb/components/directory.gohtml b/gno.land/pkg/gnoweb/components/views/directory.html
similarity index 85%
rename from gno.land/pkg/gnoweb/components/directory.gohtml
rename to gno.land/pkg/gnoweb/components/views/directory.html
index 2254886f7af8..9aedd658defa 100644
--- a/gno.land/pkg/gnoweb/components/directory.gohtml
+++ b/gno.land/pkg/gnoweb/components/views/directory.html
@@ -1,7 +1,4 @@
{{ define "renderDir" }}
-
-
-
{{ $pkgpath := .PkgPath }}
@@ -31,8 +28,5 @@
{{ $pkgpath }}
-
-
-
{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/views/help.html b/gno.land/pkg/gnoweb/components/views/help.html
new file mode 100644
index 000000000000..b4bd7f92a561
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/views/help.html
@@ -0,0 +1,38 @@
+{{ define "renderHelp" }}
+{{ $data := . }}
+
+
+
+
+{{ with render .ComponentTOC }}
+{{ template "layout/aside" .}}
+{{ end }}
+
+
+{{ template "layout/article" .Article}}
+{{ end }}
diff --git a/gno.land/pkg/gnoweb/components/views/realm.html b/gno.land/pkg/gnoweb/components/views/realm.html
new file mode 100644
index 000000000000..6e0a771e701f
--- /dev/null
+++ b/gno.land/pkg/gnoweb/components/views/realm.html
@@ -0,0 +1,8 @@
+{{ define "renderRealm" }}
+
+{{ with render .ComponentTOC }}
+{{ template "layout/aside" .}}
+{{ end }}
+
+
+{{ template "layout/article" .Article}} {{ end }}
diff --git a/gno.land/pkg/gnoweb/components/redirect.gohtml b/gno.land/pkg/gnoweb/components/views/redirect.html
similarity index 79%
rename from gno.land/pkg/gnoweb/components/redirect.gohtml
rename to gno.land/pkg/gnoweb/components/views/redirect.html
index 45dac0981cd6..cd192b850a2f 100644
--- a/gno.land/pkg/gnoweb/components/redirect.gohtml
+++ b/gno.land/pkg/gnoweb/components/views/redirect.html
@@ -10,7 +10,7 @@
{{.To}}
- {{- if .WithAnalytics -}} {{- template "analytics" }} {{- end -}}
+ {{- if .WithAnalytics -}} {{- template "layout/analytics" }} {{- end -}}