Contents Menu Expand Light mode Dark mode Auto light/dark, in light mode Auto light/dark, in dark mode Skip to content
Sextile 0.5.2
Sextile 0.5.2
  • Tutorial
    • A first frame
    • Menus and page numbers
    • State and the lifespan
    • Frames and keys
    • Sequences
    • The framework’s pages, and drawing your own
    • Testing a service
  • How-to guides
    • Link between pages
    • List more than nine items
    • An empty list, and a missing page
    • End the call
    • Customise the not-found and failed notices
    • Accept typed input
    • Type-ahead completion
    • Draw a custom frame
    • Compose a frame
    • Draw an icon
    • Draw a chart
    • Show a picture
    • Show a photograph
    • Large lettering
    • Letter on a background
    • Boxed banners
    • Centre wrapped text
    • A custom part
    • Log every page
    • Restrict access
    • Remember a caller
    • The visits log
    • Write a converter
    • Preview a page
    • Connect a BBC Micro
  • Reference
    • API reference
      • sextile
      • sextile.cli
      • sextile.content
      • sextile.content.blocks
      • sextile.forms
      • sextile.formatting
      • sextile.handlers
      • sextile.keys
      • sextile.layout
      • sextile.middleware
      • sextile.pages
      • sextile.state
      • sextile.testing
      • sextile.viewdata
      • sextile.viewdata.blocks
      • sextile.viewdata.canvas
      • sextile.viewdata.charset
      • sextile.viewdata.charting
      • sextile.viewdata.compass
      • sextile.viewdata.composition
      • sextile.viewdata.controls
      • sextile.viewdata.drawing
      • sextile.viewdata.font
      • sextile.viewdata.frame
      • sextile.viewdata.html
      • sextile.viewdata.lettering
      • sextile.viewdata.measure
      • sextile.viewdata.tiles
      • sextile.viewdata.typesetting
      • sextile.viewdata.wrapping
      • sextile.viewdata.yaff
      • sextile.visits
    • Public surface
    • Glossary
    • Keys
    • Command line
    • Layout
    • Content
    • Fonts
    • Viewdata encoding
    • Display semantics
  • Explanation
    • Why Sextile
    • Design decisions
    • The rendering pipeline
    • Middleware
    • Graphics
    • Mosaic fonts
    • How this is put together
    • Where this is going
  • Applications
    • The calendar
    • The forum
    • The weather
  • Contributing
    • Open questions and known gaps
    • Spikes
    • Revealing Sextile: the comprehensibility plan
Back to top
View this page

Menus and page numbers¶

A tutorial step: a menu on *1# whose entries lead to other pages, one of them a whole family of pages addressed by date.

Collect the pages in a router¶

Declaring pages beside their functions with a PageRouter, rather than on the app directly, is the form a service grows into: the pages are a module of their own, spread into the service in one line. Page 1 is now a menu, with an about page and a page for a single day:

import calendar
from datetime import date

from sextile import (
    MenuItem, Page, PageRequest, PageRouter, Sextile, menu_page, notice_page, prose_page,
)

SERVICE_NAME = "CALENDAR"
router = PageRouter()


@router.page("1", name="main", title="The index", keywords=("MAIN", "INDEX"))
async def main(request: PageRequest) -> Page:
    app = request.app
    return menu_page(
        request,
        title=SERVICE_NAME,
        items=[
            MenuItem("New Year's Day", "1 January 2026", app.address_for("day", day=date(2026, 1, 1))),
            app.menu_item("about"),
        ],
    )


@router.page("42{day:date}", name="day", title="One day")
async def one_day(request: PageRequest, day: date) -> Page:
    _, week, _ = day.isocalendar()
    length = 366 if calendar.isleap(day.year) else 365
    return notice_page(
        request,
        day.strftime("%A %d %B %Y"),
        "",
        f"Day {day.timetuple().tm_yday} of {length}",
        f"Week {week}",
        f"ISO {day.isoformat()}",
    )


@router.page("9", name="about", title="About this service", keywords=("ABOUT", "HELP"))
async def about(request: PageRequest) -> Page:
    return prose_page(
        request,
        "A calendar, served as Viewdata frames.",
        "It exists to demonstrate that Sextile is a framework and not one "
        "service: nothing here knows about forums, and nothing in the framework "
        "knows about calendars.",
        "Everything it shows comes from the standard library.",
    )


app = Sextile(name=SERVICE_NAME, pages=[*router])
 CALENDAR                             1a
  
 1  New Year's Day                      
   1 January 2026                       
 2  About this service                  
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
  
 1-2 select, 0 index                    

@router.page registers a page and everything the service says about it: its number, its name, its title (the header, and the words a menu shows for it), and the keywords a reader can key instead of the number. menu_page numbers its entries 1–9, so a reader chooses with one keypress.

Link to a page by its name¶

app.menu_item("about") builds a menu entry from a registered page — its title and its number — so the menu never respells a number. app.address_for("day", day=...) is the same read backwards: it builds a page number from a route’s pattern and its fields.

Address a family of pages¶

The day page’s pattern is 42{day:date}: the literal 42, then a date field. The date converter reads the eight digits after 42 as a date and hands it to the handler, so *4220260101# is 1 January 2026 — everything it shows comes from that one date:

 ONE DAY                     4220260101a
  
Thursday 01 January 2026                
                                        
Day 1 of 365                            
Week 1                                  
ISO 2026-01-01                          
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
                                        
  
 0 index                                

One page number, *4220260101#, drawn by the same code as *1#. From the menu, key 1 to reach it; or key *ABOUT# from anywhere to reach the about page by its keyword.

Next
State and the lifespan
Previous
A first frame
Copyright © Robert Smallshire
Made with Sphinx and @pradyunsg's Furo
On this page
  • Menus and page numbers
    • Collect the pages in a router
    • Link to a page by its name
    • Address a family of pages