2026-02-04 23:31:53 +01:00
|
|
|
<?php
|
|
|
|
|
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
/**
|
|
|
|
|
* Grid.js localization map used across list pages.
|
|
|
|
|
*/
|
2026-02-04 23:31:53 +01:00
|
|
|
function gridLang(): array
|
|
|
|
|
{
|
|
|
|
|
return [
|
|
|
|
|
'search' => [
|
|
|
|
|
'placeholder' => t('Search...'),
|
|
|
|
|
],
|
|
|
|
|
'sort' => [
|
|
|
|
|
'sortAsc' => t('Sort column ascending'),
|
|
|
|
|
'sortDesc' => t('Sort column descending'),
|
|
|
|
|
],
|
|
|
|
|
'pagination' => [
|
|
|
|
|
'previous' => t('Previous'),
|
|
|
|
|
'next' => t('Next'),
|
|
|
|
|
'navigate' => t('Page %d of %d'),
|
|
|
|
|
'page' => t('Page %d'),
|
|
|
|
|
'showing' => t('Showing'),
|
|
|
|
|
'of' => t('of'),
|
|
|
|
|
'to' => t('to'),
|
|
|
|
|
'results' => t('results'),
|
|
|
|
|
],
|
|
|
|
|
'loading' => t('Loading...'),
|
|
|
|
|
'noRecordsFound' => t('No records found'),
|
|
|
|
|
'error' => t('An error happened while fetching the data'),
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render a multi-select filter field with hidden input sync.
|
|
|
|
|
*
|
|
|
|
|
* @param string $id Base ID for the hidden input (select gets "-ui" suffix)
|
|
|
|
|
* @param string $label Field label (will be translated)
|
|
|
|
|
* @param string $placeholder Placeholder text (will be translated)
|
|
|
|
|
* @param array $items Array of items with 'id' and 'description' keys
|
|
|
|
|
* @param array $selected Array of selected item IDs
|
|
|
|
|
*/
|
|
|
|
|
function multiSelectFilter(
|
|
|
|
|
string $id,
|
|
|
|
|
string $label,
|
|
|
|
|
string $placeholder,
|
|
|
|
|
array $items,
|
|
|
|
|
array $selected
|
|
|
|
|
): void {
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
// The hidden input holds a comma-separated value that server-side code already expects.
|
2026-02-04 23:31:53 +01:00
|
|
|
?>
|
|
|
|
|
<label class="app-field">
|
|
|
|
|
<span><?php e(t($label)); ?></span>
|
|
|
|
|
<input type="hidden" id="<?php e($id); ?>" value="<?php e(implode(',', $selected)); ?>">
|
|
|
|
|
<select
|
|
|
|
|
id="<?php e($id); ?>-ui"
|
|
|
|
|
multiple
|
|
|
|
|
data-multi-select
|
|
|
|
|
data-sync-target="#<?php e($id); ?>"
|
|
|
|
|
data-select-all="true"
|
|
|
|
|
data-list-all="false"
|
|
|
|
|
data-search="true"
|
|
|
|
|
data-placeholder="<?php e(t($placeholder)); ?>"
|
|
|
|
|
data-search-placeholder="<?php e(t('Search...')); ?>"
|
|
|
|
|
data-select-all-label="<?php e(t('Select all')); ?>"
|
|
|
|
|
data-selected-label="<?php e(t('%d selected')); ?>"
|
|
|
|
|
>
|
|
|
|
|
<?php foreach ($items as $item): ?>
|
|
|
|
|
<?php $itemId = (string) ($item['id'] ?? ''); ?>
|
|
|
|
|
<?php if ($itemId !== ''): ?>
|
|
|
|
|
<option value="<?php e($itemId); ?>"<?php if (in_array($itemId, $selected, true)) { ?> selected<?php } ?>>
|
|
|
|
|
<?php e($item['description'] ?? ''); ?>
|
|
|
|
|
</option>
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
</select>
|
|
|
|
|
</label>
|
|
|
|
|
<?php
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render a multi-select form field for data entry.
|
|
|
|
|
*
|
|
|
|
|
* @param string $id Element ID
|
|
|
|
|
* @param string $name Form field name
|
|
|
|
|
* @param string $label Field label (will be translated)
|
|
|
|
|
* @param string $placeholder Placeholder text (will be translated)
|
|
|
|
|
* @param array $items Array of items with 'id' and 'description' keys
|
|
|
|
|
* @param array $selected Array of selected item IDs
|
|
|
|
|
* @param bool $disabled Whether the field is disabled/readonly
|
|
|
|
|
* @param string|array $labelKeys Key(s) to use for option label (tries in order)
|
|
|
|
|
* @param string|null $formId Form ID for selects outside form element
|
|
|
|
|
*/
|
|
|
|
|
function multiSelectForm(
|
|
|
|
|
string $id,
|
|
|
|
|
string $name,
|
|
|
|
|
string $label,
|
|
|
|
|
string $placeholder,
|
|
|
|
|
array $items,
|
|
|
|
|
array $selected,
|
|
|
|
|
bool $disabled = false,
|
|
|
|
|
string|array $labelKeys = 'description',
|
|
|
|
|
?string $formId = null
|
|
|
|
|
): void {
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
// Allow a fallback chain for label keys, e.g. ['description', 'label', 'name'].
|
2026-02-04 23:31:53 +01:00
|
|
|
$labelKeyList = is_array($labelKeys) ? $labelKeys : [$labelKeys];
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
// Vendor MultiSelect appends [] to the field name internally for hidden inputs.
|
|
|
|
|
// Strip a trailing [] here to avoid accidental [][] payloads.
|
|
|
|
|
$normalizedName = preg_replace('/\[\]$/', '', $name) ?: $name;
|
2026-02-04 23:31:53 +01:00
|
|
|
?>
|
|
|
|
|
<label>
|
|
|
|
|
<span><?php e(t($label)); ?></span>
|
|
|
|
|
</label>
|
|
|
|
|
<select
|
|
|
|
|
id="<?php e($id); ?>"
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
name="<?php e($normalizedName); ?>"
|
2026-02-04 23:31:53 +01:00
|
|
|
<?php if ($formId !== null): ?>form="<?php e($formId); ?>"<?php endif; ?>
|
|
|
|
|
multiple
|
|
|
|
|
data-multi-select="true"
|
|
|
|
|
data-select-all="true"
|
|
|
|
|
data-search="true"
|
|
|
|
|
data-placeholder="<?php e(t($placeholder)); ?>"
|
|
|
|
|
data-search-placeholder="<?php e(t('Search...')); ?>"
|
|
|
|
|
data-select-all-label="<?php e(t('Select all')); ?>"
|
|
|
|
|
<?php if ($disabled): ?>data-disabled="true" disabled<?php endif; ?>
|
|
|
|
|
>
|
|
|
|
|
<?php foreach ($items as $item): ?>
|
|
|
|
|
<?php $itemId = (int) ($item['id'] ?? 0); ?>
|
|
|
|
|
<?php if ($itemId > 0): ?>
|
|
|
|
|
<?php
|
|
|
|
|
$isSelected = in_array($itemId, $selected, true);
|
|
|
|
|
$itemLabel = '';
|
|
|
|
|
foreach ($labelKeyList as $key) {
|
|
|
|
|
if (isset($item[$key]) && (string) $item[$key] !== '') {
|
|
|
|
|
$itemLabel = (string) $item[$key];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
?>
|
|
|
|
|
<option value="<?php e((string) $itemId); ?>"<?php if ($isSelected) { ?> selected<?php } ?>>
|
|
|
|
|
<?php e($itemLabel); ?>
|
|
|
|
|
</option>
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
</select>
|
|
|
|
|
<?php
|
|
|
|
|
}
|
|
|
|
|
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
/**
|
|
|
|
|
* Resolve nav active state for one or many paths.
|
|
|
|
|
*
|
|
|
|
|
* @param string|array $path A single path or a list of candidate paths.
|
|
|
|
|
* @param bool $prefix Prefix matching (path starts with candidate).
|
|
|
|
|
* @return array{class:string,aria:string,isActive:bool}
|
|
|
|
|
*/
|
2026-02-04 23:31:53 +01:00
|
|
|
function navActive($path, bool $prefix = false): array
|
|
|
|
|
{
|
|
|
|
|
$current = \MintyPHP\Http\Request::path();
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
// Normalize to array to keep the matching loop simple.
|
2026-02-04 23:31:53 +01:00
|
|
|
$paths = is_array($path) ? $path : [$path];
|
|
|
|
|
$isActive = false;
|
|
|
|
|
foreach ($paths as $p) {
|
|
|
|
|
$p = (string) $p;
|
|
|
|
|
$match = $prefix ? strpos($current, $p) === 0 : $current === $p;
|
|
|
|
|
if (!$match && ($current === '' || $current === '/')) {
|
|
|
|
|
$match = $p === '' || $p === '/';
|
|
|
|
|
}
|
|
|
|
|
if ($match) {
|
|
|
|
|
$isActive = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'class' => $isActive ? 'active' : '',
|
|
|
|
|
'aria' => $isActive ? 'aria-current="page"' : '',
|
|
|
|
|
'isActive' => $isActive,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
/**
|
|
|
|
|
* Resolve active state for public page links (static pages and page/* slugs).
|
|
|
|
|
*
|
|
|
|
|
* @param array $extraSlugs Additional public slugs that should be treated as active.
|
|
|
|
|
* @return array{class:string,aria:string,isActive:bool}
|
|
|
|
|
*/
|
2026-02-04 23:31:53 +01:00
|
|
|
function navActivePublicPages(array $extraSlugs = []): array
|
|
|
|
|
{
|
|
|
|
|
$current = \MintyPHP\Http\Request::path();
|
|
|
|
|
if ($current === '') {
|
|
|
|
|
return ['class' => '', 'aria' => '', 'isActive' => false];
|
|
|
|
|
}
|
|
|
|
|
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
// "page/<slug>" routes and known standalone slugs should highlight the same nav entry.
|
2026-02-04 23:31:53 +01:00
|
|
|
$publicSlugs = array_merge(['imprint', 'privacy'], $extraSlugs);
|
|
|
|
|
$isActive = strpos($current, 'page/') === 0 || in_array($current, $publicSlugs, true);
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'class' => $isActive ? 'active' : '',
|
|
|
|
|
'aria' => $isActive ? 'aria-current="page"' : '',
|
|
|
|
|
'isActive' => $isActive,
|
|
|
|
|
];
|
|
|
|
|
}
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Load and cache the asset registry config from config/assets.php.
|
|
|
|
|
*/
|
|
|
|
|
function appAssetConfig(): array
|
|
|
|
|
{
|
|
|
|
|
// Static local cache avoids repeated filesystem access during one request.
|
|
|
|
|
static $config = null;
|
|
|
|
|
if ($config !== null) {
|
|
|
|
|
return $config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$file = dirname(__DIR__, 3) . '/config/assets.php';
|
|
|
|
|
if (!is_file($file)) {
|
|
|
|
|
$config = [];
|
|
|
|
|
return $config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$loaded = include $file;
|
|
|
|
|
$config = is_array($loaded) ? $loaded : [];
|
|
|
|
|
return $config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resolve all CSS paths for one or more asset groups.
|
|
|
|
|
*
|
|
|
|
|
* @param string[] $groupNames
|
|
|
|
|
*
|
|
|
|
|
* @return string[] List of unique web-relative asset paths.
|
|
|
|
|
*/
|
|
|
|
|
function appStylePathsForGroups(array $groupNames): array
|
|
|
|
|
{
|
|
|
|
|
$config = appAssetConfig();
|
|
|
|
|
$styles = $config['styles'] ?? [];
|
|
|
|
|
if (!is_array($styles)) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$groups = $styles['groups'] ?? [];
|
|
|
|
|
if (!is_array($groups)) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$resolved = [];
|
|
|
|
|
// Used as a fast set to keep insertion order while removing duplicates.
|
|
|
|
|
$seen = [];
|
|
|
|
|
foreach ($groupNames as $groupName) {
|
|
|
|
|
$groupKey = trim((string) $groupName);
|
|
|
|
|
if ($groupKey === '' || !isset($groups[$groupKey]) || !is_array($groups[$groupKey])) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
foreach ($groups[$groupKey] as $path) {
|
|
|
|
|
$assetPath = ltrim(trim((string) $path), '/');
|
|
|
|
|
if ($assetPath === '' || isset($seen[$assetPath])) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$seen[$assetPath] = true;
|
|
|
|
|
$resolved[] = $assetPath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $resolved;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resolve all CSS paths for a template based on grouped config entries.
|
|
|
|
|
*
|
|
|
|
|
* @return string[] List of unique web-relative asset paths.
|
|
|
|
|
*/
|
|
|
|
|
function appTemplateStylePaths(string $templateName): array
|
|
|
|
|
{
|
|
|
|
|
$config = appAssetConfig();
|
|
|
|
|
$styles = $config['styles'] ?? [];
|
|
|
|
|
if (!is_array($styles)) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$templates = $styles['templates'] ?? [];
|
|
|
|
|
if (!is_array($templates)) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$groupNames = $templates[$templateName] ?? [];
|
|
|
|
|
if (!is_array($groupNames)) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return appStylePathsForGroups($groupNames);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read a raw Buffer value without echoing it to output.
|
|
|
|
|
*/
|
|
|
|
|
function appBufferValue(string $key): string
|
|
|
|
|
{
|
|
|
|
|
ob_start();
|
|
|
|
|
$hasValue = \MintyPHP\Buffer::get($key);
|
|
|
|
|
$raw = (string) ob_get_clean();
|
|
|
|
|
return $hasValue ? trim($raw) : '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resolve page-specific CSS files declared via Buffer::set('style_groups', ...).
|
|
|
|
|
*
|
|
|
|
|
* Accepted formats:
|
|
|
|
|
* - JSON array (e.g. ["address-book"])
|
|
|
|
|
* - comma-separated list (e.g. "address-book,foo")
|
|
|
|
|
*
|
|
|
|
|
* @return string[] List of unique web-relative asset paths.
|
|
|
|
|
*/
|
|
|
|
|
function appPageStylePaths(): array
|
|
|
|
|
{
|
|
|
|
|
$raw = appBufferValue('style_groups');
|
|
|
|
|
if ($raw === '') {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$groupNames = json_decode($raw, true);
|
|
|
|
|
if (!is_array($groupNames)) {
|
|
|
|
|
$groupNames = array_filter(array_map('trim', explode(',', $raw)));
|
|
|
|
|
}
|
|
|
|
|
return appStylePathsForGroups($groupNames);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render stylesheet link tags.
|
|
|
|
|
*
|
|
|
|
|
* @param string[] $stylePaths
|
|
|
|
|
*/
|
|
|
|
|
function renderStylePaths(array $stylePaths): void
|
|
|
|
|
{
|
|
|
|
|
foreach ($stylePaths as $stylePath) {
|
|
|
|
|
echo '<link href="';
|
|
|
|
|
e(assetVersion($stylePath));
|
|
|
|
|
echo "\" rel=\"stylesheet\">\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render stylesheet link tags for the given template.
|
|
|
|
|
*/
|
|
|
|
|
function renderTemplateStyles(string $templateName): void
|
|
|
|
|
{
|
|
|
|
|
renderStylePaths(appTemplateStylePaths($templateName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render page-specific stylesheet links from Buffer::set('style_groups', ...).
|
|
|
|
|
*/
|
|
|
|
|
function renderPageStyles(): void
|
|
|
|
|
{
|
|
|
|
|
renderStylePaths(appPageStylePaths());
|
|
|
|
|
}
|