Skip to content

Commit

Permalink
✨ Add a make:navi view component generator command for Acorn (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
Log1x authored Mar 26, 2024
2 parents 94c2a8b + 3f13de8 commit e2a388e
Show file tree
Hide file tree
Showing 8 changed files with 280 additions and 50 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@ $navigation->get()->name;
$navigation->get('name', 'My menu title');
```

### Acorn Usage

If you are using Navi alongside [Acorn](https://roots.io/acorn/) (e.g. Sage), you may generate a usable view component using Acorn's CLI:

```sh
$ acorn make:navi
```

Once generated, you may use the [view component](https://laravel.com/docs/11.x/blade#components) in an existing view like so:

```php
<x-navigation />
```

### Accessing Page Objects

If your menu item is linked to a page object (e.g. not a custom link) – you can retrieve the ID of the page using the `objectId` attribute.
Expand Down
26 changes: 0 additions & 26 deletions examples/sage/app/View/Composers/Navigation.php

This file was deleted.

39 changes: 39 additions & 0 deletions examples/sage/resources/views/components/navigation.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@props([
'name' => null,
'inactive' => 'hover:text-blue-500',
'active' => 'text-blue-500',
])

@php($menu = Navi::build($name))

@if ($menu->isNotEmpty())
<ul {{ $attributes }}>
@foreach ($menu->all() as $item)
<li @class([
$item->classes,
$inactive => ! $item->active,
$active => $item->active,
])>
<a href="{{ $item->url }}">
{{ $item->label }}
</a>

@if ($item->children)
<ul>
@foreach ($item->children as $child)
<li @class([
$child->classes,
$inactive => ! $child->active,
$active => $child->active,
])>
<a href="{{ $child->url }}">
{{ $child->label }}
</a>
</li>
@endforeach
</ul>
@endif
</li>
@endforeach
</ul>
@endif
23 changes: 0 additions & 23 deletions examples/sage/resources/views/partials/navigation.blade.php

This file was deleted.

165 changes: 165 additions & 0 deletions src/Console/NaviMakeCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?php

namespace Log1x\Navi\Console;

use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputOption;

class NaviMakeCommand extends GeneratorCommand
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a Navi component';

/**
* The name and signature of the console command.
*
* @var string
*/
protected $name = 'make:navi';

/**
* The type of file being generated.
*
* @var string
*/
protected $type = 'Component';

/**
* Execute the console command.
*
* @return bool|null
*/
public function handle()
{
if (parent::handle() === false) {
return false;
}

$name = strtolower(trim($this->argument('name')));

$this->components->info("Navi component <fg=blue><x-{$name} /></> is ready for use.");
}

/**
* Build the class with the given name.
*
* @param string $name
* @return string
*/
protected function buildClass($name)
{
$contents = parent::buildClass($name);

return str_replace(
'{{ default }}',
$this->option('default') ? Str::wrap($this->option('default'), "'") : 'null',
$contents,
);
}

/**
* Get the destination view path.
*
* @param string $name
* @return string
*/
protected function getPath($name)
{
$path = $this->viewPath(
str_replace('.', '/', 'components.'.$this->getView()).'.blade.php'
);

if (! $this->files->isDirectory(dirname($path))) {
$this->files->makeDirectory(dirname($path), 0777, true, true);
}

return $path;
}

/**
* Get the view name relative to the components directory.
*
* @return string
*/
protected function getView()
{
$name = str_replace('\\', '/', $this->argument('name'));

return collect(explode('/', $name))
->map(fn ($part) => Str::kebab($part))
->implode('.');
}

/**
* Get the desired view name from the input.
*
* @return string
*/
protected function getNameInput()
{
$name = trim($this->argument('name'));

$name = str_replace(['\\', '.'], '/', $this->argument('name'));

return $name;
}

/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return $this->resolveStubPath(
'/stubs/view.stub',
);
}

/**
* Resolve the fully-qualified path to the stub.
*
* @param string $stub
* @return string
*/
protected function resolveStubPath($stub)
{
return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
? $customPath
: __DIR__.$stub;
}

/**
* Prompt for missing input arguments using the returned questions.
*
* @return array
*/
protected function promptForMissingArgumentsUsing()
{
return [
'name' => [
'What should the Navi component be named?',
'E.g. Navigation',
],
];
}

/**
* Get the console command arguments.
*
* @return array
*/
protected function getOptions()
{
return [
['default', 'd', InputOption::VALUE_OPTIONAL, 'The default menu name'],
['force', 'f', InputOption::VALUE_NONE, 'Create the view component even if the component already exists'],
];
}
}
39 changes: 39 additions & 0 deletions src/Console/stubs/view.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@props([
'name' => {{ default }},
'inactive' => 'hover:text-blue-500',
'active' => 'text-blue-500',
])

@php($menu = Navi::build($name))

@if ($menu->isNotEmpty())
<ul {{ $attributes }}>
@foreach ($menu->all() as $item)
<li @class([
$item->classes,
$inactive => ! $item->active,
$active => $item->active,
])>
<a href="{{ $item->url }}">
{{ $item->label }}
</a>

@if ($item->children)
<ul>
@foreach ($item->children as $child)
<li @class([
$child->classes,
$inactive => ! $child->active,
$active => $child->active,
])>
<a href="{{ $child->url }}">
{{ $child->label }}
</a>
</li>
@endforeach
</ul>
@endif
</li>
@endforeach
</ul>
@endif
9 changes: 8 additions & 1 deletion src/Navi.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ class Navi
*/
protected array $items = [];

/**
* The default menu.
*/
protected string $default = 'primary_navigation';

/**
* Create a new Navi instance.
*/
Expand All @@ -35,8 +40,10 @@ public static function make(array $items = []): self
/**
* Build the navigation menu items.
*/
public function build(string $menu = 'primary_navigation'): self
public function build(mixed $menu = null): self
{
$menu = $menu ?? $this->default;

if (is_string($menu)) {
$locations = get_nav_menu_locations();

Expand Down
15 changes: 15 additions & 0 deletions src/Providers/NaviServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Log1x\Navi\Providers;

use Illuminate\Support\ServiceProvider;
use Log1x\Navi\Console\NaviMakeCommand;
use Log1x\Navi\Navi;

class NaviServiceProvider extends ServiceProvider
Expand All @@ -16,4 +17,18 @@ public function register()
{
$this->app->bind('navi', fn () => Navi::make());
}

/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
if ($this->app->runningInConsole()) {
$this->commands([
NaviMakeCommand::class,
]);
}
}
}

0 comments on commit e2a388e

Please sign in to comment.