added theme support

This commit is contained in:
Mark Gregory
2026-10-20 10:19:18 +01:00
parent c5f6871e8d
commit 42c074d966
56 changed files with 2671 additions and 11 deletions
+3 -3
View File
@@ -1,9 +1,9 @@
<?php
return [
'default_theme' => env('STYLIST_DEFAULT_THEME', 'admin'),
'default_backend_theme' => env('STYLIST_BACKEND_THEME', 'admin'),
'default_frontend_theme' => env('STYLIST_FRONTEND_THEME', 'saasland'),
'default_theme' => env('STYLIST_DEFAULT_THEME', 'sonardesk-admin'),
'default_backend_theme' => env('STYLIST_BACKEND_THEME', 'sonardesk-admin'),
'default_frontend_theme' => env('STYLIST_FRONTEND_THEME', 'sonardesk'),
/*
| Themes are application resources, never module resources.
@@ -16,8 +16,8 @@ final class StylistController extends Controller
return view('stylist::index', [
'theme' => $stylist->current(), 'themes' => $stylist->all(), 'variables' => $stylist->variables(),
'settingsService' => $settings, 'accessibility' => $accessibility, 'urls' => $urls,
'activeFrontendTheme' => $siteSettings->get('frontend_theme', config('stylist.default_frontend_theme', 'saasland'), 'site'),
'activeBackendTheme' => $siteSettings->get('backend_theme', config('stylist.default_backend_theme', 'admin'), 'site'),
'activeFrontendTheme' => $siteSettings->get('frontend_theme', config('stylist.default_frontend_theme', 'sonardesk'), 'site'),
'activeBackendTheme' => $siteSettings->get('backend_theme', config('stylist.default_backend_theme', 'sonardesk-admin'), 'site'),
]);
}
}
@@ -0,0 +1,31 @@
<?php
namespace Modules\Stylist\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\View;
use Modules\Stylist\Theme\Stylist;
use Throwable;
final class ApplyActiveTheme
{
public function handle(Request $request, Closure $next)
{
$context = $request->is('admin', 'admin/*', 'stylist', 'stylist/*') ? 'backend' : 'frontend';
try {
$theme = app(Stylist::class)->current($context);
if ($theme->type() === $context) {
$path = $theme->path().'/views';
if (is_dir($path)) {
// Prepend so ordinary view('admin.index') and @extends('layouts.app')
// resolve theme files first, then original application files.
View::getFinder()->prependLocation($path);
}
}
} catch (Throwable $exception) {
report($exception); // Original application views remain available.
}
return $next($request);
}
}
+2 -1
View File
@@ -1,10 +1,11 @@
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Middleware\AdminOnly;
use Modules\Stylist\Http\Controllers\StylistController;
use Modules\Stylist\Http\Controllers\ThemeManagementController;
Route::middleware(['auth', 'verified'])->group(function (): void {
Route::middleware(['auth', 'verified', AdminOnly::class])->group(function (): void {
Route::get('/', StylistController::class)->name('index');
Route::post('/install', [ThemeManagementController::class, 'install'])->name('install');
Route::put('/{theme}/settings', [ThemeManagementController::class, 'settings'])->name('settings');
+15
View File
@@ -0,0 +1,15 @@
# SonarDesk Stylist integration — 1.0.0
- `resources/themes/sonardesk/views` contains the original frontend Blade templates.
- `resources/themes/sonardesk-admin/views` contains the original backend Blade templates.
- Both are fully editable independent view trees, with application view fallback.
- Active theme is selected by existing Stylist SettingsRepository (`frontend_theme` / `backend_theme`).
- The `ApplyActiveTheme` web middleware prepends the active theme view directory for each request.
- Public pages and authenticated customer pages use frontend; `/admin` and `/stylist` use backend.
- Controllers, routes, licensing, payments, APIs and mail templates remain unchanged.
- Theme management now requires AdminOnly permissions.
- Existing CSS/JS assets remain in place. Replacement themes may provide new layout asset links.
- Run `php artisan optimize:clear` and `php artisan migrate` after deployment.
- Check `/stylist` as an administrator, then verify public, account, admin, and checkout pages.
- If database already contains old `frontend_theme`/`backend_theme` values, activate the new bundled themes from Stylist.
- Theme ZIP installation security and the completeness of third-party theme templates require separate review before production use.
@@ -29,8 +29,8 @@ final class TenantThemeResolver
$settingKey = $context === 'frontend' ? 'frontend_theme' : 'backend_theme';
$default = $context === 'frontend'
? config('stylist.default_frontend_theme', 'saasland')
: config('stylist.default_backend_theme', config('stylist.default_theme', 'admin'));
? config('stylist.default_frontend_theme', 'sonardesk')
: config('stylist.default_backend_theme', config('stylist.default_theme', 'sonardesk-admin'));
return (string) $this->settings->get($settingKey, $default, 'site');
}
@@ -61,6 +61,9 @@ final class ThemePackageManager
public function uninstall(Theme $theme): void
{
if (in_array($theme->key(), ['sonardesk', 'sonardesk-admin'], true)) {
throw new RuntimeException('Bundled SonarDesk themes cannot be uninstalled.');
}
$active = $theme->type() === 'frontend'
? $this->settings->get('frontend_theme', config('stylist.default_frontend_theme'), 'site')
: $this->settings->get('backend_theme', config('stylist.default_backend_theme'), 'site');
+2 -2
View File
@@ -17,8 +17,8 @@ final class Stylist
return $this->loader->find($requested);
} catch (ThemeNotFoundException) {
$fallback = $context === 'frontend'
? (string) config('stylist.default_frontend_theme', 'saasland')
: (string) config('stylist.default_backend_theme', config('stylist.default_theme', 'admin'));
? (string) config('stylist.default_frontend_theme', 'sonardesk')
: (string) config('stylist.default_backend_theme', config('stylist.default_theme', 'sonardesk-admin'));
if ($requested !== $fallback) {
return $this->loader->find($fallback);
}