Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reimagine Navigation rendering features #199

Open
wants to merge 11 commits into
base: 3.x
Choose a base branch
from
23 changes: 23 additions & 0 deletions src/Classes/LinkRenderers/GenericLinkRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace LaraZeus\Sky\Classes\LinkRenderers;

use Illuminate\Database\Eloquent\Model;

class GenericLinkRenderer extends NavLinkRenderer
{
public function getModel(): ?Model
atmonshi marked this conversation as resolved.
Show resolved Hide resolved
{
return null;
}

public function getLink(): ?string
{
return $this->item['data']['url'];
}

public function isActiveRoute(): bool
{
return false;
}
}
37 changes: 37 additions & 0 deletions src/Classes/LinkRenderers/LibraryLinkRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace LaraZeus\Sky\Classes\LinkRenderers;

use Illuminate\Database\Eloquent\Model;
use LaraZeus\Sky\Models\Library;
use LaraZeus\Sky\SkyPlugin;

class LibraryLinkRenderer extends NavLinkRenderer
{
public static string $renders = 'library-link';

public function getModel(): ?Model
atmonshi marked this conversation as resolved.
Show resolved Hide resolved
{
return SkyPlugin::get()->getModel('Tag')::find($this->item['data']['library_id']);
}

public function getLink(): ?string
{
/**
* @var Library $tag
*/
$tag = $this->getModel();

return route('library.tag', $tag->slug);
}

public function isActiveRoute(): bool
{
/**
* @var Library $tag
*/
$tag = $this->getModel();

return str(request()->url())->contains($tag->library->first()->slug);
}
}
46 changes: 46 additions & 0 deletions src/Classes/LinkRenderers/NavLinkRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace LaraZeus\Sky\Classes\LinkRenderers;

use Illuminate\Database\Eloquent\Model;

abstract class NavLinkRenderer
{
public static string $renders;
mallardduck marked this conversation as resolved.
Show resolved Hide resolved

public function __construct(
protected array $item
) {
}

// TODO: something to control these classes for end-user?
public static string $activeClasses = 'border-b border-b-secondary-500 text-secondary-500';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned - having something to control this could be nice, tho not necessary immediately.


public static string $defaultActiveClass = 'border-transparent';

abstract public function getModel(): ?Model;

abstract public function getLink(): ?string;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think this one was made nullable on accident 🤔 - technically the most "empty" thing we need out of this is an empty string. Don't think it actually needs to be able to be null?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a use case come to mind, I did use it in on project but for the love of god cant find which one was...

the menu can have nested items, for a dropdown menu with sub nav, so maybe in this case the link can be null!


abstract public function isActiveRoute(): bool;

public function getActiveClass(): string
{
return $this->isActiveRoute() ?
self::$activeClasses :
self::$defaultActiveClass;
}

/**
* @return array{}
*/
public function getPreparedLink(string $classes = ''): array
{
return [
'classes' => $classes . ' ' . $this->getActiveClass(),
'target' => $this->item['data']['target'] ?? '_self',
'link' => $this->getLink(),
'label' => $this->item['label'],
];
}
}
39 changes: 39 additions & 0 deletions src/Classes/LinkRenderers/PageLinkRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace LaraZeus\Sky\Classes\LinkRenderers;

use Illuminate\Database\Eloquent\Model;
use LaraZeus\Sky\Models\Post;
use LaraZeus\Sky\SkyPlugin;

class PageLinkRenderer extends NavLinkRenderer
{
public static string $renders = 'page-link';

public function getModel(): ?Model
{
return SkyPlugin::get()->getModel('Post')::page()
->whereDate('published_at', '<=', now())
->find($this->item['data']['page_id']);
}

public function getLink(): ?string
{
/**
* @var Post $page
*/
$page = $this->getModel();

return route('page', $page);
}

public function isActiveRoute(): bool
{
/**
* @var Post $page
*/
$page = $this->getModel();

return request()->routeIs('page', $page);
}
}
38 changes: 38 additions & 0 deletions src/Classes/LinkRenderers/PostLinkRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace LaraZeus\Sky\Classes\LinkRenderers;

use Illuminate\Database\Eloquent\Model;
use LaraZeus\Sky\Models\Post;
use LaraZeus\Sky\SkyPlugin;

class PostLinkRenderer extends NavLinkRenderer
{
public static string $renders = 'post-link';

public function getModel(): ?Model
{
return SkyPlugin::get()->getModel('Post')::whereDate('published_at', '<=', now())
->find($this->item['data']['post_id']);
}

public function getLink(): ?string
{
/**
* @var Post $post
*/
$post = $this->getModel();

return route('post', $post);
}

public function isActiveRoute(): bool
{
/**
* @var Post $post
*/
$post = $this->getModel();

return request()->routeIs('post', $post);
}
}
77 changes: 38 additions & 39 deletions src/Classes/RenderNavItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,51 @@

namespace LaraZeus\Sky\Classes;

use LaraZeus\Sky\Classes\LinkRenderers\GenericLinkRenderer;
use LaraZeus\Sky\Classes\LinkRenderers\NavLinkRenderer;
use LaraZeus\Sky\SkyPlugin;

class RenderNavItem
{
public static function render(array $item, string $class = ''): string
{
$color = 'border-b border-b-secondary-500 text-secondary-500';

if ($item['type'] === 'page-link' || $item['type'] === 'page_link') {
$page = SkyPlugin::get()->getModel('Post')::page()->whereDate('published_at', '<=', now())->find($item['data']['page_id']) ?? '';
$activeClass = (request()->routeIs('page', $page)) ? $color : 'border-transparent';

return '<a class="' . $class . ' ' . $activeClass . '"
target="' . ($item['data']['target'] ?? '_self') . '"
href="' . route('page', $page) . '"
>' .
$item['label'] .
'</a>';
} elseif ($item['type'] === 'post-link' || $item['type'] === 'post_link') {
$post = SkyPlugin::get()->getModel('Post')::find($item['data']['post_id']) ?? '';
$activeClass = (request()->routeIs('post', $post)) ? $color : 'border-transparent';

return '<a class="' . $class . ' ' . $activeClass . '"
target="' . ($item['data']['target'] ?? '_self') . '"
href="' . route('post', $post) . '"
>' .
$item['label'] .
'</a>';
} elseif ($item['type'] === 'library-link' || $item['type'] === 'library_link') {
$tag = SkyPlugin::get()->getModel('Tag')::find($item['data']['library_id']) ?? '';
$activeClass = (str(request()->url())->contains($tag->library->first()->slug)) ? $color : 'border-transparent';

return '<a class="' . $class . ' ' . $activeClass . '"
target="' . ($item['data']['target'] ?? '_self') . '"
href="' . route('library.tag', $tag->slug) . '"
/**
* @var class-string<NavLinkRenderer>
*/
public static string $defaultRendererClass = GenericLinkRenderer::class;

private static function anchorLink(
string $classes,
string $target,
string $link,
string $label,
): string {
// TODO: make this component based?
mallardduck marked this conversation as resolved.
Show resolved Hide resolved
// Then it's probably easier for users to further customize this?
mallardduck marked this conversation as resolved.
Show resolved Hide resolved
return '<a class="' . $classes . '"
target="' . $target . '"
href="' . $link . '"
>' .
$item['label'] .
'</a>';
$label . // TODO: allow optional wrapping link text in span?
mallardduck marked this conversation as resolved.
Show resolved Hide resolved
// Or maybe support this customization via components?
'</a>';
}

public static function render(array $item, string $class = ''): string
{
$itemType = $item['type'];
if (str($itemType)->contains('_')) {
$itemType = str($itemType)->replace('_', '-')->toString();
}
$renderersMap = SkyPlugin::get()->getNavRenderers();
if (array_key_exists($itemType, $renderersMap)) {
$rendererClass = $renderersMap[$itemType];
$renderer = new $rendererClass($item);
} else {
return '<a class="' . $class . '"
target="' . ($item['data']['target'] ?? '_self') . '"
href="' . $item['data']['url'] . '"
>' .
$item['label'] .
'</a>';
$renderer = new static::$defaultRendererClass($item);
}

/**
* @var NavLinkRenderer $renderer
*/
return static::anchorLink(...$renderer->getPreparedLink($class));
}
}
32 changes: 32 additions & 0 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Illuminate\Support\Str;
use LaraZeus\Sky\Classes\LinkRenderers\LibraryLinkRenderer;
use LaraZeus\Sky\Classes\LinkRenderers\NavLinkRenderer;
use LaraZeus\Sky\Classes\LinkRenderers\PageLinkRenderer;
use LaraZeus\Sky\Classes\LinkRenderers\PostLinkRenderer;

trait Configuration
{
Expand Down Expand Up @@ -55,6 +59,11 @@ trait Configuration

protected array $itemTypes = [];

/**
* @var class-string<NavLinkRenderer>[]
*/
protected array $navRenderers = [];

protected array | Closure $extraFields = [];

public function navigationGroupLabel(Closure | string $lable): static
Expand Down Expand Up @@ -279,4 +288,27 @@ public function hideResources(array $resources = []): static

return $this;
}

/**
* @param class-string<NavLinkRenderer> $rendererClass
* @return $this
*/
public function navRenderer(string $rendererClass): static
{
$this->navRenderers[$rendererClass::$renders] = $rendererClass;

return $this;
}

public function getNavRenderers(): array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, first note: we cant use the plugin configuration class for any FE stuff. since the panel is not available, and Filament will load the default one. and in some cases the plugin is not registered in the default panel.

so if I have AdminPanel and CmsPanel and sky only registered in CmsPanel but the ->default() is CmsPanel... :) will it will throw an exception.

that is way I kept the config file, for all frontend stugg. just need to move this one to the config file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohh - fair call out. I hadn't gotten to my task of "customize the zeus theme/template" yet! I've only been testing the navigation in my own sites templates so far. So I think once I setup the Blog's theme to match my template it'll make more sense to me what's going on here.

{
return array_merge(
[
PageLinkRenderer::$renders => PageLinkRenderer::class,
PostLinkRenderer::$renders => PostLinkRenderer::class,
LibraryLinkRenderer::$renders => LibraryLinkRenderer::class,
],
$this->navRenderers
);
}
}