212 lines
8.1 KiB
PHP
212 lines
8.1 KiB
PHP
<?php
|
|
|
|
namespace Modules\Stylist\Providers;
|
|
|
|
use Illuminate\Support\Facades\Blade;
|
|
use Illuminate\Support\Facades\View;
|
|
use Illuminate\Support\ServiceProvider;
|
|
use Modules\Stylist\Console\CreateThemeCommand;
|
|
use Modules\Stylist\Console\FindDuplicateViewsCommand;
|
|
use Modules\Stylist\Console\InspectThemesCommand;
|
|
use Modules\Stylist\Console\PublishAssetsCommand;
|
|
use Modules\Stylist\Console\ThemeDoctorCommand;
|
|
use Modules\Stylist\Console\ValidateThemeCommand;
|
|
use Modules\Stylist\Html\ThemeHtmlBuilder;
|
|
use Modules\Stylist\Html\ThemeSeoBuilder;
|
|
use Modules\Stylist\Support\FrontendNavigation;
|
|
use Modules\Stylist\Support\ModuleInfo;
|
|
use Modules\Stylist\Services\FrontendContent;
|
|
use Modules\Stylist\Services\ThemeSettings;
|
|
use Modules\Stylist\Theme\Loader;
|
|
use Modules\Stylist\Theme\Stylist;
|
|
|
|
final class StylistServiceProvider extends ServiceProvider
|
|
{
|
|
protected string $moduleName = 'Stylist';
|
|
|
|
protected string $moduleNameLower = 'stylist';
|
|
|
|
public function register(): void
|
|
{
|
|
$this->app->register(RouteServiceProvider::class);
|
|
|
|
$this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower());
|
|
|
|
$this->app->singleton('stylist', fn ($app) => $app->make(Stylist::class));
|
|
$this->app->singleton('stylist.html', fn ($app) => $app->make(ThemeHtmlBuilder::class));
|
|
$this->app->singleton('stylist.seo', fn ($app) => $app->make(ThemeSeoBuilder::class));
|
|
}
|
|
|
|
public function boot(): void
|
|
{
|
|
$this->registerViews();
|
|
$this->registerThemeViews();
|
|
$this->registerTranslations();
|
|
$this->registerPublishing();
|
|
$this->registerHelpers();
|
|
$this->registerBlade();
|
|
|
|
if ($this->app->runningInConsole()) {
|
|
$this->commands([
|
|
PublishAssetsCommand::class,
|
|
ValidateThemeCommand::class,
|
|
InspectThemesCommand::class,
|
|
FindDuplicateViewsCommand::class,
|
|
ThemeDoctorCommand::class,
|
|
CreateThemeCommand::class,
|
|
]);
|
|
}
|
|
|
|
$this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations'));
|
|
|
|
View::composer('*', function ($view): void {
|
|
if (! $this->app->bound(Stylist::class)) {
|
|
return;
|
|
}
|
|
|
|
$view->with('activeTheme', $this->app->make(Stylist::class)->current());
|
|
});
|
|
|
|
|
|
View::composer('stylist-theme-saasland::*', function ($view): void {
|
|
$theme = $this->app->make(Loader::class)->find('saasland');
|
|
$settings = $this->app->make(ThemeSettings::class)->get($theme);
|
|
$navigation = $this->app->make(FrontendNavigation::class);
|
|
$homepage = $this->app->make(FrontendContent::class)->homepage($settings);
|
|
|
|
$view->with([
|
|
'siteTitle' => filled($settings['site_title'] ?? null) ? $settings['site_title'] : config('app.name', 'Saasland'),
|
|
'siteDescription' => filled($settings['site_description'] ?? null) ? $settings['site_description'] : 'Modern software for modern companies.',
|
|
'logoUrl' => $settings['logo_url'] ?? null,
|
|
'facebookUrl' => $settings['facebook_url'] ?? null,
|
|
'xUrl' => $settings['x_url'] ?? null,
|
|
'linkedinUrl' => $settings['linkedin_url'] ?? null,
|
|
'primaryNavigation' => $navigation->primary(),
|
|
'footerNavigation' => $navigation->footer(),
|
|
'themeSettings' => $settings,
|
|
...$homepage,
|
|
]);
|
|
});
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
private function registerThemeViews(): void
|
|
{
|
|
foreach ($this->themeRoots() as $root) {
|
|
if (! is_dir($root)) {
|
|
logger()->warning('Stylist theme root does not exist', [
|
|
'root' => $root,
|
|
]);
|
|
|
|
continue;
|
|
}
|
|
|
|
$themeDirectories = glob($root.'/*', GLOB_ONLYDIR) ?: [];
|
|
|
|
foreach ($themeDirectories as $themeDirectory) {
|
|
$themeViewsPath = $themeDirectory.'/views';
|
|
|
|
if (! is_dir($themeViewsPath)) {
|
|
continue;
|
|
}
|
|
|
|
$themeKey = strtolower(basename($themeDirectory));
|
|
|
|
// Themes always live outside the module, normally in resources/themes.
|
|
// Register the canonical namespace and the legacy namespace as an alias
|
|
// to the same application-owned directory. The alias keeps existing
|
|
// routes and Blade templates working without reintroducing module themes.
|
|
$namespaces = [
|
|
"stylist-theme-{$themeKey}",
|
|
"stylist-module-theme-{$themeKey}",
|
|
];
|
|
|
|
$componentsPath = $themeViewsPath.'/components';
|
|
|
|
// The common theme is the application-wide owner of layouts,
|
|
// authentication, settings and shared components. Livewire 4
|
|
// resolves its default full-page layout through layouts::app,
|
|
// so point that compatibility namespace at the common theme.
|
|
if ($themeKey === 'common') {
|
|
$layoutsPath = $componentsPath.'/layouts';
|
|
|
|
if (is_dir($layoutsPath)) {
|
|
View::addNamespace('layouts', $layoutsPath);
|
|
Blade::anonymousComponentPath($layoutsPath, 'layouts');
|
|
}
|
|
|
|
View::addNamespace('common', $themeViewsPath);
|
|
|
|
if (is_dir($componentsPath)) {
|
|
Blade::anonymousComponentPath($componentsPath, 'common');
|
|
}
|
|
}
|
|
|
|
foreach ($namespaces as $namespace) {
|
|
View::addNamespace($namespace, $themeViewsPath);
|
|
|
|
if (is_dir($componentsPath)) {
|
|
Blade::anonymousComponentPath($componentsPath, $namespace);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private function normalisePath(string $path): string
|
|
{
|
|
return rtrim(
|
|
str_replace('\\', '/', realpath($path) ?: $path),
|
|
'/'
|
|
);
|
|
}
|
|
|
|
/** @return array<int, string> */
|
|
private function themeRoots(): array
|
|
{
|
|
return array_values(array_unique(array_filter([
|
|
(string) config('stylist.themes_path'),
|
|
])));
|
|
}
|
|
|
|
private function registerTranslations(): void
|
|
{
|
|
$langPath = resource_path('lang/modules/'.ModuleInfo::nameLower());
|
|
$sourcePath = module_path(ModuleInfo::name(), 'Resources/lang');
|
|
|
|
$this->loadTranslationsFrom(is_dir($langPath) ? $langPath : $sourcePath, ModuleInfo::nameLower());
|
|
}
|
|
|
|
private function registerPublishing(): void
|
|
{
|
|
$this->publishes([
|
|
module_path(ModuleInfo::name(), 'Config/config.php') => config_path('stylist.php'),
|
|
], ['config', 'stylist-config']);
|
|
|
|
}
|
|
|
|
private function registerHelpers(): void
|
|
{
|
|
foreach (glob(module_path(ModuleInfo::name(), 'Helpers/*.php')) ?: [] as $filename) {
|
|
require_once $filename;
|
|
}
|
|
}
|
|
|
|
private function registerBlade(): void
|
|
{
|
|
Blade::directive('themeVariables', fn () => '<?php echo stylist_html()->variables(); ?>');
|
|
Blade::directive('themeStylesheet', fn ($expression) => '<?php echo stylist_html()->stylesheet('.($expression ?: 'null').'); ?>');
|
|
Blade::directive('themeScript', fn ($expression) => '<?php echo stylist_html()->script('.($expression ?: 'null').'); ?>');
|
|
Blade::directive('themeSwitcher', fn () => '<?php echo stylist_html()->switcher(); ?>');
|
|
Blade::directive('themeSeo', fn ($expression) => '<?php echo app(\Modules\Stylist\Html\ThemeSeoBuilder::class)->render('.($expression ?: '[]').'); ?>');
|
|
}
|
|
}
|