little refactore

This commit is contained in:
2026-04-01 16:31:59 +02:00
parent e97d1ddd31
commit 83b65812d0
12 changed files with 942 additions and 748 deletions

View File

@@ -211,8 +211,6 @@ $componentPageConfig = [
'tenantSsoToggle' => [],
'standardDetailPage' => [],
'globalSearch' => [
'inputSelector' => '#side-search',
'resultsSelector' => '[data-global-search-results]',
'appBase' => localeBase(),
],
'tabs' => [
@@ -339,6 +337,7 @@ $componentPageConfig['moduleRuntimeComponents'] = $moduleRuntimeComponents;
<script src="<?php e(assetVersion('vendor/fslightbox/fslightbox.js')); ?>"></script>
<?php require __DIR__ . '/partials/app-confirm-dialog.phtml'; ?>
<?php if ($isLoggedIn): ?>
<?php require __DIR__ . '/partials/app-search-dialog.phtml'; ?>
<?php require __DIR__ . '/partials/app-session-warning-dialog.phtml'; ?>
<?php endif; ?>
<?php foreach ($moduleBodyEndTemplateSlots as $slot): ?>

View File

@@ -15,13 +15,6 @@ $hasAdminPanel = layoutHasAdminPanel($layoutAuth);
<i class="bi bi-house"></i>
</button>
</li>
<li>
<button type="button" id="aside-tab-search" data-aside-target="search" role="tab" aria-selected="false"
aria-controls="aside-panel-search" aria-label="<?php e(t('Search')); ?>"
data-tooltip="<?php e(t('Search')); ?>" data-tooltip-pos="right">
<i class="bi bi-search"></i>
</button>
</li>
<?php
// ── Module-contributed aside tabs (aside.tab_panel slot) ──
$moduleSlots = is_array($layoutNav['moduleSlots'] ?? null) ? $layoutNav['moduleSlots'] : [];

View File

@@ -279,7 +279,6 @@ $csrfKey = trim((string) ($layoutNav['csrfKey'] ?? \MintyPHP\Session::$csrfSessi
$csrfToken = (string) ($layoutNav['csrfToken'] ?? '');
$moduleSlots = is_array($layoutNav['moduleSlots'] ?? null) ? $layoutNav['moduleSlots'] : [];
$modulePanelSlots = is_array($moduleSlots['aside.tab_panel'] ?? null) ? $moduleSlots['aside.tab_panel'] : [];
$moduleSearchSlots = is_array($moduleSlots['search.resource_item'] ?? null) ? $moduleSlots['search.resource_item'] : [];
?>
<aside class="app-sidebar" id="app-sidebar" data-app-component="sidebar-toggle">
<?php if ($currentTenant): ?>
@@ -376,163 +375,5 @@ $moduleSearchSlots = is_array($moduleSlots['search.resource_item'] ?? null) ? $m
</nav>
<?php endforeach; ?>
<div id="aside-panel-search" class="app-sidebar-panel" data-app-component="global-search" data-aside-panel="search"
data-aside-title="<?php e(t('Search')); ?>" role="tabpanel" aria-labelledby="aside-tab-search" hidden>
<form class="app-search" >
<input type="search" name="side-search" id="side-search" placeholder="<?php e(t('Search...')); ?>"
aria-label="<?php e(t('Search')); ?>">
<span class="app-search-shortcut" data-search-shortcut aria-hidden="true"></span>
</form>
<div class="app-search-empty-state" data-global-search-empty>
<i class="bi bi-search" aria-hidden="true"></i>
<p><?php e(t('To start searching, type in the search field.')); ?></p>
<small class="muted" data-search-empty-hint-template="<?php e(t('Tip: Use {shortcut} to focus search quickly.')); ?>"></small>
</div>
<nav id="global-search">
<ul class="app-search-results" data-global-search-results aria-live="polite">
<?php if ($canViewUsers): ?>
<?php $usersSearch = navActive('admin/users', true); ?>
<li data-search-key="users" data-search-base="<?php e(lurl('admin/users')); ?>">
<a href="<?php e(lurl('admin/users')); ?>" class="<?php e($usersSearch['class']); ?>" <?php echo $usersSearch['aria']; ?>>
<span><?php e(t('Users')); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php endif; ?>
<?php if ($canViewTenants): ?>
<?php $tenantsSearch = navActive('admin/tenants', true); ?>
<li data-search-key="tenants" data-search-base="<?php e(lurl('admin/tenants')); ?>">
<a href="<?php e(lurl('admin/tenants')); ?>" class="<?php e($tenantsSearch['class']); ?>" <?php echo $tenantsSearch['aria']; ?>>
<span><?php e(t('Tenants')); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php endif; ?>
<?php if ($canViewDepartments): ?>
<?php $departmentsSearch = navActive('admin/departments', true); ?>
<li data-search-key="departments" data-search-base="<?php e(lurl('admin/departments')); ?>">
<a href="<?php e(lurl('admin/departments')); ?>"
class="<?php e($departmentsSearch['class']); ?>" <?php echo $departmentsSearch['aria']; ?>>
<span><?php e(t('Departments')); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php endif; ?>
<?php if ($canViewRoles): ?>
<?php $rolesSearch = navActive('admin/roles', true); ?>
<li data-search-key="roles" data-search-base="<?php e(lurl('admin/roles')); ?>">
<a href="<?php e(lurl('admin/roles')); ?>" class="<?php e($rolesSearch['class']); ?>" <?php echo $rolesSearch['aria']; ?>>
<span><?php e(t('Roles')); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php endif; ?>
<?php if ($canViewPermissions): ?>
<?php $permissionsSearch = navActive('admin/permissions', true); ?>
<li data-search-key="permissions" data-search-base="<?php e(lurl('admin/permissions')); ?>">
<a href="<?php e(lurl('admin/permissions')); ?>"
class="<?php e($permissionsSearch['class']); ?>" <?php echo $permissionsSearch['aria']; ?>>
<span><?php e(t('Permissions')); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php endif; ?>
<?php if ($canViewJobs): ?>
<?php $scheduledJobsSearch = navActive('admin/scheduled-jobs', true); ?>
<li data-search-key="scheduled-jobs" data-search-base="<?php e(lurl('admin/scheduled-jobs')); ?>">
<a href="<?php e(lurl('admin/scheduled-jobs')); ?>"
class="<?php e($scheduledJobsSearch['class']); ?>" <?php echo $scheduledJobsSearch['aria']; ?>>
<span><?php e(t('Scheduled jobs')); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php endif; ?>
<?php
$pagesSearch = navActivePublicPages();
?>
<li data-search-key="pages" data-search-base="<?php e(lurl('')); ?>">
<a href="<?php e(lurl('')); ?>" class="<?php e($pagesSearch['class']); ?>" <?php echo $pagesSearch['aria']; ?>>
<span><?php e(t('Pages')); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php if ($canViewDocs): ?>
<?php $docsSearch = navActive('admin/docs', true); ?>
<li data-search-key="docs" data-search-base="<?php e(lurl($docsDefaultPath)); ?>">
<a href="<?php e(lurl($docsDefaultPath)); ?>" class="<?php e($docsSearch['class']); ?>" <?php echo $docsSearch['aria']; ?>>
<span><?php e(t('Documentation')); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php endif; ?>
<?php $hotkeysSearch = navActive('help/hotkeys', true); ?>
<li data-search-key="hotkeys" data-search-base="<?php e(lurl('help/hotkeys')); ?>">
<a href="<?php e(lurl('help/hotkeys')); ?>" class="<?php e($hotkeysSearch['class']); ?>" <?php echo $hotkeysSearch['aria']; ?>>
<span><?php e(t('Keyboard shortcuts')); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php if ($canViewMailLog): ?>
<?php $mailLogSearch = navActive('admin/mail-log', true); ?>
<li data-search-key="mail-log" data-search-base="<?php e(lurl('admin/mail-log')); ?>">
<a href="<?php e(lurl('admin/mail-log')); ?>" class="<?php e($mailLogSearch['class']); ?>"
<?php echo $mailLogSearch['aria']; ?>>
<span><?php e(t('Mail logs')); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php endif; ?>
<?php
$coreSearchKeys = [
'users' => true,
'tenants' => true,
'departments' => true,
'roles' => true,
'permissions' => true,
'scheduled-jobs' => true,
'pages' => true,
'docs' => true,
'hotkeys' => true,
'mail-log' => true,
];
foreach ($moduleSearchSlots as $searchSlot):
if (!is_array($searchSlot)) { continue; }
$slotKey = trim((string) ($searchSlot['key'] ?? ''));
if ($slotKey === '' || isset($coreSearchKeys[$slotKey])) { continue; }
$slotPermission = trim((string) ($searchSlot['permission'] ?? ''));
if ($slotPermission !== '' && empty($layoutAuth[$slotPermission])) { continue; }
$slotLabel = trim((string) ($searchSlot['label'] ?? ''));
if ($slotLabel === '') { continue; }
$slotBase = trim((string) ($searchSlot['base_url'] ?? ''));
if ($slotBase === '') { continue; }
$slotHref = $slotBase;
$slotActive = ['class' => '', 'aria' => ''];
if (!str_starts_with($slotBase, '/') && !str_starts_with($slotBase, 'http://') && !str_starts_with($slotBase, 'https://')) {
$slotHref = lurl($slotBase);
$slotActive = navActive($slotBase, true);
}
?>
<li data-search-key="<?php e($slotKey); ?>" data-search-base="<?php e($slotHref); ?>">
<a href="<?php e($slotHref); ?>" class="<?php e($slotActive['class'] ?? ''); ?>"
<?php echo $slotActive['aria'] ?? ''; ?>>
<span><?php e(t($slotLabel)); ?></span>
<span class="badge" data-search-count>0</span>
</a>
<ul class="app-search-preview" data-search-preview></ul>
</li>
<?php endforeach; ?>
</ul>
</nav>
</div>
</div>
</aside>

View File

@@ -0,0 +1,66 @@
<?php
/**
* Command-palette search dialog.
*
* Opened via Ctrl+K / Cmd+K or topbar search trigger.
* Results are rendered dynamically by JS from the /admin/search/data API.
*/
?>
<dialog
data-app-search-dialog
data-app-component="global-search"
data-search-endpoint="<?php e(lurl('admin/search/data')); ?>"
data-search-results-page="<?php e(lurl('search')); ?>"
aria-labelledby="app-search-dialog-title"
>
<article class="app-dialog-lg app-search-dialog">
<header class="app-search-dialog-header">
<h2 id="app-search-dialog-title" class="visually-hidden"><?php e(t('Search')); ?></h2>
<form class="app-search-dialog-form" autocomplete="off">
<i class="bi bi-search app-search-dialog-icon" aria-hidden="true"></i>
<input
type="search"
name="search-dialog-input"
id="search-dialog-input"
class="app-search-dialog-input"
placeholder="<?php e(t('Search...')); ?>"
aria-label="<?php e(t('Search')); ?>"
aria-autocomplete="list"
aria-controls="app-search-dialog-results"
autocomplete="off"
>
<kbd class="app-search-dialog-shortcut" data-search-shortcut aria-hidden="true"></kbd>
</form>
<button type="button" class="close" data-app-search-dialog-close aria-label="<?php e(t('Close')); ?>" title="<?php e(t('Close')); ?>"></button>
</header>
<div class="app-search-dialog-body">
<div class="app-search-dialog-empty-state" data-search-dialog-empty data-no-results-text="<?php e(t('No results found')); ?>">
<p class="muted"><?php e(t('To start searching, type in the search field.')); ?></p>
<small class="muted" data-search-empty-hint-template="<?php e(t('Tip: Use {shortcut} to focus search quickly.')); ?>"></small>
</div>
<div class="app-search-dialog-loading" data-search-dialog-loading hidden>
<p class="muted" aria-live="polite"><?php e(t('Searching...')); ?></p>
</div>
<div class="app-search-dialog-error" data-search-dialog-error hidden>
<p class="muted"><?php e(t('Search failed. Please try again.')); ?></p>
</div>
<ul
id="app-search-dialog-results"
class="app-search-dialog-results"
data-search-dialog-results
role="listbox"
aria-label="<?php e(t('Search results')); ?>"
hidden
></ul>
</div>
<footer class="app-search-dialog-footer" data-search-dialog-footer hidden>
<a href="<?php e(lurl('search')); ?>" data-search-dialog-view-all class="app-search-dialog-view-all">
<?php e(t('View all results')); ?>
<i class="bi bi-arrow-right" aria-hidden="true"></i>
</a>
<span class="app-search-dialog-footer-hint muted">
<kbd>Esc</kbd> <?php e(t('to close')); ?>
</span>
</footer>
</article>
</dialog>

View File

@@ -38,7 +38,13 @@ $moduleTopbarSlots = is_array($moduleSlots['topbar.right_item'] ?? null) ? $modu
</li>
<li id="async-messages" role="status" aria-live="polite" aria-hidden="true"></li>
</ul>
<div class="app-topbar-center" aria-hidden="true"></div>
<div class="app-topbar-center">
<button type="button" class="app-topbar-search-trigger" data-app-search-trigger aria-label="<?php e(t('Search')); ?>" title="<?php e(t('Search')); ?>">
<i class="bi bi-search" aria-hidden="true"></i>
<span class="app-topbar-search-trigger-text"><?php e(t('Search...')); ?></span>
<kbd class="app-topbar-search-trigger-shortcut" data-search-trigger-shortcut aria-hidden="true"></kbd>
</button>
</div>
<ul class="app-topbar-right">
<?php if ($canSwitchTenant): ?>
<li class="app-topbar-tenant-slot" data-app-component="tenant-switcher" data-tenant-switcher data-tooltip="<?php e(t('Tenant')); ?>" data-tooltip-pos="bottom">