A minimalistic event calendar Tool for Laravel's Nova 4

Overview

Event calendar for Laravel Nova 4

The design of the calendar in both clear and dark mode

An event calendar that displays Nova resources or other time-related data in your Nova 4 project on a monthly calendar view.

The calendar view adapts nicely to clear and dark mode:

Clear and dark mode next to each other

What can it do?

This calendar tool for Nova 4 shows existing Nova resources and, if you want, dynamically generated events, but comes without database migrations or Eloquent models itself. This is considered a feature. Your project is expected to already contain certain Nova resources for Eloquent models with DateTime fields or some other source of time-related data that can be used to generate the calendar events displayed to the end user.

The following features are supported:

  • Automatically display single-day events on a monthly calendar view in both clear and dark mode
  • Completely customize both visual style and event content on a per-event basis
  • Add badges to individual events to indicate status or attract attention
  • Allows end users to navigate through the calendar with hotkeys
  • Allows end users to navigate to the resources' Detail or Edit views by clicking events
  • Mix multiple types of Nova resources on the same calendar
  • Display events that are not related to Nova resources
  • Month and day names are automatically presented in your app's locale

What can it not do (yet)?

The following features are not yet supported:

  • Multi-day events (first new feature in the pipeline)
  • Creating new events directly from the calendar view
  • Drag and drop support to change event dates
  • Proper responsiveness for display on small screens
  • Integration with external calendar services

Please create or upvote feature request discussions in the GitHub repo for the features you think would be most valuable to have.

What can you do?

Developers who are interested in working together on this tool are highly welcomed. Take a look at the open issues (those labelled 'good first issue' are great for new contributors) or at the feature request discussions and we'll get you going quickly.

Installation

composer require wdelfuego/nova-calendar

Usage

The calendar just needs a single data provider class that supplies event data to the frontend, and for the data provider and tool to be added to your NovaServiceProvider:

  1. Create a data provider class with a name of your choice anywhere you like in your project, or run the following artisan command to create the default data provider:

    php artisan create:default-calendar-data-provider

    If you choose to make the data provider yourself, make it a subclass of Wdelfuego\NovaCalendar\DataProvider\MonthCalendar.

  2. In the data provider, implement the novaResources() method to specify which Nova resources are to be included and which of their model's attributes should be used to determine the date and start time of your event.

    The novaResources() method must return an array that maps Nova resource classes to attribute names. The attribute must be casted to a DateTime object by the underlying Eloquent model. If you return an empty array, the calendar will work but will not contain any events.

    For example, to make the calendar show your users as events on the date their accounts were created, implement novaResources() as follows:

    namespace App\Providers;
    
    use Wdelfuego\NovaCalendar\DataProvider\MonthCalendar;
    use App\Nova\User;
    
    class CalendarDataProvider extends MonthCalendar
    {
        public function novaResources() : array
        {
            return [
                User::class => 'created_at'
            ];
        }	
    }
    

    This is the only method that's required. You can include more types of Nova resources to be shown on the calendar by simply adding more class names and attributes to the novaResources() method.

  3. Finally, edit your NovaServiceProvider at app/NovaServiceProvider.php to add the calendar to its tools() method and to register your data provider class as the default calendar data provider:

    use Wdelfuego\NovaCalendar\NovaCalendar;
    use Wdelfuego\NovaCalendar\Interface\CalendarDataProviderInterface;
    use App\Providers\CalendarDataProvider;
    
    public function tools()
    {
        return [
           new NovaCalendar,
        ];
    }
    
    public function register()
    {
        $this->app->bind(CalendarDataProviderInterface::class, function($app) {
            return new CalendarDataProvider();
        });
    }
    
  4. If you're using Nova's default main menu, you're already done.

    If you've defined your main menu manually in the boot() method of your NovaServiceProvider, don't forget to add a MenuSection that links to the calendar:

    MenuSection::make('Calendar')
        ->path('/wdelfuego/nova-calendar')
        ->icon('calendar'),
    

That's it! Your calendar should now be up and running.

Hotkeys

You can navigate through the months using the hotkeys Alt + arrow right or Alt + arrow left and jump back to the current month using Alt + H (or by clicking the month name that's displayed above the calendar).

Customization

You can customize the display of your events and add badges and notes to them to make the calendar even more usable for your end users.

Event customization

You can customize event info (name, start time, end time, notes, badges) and customize the CSS styles applied to the event div by implementing the customizeEvent(Event $event) method in your calendar data provider. Every event gets passed through this method before it's delivered to the frontend. The method must return the customized event.

By default, your events get the title that the Nova resource's title() method returns and the start time is set to the value of the attribute specified in your data provider's novaResources() method. Other event fields are left empty by default but can easily be loaded from the event's associated model:

protected function customizeEvent(Event $event) : Event
{
    if($event->model())
    {
        $event->end($event->model()->datetime_end);
        $event->name($event->model()->name);
        $event->notes($event->model()->notes);
    }
    return $event;
}

Your customization can be a lot more complex, too:

use Wdelfuego\NovaCalendar\Event;

protected function customizeEvent(Event $event) : Event
{
    // Give each event a duration of 4 hours (for display only)
    $event->end($event->start()->copy()->addHour(4));

    // For events that have an underlying Eloquent model..
    if($event->model())
    {
        // Prefix each event's name with its ID
        $event->name($event->model()->id .' - ' .$event->name());

        // Add a warning emoji badge if the end user should 
        // be warned about the model's state
        if($event->model()->isInACertainState())
        {
            $event->addBadges('⚠️');
        }

        // Add a note to the event that is displayed right below
        // the event's name in the calendar view
        if($event->model()->someSpecialCase())
        {
            $event->notes('Something special is going on');
        }
    }

    // Display all events without time info
    $event->hideTime();

    return $event;
}

The following customization methods with regard to the display of the Event in the calendar view are available.

Chainable customization methods

All of these methods return the Event itself so you can chain them in the customizeEvent method:

  • hideTime() hides start and (if available) end times in the calendar view.
  • displayTime() enables the display of start and end times.
  • withName(string $v) updates the name of the event.
  • withStart(DateTimeInterface $v) updates the date and start time of the event (it will be displayed on the calendar accordingly).
  • withEnd(DateTimeInterface $v) updates the end time of the event. Note: if you supply an end timestamp, its date value is completely ignored by this package for now. All events are assumed to be single day events. Its time value will be used as the event's end time.
  • withNotes(string $v) updates the notes displayed below the name and, if enabled, the time info of the event.
  • addBadge(string $v) adds a badge to the event's upper right corner. You can simply set letters, short strings or emoji. The use of 'X' as a badge isn't recommended because it could be mistaken for a close button.
  • addBadges(string ...$v) adds 1 or more badges with one call. This method doesn't expect an array but an argument for each badge you want to add.
  • removeBadge(string $v) and removeBadges(string ...$v) do the same but they remove rather than add badges.
  • withStyle(string $v) to set the CSS style applied to the div of this specific event (see 'Adding custom event styles' below).

Non-chainable customization methods

Corresponding methods are available in non-chainable form, if you prefer to work with those.

These function as setters when you supply an argument, and as getters when you don't.

  • name(string $v = null)
  • start(DateTimeInterface $v = null)
  • end(DateTimeInterface $v = null)
  • notes(string $v = null)
  • badges(array $v = null)

Customizing the CSS

You can customize the CSS that is applied to the event divs in the calendar view on a per-event basis, or on a global basis by customizing the default event style.

Customizing the default event style

In your calendar data provider, implement the eventStyles() method to return the CSS that you want to apply to all events by default:

For example, to make the default style white with black text:

public function eventStyles() : array
{
    return [
        'default' => [
            'color' => '#000',
            'background-color' => '#fff'
        ],
    ];
}

Adding custom event styles

To add custom event styles, add them to the array returned by eventStyles in your calendar data provider:

public function eventStyles() : array
{
    return [
        'special' => [
            'color' => '#f00',
        ],
        'warning' => [
            'border' => '1px solid #f00'
        ]
    ];
}

Then call style or withStyle in your customizeEvent method using the name of the style (in this example, 'special' or 'warning') to apply them to individual events, for example:

use Wdelfuego\NovaCalendar\Event;
use App\Nova\SomeResourceClass;

protected function customizeEvent(Event $event) : Event
{
    // For events that have an underlying Eloquent model..
    if($event->model())
    {
        if($event->model()->isInACertainState())
        {
            $event->style('warning');
        }
    }

    // Display all events that have a specific class of Nova
    // resource with a specific style:
    if($event->hasNovaResource(SomeResourceClass::class))
    {
        $event->style('special');
    }

    // Or conversely, display all events that don't have a 
    // Nova resource with a specific style:
    if(!$event->hasNovaResource())
    {
        $event->style('special');
    }

    return $event;
}

Calendar customization

Changing the default menu icon and label

In your NovaServiceProvider, update the tools() method as follows:

public function tools()
{
    return [
        (new NovaCalendar)->withMenuLabel('Label')->withMenuIcon('HeroIcon'),
    ];
}    

Changing the first day of the week

In your calendar data provider, implement the constructor to call its parent constructor and make a call to startWeekOn() to let the weeks start on the day of your choice. You can use the constants defined in NovaCalendar to specify the day.

For example, to start your weeks on wednesday:

use Wdelfuego\NovaCalendar\NovaCalendar;

public function __construct(int $year = null, int $month = null)
{
    parent::__construct($year, $month);
    $this->startWeekOn(NovaCalendar::WEDNESDAY);
}    
    

Changing what happens when an event is clicked

Implement the following method in your calendar data provider to change the URL that the user is sent to when they click the event:

protected function urlForResource(NovaResource $resource)
{
    return '/resources/' .$resource::uriKey() .'/' .$resource->id;
}

This example shows the default behavior. If you append /edit to the string, users will be sent directly to the resource's Edit view, instead of to its Detail view.

A future release will offer a more reliable way to generate these type of URL parts based on route names such as nova.pages.edit and nova.pages.detail.

Adding events from other sources

If the events you want to show don't have a related Nova resource, you can still add them to the calendar. In your calendar data provider, implement the nonNovaEvents method to push any kind of event data you want to the frontend.

The method should return an array of Events:

use Wdelfuego\NovaCalendar\Event;

protected function nonNovaEvents() : array
{
    return [
        (new Event("This is now", now()))
            ->addBadges('D')
            ->withNotes('This is a dynamically created event')
    ];
}
    

If you are going to return a long list of events here, or do a request to an external service, you can use the firstDayOfCalendar() and lastDayOfCalendar() methods inherited from Wdelfuego\NovaCalendar\DataProvider\MonthCalendar to limit the scope of your event generation to the date range that is currently being requested by the frontend.

Any events you return here that fall outside that date range are never displayed, so it's a waste of your and your users' resources if you still generate them.

Support

For any problems you might run into, please open an issue on GitHub.

For feature requests, please upvote or open a feature request discussion on GitHub.

Comments
  • str_contains(): Argument #1 ($haystack) must be of type string, Closure given

    str_contains(): Argument #1 ($haystack) must be of type string, Closure given

    Using tenancy for laravel PHP 8.1.1 Nova 4 latest

    [stacktrace]
    #0 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Support\\Str.php(242): str_contains(Object(Closure), '@')
    #1 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Support\\Str.php(692): Illuminate\\Support\\Str::contains(Object(Closure), Array)
    #2 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(307): Illuminate\\Support\\Str::parseCallback(Object(Closure))
    #3 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(287): Illuminate\\Routing\\Route->parseControllerCallback()
    #4 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(272): Illuminate\\Routing\\Route->getControllerClass()
    #5 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\formfeed-uk\\nova-dependable-panel\\src\\Http\\Middleware\\InterceptValidationFailure.php(64): Illuminate\\Routing\\Route->getController()
    #6 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\formfeed-uk\\nova-dependable-panel\\src\\Http\\Middleware\\InterceptValidationFailure.php(31): Formfeed\\DependablePanel\\Http\\Middleware\\InterceptValidationFailure->isDependentFieldRequest(Object(Illuminate\\Http\\Request))
    #7 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Formfeed\\DependablePanel\\Http\\Middleware\\InterceptValidationFailure->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #8 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\formfeed-uk\\nova-dependable-panel\\src\\Http\\Middleware\\InterceptDependentFields.php(31): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #9 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Formfeed\\DependablePanel\\Http\\Middleware\\InterceptDependentFields->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #10 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\nova\\src\\Http\\Middleware\\BootTools.php(20): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #11 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Laravel\\Nova\\Http\\Middleware\\BootTools->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #12 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\nova\\src\\Http\\Middleware\\DispatchServingNovaEvent.php(24): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #13 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Laravel\\Nova\\Http\\Middleware\\DispatchServingNovaEvent->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #14 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\inertiajs\\inertia-laravel\\src\\Middleware.php(92): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #15 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Inertia\\Middleware->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #16 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #17 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #18 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken.php(78): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #19 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #20 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\View\\Middleware\\ShareErrorsFromSession.php(49): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #21 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #22 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Session\\Middleware\\StartSession.php(121): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #23 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Session\\Middleware\\StartSession.php(64): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest(Object(Illuminate\\Http\\Request), Object(Illuminate\\Session\\Store), Object(Closure))
    #24 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Session\\Middleware\\StartSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #25 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\stancl\\tenancy\\src\\Middleware\\IdentificationMiddleware.php(36): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #26 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\stancl\\tenancy\\src\\Middleware\\InitializeTenancyBySubdomain.php(52): Stancl\\Tenancy\\Middleware\\IdentificationMiddleware->initializeTenancy(Object(Illuminate\\Http\\Request), Object(Closure), 'checkpoint')
    #27 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\stancl\\tenancy\\src\\Middleware\\InitializeTenancyByDomainOrSubdomain.php(22): Stancl\\Tenancy\\Middleware\\InitializeTenancyBySubdomain->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #28 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Stancl\\Tenancy\\Middleware\\InitializeTenancyByDomainOrSubdomain->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #29 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #30 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #31 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Cookie\\Middleware\\EncryptCookies.php(67): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #32 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #33 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #34 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(726): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
    #35 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(703): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))
    #36 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(667): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))
    #37 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(656): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))
    #38 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(190): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))
    #39 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(141): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))
    #40 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\livewire\\livewire\\src\\DisableBrowserCache.php(19): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #41 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Livewire\\DisableBrowserCache->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #42 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\nova\\src\\Http\\Middleware\\ServeNova.php(23): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #43 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Laravel\\Nova\\Http\\Middleware\\ServeNova->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #44 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\barryvdh\\laravel-debugbar\\src\\Middleware\\InjectDebugbar.php(66): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #45 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Barryvdh\\Debugbar\\Middleware\\InjectDebugbar->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #46 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #47 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #48 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #49 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #50 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #51 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #52 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #53 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #54 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #55 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #56 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\HandleCors.php(49): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #57 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Http\\Middleware\\HandleCors->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #58 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\TrustProxies.php(39): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #59 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Http\\Middleware\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
    #60 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
    #61 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(165): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
    #62 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(134): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))
    #63 C:\\Users\\Jeremiah\\Desktop\\projects\\valet\\app2\\public\\index.php(52): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))
    #64 C:\\Users\\Jeremiah\\AppData\\Roaming\\Composer\\vendor\\cretueusebiu\\valet-windows\\server.php(241): require('C:\\\\Users\\\\Jeremi...')
    #65 {main}
    
    invalid 
    opened by jeremiahsherrill 8
  • How can I have two or more distinct calendars ?

    How can I have two or more distinct calendars ?

    I would like to have multiple calendars, completely distinct from each other, on different URIs.

    I see how I can change the URI of a single calendar, but can't seem to figure out how to have two distinct calendars.

    Some guidance would be much appreciated.

    Many thanks!

    duplicate enhancement 
    opened by vesper8 5
  • Nova resources added with a start and end date are not shown on the calendar if the end date is null

    Nova resources added with a start and end date are not shown on the calendar if the end date is null

    Discussed in https://github.com/wdelfuego/nova-calendar/discussions/34

    Originally posted by pitchayakit August 26, 2022 For example, I have 2 rows for some resources like

    1. starts_at, end_at --> this row works properly
    2. starts_at, null --> if end_at is null, should be considered for a single day but I didn't see how to display it on calendar.

    https://github.com/wdelfuego/nova-calendar/blob/571673911c01978a2dfa44d4791f4e4e0f7068d3/resources/CalendarDataProvider.default.php#L39

    Could you please suggest a solution?

    bug fixed 
    opened by wdelfuego 3
  • Added custom URI

    Added custom URI

    This PR allow you to customize the URI of the tool by publishing the new config file.

    Added a default value to fallback to wdelfuego/nova-calendar for non-breaking change.

    enhancement implemented 
    opened by kichetof 3
  • Calendar menu link giving 404

    Calendar menu link giving 404

    I am using the latest nova version and just installed nova-calendar. I have removed the nova prefix from my url through the config file of nova and its just '/' . When i add the calendar in the menu the modal shows 404 no page found. Any help with this is much appreciated

    invalid 
    opened by alexWaterfront 3
  • Consider PHP8.0

    Consider PHP8.0

    This package will not install on my version of PHP, which is 8.0.24. I would suggest considering making it PHP 8.0 compatible. For now, all AWS PHP-managed instances are using 8.0.*, and so many of us that deploy to Amazon are locked into it. Otherwise, the package looks really promising.

    enhancement implemented 
    opened by alekmlynek 2
  • Change artisan command and prefix

    Change artisan command and prefix

    Hi @wdelfuego and thanks for this great package.

    I'd like to request the following change:

    To create the default calendar data provider there is the following artisan command provided by this package:

    php artisan create:default-calendar-data-provider
    

    The command should be refactored to the following usage:

    php artisan nova-calendar:create-default-calendar-data-provider
    

    This will ensure that you can add more commands in the future under the same namespace and will separate the CLI from default artisan commands to those that are supported by third parties.

    If you agree with this change I will submit the needed changes as a PR in the next days.

    enhancement implemented 
    opened by Lednerb 2
  • Add support for applying multiple styles to a single event

    Add support for applying multiple styles to a single event

    Right now, the $event->style() and $event->withStyle() helpers only allow setting the single event style. It is desirable to be able to apply multiple style classes to a single event.

    enhancement implemented 
    opened by wdelfuego 2
  • Added the ability to customize the page title via a configuration option

    Added the ability to customize the page title via a configuration option

    Just to be able to change the currently hard coded page title ("Nova Calendar") to another value.

    I added the config option nova-calendar.title, where users can change the default value. If no value is provided in the config file, the default one is maintained ("Nova Calendar").

    Also added the new option in the corresponding section in the docs.

    opened by javoscript 1
  • Day borders are too dark in light mode

    Day borders are too dark in light mode

    Under some conditions, the default layout of the calendar has borders that are too dark.

    I haven’t been able to reproduce this yet.

    If you encounter this issue, please indicate your os and browser and if you can, inspect the html elements and let me know which css class causes the borders to turn out so dark.

    bug fixed 
    opened by wdelfuego 1
  • Allow (some) customization of calendar day cells

    Allow (some) customization of calendar day cells

    The CSS applied to events is already very customizable. It would be nice to have something similar for the calendar day cells (td elements in the table). Could possibly even use the same style definitions already supplied by the calendar data provider.

    enhancement implemented 
    opened by wdelfuego 1
  • Version 2.0

    Version 2.0

    Thanks a lot for your input! I'll be exploring something analogous to this, hope to launch the feature with version 2.0 in January or February.

    Originally posted by @wdelfuego in https://github.com/wdelfuego/nova-calendar/issues/43#issuecomment-1340992825

    Regarding that, I was wondering if you could tell which features might be included and if you still plan on releasing it in Jan/Feb? Anyway, thank you for that amazing package, made my life a lot easier already.

    opened by mrvnklm 0
  • Adds compatibility for Laravel 8

    Adds compatibility for Laravel 8

    This tiny change to the composer.json file adds compatibility to Laravel 8 (tested and works great).

    The requirements do not mention it but because of the inclusion of "illuminate/support": "^9.0",, this currently only works for Laravel 9 or higher.

    Please consider merging this PR so that I don't have to manage a fork just to make it work on Laravel 8.

    It should be noted that Laravel Nova v4 explicitly supports both Laravel 8 & 9

    Many thanks for your awesome calendar!

    opened by vesper8 1
  • Added Timeline, Daily and Weekly views support

    Added Timeline, Daily and Weekly views support

    Added support for the Timeline (horizontal timescale), Daily and Weekly views

    User can customize:

    • time slot interval (only in these 3 views)
    • opening and closing hours (to save screen space and not render night hours if not needed)

    The user can navigate between views:

    • from the monthly view directly to the week (by clicking on the week number) or the daily view (by clicking on the day number)
    • from the week view to the daily view (by clicking on the day number)

    Tasks to be performed:

    • adding an Event grouping (for example grouping Events by resource such as specialist or location)
    • consideration of the continued use of the DataProvider as injection or rotation versus the Calendar Checker approach
    • data provider refactoring, class is larger than it should be
    enhancement help wanted awaiting PR 
    opened by bb140856 19
  • PHP 7 Compatibility

    PHP 7 Compatibility

    Needed to use this package with PHP 7, so have made the nessersary adjustments to make it backwards compatible.

    Let me know if you need me to do anything else.

    enhancement in progress 
    opened by donovanhare 4
  • Supply the CalendarDataProvider to the CalendarController per instance instead of through global dependency injection

    Supply the CalendarDataProvider to the CalendarController per instance instead of through global dependency injection

    Right now, the CalendarController expects a CalendarDataProviderInterface which is supplied through dependency injection.

    For that to work, users of this package need to manually bind their own calendar data provider to the CalendarDataProviderInterface class in the boot() method of their NovaServiceProvider:

    use App\Providers\CalendarDataProvider;
    
    public function register()
    {
        $this->app->bind(CalendarDataProviderInterface::class, function($app) {
            return new CalendarDataProvider();
        });
    }
    

    It would be nice if instead, the calendar data provider could be supplied through the tool's constructor within the tools() method, like this:

    use App\Providers\CalendarDataProvider;
    
    public function tools()
    {
        return [
            new NovaCalendar(new CalendarDataProvider),
        ];
    }
    

    That would open the door to having multiple instances of the calendar Tool, each with their own data provider. It would have the added benefit of making the installation of the package slightly simpler.

    Any questions or doubts?

    Add a comment to this issue and we'll talk about it.

    enhancement 
    opened by wdelfuego 3
  • Add docblocks

    Add docblocks

    The following files need docblocks:

    • src/DataProvider/MonthCalendar.php
    • src/Http/Controllers/CalendarController.php
    • src/Event.php
    • src/CalendarDay.php

    I'm marking this 'good first issue' because it's a small task that will help a lot in getting to understand the internals of this package, and new contributors can do parts of it.

    Getting started

    1. Make a clone of this repo and clone that to your own computer
    2. Add the docblocks locally, then commit and push the changes to your repo on GitHub
    3. Send a pull request

    Follow the DocBlock guidelines as described by Spatie; most importantly:

    Don't use docblocks for methods that can be fully type hinted (unless you need a description).

    Any questions or doubts?

    Add a comment to this issue and we'll talk about it

    documentation good first issue 
    opened by wdelfuego 0
Owner
wdelfuego
wdelfuego
This Laravel Nova settings tool based on env, using nativ nova fields and resources

Nova Settings Description This Laravel Nova settings tool based on env, using nativ nova fields and resources Features Using native Nova resources Ful

Artem Stepanenko 21 Dec 28, 2022
This Laravel Nova package adds a Trumbowyg field to Nova's arsenal of fields.

Nova Trumbowyg Field This Laravel Nova package adds a Trumbowyg field to Nova's arsenal of fields. Requirements php: >=8.0 laravel/nova: ^4.0 Installa

outl1ne 3 Sep 25, 2022
Composer package which adds support for HTML5 elements using Laravels Form interface (e.g. Form::date())

Laravel HTML 5 Inputs Composer package which adds support for HTML5 elements by extending Laravel's Form interface (e.g. Form::date()) Adds support fo

Small Dog Studios 11 Oct 13, 2020
A package to flash multiple messages using Laravels default session message flashing system

Flash multiple advanced messages with both text, messages and links An opinionated solution for flashing multiple advanced messages from the backend a

Bilfeldt 6 Jan 18, 2022
Adds a way to write php and run it directly in Laravels' Artisan Tinker.

Adds a way to write php in PhpStorm/IDEA and run it directly as if through laravel artisan tinker - allowing you to quickly run a piece of code with a

Robbin 120 Jan 2, 2023
Nebula is a minimalistic and easy to use administration tool for Laravel applications, made with Laravel, Alpine.js, and Tailwind CSS.

Nebula Nebula is a minimalistic and easy to use administration tool for Laravel applications, made with Laravel, Alpine.js, and Tailwind CSS. Nebula m

Nebula 228 Nov 11, 2022
This tool gives you the ability to set the default collapse state for Nova 4.0 menu items.

Nova Menu Collapsed This tool gives you the ability to set the default collapse state for Nova 4.0 menu items. Requirements php: >=8.0 laravel/nova: ^

Artem Stepanenko 10 Nov 17, 2022
A Laravel Nova tool for viewing your application logs

This package makes it easy to view your Laravel application logs inside of Nova. It even supports polling. Installation You can install the Nova tool

The Laravel Framework 117 Dec 11, 2022
Scribbl is a fast and minimalistic note-taking app built with Laravel

Scribbl is a fast and minimalistic note-taking app built with Laravel

Cam White (Jex) 5 Nov 13, 2022
Add The Events Calendar support to Sage 10.

The Events Calendar support for Sage 10 Add The Events Calendar support to Sage 10. For the time being there can only be a blade view, the default-tem

Supermundano 10 Nov 5, 2022
Laravel Livewire component to show Events in a good looking monthly calendar

Livewire Calendar This package allows you to build a Livewire monthly calendar grid to show events for each day. Events can be loaded from within the

Andrés Santibáñez 680 Jan 4, 2023
The Most Popular JavaScript Calendar as a Filament Widget 💛

The Most Popular JavaScript Calendar as a Filament Widget ?? Features Accepts all configurations from FullCalendar Event click and drop events Upcomin

Guilherme Saade 62 Dec 31, 2022
List of 77 languages for Laravel Framework 4, 5, 6, 7 and 8, Laravel Jetstream , Laravel Fortify, Laravel Breeze, Laravel Cashier, Laravel Nova and Laravel Spark.

Laravel Lang In this repository, you can find the lang files for the Laravel Framework 4/5/6/7/8, Laravel Jetstream , Laravel Fortify, Laravel Cashier

Laravel Lang 6.9k Jan 2, 2023
This repo is for the Laracon 2021 talk "Manage SEO with Laravel and Nova"

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Kristin 7 Dec 9, 2022
⚙️Laravel Nova Resource for a simple key/value typed setting

Laravel Nova Resource for a simple key/value typed setting Administer your Laravel Simple Setting in Nova Pre-requisites This Nova resource package re

elipZis 5 Nov 7, 2022
Laravel Nova Ban simplify blocking and banning Eloquent models.

Laravel Nova Ban Introduction Behind the scenes cybercog/laravel-ban is used. Contents Installation Usage Prepare bannable model Prepare bannable mode

cybercog 39 Sep 29, 2022
🖼️ Laravel Nova Field for uploading and cropping images using Slim Image Cropper

??️ Laravel Nova Field for uploading and cropping images using Slim Image Cropper

Marius 5 Apr 2, 2022
A customisable Laravel Nova card that fetches data through ajax calls.

Ajax Table Card Description A customisable Laravel Nova card that fetches data through ajax calls. Why? To allow displaying certain data on the dashbo

TwentyOne34 Technologies Corp. 4 Mar 8, 2022
Laravel Nova filter for Spatie/laravel-tags

SpatieTagsNovaFilter This package allows you to filter resources by tags. (using the awesome Spatie/laravel-tags and Vue-MultiSelect ) Installation Fi

Mahi-Mahi 3 Aug 4, 2022