Initial Commit

This commit is contained in:
Mark Gregory
2026-08-15 22:29:42 +01:00
parent 101935dffb
commit 37d477081d
61 changed files with 91 additions and 2024 deletions
@@ -80,10 +80,12 @@ final class StylistServiceProvider extends ServiceProvider
private function registerViews(): void
{
$sourcePath = module_path(ModuleInfo::name(), 'Resources/views');
$viewPath = resource_path('views/modules/'.ModuleInfo::nameLower());
$this->publishes([$sourcePath => $viewPath], ['views', 'stylist-module-views']);
$this->loadViewsFrom([$viewPath, $sourcePath], ModuleInfo::nameLower());
// Module-owned package views stay inside the module. Application overrides
// belong to resources/themes/{theme}/views/modules/stylist, which Stylist
// registers as the authoritative themed namespace. Never publish back into
// resources/views; the standard baseline intentionally has no legacy view tree.
$this->loadViewsFrom($sourcePath, ModuleInfo::nameLower());
}
private function registerThemeViews(): void
@@ -51,6 +51,18 @@ final class TenantThemeResolver
'admin/*',
'helpdesk',
'helpdesk/*',
'login',
'register',
'forgot-password',
'reset-password',
'reset-password/*',
'confirm-password',
'user/confirm-password',
'two-factor-challenge',
'verify-email',
'verify-email/*',
'email/verify',
'email/verify/*',
) || $request->routeIs(
'dashboard',
'profile.edit',
@@ -58,6 +70,11 @@ final class TenantThemeResolver
'security.edit',
'admin.*',
'helpdesk.*',
'login',
'register',
'password.*',
'verification.*',
'two-factor.*',
)
? 'backend'
: 'frontend';
@@ -39,4 +39,14 @@ final class TenantThemeResolverTest extends TestCase
$this->assertSame('backend', app(TenantThemeResolver::class)->context());
}
public function test_authentication_requests_use_backend_context(): void
{
foreach (['/login', '/register', '/forgot-password', '/reset-password/token', '/user/confirm-password', '/two-factor-challenge', '/email/verify'] as $uri) {
$request = Request::create($uri, 'GET');
$this->app->instance('request', $request);
$this->assertSame('backend', app(TenantThemeResolver::class)->context(), $uri);
}
}
}
@@ -27,6 +27,15 @@ final class ThemeManifestTest extends TestCase
parent::tearDown();
}
public function test_bundled_default_themes_have_valid_manifests(): void
{
foreach (['backend', 'frontend'] as $key) {
$theme = app(Loader::class)->fromPath(resource_path("themes/{$key}"));
$this->assertSame($key, $theme->key());
}
}
public function test_manifest_is_normalised(): void
{
$path = $this->themesPath.'/sample';
@@ -29,4 +29,17 @@ final class WelcomeThemeViewTest extends TestCase
view('welcome')->getPath(),
);
}
public function test_application_views_exist_only_inside_themes(): void
{
$this->assertDirectoryDoesNotExist(resource_path('views'));
$this->assertDirectoryDoesNotExist(resource_path('css'));
$this->assertDirectoryDoesNotExist(resource_path('js'));
}
public function test_backend_compiled_assets_are_owned_by_the_backend_theme(): void
{
$this->assertFileExists(resource_path('themes/backend/assets/css/app.css'));
$this->assertFileExists(resource_path('themes/backend/assets/js/passkeys.js'));
}
}