headlesslaravel / cards
Headless Cards for Laravel
Fund package maintenance!
headlesslaravel
Installs: 37
Dependents: 1
Suggesters: 0
Security: 0
Stars: 1
Watchers: 1
Forks: 1
Open Issues: 3
pkg:composer/headlesslaravel/cards
Requires
- php: ^8.0
Requires (Dev)
- nunomaduro/collision: ^5.3
- nunomaduro/larastan: ^0.7.12
- orchestra/testbench: ^6.15
- phpmd/phpmd: ^2.10
- phpunit/phpunit: ^9.3
- spatie/laravel-ray: ^1.23
README
Installation
You can install the package via composer:
composer require headlesslaravel/cards
Make a card class to manage multiple cards of one type:
php artisan make:cards Dashboard
Then add the class to an endpoint:
Route::cards('api/dashboard', Dashboard::class);
<?php namespace App\Http\Cards; use HeadlessLaravel\Cards\Cards; class Dashboard extends Cards { public function cards(): array { return [ Card::make('Total Users') ->link('/users') ->component('number-card') ->value(function() { return User::count(); }), ]; } }
/api/dashboard
{
"data": [
{
"key": "total_users",
"title": "Total Users",
"value": 5,
"component": "number-card",
"link": "/users",
"endpoint": "api/dashboard/total-users"
}
]
}
You can also reference the single method using the key in slug format.
This is useful when you want your ui to update / filter a single card.
/api/dashboard/total-users
{
"key": "total_users",
"title": "Total Users",
"value": 5,
"component": "number-card",
"link": "/users",
"endpoint": "api/dashboard/total-users"
}
This is only a basic example. The real power comes in the filtering multiple cards using one query string and validating that the query string is accurate.
<?php namespace App\Http\Cards; use HeadlessLaravel\Cards\Cards; class Dashboard extends Cards { public function rules() { return [ 'from' => ['nullable', 'date', 'before_or_equal:to'], 'to' => ['nullable', 'date', 'after_or_equal:from'], ]; } public function cards(): array { return [ Card::make('Total Users') ->link('/users') ->component('number-card') ->value(function() { return User::whereBetween('created_at', [ Request::input('from', now()), Request::input('to', now()) ])->count(); }), Card::make('Total Orders', 'total_orders') ->link('/orders') ->component('number-card') ->value(function() { return Order::whereBetween('created_at', [ Request::input('from', now()), Request::input('to', now()) ])->count(); }), ]; } }
Which results in both models being filtered by the same query string.
/dashboard?from=...&to=...
{
"data": [
{
"key": "total_users",
"title": "Total Users",
"value": 5,
"component": "number-card",
"link": "/users",
"endpoint": "api/dashboard/total-users"
},
{
"key": "total_orders",
"title": "Total Orders",
"value": 50,
"component": "number-card",
"link": "/orders",
"endpoint": "api/dashboard/total-orders"
}
]
}
The filters also work on a single card request:
/dashboard/total-users?from=...&to=...
/dashboard/total-orders?from=...&to=...
You can pass a number of things as values:
Views
Card::make('Welcome')->view('cards.welcome');
{
"key": "welcome",
"title": "Welcome",
"value": "<h1>Welcome!</h1>",
"component": null,
"link": null,
"endpoint": "api/dashboard/welcome"
}
Http
Card::make('Weather')->http('api.com/weather', 'data.results.0');
{
"key": "weather",
"title": "Weather",
"value": {
"today": "90 degrees",
"tomorrow": "50 degrees"
},
"component": null,
"link": null,
"endpoint": "api/dashboard/weather"
}
Which is just shorthand for:
Card::make('Weather') ->value(function() { return Http::get('api.com/weather')->json('data.results.0'); }),
Cache
Any values in a callable can be cached: (seconds)
Card::make('Weather') ->cache(60) ->value(function() { return Http::get('api.com/weather')->json('data.today'); }),
License
The MIT License (MIT). Please see License File for more information.