Awn Awn
Back to Awn
Documentation menu — Build a theme
Build / Build a theme
Version
1.0
Last verified
2026-08-09

Build themes

Current theme tree:

resources/views/themes/{karam,najda}/
├── theme.json
├── site.blade.php
└── partials/
    ├── cms-page.blade.php
    ├── footer.blade.php
    ├── header.blade.php
    ├── home-content.blade.php
    ├── plugin-page.blade.php
    └── slots/{before-footer,home-after-hero,page-after-content}.blade.php

Shared assets are resources/css/app.css and resources/js/app.js; manifests do not declare bundles. Thumbnails are public paths and validation checks they exist.

Registration and manifest

Add a ThemeKey, package directory/manifest/views, static namespace handling, and enum-exhaustive Charity preview handling. Required manifest keys: slug, name, description, version, theme_api, capabilities, settings; thumbnail is optional. Slug equals enum. Current themes provide all three slot capabilities, plugin pages, and site navigation.

Setting types are color, select, boolean, text, number. Each requires type, label, default; select needs options. UpdateThemeRequest validates declarations and ThemeSettings::from() merges defaults, ignores undeclared input, normalizes hex colors/options/booleans/tag-free bounded text/clamped numbers, and derives color_primary_on.

ThemeSettings::from(array $settings, ThemeManifest $manifest): self;
toArray(): array;
get(string $key, mixed $default = null): mixed;
formatNumber(int|float|string $value): string;
radiusCss(): string;
fontCss(): string;

Allowed fonts: tajawal, cairo, system; radii: sharp, soft, round; numerals: western, arabic.

Rendering

Render plugin page, CMS page, or home content; render all $pluginSlots; escape tenant text; use only platform-created raw slot/page HTML. Preview should be noindex and published routes must hide drafts.

Themes never render organization-dashboard or Super Admin contributions. Those are platform UI surfaces. A business plugin relates to a theme only through declared public capabilities such as slots, plugin pages, and site navigation; use direct theme constraints only for true theme add-ons. See Public pages and theme integration.

Tutorial: safe visual setting

Add a bounded manifest definition, read it via $theme->settings->get(), map it to complete static classes rather than raw CSS, expose it through Appearance, then run:

php artisan awn:extensions:validate
php artisan view:cache
npm run build
php artisan test --compact

Theme switching changes assignment/settings only and is blocked if an enabled plugin would become incompatible.