-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Default responsive menu with caching (#79)
- Loading branch information
Showing
11 changed files
with
294 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
{{-- | ||
This is a mobile navigation slideover component for handling multi-level navigations. It makes use of recursion to handle multiple levels of navigation dynamically. | ||
## Properties | ||
- `id` Unique identifier for the current navigation layer. | ||
- `children` Navigation children data | ||
- `title` Title displayed in the header. Defaults to "Menu". | ||
- `hasParent` Indicates if the current menu is a child of another menu. Defaults to false. | ||
- `tag` Base HTML tag for the slideover component. Set this to 'form' for the main navigation or 'div' for nested menus. | ||
- `parentUrl` URL used for navigating to the parent item when in a nested menu. Displayed with a "Go to" link. | ||
## Slots | ||
- `headerButton` This slot allows the customization of the button placed at the left in the header for navigation. | ||
--}} | ||
@props(['id', 'children', 'title' => __('Menu'), 'hasParent' => false, 'tag' => 'form', 'parentUrl' => '']) | ||
@slots(['headerButton']) | ||
|
||
<x-rapidez::slideover.mobile | ||
:title="(string) $title" | ||
:$id | ||
:$hasParent | ||
:$tag | ||
> | ||
<x-slot:headerButton> | ||
<div class="absolute left-0 top-1/2 -translate-y-1/2 cursor-pointer text-white"> | ||
@include('rapidez-statamic::navigation.header-button') | ||
</div> | ||
</x-slot:headerButton> | ||
<div class="bg-inactive-100 flex w-full flex-1 flex-col"> | ||
<ul class="mt-5 flex flex-col divide-y border-y bg-white"> | ||
@if ($hasParent && $parentUrl) | ||
<li> | ||
<a href="{{ $parentUrl }}" class="normal flex items-center justify-between p-5 font-semibold"> | ||
@lang('Go to :item', ['item' => strtolower($title)]) | ||
</a> | ||
</li> | ||
@endif | ||
@foreach ($children ?: [] as $child) | ||
<li class="relative"> | ||
@if ($child['title'] ?? '') | ||
<a href="{{ $child['url'] }}" class="flex items-center justify-between p-5 font-semibold"> | ||
{{ $child['title'] }} | ||
@if ($child['children']) | ||
<x-heroicon-o-chevron-right class="size-4" /> | ||
@endif | ||
</a> | ||
@endif | ||
@if ($child['children']) | ||
@php($childId = uniqid(Str::snake("{$child['title']}" ?? ''))) | ||
<label class="absolute inset-0 cursor-pointer" for="{{ $childId }}"></label> | ||
<x-rapidez-statamic::nav-layer | ||
:id="$childId" | ||
:children="$child['children'] ?? []" | ||
:title="$child['title'] ?? ''" | ||
:parent-url="$child['url']" | ||
has-parent | ||
tag="div" | ||
></x-rapidez-statamic::nav-layer> | ||
@endif | ||
</li> | ||
@endforeach | ||
</ul> | ||
{{ $slot }} | ||
</div> | ||
</x-rapidez::slideover.mobile> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
@props(['nav' => 'nav:main', 'mobileNav' => 'nav:main']) | ||
@php | ||
// This combines multiple navigations into one for desktop and mobile seperately, only neccessary if you have multiple navigations | ||
$navData = collect($nav)->flatMap(fn ($menu) => RapidezStatamic::nav($menu)); | ||
$mobileNavData = collect($mobileNav)->flatMap(fn ($menu) => RapidezStatamic::nav($menu)); | ||
@endphp | ||
<nav class="lg:hidden"> | ||
<x-rapidez-statamic::nav-layer | ||
id="navigation" | ||
is-form | ||
:children="$mobileNavData" | ||
/> | ||
</nav> | ||
|
||
<nav class="relative border-y max-lg:hidden"> | ||
<ul class="text-neutral [&>:not(:hover)]:hover:text-inactive flex items-center justify-center gap-8 text-sm font-semibold"> | ||
@foreach ($navData as $item) | ||
<li class="group"> | ||
<a class="relative flex py-5 transition" href="{{ $item['url'] }}"> | ||
{{ $item['title'] }} | ||
@if ($item['children']) | ||
<div class="bg-primary absolute inset-x-0 bottom-0 z-50 h-0.5 w-full origin-right translate-y-1/2 scale-x-0 transition group-hover:origin-left group-hover:scale-x-100"></div> | ||
@endif | ||
</a> | ||
@if ($item['children']) | ||
<div class="pointer-events-none absolute inset-x-0 top-full -translate-y-1 border-t bg-white opacity-0 transition group-hover:pointer-events-auto group-hover:translate-y-0 group-hover:opacity-100"> | ||
<div class="bg-neutral/50 pointer-events-none absolute inset-x-0 top-full h-screen"></div> | ||
<div class="container relative flex overflow-hidden"> | ||
<ul class="w-full columns-3 flex-col gap-x-12 py-10 font-bold xl:columns-4"> | ||
@foreach ($item['children'] as $item) | ||
<li class="flex break-inside-avoid flex-col gap-1 pb-5"> | ||
<a href="{{ $item['url'] }}">{{ $item['title'] }}</a> | ||
<ul class="[&>:not(:hover)]:hover:text-inactive flex flex-col font-medium"> | ||
@foreach ($item['children'] as $item) | ||
<li class="transition"> | ||
<a href="{{ $item['url'] }}">{{ $item['title'] }}</a> | ||
</li> | ||
@endforeach | ||
</ul> | ||
</li> | ||
@endforeach | ||
</ul> | ||
</div> | ||
</div> | ||
@endif | ||
</li> | ||
@endforeach | ||
</ul> | ||
</nav> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{{-- This is shown on the first slideover of the mobile menu, this is empty by default but can be overridden --}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
namespace Rapidez\Statamic\Exceptions; | ||
|
||
use Exception; | ||
|
||
class NavException extends Exception | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
namespace Rapidez\Statamic\Facades; | ||
|
||
use Illuminate\Support\Facades\Facade; | ||
use Rapidez\Statamic\RapidezStatamic as RapidezStatamicFacade; | ||
|
||
/** | ||
* @see \Rapidez\Statamic\RapidezStatamic | ||
*/ | ||
class RapidezStatamic extends Facade | ||
{ | ||
protected static function getFacadeAccessor() | ||
{ | ||
return RapidezStatamicFacade::class; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
|
||
namespace Rapidez\Statamic\Listeners; | ||
|
||
use Illuminate\Support\Facades\Cache; | ||
use Statamic\Events\NavTreeSaved; | ||
use Statamic\Eloquent\Structures\NavTree; | ||
|
||
class ClearNavTreeCache | ||
{ | ||
public function handle(NavTreeSaved $event): void | ||
{ | ||
/** @var NavTree $tree */ | ||
$tree = $event->tree; | ||
|
||
Cache::forget('nav:' . $tree->handle() . '-' . config('rapidez.store')); | ||
Cache::driver('array')->forget('global-link' . '-' . config('rapidez.store')); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
|
||
namespace Rapidez\Statamic\Listeners; | ||
|
||
use Statamic\Events\NavCreated; | ||
use Statamic\Structures\Nav; | ||
|
||
class SetCollectionsForNav | ||
{ | ||
public function handle(NavCreated $event): void | ||
{ | ||
/** @var Nav $nav */ | ||
$nav = $event->nav; | ||
|
||
$nav | ||
->collections(config('rapidez.statamic.navigation.allowed_collections')) | ||
->save(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
|
||
namespace Rapidez\Statamic; | ||
|
||
use Illuminate\Support\Facades\Cache; | ||
use Statamic\Statamic; | ||
use Statamic\Eloquent\Entries\Entry; | ||
use Rapidez\Core\Facades\Rapidez; | ||
use Rapidez\Statamic\Exceptions\NavException; | ||
use Statamic\Structures\Page; | ||
|
||
class RapidezStatamic | ||
{ | ||
protected array $navCache = []; | ||
|
||
public function nav(string $tag): array | ||
{ | ||
throw_unless( | ||
str($tag)->startsWith('nav:'), | ||
NavException::class, | ||
'You can only use a nav tag to get a navigation tree.' | ||
); | ||
|
||
return Cache::rememberForever($tag . '-' . config('rapidez.store'), fn() => $this->buildMenu($tag)); | ||
} | ||
|
||
protected function buildMenu(string $key): array | ||
{ | ||
$nav = Statamic::tag($key)->fetch(); | ||
|
||
$cacheKey = $key . '-' . config('rapidez.store'); | ||
$this->navCache[$key] = Cache::get($cacheKey, []); | ||
|
||
return $this->buildTree($nav, $key); | ||
} | ||
|
||
protected function buildTree(array $items, string $nav): array | ||
{ | ||
$tree = []; | ||
|
||
foreach ($items as $item) { | ||
if ($item['children']) { | ||
$children = $this->buildTree($item['children'], $nav); | ||
if ($children) { | ||
$item['children'] = $children; | ||
} | ||
} | ||
|
||
$item['url'] = $this->determineEntryUrl($item['entry_id']->augmentable(), $nav); | ||
|
||
$tree[] = $item; | ||
} | ||
|
||
return $tree; | ||
} | ||
|
||
public function determineEntryUrl(Entry|Page $entry, string $nav = 'global-link'): string | ||
{ | ||
$cacheKey = $nav . '-' . config('rapidez.store'); | ||
|
||
if ( ! isset($this->navCache[$nav][$entry->id()])) { | ||
$linkedRunwayResourceKey = $entry | ||
->data() | ||
->keys() | ||
->firstWhere(fn($field) => collect([ | ||
...config('rapidez.statamic.navigation.allowed_collections'), | ||
'linked_', | ||
])->firstWhere(fn($key) => str($field)->startsWith($key))); | ||
|
||
if (!$linkedRunwayResourceKey || !$entry->{$linkedRunwayResourceKey} || $entry->slug()) { | ||
return $entry->url() ?? ''; | ||
} | ||
|
||
$suffix = match (true) { | ||
str($linkedRunwayResourceKey)->contains('category') => Rapidez::config('catalog/seo/category_url_suffix', ''), | ||
str($linkedRunwayResourceKey)->contains('product') => Rapidez::config('catalog/seo/product_url_suffix', ''), | ||
default => '', | ||
}; | ||
|
||
$this->navCache[$nav][$entry->id()] = '/' . $entry->{$linkedRunwayResourceKey}['url_path'] . $suffix; | ||
|
||
Cache::forever($cacheKey, $this->navCache[$nav]); | ||
} | ||
|
||
return $this->navCache[$nav][$entry->id()]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters