Theme development standards

EdgePress guide

Keep content portable and themes focused.

A theme shapes the shared layout and the appearance of page elements. Page copy and media stay with the site content so a theme can change without rewriting pages.

Separate page content from presentation

Page files define their rows, elements, localized text, links, and media references. A theme defines the shared HTML layout, typography, colors, spacing, responsive behavior, and the visual treatment of those elements.

Keep theme identifiers stable and keep all page element types usable across themes. A visitor should see the same information when the site changes from Lumen to another theme.

Project structure
config.yml
content/
  pages/home/en.md
  assets/images/home-banner.webp
themes/
  lumen/
    theme.json
    layouts/layout.html
    layouts/partials/
    assets/style.css

Store media with content

Put page illustrations, banners, logos, and downloadable files under content/assets/. EdgePress publishes each file at the same path from the site root. For example, content/assets/images/home-banner.webp is referenced as /images/home-banner.webp.

Keep themes/<name>/assets/ for shared stylesheets and theme behavior. This lets page images survive a theme change and prevents one theme from owning site-wide editorial media.

Give images meaningful alternative text, declare intrinsic dimensions, and add responsive image candidates when the page needs more than one size.

Build an accessible shared layout

Use semantic header, navigation, main, and footer landmarks. Include a skip link, one main landmark, a visible keyboard focus style, and one page-level h1.

Escape ordinary layout placeholders. Use raw placeholders only for generated page content, JSON-LD, and generated navigation. Keep page text, media captions, and URLs validated by the page renderer.

Check text and controls in both light and dark palettes where supported. Honor reduced-motion preferences and keep controls usable on narrow screens.

Give each theme a clear visual direction

Keep colors, type, borders, surfaces, and element spacing in the theme stylesheet. Use shared CSS variables for the palette and avoid placing visual choices in page JSON.

The JS.GRIPE theme set demonstrates distinct directions. Atelier uses ink-wash colors and archival paper, Default uses spare linework, Signal uses a warm pastoral storybook palette, and Lumen keeps a calm silver-and-blue editorial look.

Change and review a theme

  1. Select the theme

    Set the theme name in the root config.yml and choose lumen there.

  2. Build the shared system

    Edit the theme layout, partials, stylesheet, and local interaction scripts. Keep each page element readable and consistent with the chosen visual direction.

  3. Review pages at different sizes

    Build the site and run the EdgePress page check. Review keyboard focus, color contrast, media descriptions, mobile layout, and both color schemes before publishing.

    edgepress check

Show articles for one project

Use post-list with category: edgepress, or categories: [blog, uncategorized], to select columns independently of tags. Lists are newest first and choose the current language version when available. count accepts 1 to 12; longer single-category lists link to a localized category archive.

A project article list
[
  {
    "columns": 1,
    "cells": [
      [
        {
          "type": "post-list",
          "title": "EdgePress articles",
          "category": "edgepress",
          "count": 6
        }
      ]
    ]
  }
]

Set category: edgepress in article front matter. Omitted categories default to uncategorized. Tags are displayed on individual articles; tag filters and tag archives are removed. Set site.archive.categories for the main journal and match those categories when paginating a latest-posts homepage.

Built-in themes ship Noto Sans, Noto Serif and variable simplified/traditional Chinese fonts with the site, without a font CDN. Unicode-range WOFF2 subsets load only the glyphs used on the page. Traditional locales prefer traditional letterforms. UI, articles, Pages and Chinese code text use bundled glyphs without requiring visitors to install Chinese fonts.

Use shared font variables in custom themes
:root { font-family: var(--edgepress-font-sans); }
h1, h2 { font-family: var(--edgepress-font-serif); }
pre, code { font-family: var(--edgepress-font-mono); }

Coverage includes Latin, Greek, Cyrillic and common simplified/traditional Chinese, rather than all Unicode. Language packs using other scripts, such as Arabic, also need the corresponding Noto font and unicode-range. Keep fonts same-origin, licensed and content-hashed. fonts:sync maintains font assets; ordinary builds need no font downloads.

PDF, DOC/DOCX, PPT/PPTX and XLS/XLSX use a locally bundled browser renderer. The document opens automatically, without Office software or a conversion server. Store local files under content/assets/documents/. Shared URLs must return document bytes with CORS and use a registered external-api consent service; no request is sent before current consent.

Article or Pages text
!document[Annual report](/documents/report.docx)
!document[Shared PDF](https://files.example/download/123){format=pdf service=documents}
Pages document block
[
  {
    "type": "document",
    "title": "Annual report",
    "src": "/documents/report.xlsx"
  }
]

Documents scroll through numbered, separated pages, without previous/next buttons. Use document for PDF and Office; use media-viewer for locally bundled images, video or mixed attachments. Only the selected media attachment mounts; video bytes wait for Play. For remote resources, set service to an enabled external-api consent service and explicitly allow each image/media/connect origin in its CSP. Captions require captionLanguage; use silent: true without captions only for a genuinely silent clip.

Pages viewer elements
[
  {
    "columns": 1,
    "cells": [
      [
        {
          "type": "document",
          "title": "Report",
          "src": "/documents/report.pdf"
        },
        {
          "type": "media-viewer",
          "title": "Photos and video",
          "items": [
            {
              "type": "image",
              "src": "/images/photo.webp",
              "originalSrc": "/images/photo-original.webp",
              "alt": "Detail of the project interface"
            },
            {
              "type": "video",
              "src": "/videos/walkthrough.mp4",
              "poster": "/images/poster.webp",
              "label": "Project walkthrough",
              "captions": "/videos/walkthrough.en.vtt",
              "captionLanguage": "en"
            }
          ]
        }
      ]
    ]
  }
]