Skip to content

Your first extension ​

A reading list: a type for articles, and a screen listing the ones you haven't read.

1. Make a folder ​

reading/
  manifest.json
  index.html
  main.js

2. The manifest ​

json
{
  "id": "dev.you.reading",
  "name": "Reading list",
  "version": "0.1.0",
  "sdk": "1",
  "types": [
    {
      "key": "article",
      "name": "Article",
      "fields": [
        { "key": "url", "name": "Link", "kind": "url" },
        { "key": "read", "name": "Read", "kind": "boolean" }
      ]
    }
  ],
  "screens": [{ "id": "unread", "title": "Unread", "entry": "index.html" }]
}
  • id is a reverse domain name you control.
  • Top-level screens make one app, named after the extension. For several apps, see Apps and screens.

3. The screen ​

index.html:

html
<!doctype html>
<meta charset="utf-8" />
<style>
  body { font-family: var(--pages-font); color: var(--pages-text); }
  a { color: var(--pages-accent); }
</style>
<ul id="list"></ul>
<script type="module" src="main.js"></script>

Screens can't run inline scripts, so the code goes in its own file.

main.js:

js
import { connect } from '/__pages/sdk.js'

const pages = await connect()
const { client, types } = pages
const list = document.getElementById('list')

async function render() {
  const { rows } = await client.objects.query({ query: { type: types.article.id } })
  list.replaceChildren(
    ...rows
      .filter((row) => pages.values(row, 'article').read?.value !== true)
      .map((row) => {
        const item = document.createElement('li')
        const link = document.createElement('a')
        link.textContent = row.name
        link.href = '#'
        link.onclick = () => pages.navigate({ object: row.id })
        item.append(link)
        return item
      })
  )
}

await render()
for await (const _ of client.changes()) await render()
  • pages.types.article.id is the ID of the type in this workspace. Types are found by ID, never by name.
  • pages.values(row, 'article') reads a row's fields by their keys.
  • client.changes() yields after any edit to the workspace.

4. Load it ​

In Sorus, click + beside Apps, then Load a folder (developer)…, and pick reading/. Sorus creates the Article type, and Reading list appears under Apps with a Dev badge.

Make an Article (type >Article in a page), open Reading list, and it's there. Edit main.js and save: the screen reloads.

Next ​