diff --git a/app/Theming/ThemeModule.php b/app/Theming/ThemeModule.php index 594aa0701..12b1486be 100644 --- a/app/Theming/ThemeModule.php +++ b/app/Theming/ThemeModule.php @@ -4,13 +4,13 @@ namespace BookStack\Theming; use BookStack\Exceptions\ThemeException; -class ThemeModule +readonly class ThemeModule { public function __construct( - public readonly string $name, - public readonly string $description, - public readonly string $folderName, - public readonly string $version, + public string $name, + public string $description, + public string $folderName, + public string $version, ) { } diff --git a/dev/docs/logical-theme-system.md b/dev/docs/logical-theme-system.md index 0063c4e8b..9457ca78b 100644 --- a/dev/docs/logical-theme-system.md +++ b/dev/docs/logical-theme-system.md @@ -99,6 +99,41 @@ Theme::listen(ThemeEvents::APP_BOOT, function($app) { }); ``` +## Custom View Registration Example + +Using the logical theme system, you can register custom views to be rendered before/after other existing views, providing a flexible way to add content without needing to override and/or replicate existing content. This is done by listening to the `THEME_REGISTER_VIEWS`. + +**Note:** You don't need to use this to override existing views, or register whole new main views to use, since that's done automatically based on their existence. This is just for advanced capabilities like inserting before/after existing views. + +This event provides a `ThemeViews` instance which has the following methods made available: + +- `renderBefore(string $targetView, string $localView, int $priority)` +- `renderAfter(string $targetView, string $localView, int $priority)` + +The target view is the name of that which we want to insert our custom view relative to. +The local view is the name of the view we want to add and render. +The priority provides a suggestion to the ordering of view display, with lower numbers being shown first. This defaults to 50 if not provided. + +Here's an example of this in use: + +```php +renderBefore('layouts.parts.header', 'welcome-banner', 4); + $themeViews->renderAfter('layouts.parts.header', 'information-alert'); + $themeViews->renderAfter('layouts.parts.header', 'additions.password-notice', 20); +}); +``` + +In this example, we're inserting custom views before and after the main header bar. +BookStack will look for a `welcome-banner.blade.php` file within our theme folder (or a theme module view folder) to render before the header. It'll look for the `information-alert.blade.php` and `additions/password-notice.blade.php` views to render afterwards. +The password notice will be shown above the information alert view, since it has a specified priority of 20, whereas the information alert view would default to a priority of 50. + ## Custom Command Registration Example The logical theme system supports adding custom [artisan commands](https://laravel.com/docs/8.x/artisan) to BookStack. diff --git a/dev/docs/theme-system-modules.md b/dev/docs/theme-system-modules.md new file mode 100644 index 000000000..c25a60241 --- /dev/null +++ b/dev/docs/theme-system-modules.md @@ -0,0 +1,60 @@ +# Theme System Modules + +A theme system module is a collection of customizations using the [visual](visual-theme-system.md) and [logical](logical-theme-system.md) theme systems, provided along with some metadata, that can be installed alongside other modules within a theme. They can effectively be thought of as "plugins" or "extensions" that can be applied in addition to any customizations in the active theme. + +### Module Location + +Modules are contained within a folder themselves, which should be located inside a `modules` folder within a [BookStack theme folder](visual-theme-system.md#getting-started). +As an example, starting from the `themes/` top-level folder of a BookStack instance: + +```txt +themes +└── my-theme + └── modules + ├── module-a + │ └── bookstack-module.json + └── module-b + └── bookstack-module.json +``` + +### Module Format + +A module exists as a folder in the location [as detailed above](#module-location). +The content within the module folder should then follow this format: + +- `bookstack-module.json` - REQUIRED - A JSON file containing [the metadata](#module-json-metadata) for the module. +- `functions.php` - OPTIONAL - A PHP file containing code for the [logical theme system](logical-theme-system.md). +- `icons/` - OPTIONAL - A folder containing any icons to use as per [the visual theme system](visual-theme-system.md#customizing-icons). +- `lang/` - OPTIONAL - A folder containing any language files to use as per [the visual theme system](visual-theme-system.md#customizing-text-content). +- `public/` - OPTIONAL - A folder containing any files to expose into public web-space as per [the visual theme system](visual-theme-system.md#publicly-accessible-files). +- `views/` - OPTIONAL - A folder containing any view additions or overrides as per [the visual theme system](visual-theme-system.md#customizing-view-files). + +You can create additional directories/files for your own needs within the module, but ideally name them something unique to prevent conflicts with the above structure. + +### Module JSON Metadata + +Modules are required to have a `bookstack-module.json` file in the top level directory of the module. +This must be a JSON file with the following properties: + +- `name` - string - An (ideally unique) name for the module. +- `description` - string - A short description of the module. +- `version` - string - A string version number generally following [semantic versioning](https://semver.org/). + - Examples: `v0.4.0`, `4.3.12`, `v0.1.0-beta4`. + +### Customization Order/Precedence + +It's possible that multiple modules may override/customize the same content. +Right now, there's no assurance in regard to the order in which modules may be loaded. +Generally they will be used/searched in order of their module folder name, but this is not assured and should not be relied upon. + +It's also possible that modules customize the same content as the configured theme. +In this scenario, the theme takes precedence. Modules are designed to be more portable and instance abstract, whereas the theme folder would typically be specific to the instance. +This allows the theme to be used to customize or override module content for the BookStack instance, without altering the module code itself. + +### Module Best Practices + +Here are some general best practices when it comes to creating modules: + +- Use a unique name and clear description so the user can understand the purpose of the module. +- Increment the metadata version on change, keeping to [semver](https://semver.org/) to indicate compatibility of new versions. +- Where possible, prefer to [insert views before/after](logical-theme-system.md#custom-view-registration-example) instead of overriding existing views, to reduce likelihood of conflicts or update troubles. \ No newline at end of file diff --git a/dev/docs/visual-theme-system.md b/dev/docs/visual-theme-system.md index 8a76ddb00..8d5669b82 100644 --- a/dev/docs/visual-theme-system.md +++ b/dev/docs/visual-theme-system.md @@ -4,7 +4,7 @@ BookStack allows visual customization via the theme system which enables you to This is part of the theme system alongside the [logical theme system](./logical-theme-system.md). -**Note:** This theme system itself is maintained and supported but usages of this system, including the files you are able to override, are not considered stable and may change upon any update. You should test any customizations made after updates. +**Note:** This theme system itself is maintained and supported, but usages of this system, including the files you are able to override, are not considered stable and may change upon any update. You should test any customizations made after updates. ## Getting Started @@ -18,6 +18,9 @@ You'll need to tell BookStack to use your theme via the `APP_THEME` option in yo Content placed in your `themes//` folder will override the original view files found in the `resources/views` folder. These files are typically [Laravel Blade](https://laravel.com/docs/10.x/blade) files. As an example, I could override the `resources/views/books/parts/list-item.blade.php` file with my own template at the path `themes//books/parts/list-item.blade.php`. +In addition to overriding original views, this could be used to add new views for use via the [logical theme system](logical-theme-system.md). +By using the `THEME_REGISTER_VIEWS` logical event, you can also register your views to be rendered before/after existing views. An example of this can be found in our [logical theme guidance](logical-theme-system.md#custom-view-registration-example). + ## Customizing Icons SVG files placed in a `themes//icons` folder will override any icons of the same name within `resources/icons`. You'd typically want to follow the format convention of the existing icons, where no XML deceleration is included and no width & height attributes are set, to ensure optimal compatibility.