From 6404f902a2244b4f6dcb9de0f0694e3b0b4f7278 Mon Sep 17 00:00:00 2001 From: Jess Archer Date: Thu, 7 Dec 2023 01:00:49 +1000 Subject: [PATCH] [1.x] Custom card CSS (#157) * Allow cards to include custom CSS * Fix code styling * Allow Htmlable CSS * Fix code styling * Add tests * Fix code styling --------- Co-authored-by: jessarcher --- resources/views/components/pulse.blade.php | 8 +--- src/Facades/Pulse.php | 2 +- src/Livewire/Card.php | 26 ++++++++++ src/Pulse.php | 36 +++++++++++--- tests/Feature/Livewire/CustomCardTest.php | 55 ++++++++++++++++++++++ tests/fixtures/custom.css | 3 ++ 6 files changed, 117 insertions(+), 13 deletions(-) create mode 100644 tests/Feature/Livewire/CustomCardTest.php create mode 100644 tests/fixtures/custom.css diff --git a/resources/views/components/pulse.blade.php b/resources/views/components/pulse.blade.php index b3930042..4a2c3458 100644 --- a/resources/views/components/pulse.blade.php +++ b/resources/views/components/pulse.blade.php @@ -11,15 +11,11 @@ - + {!! Laravel\Pulse\Facades\Pulse::css() !!} @livewireStyles - + {!! Laravel\Pulse\Facades\Pulse::js() !!}
diff --git a/src/Facades/Pulse.php b/src/Facades/Pulse.php index 6471aaa4..78c93e8b 100644 --- a/src/Facades/Pulse.php +++ b/src/Facades/Pulse.php @@ -24,7 +24,7 @@ * @method static \Laravel\Pulse\Pulse resolveAuthenticatedUserIdUsing(callable $callback) * @method static mixed|null withUser(\Illuminate\Contracts\Auth\Authenticatable|string|int|null $user, callable $callback) * @method static \Laravel\Pulse\Pulse rememberUser(\Illuminate\Contracts\Auth\Authenticatable $user) - * @method static string css() + * @method static string|self css(array|string|\Illuminate\Contracts\Support\Htmlable|null $path = null) * @method static string js() * @method static bool registersRoutes() * @method static \Laravel\Pulse\Pulse ignoreRoutes() diff --git a/src/Livewire/Card.php b/src/Livewire/Card.php index bc284df5..3b3036a4 100644 --- a/src/Livewire/Card.php +++ b/src/Livewire/Card.php @@ -4,7 +4,9 @@ use Illuminate\Contracts\Support\Renderable; use Illuminate\Support\Facades\View; +use Laravel\Pulse\Facades\Pulse; use Livewire\Component; +use Livewire\Livewire; abstract class Card extends Component { @@ -43,4 +45,28 @@ public function placeholder(): Renderable 'class' => $this->class, ]); } + + /** + * Capture component-specific CSS. + * + * @return void + */ + public function dehydrate() + { + if (Livewire::isLivewireRequest()) { + return; + } + + Pulse::css($this->css()); + } + + /** + * Define any CSS that should be loaded for the component. + * + * @return string|\Illuminate\Contracts\Support\Htmlable|array|null + */ + protected function css() + { + return null; + } } diff --git a/src/Pulse.php b/src/Pulse.php index 696bb721..9983e6be 100644 --- a/src/Pulse.php +++ b/src/Pulse.php @@ -7,8 +7,11 @@ use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Contracts\Foundation\Application; +use Illuminate\Contracts\Support\Htmlable; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Lottery; +use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; use Laravel\Pulse\Contracts\Ingest; use Laravel\Pulse\Contracts\Storage; @@ -89,6 +92,13 @@ class Pulse */ protected $handleExceptionsUsing = null; + /** + * The CSS paths to include on the dashboard. + * + * @var list + */ + protected $css = [__DIR__.'/../dist/pulse.css']; + /** * Create a new Pulse instance. */ @@ -428,15 +438,29 @@ public function rememberUser(Authenticatable $user): self } /** - * Return the compiled CSS from the vendor directory. + * Register or return CSS for the Pulse dashboard. + * + * @param string|Htmlable|list|null $css */ - public function css(): string + public function css(string|Htmlable|array|null $css = null): string|self { - if (($content = file_get_contents(__DIR__.'/../dist/pulse.css')) === false) { - throw new RuntimeException('Unable to load Pulse dashboard CSS.'); + if (func_num_args() === 1) { + $this->css = array_values(array_unique(array_merge($this->css, Arr::wrap($css)))); + + return $this; } - return $content; + return collect($this->css)->reduce(function ($carry, $css) { + if ($css instanceof Htmlable) { + return $carry.Str::finish($css->toHtml(), PHP_EOL); + } else { + if (($contents = @file_get_contents($css)) === false) { + throw new RuntimeException("Unable to load Pulse dashboard CSS path [$css]."); + } + + return $carry."".PHP_EOL; + } + }, ''); } /** @@ -448,7 +472,7 @@ public function js(): string throw new RuntimeException('Unable to load the Pulse dashboard JavaScript.'); } - return $content; + return "".PHP_EOL; } /** diff --git a/tests/Feature/Livewire/CustomCardTest.php b/tests/Feature/Livewire/CustomCardTest.php new file mode 100644 index 00000000..d17b0177 --- /dev/null +++ b/tests/Feature/Livewire/CustomCardTest.php @@ -0,0 +1,55 @@ +assertOk(); + + $css = Pulse::css(); + + expect($css)->toContain(<<<'HTML' + + HTML); +}); + +it('loads custom css using a Htmlable', function () { + Livewire::test(CustomCardWithCssHtmlable::class) + ->assertOk(); + + $css = Pulse::css(); + + expect($css)->toContain(''); +}); + +class CustomCardWithCssPath extends Card +{ + public function render() + { + return '
'; + } + + protected function css() + { + return __DIR__.'/../../fixtures/custom.css'; + } +} + +class CustomCardWithCssHtmlable extends Card +{ + public function render() + { + return '
'; + } + + protected function css() + { + return new HtmlString(''); + } +} diff --git a/tests/fixtures/custom.css b/tests/fixtures/custom.css new file mode 100644 index 00000000..1f3aaeb2 --- /dev/null +++ b/tests/fixtures/custom.css @@ -0,0 +1,3 @@ +.custom-class { + color: purple; +}