@use('Core\Access\Permission') @use('Core\Area\Cms\Models\User') @use('Core\Internal\Navigation\PanelMenu') @use('Core\Localization\Locales') @use('Illuminate\Support\Str') @use('Layout\Cms\Shell\CmsShellResolver') @use('Layout\Engine\A11yPreferences') @use('Services\Layout\Contracts\LayoutAreaScopes') @props([ 'title' => null, 'breadcrumbs' => [], 'robots' => 'noindex, nofollow', 'instance' => [], 'heading' => true, ]) @php /** Shell resolvido: identidade + regiões + posição da navegação (ADR-036). */ $shell = app(CmsShellResolver::class)->resolve(is_array($instance) ? $instance : []); $a11y = A11yPreferences::fromRequest(request()); $currentUser = auth()->user(); $currentUser = $currentUser instanceof User ? $currentUser : null; /** * O menu de usuário mostra o perfil (ADR-033): carregar **aqui** evita *lazy loading* na view * (`Model::preventLazyLoading`) e um segundo request por linha. */ $currentUser?->loadMissing('role'); /** Navegação do manifesto: agrupada, ordenada e filtrada por permissão (ADR-033/ADR-036). */ $panelMenu = $currentUser === null ? null : app(PanelMenu::class); $menu = $panelMenu === null ? [] : $panelMenu->fromManifest($currentUser); /** Lista plana (navegação rápida Ctrl+K): o Core fornece o índice; o shell só traduz. */ $paletteItems = []; /** * Índice de busca: **sem acento** e minúsculo — o teclado brasileiro digita `noticias` e * precisa achar `Notícias`. O filtro do cliente normaliza com a mesma regra (NFD + diacríticos). */ $searchIndex = static fn (string $text): string => mb_strtolower(Str::ascii($text)); foreach ($panelMenu?->flat($currentUser) ?? [] as $entry) { $paletteItems[] = [ 'title_key' => $entry['title'], 'context_key' => $entry['context'], 'url' => $entry['url'], 'search' => $searchIndex(trim(__($entry['title']).' '.($entry['context'] === null ? '' : __($entry['context'])))), ]; } $brand = $shell->brand(); $pageTitle = filled($title) ? $title.' · '.$brand : $brand; /** * Ação "Configurar layout da área" (P1.S4b/ADR-016): **uma** ação compartilhada, nunca uma * permissão por módulo. Só aparece quando a tela atual tem contrapartida viva no portal * (`noticias.cms.index` → `noticias`) e o usuário tem a permissão da superfície de layout — * Configurações/Menus/superfície de layout não a exibem, então nunca há link morto. */ $areaLayoutScope = null; if ($currentUser !== null && config('layout.area_action', true) && Permission::allows('Layout', Permission::EDIT, $currentUser)) { $areaLayoutScope = app(LayoutAreaScopes::class)->scopeFor(request()->route()?->getName()); } /** Breadcrumb sempre começa no painel: a tela atual nunca é o único item (duplica o `

`). */ $crumbs = is_array($breadcrumbs) ? array_values($breadcrumbs) : []; $dashboardUrl = route('cms.dashboard'); if ($crumbs !== [] && (($crumbs[0]['url'] ?? null) !== $dashboardUrl)) { array_unshift($crumbs, ['label' => __('layout::shell.dashboard'), 'url' => $dashboardUrl]); } @endphp attributes() as $a11yAttribute => $a11yValue) {{ $a11yAttribute }}="{{ $a11yValue }}" @endforeach > {{ $pageTitle }} @vite(['src/layout/Cms/Assets/css/app.css', 'src/layout/Cms/Assets/js/app.js']) {{-- Identidade própria só quando há override (default: nenhuma requisição extra) — ADR-036/022. --}} @if ($shell->hasIdentityOverrides()) @endif @stack('styles') @include('portal::partials.a11y-bar', ['a11y' => $a11y]) @if ($shell->header) @include('cms::partials.header', ['shell' => $shell, 'currentUser' => $currentUser]) @endif
@if ($shell->sidebarBeforeContent()) @include('cms::partials.sidebar', ['shell' => $shell, 'menu' => $menu]) @endif
@if (filled($title) && $heading) {{-- O shell é dono do `

` da tela: nenhuma tela do painel nasce sem título. `heading=false` só para telas que trazem o próprio título (acesso). --}}

{{ $title }}

@endif @if ($crumbs !== []) @endif @if ($areaLayoutScope !== null) {{-- Ação de área (P1.S4b): link real, com texto visível e ícone Lucide — sem inline/CSS novo e sem depender de JS (ADR-010/ADR-025). --}}
{{ __('layout-service::cms.area_action') }}
@endif @isset($actions)
{{ $actions }}
@endisset {{ $slot }}
@if ($shell->footer) @include('cms::partials.footer', ['shell' => $shell]) @endif
@if ($shell->sidebarAfterContent()) @include('cms::partials.sidebar', ['shell' => $shell, 'menu' => $menu]) @endif
{{-- Overlay do painel off-canvas: só aparece com JS + tela pequena (ADR-036). --}} @if ($shell->hasSidebar() && $shell->sidebarPosition->isColumn()) @endif @if ($shell->isOrbital()) @include('cms::partials.orbital', ['shell' => $shell, 'menu' => $menu]) @endif @if ($paletteItems !== []) @include('cms::partials.palette', ['paletteItems' => $paletteItems]) @endif @stack('modals') @stack('scripts')