A reusable element tree with typed parameters.

Views

A view is a reusable piece of a page: an element tree with typed parameters that a page, or another view, mounts with use. A parameter is an entity's record or a query's row, and every value inside the view is written against those parameters, so a view carries no data of its own and cannot read anything its caller did not hand it:

app projects "Projects" {}

entity Project {
  name:   text
  client: text
  due:    date
  status: text
}

entity Invoice {
  number:  text
  project: ref Project on delete cascade
}

view project-card (project: Project) {
  card title project.name {
    columns {
      column {
        text project.client style muted
      }
      column {
        badge project.status colour by state
      }
    }
    text "Due " + project.due format relative when project.due != null
    each invoice in Invoice where project == project.id sort due desc limit 3 {
      text invoice.number
    }
  }
}

page projects "Projects" list Project {
  each project in Project where status != "closed" layout grid {
    use project-card (project)
  }
}

page project-detail "Project" detail Project {
  use project-card (this)
}

The elements are card, columns and column, tabs and tab, text, badge, image, link, each and use. Any element takes a trailing when <expr> that hides it; text takes style and format, badge takes colour by, image takes alt, and link takes to. An each runs a tenant-scoped query and binds each row to a name; use mounts a view and passes its arguments by position or by name.

Views cannot mount themselves, directly or through another view, and a use must pass exactly the parameters the view declares, each of the declared kind. A view may also carry the detail sugar (section, related, jobs, action) when it has exactly one entity parameter, which those blocks bind to. Everything a view shows comes from the records it was given and from its own each elements, and an each runs through the same tenant-scoped data layer as a query.