[ '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 { // The hidden input holds a comma-separated value that server-side code already expects. ?> $isActive ? 'active' : '', 'aria' => $isActive ? 'aria-current="page"' : '', 'isActive' => $isActive, ]; } /** * 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} */ function navActivePublicPages(array $extraSlugs = []): array { $current = \MintyPHP\Http\Request::path(); if ($current === '') { return ['class' => '', 'aria' => '', 'isActive' => false]; } // "page/" routes and known standalone slugs should highlight the same nav entry. $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, ]; } /** * 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 '\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()); }