Code Monkey home page Code Monkey logo

filament-navigation's Introduction

Build structured navigation menus in Filament.

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

This plugin for Filament provides a Navigation resource that lets you build structural navigation menus with a clean drag-and-drop UI.

Installation

Begin by installing this package via Composer:

composer require ryangjchandler/filament-navigation

Run migrations.

php artisan migrate

Publish the package's assets:

php artisan filament:assets

Usage

You first need to register the plugin with Filament. This can be done inside of your PanelProvider, e.g. AdminPanelProvider.

use RyanChandler\FilamentNavigation\FilamentNavigation;

return $panel
    ->plugin(FilamentNavigation::make());

If you wish to customise the navigation group, sort or icon, you can use the NavigationResource::navigationGroup(), NavigationResource::navigationSort() and NavigationResource::navigationIcon() methods.

Data structure

Each navigation menu is required to have a name and handle. The handle should be unique and used to retrieve the menu.

Items are stored inside of a JSON column called items. This is a recursive data structure that looks like:

[
    {
        "label": "Home",
        "type": "external-link",
        "data": {
            "url": "/",
            "target": "_blank",
        },
        "children": [
            // ...
        ],
    }
]

The recursive structure makes it really simple to render nested menus / dropdowns:

<ul>
    @foreach($menu->items as $item)
        <li>
            {{ $item['label'] }}

            @if($item['children'])
                <ul>
                    {{-- Render the item's children here... --}}
                </ul>
            @endif
        </li>
    @endforeach
</ul>

Retrieving a navigation object

To retrieve a navigation object, provide the handle to the RyanChandler\FilamentNavigation\Models\Navigation::fromHandle() method.

use RyanChandler\FilamentNavigation\Models\Navigation;

$menu = Navigation::fromHandle('main-menu');

Custom item types

Out of the box, this plugin comes with a single "item type" called "External link". This item type expects a URL to be provided and an optional "target" (same tab or new tab).

It's possible to extend the plugin with custom item types. Custom item types have a name and an array of Filament field objects (or a Closure that produces an array) that will be displayed inside of the "Item" modal.

This API allows you to deeply integrate navigation menus with your application's own entities and models.

return $panel
    ->plugin(
        FilamentNavigation::make()
            ->itemType('post', [
                Select::make('post_id')
                    ->//...
            ])
    );

All custom fields for the item type can be found inside of the data property on the item.

Global custom fields

There might be cases where you want all item types to have an additional set of fields. This is useful for classes, custom IDs and more.

To register global custom fields, use the withExtraFields() method on the plugin object.

return $panel
    ->plugin(
        FilamentNavigation::make()
            ->withExtraFields([
                TextInput::make('classes'),
            ]),
    );

The Navigation field type

This plugin also provides a custom Filament field that can be used to search and select a navigation menu inside other forms and resources.

use RyanChandler\FilamentNavigation\Filament\Fields\NavigationSelect;

->schema([
    NavigationSelect::make('navigation_id'),
])

By default, this field will not be searchable and the value for each option will be the menu id.

To make the field searchable, call the ->searchable() method.

->schema([
    NavigationSelect::make('navigation_id')
        ->searchable(),
])

If you wish to change the value for each option, call the ->optionValue() method.

->schema([
    NavigationSelect::make('navigation_id')
        ->optionValue('handle'),
])

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.

filament-navigation's People

Contributors

atmonshi avatar blackmunk avatar bumbummen99 avatar danielbehrendt avatar dependabot[bot] avatar devmatheus avatar digitall-it avatar dood- avatar fdt2k avatar flxsource avatar github-actions[bot] avatar happytodev avatar howdu avatar ihahachi avatar justrau avatar koupisbean avatar kristories avatar laravel-shift avatar lordjoo avatar mrfade avatar mynamespace avatar neurotools avatar ryangjchandler avatar sten avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

filament-navigation's Issues

Unable to add items

I can create a navigation fine, but when trying to add an item, there's a livewire error:

Livewire Entangle Error: Livewire property ['mountedActionsData.0.type'] cannot be found on component: ['app.filament.resources.navigation-resource.pages.edit-navigation']

Versions:

  • Filament 3.0.103
  • Filament Navigation 1.0.0-beta4
  • Filament Spatie Translatable 3.0.103

NB: It also happens even when anything Translatable related is absent

Handle changes after Name change of menu. Can break sites if a user changed the name without noticing the handle change

Hey,

Love this package, super useful and extendable! Thanks for your work on it.

I've noticed that when setting a Name for a navigation, the Handle is set automatically, which is slick. But if a user was coming back and updating the name of a navigation, the Handle is still updated again even if it has been specifically set to something.

Example use case: Footer menus

A common footer layout is 3 or 4 columns with a menu in each column. The handles could be named something to be looked up like footer_menu_1, footer_menu_2, footer_menu_3, footer_menu_4.

However, the Names for the fields might be something like Support, About us, etc. If an unsuspecting admin were to want to change the Name of a footer menu, they would quite likely also accidentally update the Handle which would stop the menu showing entirely.

Possible solutions include making the Handle field readonly when editing the menu, or not doing the auto update of the Handle if the Handle already has a value. Similar examples to this are on the Filament website when dealing with slugs here https://v2.filamentphp.com/tricks/generate-slugs-without-overriding

Interested to know your thoughts.

Cheers!

Ralph

Allow PHP 8.0

Hey friend,

Can you reduce the minimal PHP version to 8.0?

Differing schemas state persisted

When the schema changes between different item types the data of the previous item type is still persisted.

Give the following item types:

FilamentNavigation::addItemType('TypeA', [
    Select::make('url'),
    TextInput::make('label'),
]);

FilamentNavigation::addItemType('Type B', [
    Select::make('url'),
]);
  1. create a nav item of Type A
  2. edit it, changing the type to Type B
  3. save

You will see the saved JSON contains a label property even though Type B doesn't have this field.

I believe the offending code is this block:

$component
->getContainer()
->getComponent(fn (Component $component) => $component instanceof Group)
->getChildComponentContainer()
->fill();

I think it fills the previous state into the new form even though there are aren't fields to contain some of the state.

Livewire issues when accessing menu

@ryangjchandler

I am encountering an issue when using the latest version of the package on a fresh install of Filament 3 where only the overlay appears when you click "Add Item" or try to edit an existing item. The form is missing.

Is there something I have missed in the setup?

Screenshot 2023-08-25 at 17 34 28

addItemType breaks translations

I found a strange bug. FilamentNavigation::addItemType breaks translations of buttons and placeholders on select. If you change Select to TextInput, everything is fine.

image
image
image

Menu Item Order

Not sure if this is an issue just on my machine or not, but when saving a menu it appears that the UUID is causing the JSON column to default sort the menu items in ascending order (for indexing purposes, I believe). This prevents the menu item order from being preserved.

This can be seen by saving a menu then just refreshing the page.

Custom item types error when using searchable select

Discussed in #14

Originally posted by titantwentyone June 11, 2022
Thanks for the package! I was wanting to integrate this with a Post model however I am little unclear on how this is achieved, I've assumed that FilamentNavigation::addItemType is to be used in the boot method of my AppServiceProvider. This gets me so far but I get console errors using the example in the docs:

Alpine Expression Error: Cannot read properties of null (reading 'post_id')

I'm unsure what post_id refers to here in terms of my model (if anything - I assume this used to populate the filed name within data), which, for simplicity's sake, just has id, title and content. (I tried id as well with the same result.). Is there another step needed?

Searchable item type failing when selected

When creating a navigation item with a searchable item type, selecting the type throws an Alpine error, and displays an empty, unstyled select element. If saved without selecting a target, the select element works correctly upon reopening the modal. Changing the item type after that point doesn't cause a problem either.

image

Error
module.esm.js:416 Alpine Expression Error: Cannot read properties of null (reading 'target')

Expression: "selectFormComponent({
                        getOptionLabelUsing: async () => {
                            return await $wire.getSelectOptionLabel('mountedActionData.data.target')
                        },
                        getOptionLabelsUsing: async () => {
                            return await $wire.getSelectOptionLabels('mountedActionData.data.target')
                        },
                        getOptionsUsing: async () => {
                            return await $wire.getSelectOptions('mountedActionData.data.target')
                        },
                        getSearchResultsUsing: async (search) => {
                            return await $wire.getSelectSearchResults('mountedActionData.data.target', search)
                        },
                        isAutofocused: false,
                        isMultiple: false,
                        hasDynamicOptions: true,
                        hasDynamicSearchResults: false,
                        loadingMessage: 'Loading...',
                        maxItems: null,
                        noSearchResultsMessage: 'No options match your search.',
                        options: JSON.parse(atob('eyJhYm91dCI6IkFib3V0IiwiYm9va2luZ3MiOiJCb29raW5ncyIsImNvbnRhY3QiOiJDb250YWN0IiwiZWR1Y2F0aW9uIjoiRWR1Y2F0aW9uIiwiaG9tZSI6IkhvbWUgUGFnZSIsInBvcGVyYSI6IlBvcGVyYSIsInNob3dzIjoiU2hvd3MiLCJzb2NpYWwtcHJlc2NyaWJpbmciOiJTb2NpYWwgUHJlc2NyaWJpbmcifQ==')),
                        placeholder: 'Select an option',
                        searchingMessage: 'Searching...',
                        searchPrompt: 'Start typing to search...',
                        state: $wire.entangle('mountedActionData.data.target').defer,
                    })"

Still a small bug with custom item types using searchable

Searchable is working now... until you have more than item type. It will display and load the link options for the first resource you choose, but say you clicked the wrong one and go back into the Type select and choose a different resource, it's link options are now empty. You need to close the modal and re-add a menu item (and pick the resource you want first) for it's links to show up.

Hopefully that made sense, here is a quick screen recording:

filament-navigation

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.