Page

Parameters

We can config the page's:

  1. Name: Or ID. The name of the page should be unique. In the web GUI provider, the name of a page will be used as the path of the page.

  2. Title: In the web GUI provider, the title of a page will be used as the title of the page and the text of its link in the side nav.

  3. Emoji: Optional. The emoji will be used as an icon in the side nav and browser favicon. An emoji shortcode works here too.

  4. Hidden: Optional. A hidden page is kept off the side nav list. It is served like any other page: a link to its url still lands on it, and the nav shows it while it is the page being read. For a page something else links to — a detail page, a page an iframe embeds — rather than one a visitor picks off the list.

The config type in package is:

type PageConfig struct {
	Name   string `json:"name"`
	Title  string `json:"title"`
	Emoji  string `json:"emoji"`
	Hidden bool   `json:"hidden,omitzero"`
}

Page Function

The function signature of Page Function is defined as:

type RunFunc func(p *Params) error

Where Params contains these parameters to operate the page:

type Params struct {
	Context context.Context

	State   *State
	Main    *Container
	Sidebar *Container
}

Main and Sidebar is the root container component of the main and sidebar part shown in the layout image.

We can show a text in the Main container by:

tgcomp.Text(p.Main, "Hello")

The State in Params provided for

  1. The component that need to pass state. For example: the checked state of checkbox.
  2. The state that user need to store. For example: The todo items in the Todo App.

Interrupting a run

A page function runs again on every event, and the run before it is cut short. Context is how that reaches the work the page does: it is cancelled when a new event arrives, or when the session closes.

Hand it to anything slow, and the user moving on stops the work instead of leaving it to finish into a screen nobody is looking at:

func Main(p *tgframe.Params) error {
	req, err := http.NewRequestWithContext(p.Context, "GET", url, nil)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	...
}

A page function that ignores Context is still interrupted, but only at the next component it draws — a run that computes for a while without drawing anything holds the next event until it gets there.

Returning the cancellation is fine: a cut run reports nothing to the client, since the run replacing it is about to paint the screen anyway, and it leaves the components of the last finished run in place — a click or an upload naming one of them still lands.

Example for adding a page

  • No emoji icon
app.AddPage("index", "Index", Main)
  • With a emoji icon
app.AddPageByConfig(&tgframe.PageConfig{
	Name:  "page2",
	Title: "Page2",
	Emoji: "🔄",
}, Page2)
  • Reached by url, not off the nav
app.AddPageByConfig(&tgframe.PageConfig{
	Name:   "page3",
	Title:  "Page3",
	Hidden: true,
}, Page3)

Page name in the URL

By default the web executor serves each page at its own path, /{name}, and redirects / to the first page added.

An app served from a static path — or opened from a file — cannot rely on the server routing those paths. SetHashPageNameMode moves the page name into the URL fragment, /#/{name}, so every page is served from /:

app.SetHashPageNameMode(true)

The fragment starts with #/, not a bare #. For a page named novel:

http://localhost:3000/#/novel   ✓ opens novel
http://localhost:3000/#novel    ✗ not a page link

With no fragment, the first page added is shown.