PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/g1lnkytfqcjwllws63gvf0mv9yt04aswy4y9amhm/home/theme/v0

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
v0
Namespace
g1lnkytfqcjwllws63gvf0mv9yt04aswy4y9amhm / home / theme
Files
3 (gnomod.toml)
Exported functions
1
Module
gno.land/r/g1lnkytfqcjwllws63gvf0mv9yt04aswy4y9amhm/home/theme/v0
gno
0.9

Files (3)

  • gnomod.tomltoml
  • theme.gnogno
  • theme_test.gnogno
theme.gnogno
1// Package theme is the first look of gno.land/r/g1lnkytfqcjwllws63gvf0mv9yt04aswy4y9amhm/home.2//3// It draws a header card as inline SVG, a divider and a footer, on top of the4// slot machinery the home realm provides. Everything else on the page comes5// from slots, so this file only decides HOW things are drawn, never WHAT is6// said.7//8// It is a candidate, not the page. Deploying it registers it (see init); the9// authority accepts it in a separate transaction. To change the look in a way10// slots and style knobs cannot express, copy this directory to theme/v1, edit,11// deploy, Accept. The home realm and every slot stay exactly where they are.12//13// Style knobs read from slots (all optional):14//15//	style.accent  #RRGGBB   brass by default16//	style.bg      #RRGGBB   card background17//	style.fg      #RRGGBB   card text18//	style.header  card | plain | none19//20// Widgets this theme adds to the layout, beside every slot and the home21// realm's computed placeholders:22//23//	:header:   the card (or a plain heading, or nothing, per style.header)24//	:divider:  a thin accent rule25//	:footer:   realm · revision · block · chain · theme · links26package theme2728import (29	"encoding/base64"30	"strconv"31	"strings"3233	"chain/runtime"3435	"gno.land/r/g1lnkytfqcjwllws63gvf0mv9yt04aswy4y9amhm/home"36)3738const (39	defaultAccent = "#D9A441"40	defaultBg     = "#14161C"41	defaultFg     = "#F4EFE6"42)4344// DefaultLayout is what renders when no layout slot is set. content/layout.md45// starts as a copy of it; push that slot to depart from it.46const DefaultLayout = `:header:4748<gno-columns>49![Clockwork](https://avatars.githubusercontent.com/u/6826762?s=400)50<gno-columns-sep />51:intro:5253:links:54</gno-columns>5556## Now5758:now:5960## Previously6162:previously:6364## Stack6566:stack:6768## Before the rabbit hole6970:before:7172## Numbers7374:numbers:7576:divider:7778:about:7980:footer:81`8283type clockwork struct{}8485var instance = &clockwork{}8687// Instance returns the theme object, for a caller that would rather register88// it explicitly than rely on this realm's init having done it.89func Instance() home.Theme { return instance }9091// init nominates this theme. Deploying is what registers it; it serves92// nothing until the authority runs Accept("<this path>").93func init(cur realm) {94	home.Register(cross(cur), instance)95}9697// Render draws the profile page and hands every other path to the built-in98// views, so the editor and the system page look the same under any theme.99func (clockwork) Render(path string) string {100	if path != "" {101		return home.Fallback(path)102	}103	layout := home.Layout()104	if layout == "" {105		layout = DefaultLayout106	}107	f := home.NewFiller()108	f.Add("header", header)109	f.Add("divider", divider)110	f.Add("footer", footer)111	return f.Fill(layout)112}113114// ---------------------------------------------------------------------------115// Widgets116117func header() string {118	name := home.Get("name")119	if name == "" {120		name = home.Path()121	}122	tagline := home.Get("tagline")123	switch home.Style("header", "card") {124	case "none":125		return ""126	case "plain":127		out := "# " + name + "\n"128		if tagline != "" {129			out += "\n_" + tagline + "_\n"130		}131		return out132	}133	meta := home.Get("handle")134	if meta != "" {135		meta += " · "136	}137	meta += "rev " + strconv.Itoa(home.Revision()) +138		" · block " + strconv.FormatInt(runtime.ChainHeight(), 10)139	return image(name, card(name, tagline, meta))140}141142func divider() string {143	accent := color("accent", defaultAccent)144	svg := `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 10" width="1200" height="10">` +145		`<defs><linearGradient id="g" x1="0" x2="1"><stop offset="0" stop-color="` + accent + `"/>` +146		`<stop offset="1" stop-color="` + accent + `" stop-opacity="0"/></linearGradient></defs>` +147		`<rect width="1200" height="10" rx="5" fill="url(#g)"/></svg>`148	return image("", svg)149}150151func footer() string {152	theme := home.LivePath()153	if theme == "" {154		theme = "built-in"155	}156	return "`" + home.Path() + "` · rev " + strconv.Itoa(home.Revision()) +157		" · block " + strconv.FormatInt(runtime.ChainHeight(), 10) +158		" · " + runtime.ChainID() +159		" · theme `" + theme + "`" +160		" · [slots](" + home.Link("slots") + ")" +161		" · [edit](" + home.Link("edit") + ")" +162		" · [system](" + home.Link("system") + ")"163}164165// ---------------------------------------------------------------------------166// SVG167168// card draws the header: name, tagline and a meta line on a rounded panel,169// with a gear on the right. Text is clipped, not wrapped, so keep the170// tagline to one line.171func card(name, tagline, meta string) string {172	accent := color("accent", defaultAccent)173	bg := color("bg", defaultBg)174	fg := color("fg", defaultFg)175176	var b strings.Builder177	b.WriteString(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 300" width="1200" height="300" role="img" aria-label="`)178	b.WriteString(esc(name))179	b.WriteString(`"><defs><clipPath id="c"><rect width="1200" height="300" rx="24"/></clipPath>`)180	b.WriteString(`<clipPath id="t"><rect x="64" y="30" width="820" height="250"/></clipPath></defs>`)181	b.WriteString(`<g clip-path="url(#c)">`)182	b.WriteString(`<rect width="1200" height="300" fill="` + bg + `"/>`)183	b.WriteString(`<rect width="14" height="300" fill="` + accent + `"/>`)184	// The gear: a thick dashed ring reads as teeth without a single path command.185	b.WriteString(`<g transform="translate(1030 150)" fill="none" stroke="` + accent + `" opacity="0.9">`)186	b.WriteString(`<circle r="82" stroke-width="30" stroke-dasharray="21 15.8"/>`)187	b.WriteString(`<circle r="42" stroke-width="12"/>`)188	b.WriteString(`<circle r="11" fill="` + accent + `" stroke="none"/>`)189	b.WriteString(`</g>`)190	b.WriteString(`<g clip-path="url(#t)" fill="` + fg + `" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">`)191	b.WriteString(`<text x="64" y="132" font-size="76" font-weight="700">` + esc(name) + `</text>`)192	if tagline != "" {193		b.WriteString(`<text x="64" y="188" font-size="30" opacity="0.85">` + esc(tagline) + `</text>`)194	}195	b.WriteString(`<text x="64" y="246" font-size="24" fill="` + accent + `" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace">` + esc(meta) + `</text>`)196	b.WriteString(`</g></g></svg>`)197	return b.String()198}199200// image wraps an SVG document as a markdown image with a data: URI. gnoweb201// rejects every data: image except image/svg+xml, and gno.land's CSP allows202// data: in img-src, so this is the one way to draw without hosting anything.203func image(alt, svg string) string {204	alt = strings.NewReplacer("[", "", "]", "", "\n", " ").Replace(alt)205	return "![" + alt + "](data:image/svg+xml;base64," +206		base64.StdEncoding.EncodeToString([]byte(svg)) + ")"207}208209// color returns the style knob when it is a well-formed #RRGGBB, else the210// default. Knobs are admin-written, but a value is still pasted into markup,211// so the shape is checked rather than trusted.212func color(key, fallback string) string {213	v := home.Style(key, fallback)214	if isHexColor(v) {215		return v216	}217	return fallback218}219220func isHexColor(s string) bool {221	if len(s) != 7 || s[0] != '#' {222		return false223	}224	for i := 1; i < 7; i++ {225		c := s[i]226		switch {227		case c >= '0' && c <= '9', c >= 'a' && c <= 'f', c >= 'A' && c <= 'F':228		default:229			return false230		}231	}232	return true233}234235// esc escapes text for an SVG element body or attribute.236func esc(s string) string {237	return strings.NewReplacer(238		"&", "&amp;",239		"<", "&lt;",240		">", "&gt;",241		"\"", "&quot;",242		"\n", " ",243	).Replace(s)244}245

Functions

  • Instance() interface {Render func(string) string}

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

Rendered

RenderedRawgnoweb ↗

Render unavailable

rate limit exceeded — the render query is served by the Gnoland archive RPC.

vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.