TL;DR
TL;DR
- The sidebar, the new section switcher, and breadcrumbs all read the same
config/menu.phplist — so they can’t drift. - Sections are resolved by longest URL-prefix match, so a detail page like
/admin/roles/42/editkeeps its parent section active even when no menu leaf matches it. - One
SectionResolveraction + Pest tests. Code is public in cleaniquecoders/kickoff.
Drift Problemi
Drift Problemi
Çoğu kenar çubuğu (sidebar) benzer bir şekilde sorun yaşar: bir sayfa ekler, menüye bağlarsınız ve ardından breadcrumb’ı unutur. Artık navigasyon bir şeyi söylerken breadcrumb başka bir şey söyler. Hata kodda değildir — sorun, aynı ağaç için iki gerçeklik kaynağına sahip olmaktır.
Bu nedenle ‘kickoff’ projesinde her şeyi tek bir listeye indirdim. config/menu.php yapıcıları isimlendirir ve diğer her şey buradan türetilir.
// config/menu.php
return [
'globals' => ['sidebar'], // sabit üst (Dashboard, Notifications)
'sections' => ['administration'], // kıvrımlı bölüm grupları
'footer' => ['sidebar-footer'], // sabit alt
];
Bir bölüm eklemek için menü yapıcısını oluşturun ve anahtarını buraya ekleyin. Bu, sözleşmenin tamamıdır.
Aktif Bölümü Belirleme
Aktif Bölümü Belirleme
Bölüm değiştirme aracı, hangi bölümün mevcut sayfayı sahip olduğunu bilmelidir. Tam URL’yi menü öğeleriyle karşılaştırmak hemen başarısız olur — detay sayfaları (/admin/roles/42/edit) menü öğesi değildir. Çözüm, en uzun ön ek kazanır:
foreach (self::leafUrls($items->all()) as $url) {
if ($currentUrl === $url || str_starts_with($currentUrl, rtrim($url, "https://dev.to/")."https://dev.to/")) {
$matchLen = max($matchLen, strlen($url));
}
}
// ...
$active = collect($sections)->where('matchLen', '>', 0)
->sortByDesc('matchLen')->first() ?? ($sections[0] ?? null);
Vurgulanması gereken iki tasarım kararı:
| Karar | Neden |
|---|---|
| En uzun ön ek eşleşmesi, tam değil | Alt sayfalar ana bölümün seçili kalmasını sağlar |
| Etiket/simge/indi geldiği yer yapılandırıcı başlığından gelir | Düplike metadata yok — yapılandırıcı gerçek bilgi kaynağıdır |
Yetkisiz veya boş bölümler resolve() içinde atlanır | Değiştirici, giremeyeceğiniz bir bölümü asla görüntülemez |
| Hiçbir eşleşme yoksa ilk bölüme düşme | Bir hub sayfası hala anlamlı bir aktif duruma sahip olur |
Çözümleyici, görünür bölümleri ve aktif olanı döner, böylece Blade görünümü üzerine yük taşımaz — yalnızca ne verilirse onu işler.
Aynı Ağaçtan Breadcrumbs
Aynı Ağaçtan Breadcrumbs
Breadcrumb’lar aynı config/menu.php‘yi okuduğu için, sidebar ile çelişemezler. Yaprak sayfalar tamamen otomatik; detay sayfaları ana sayfalarını çözümler ve bir yaprak ekler:
Breadcrumb::current(); // Dashboard > Administration > Settings
Breadcrumb::for('admin.roles.index')->push(__('Role Details'));
Çözümleyiciyi Test Etme
Çözümleyiciyi Test Etme
Tarayıcıya ihtiyaç duymadan, Pest ile kolayca kilitlenebilen saf mantık türüdür.
test(, function () {
actingAs($this->admin);
// KENDİSİ BİR MENÜ YAPRAĞI OLMAYAN ALT SAYFA.
app()->instance(, Request::create(route().));
$active = SectionResolver::resolve()[];
expect($active[])->toBe()
->and($active[])->toBeTrue();
});
Dikkate değer diğer durumlar: her bölüm gerçek (non-#) iniş URL’sine sahiptir ve eşleşmeyen bir yol, ilk bölüme düşer.
Özet
Özet
İki arayüz yüzeyi aynı hiyerarşiyi açıklıyorsa, her birinin onu sahiplenmesine izin vermeyin. Onlara bir kayıt verin ve türetin. Bölüm değiştirme aracı, önceden var olan bir listeyi okuyan başka bir okuyucu olduğu için neredeyse ücretsiz eklenmiştir.
Kod halka açık: cleaniquecoders/kickoff.
Kaynak: Orijinal Makale


