think.studio/nova-thinkit

Laravel Nova small kit for quicker development.

1.7.1 2023-12-14 14:36 UTC

This package is auto-updated.

Last update: 2024-11-14 16:38:13 UTC


README

Packagist License Packagist Version Total Downloads Build Status Code Coverage Scrutinizer Code Quality

Laravel Nova small kit for quicker development.

Installation

You can install the package via composer:

composer require think.studio/nova-thinkit

# optional publish configs
php artisan vendor:publish --provider="NovaThinKit\ServiceProvider" --tag="config"
# optional publish translations
php artisan vendor:publish --provider="NovaThinKit\ServiceProvider" --tag="lang"

Usage

Actions

Login to different guard

public function actions(NovaRequest $request)
{
    return [
        (new \NovaThinKit\Nova\Actions\LoginToDifferentGuard(
            route('dashboard.overview'),
            'owners_web',
            __('Login to owner dashboard'),
            __('Are you sure you want to continue?'),
        ))
            // optional callback how to find correct user
            ->findIdUsing(fn (Contact $model) => Owner::query()->where('contact_id', $model->getKey())->first()?->getKey())
            // other default method actions...
            ->canRun(fn ($request, Contact $model) => $model->role === "owner"),
    ];
}

Send reset password notification

use NovaThinKit\Nova\Actions\LoginToDifferentGuard;

public function actions(NovaRequest $request)
{
    return [
    ( \NovaThinKit\Nova\Actions\SendResetPasswordEmail::make('contacts', __('Send reset password'), __('Are you sure you want to continue?')))
            // optional callback how to find correct user
            ->findIdUsing(fn (Contact $model) => Owner::query()->where('contact_id', $model->getKey())->first()?->getKey())
            // other default method actions...
            ->canRun(fn ($request, Contact $model) => $model->role === "owner"),
    ];
}

Filters

Dynamic Boolean filter

\NovaThinKit\Nova\Filters\DynamicBooleanFilter::make([
    'Active' => 'active',
    'Paused' => 'paused',
]  /* options */, 'status' /* column to filter */, 'Status'  /* title */),

// Useful with HumanReadable enums:
\NovaThinKit\Nova\Filters\DynamicBooleanFilter::make(array_flip(CompanyStatus::options()), 'status', 'Status'),

Use filter for relation. For example add filter to Author to filter Posts:

\NovaThinKit\Nova\Filters\DynamicBooleanFilter::make(array_flip(CompanyStatus::options()), 'status', 'Posts Status')->forRelation('posts'),

Empty or null filed filter

\NovaThinKit\Nova\Filters\EmptyFieldFilter::make('post_title' /* column to filter */, 'Title'  /* title */),

Use filter for relation. For example add filter to Author to filter Posts:

\NovaThinKit\Nova\Filters\EmptyFieldFilter::make('posts.post_title', 'Posts Title'),

BelongsTo filter

Filter by related belongsTo relation.

use NovaThinKit\Nova\Filters\BelongsToFilter;

public function filters(NovaRequest $request)
{
    return [
        // type - this is belongsTo() relation method name
        new BelongsToFilter('type'),
        // or
        (new BelongsToFilter('type'))->setTitleKeyName('title'),
        // or
        (new BelongsToFilter('type'))->setFilterName('Filter by type'),
    ];
}

BelongsToMany filter

Filter by related belongsToMany relation.

public function filters(NovaRequest $request)
{
    return [
       \NovaThinKit\Nova\Filters\BelongsToManyFilter::make('tags')
                ->setTitleKeyName('name' /* label key name */)
                ->setFilterName('By tag'),
    ];
}

Metadata table

MetaFieldUpdater

If you have standalone table what contains meta values. You can use MetaFieldUpdater to quicker update these values from main resource:

public function fields(NovaRequest $request)
{
    $metaFieldUpdater = new \NovaThinKit\Nova\Helpers\MetaFieldUpdater(
        'metaData' /* hasMany relation method name */,
        'key' /* key name in neta table */,
        'value' /* data name in neta table */
    );

    return [
        $metaFieldUpdater->field(
            Select::make('University', 'university')->options(University::options())
        ),
        // ALso works with flexible
        $metaFieldUpdater->field(
            Flexible::make('Ethos list', 'cf-numeric_list_with_team')
                ->limit(20)
                ->useLayout(EthosItemLayout::class),
        ),
    ];
}

Feature image functionality

Add interface and trait to model

class Page extends Model implements \NovaThinKit\FeatureImage\Models\WithFeatureImage
{
    use \NovaThinKit\FeatureImage\Models\HasFeatureImage;
    
    // Optionally you can change default storage directory
    public function featureImageManagerDirectory(): string
    {
        return 'page/' . $this->getKey();
    }
    
    // Optionally you can change default image-manager
    protected function createFeatureImageManager(?string $tag = null): ImageManager
    {
    if (!$this->featureImageManager) {
            $this->featureImageManager = FeatureImageManager::fromConfig([
                'disk'                 => 'feature-images',
                'immutableExtensions' => [ '.svg', '.gif' ],
                'original'             => [
                    'methods' => [
                        'fit'      => [ \Spatie\Image\Manipulations::FIT_CROP, 2800, 1800 ],
                        'optimize' => [],
                    ],
                    'srcset'  => '2800w',
                ],
                'deletedFormats'       => [],
                'formats'              => [
                    'thumb' => [
                        'methods' => [
                            'fit'      => [ \Spatie\Image\Manipulations::FIT_CONTAIN, 450, 300 ],
                            'optimize' => [],
                        ],
                        'srcset'  => '450w',
                    ],
                ],
            ]);
        }
        
        if($tag === 'fooBar') {
            $this->featureImageManager->disk = 'baz';
        }

        return $this->featureImageManager;
    }
}

Add trait to resource

class Page extends Resource
{
    use \NovaThinKit\FeatureImage\Nova\HasFeatureImage;
    
    // ... other methods
    
    public function fields(NovaRequest $request)
    {
        return [
            // other fields
            $this->fieldFeatureImage(),
        ];
    }
}

Page templates (Dynamic fields based on template field)

Create template fields wrapper

namespace App\Nova\ResourceTemplates\Pages;

use NovaThinKit\Nova\Helpers\MetaFieldUpdater;
use NovaThinKit\Nova\ResourceTemplates\ResourceTemplate;

class HomePageTemplate extends ResourceTemplate
{
    public function fields(NovaRequest $request): array
    {
        $metaUpdater = new MetaFieldUpdater('meta', 'key', 'value');

        return [
            Text::make('Some Custom text', 'some_custom_text')
                ->hideWhenCreating()
                ->hideFromIndex()
                ->showOnPreview(),
            $metaUpdater->field(
                Text::make('Custom text', 'custom_text')
                    ->hideWhenCreating()
                    ->hideFromIndex()
                    ->showOnPreview(),
            ),
        ];
    }
}

Add mapping

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        \NovaThinKit\Nova\ResourceTemplates\TemplateFinder::templatesMap(Page::class, [
            'home'           => HomePageTemplate::class,
            'contact'        => ContactPageTemplate::class,
        ]);
    }
}

Finally, update resource

class Page extends Resource
{
    use \NovaThinKit\Nova\ResourceTemplates\HasTemplate;

    public function fields(NovaRequest $request)
    {
        return [
            ID::make()->sortable(),

            ...$this->templateFields($request),
        ];
    }
}

Credits

  • Think Studio