Color mode

Overview

When to use it

Use a Page Type when a plugin provides a page with its own URL, for example:

  • Garden Explorer
  • A plugin report screen
  • A listing page generated by a plugin
  • A custom search or browse page

You do not need a Page Type when you only want to display something inside an article body.

Diagram source
text
flowchart TD
    Q{"What does the plugin display?"}
 
    Q -->|"A page with its own URL"| Page["pageTypes"]
    Q -->|"Embedded in an article body"| Renderer["renderers"]
 
    Page --> P1["Example: /explore"]
    Page --> P2["Example: /report"]
 
    Renderer --> R1["Canvas"]
    Renderer --> R2["Bases"]
    Renderer --> R3["Excalidraw"]

Features embedded inside an article, such as Canvas, Bases, and Excalidraw, use renderers instead.

Responsibilities

Layer Responsibility
Core Page Type contract, validation, path enumeration, resolution, and conflicts
Plugin Page Type ID, public paths, and a framework-independent HTML body
HonoX integration Generic route resolver and SSG parameter helper
Site application Catch-all route, document frame, metadata, and safe HTML rendering
Theme Tokens and stable hooks; no knowledge of a Page Type ID is required

A plugin does not own the whole page. The overall relationship looks like this:

Diagram source
text
flowchart LR
    Plugin["Plugin<br/>Provides the page"]
    Core["Core<br/>Page contract / resolution"]
    Integration["HonoX Integration<br/>Routing / SSG"]
    Site["Site<br/>Document / rendering"]
    Theme["Theme<br/>CSS"]
 
    Plugin --> Core
    Core --> Integration
    Integration --> Site
    Theme --> Site

The route and document frame are owned by the site application. A plugin provides the page content, but it does not generate a whole document:

html
<html>
<head>
...
<body>

PluginPageContext.manifest is the resolved manifest. Its entries still contains draft and scheduled, so a Page Type must read publicEntries (routable) or discoverableEntries (public only) for page output instead.

Diagram source
text
flowchart LR
    All["All content"]
    Publish["Publish boundary"]
    Public["publicEntries / discoverableEntries"]
    Page["Plugin page"]
 
    All --> Publish
    Publish --> Public
    Public --> Page

A Page Type should not search for non-public content on its own. This keeps the Page System on the same publication boundary as a normal site.

The problem the Page System solves

Before the Page System, every plugin with a standalone page needed a dedicated route on the site side:

Diagram source
text
flowchart LR
    Request["Request"]
    Route["Plugin-specific route"]
    Component["Plugin-specific component"]
    Frame["Site document frame"]
 
    Request --> Route
    Route --> Component
    Component --> Frame

That approach did not work by adding a plugin alone; it also required changing the site application's routes, which coupled plugins tightly to the site.

With the Page System, every plugin page participates in one shared route resolver:

Diagram source
text
flowchart LR
    Request["Request"]
    Catch["Catch-all route"]
    Resolver["resolveRiebeckiteRoute"]
    Page["Plugin page"]
    Content["Content"]
    Redirect["Redirect"]
 
    Request --> Catch
    Catch --> Resolver
 
    Resolver --> Page
    Resolver --> Content
    Resolver --> Redirect

Adding a new plugin page no longer requires adding a HonoX route.

Local Graph

Nearby Notes