Files
ABSDEV/Modules/Stylist
2026-07-24 14:19:51 +01:00
..
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-24 14:19:51 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00
2026-07-23 17:23:57 +01:00

Stylist Module

Tenant-aware styling module for Laravel 13 / nwidart Laravel Modules.

Theme layout

Each theme is self-contained:

resources/themes/{theme}/
├── theme.json
├── css/theme.css
└── views/
    ├── layouts/app.blade.php
    ├── components/page-hero.blade.php
    └── livewire/theme-preview.blade.php

The active tenant/company resolves to a theme key such as default, mpba, or abbott.

Rendering themed views

Use the helper from controllers, Blade components, and Livewire components:

return stylist_view('layouts.app');

It checks views in this order:

stylist-theme-{active-theme}::{view}
stylist-theme-{default-theme}::{view}
stylist::{view}

Livewire

Keep the PHP component class shared and put the template in each theme:

Livewire/ThemePreview.php
resources/themes/default/views/livewire/theme-preview.blade.php
resources/themes/mpba/views/livewire/theme-preview.blade.php

The component renders with:

return stylist_view('livewire.theme-preview', ['stats' => $this->stats]);

Tenant assignment

Add or use these fields on companies:

theme_key
brand_primary
brand_secondary
brand_accent
logo_path
favicon_path
theme_settings

Then assign:

$company->update(['theme_key' => 'mpba']);

Publishing

php artisan vendor:publish --tag=stylist-config
# or
php artisan stylist:publish-assets

Themes are not published from or stored inside the module. Install them directly under `resources/themes`.

Blade helpers

<html data-theme="{{ stylist()->current()->key() }}">
    @themeVariables
    @themeStylesheet
</html>

Self-contained application themes

Application themes live in resources/themes/{theme} and own their runtime assets:

resources/themes/example/
├── theme.json
├── css/theme.css
├── js/app.js
└── views/home.blade.php

Use @themeStylesheet('css/theme.css'), @themeScript('js/app.js'), or theme_asset('images/example.svg'). Assets are served from the selected theme directory by the stylist.theme.asset route; they do not need to be copied into public/themes or added to the global Vite inputs.

Appearance and colour variants

Themes may declare appearances (light, dark, auto) and named accents in theme.json. Include @themeVariables in the document <head> before the theme stylesheet to prevent a flash of the wrong appearance. Add @themeSwitcher anywhere in a Blade layout for a ready-made runtime selector. User choices are stored in localStorage and are applied without rebuilding assets or reloading the page.

Theme manifest compatibility

Stylist accepts versioned manifests while remaining compatible with older themes. New manifests should declare:

{
  "manifest_version": 1,
  "key": "design-gallery",
  "name": "Design Gallery"
}

manifest_version defaults to 1 when omitted. Unknown manifest fields are preserved and ignored by Stylist unless the current version explicitly uses them, allowing Theme Builder to add future metadata without preventing theme discovery.

Appearance and accent features are optional. Stylist derives the internal capability flags only when the corresponding definitions exist:

{
  "appearances": ["light", "dark", "system"],
  "accents": ["blue", "neutral"],
  "default_appearance": "system",
  "default_accent": "neutral"
}

Legacy themes with none of these fields continue to load unchanged and do not receive appearance or accent controls.

Additional boolean capabilities may be declared explicitly:

{
  "capabilities": {
    "marketplace": true
  }
}

Validate a theme

Validate an installed theme key, unpacked theme directory, or ZIP package:

php artisan stylist:validate design-gallery
php artisan stylist:validate resources/themes/design-gallery
php artisan stylist:validate ~/Downloads/design-gallery.zip

The command checks the manifest, required entry view, stylesheet, script, declared assets, preview and accessibility issues. It exits with a failure status when errors are found.

Theme inheritance and diagnostics

Shared application views belong to the common theme. Child themes declare inheritance without copying those views:

{
  "name": "Dashboard",
  "slug": "admin",
  "extends": "common"
}

Resolution order is the active theme, each declared parent, the configured fallback, the common theme, module defaults, then Laravel's normal views.

Use these maintenance commands:

php artisan stylist:inspect
php artisan stylist:duplicates
php artisan stylist:doctor
php artisan stylist:create-theme customer --parent=common --name="Customer Portal"

stylist:duplicates fails when the same relative Blade task path exists in more than one theme. Add a child view only when it is a deliberate replacement; this application enforces one authoritative view per task.