diff --git a/database/sqlite.database b/database/database.sqlite similarity index 87% rename from database/sqlite.database rename to database/database.sqlite index 51e3c6632..1a9e27435 100644 Binary files a/database/sqlite.database and b/database/database.sqlite differ diff --git a/docs/column-types/icon_column.md b/docs/column-types/icon_column.md new file mode 100644 index 000000000..28c74458f --- /dev/null +++ b/docs/column-types/icon_column.md @@ -0,0 +1,87 @@ +--- +title: Icon Columns (beta) +weight: 10 +--- + +Icon columns provide a way to display icons in your table without having to use `format()` or partial views. + +### setIcon +setIcon requires a valid path to an SVG (Directly or via a Library), it receives the $row, and $value (if available) to help you customise which icon to use +```php +IconColumn::make('Icon', 'status') + ->setIcon(function ($row, $value) { + if($value == 1) { + return "heroicon-o-check-circle"; + } + else + { + return "heroicon-o-x-circle"; + } + }), +``` + +### attributes +Attributes receives the $row, and $value (if available) to help you customise which attributes to apply, you may pass both classes, and other SVG specific attributes. +```php +IconColumn::make('Icon', 'status') + ->setIcon(function ($row, $value) { if($value == 1) { return "heroicon-o-check-circle"; } else { return "heroicon-o-x-circle"; } }) + ->attributes(function ($row, $value) { + if($value == 1) { + return [ + 'class' => 'w-6 h-6', + 'stroke' => '#008000' + ]; + } + else + { + return [ + 'class' => 'w-3 h-3', + 'stroke' => '#FF0000' + ]; + } + }), +``` + +For example: +### Example +```php +IconColumn::make('Icon', 'status') + ->setIcon(function ($row, $value) { if($value == 1) { return "heroicon-o-check-circle"; } else { return "heroicon-o-x-circle"; } }) + ->attributes(function ($row, $value) { + if($value == 3) { + return [ + 'class' => 'w-3 h-3', + 'stroke' => '#008000' + ]; + } + else if($value == 2) { + return [ + 'class' => 'w-3 h-3', + 'stroke' => '#0000FF' + ]; + } + else + { + return [ + 'class' => 'w-3 h-3', + 'stroke' => '#FF0000' + ]; + } + }), +``` + +Please also see the following for other available methods: + \ No newline at end of file diff --git a/docs/column-types/image_columns.md b/docs/column-types/image_columns.md index 5e6868792..4225593b3 100644 --- a/docs/column-types/image_columns.md +++ b/docs/column-types/image_columns.md @@ -1,6 +1,6 @@ --- title: Image Columns -weight: 10 +weight: 11 --- Image columns provide a way to display images in your table without having to use `format()` or partial views: diff --git a/docs/column-types/link_columns.md b/docs/column-types/link_columns.md index e3f3120a4..1e4aa7fa1 100644 --- a/docs/column-types/link_columns.md +++ b/docs/column-types/link_columns.md @@ -1,6 +1,6 @@ --- title: Link Columns -weight: 11 +weight: 12 --- Link columns provide a way to display HTML links in your table without having to use `format()` or partial views: diff --git a/docs/column-types/livewire_component_column.md b/docs/column-types/livewire_component_column.md index b12ada72e..9b1851299 100644 --- a/docs/column-types/livewire_component_column.md +++ b/docs/column-types/livewire_component_column.md @@ -1,6 +1,6 @@ --- title: Livewire Component (beta) -weight: 12 +weight: 13 --- Livewire Component Columns allow for the use of a Livewire Component as a Column. diff --git a/docs/column-types/sum_column.md b/docs/column-types/sum_column.md index d63aa8f47..b15288ef2 100644 --- a/docs/column-types/sum_column.md +++ b/docs/column-types/sum_column.md @@ -1,6 +1,6 @@ --- title: Sum Columns (beta) -weight: 13 +weight: 14 --- Sum columns provide an easy way to display the "Sum" of a field on a relation. diff --git a/docs/column-types/view_component_column.md b/docs/column-types/view_component_column.md index 4b1b9a033..f3dd04276 100644 --- a/docs/column-types/view_component_column.md +++ b/docs/column-types/view_component_column.md @@ -1,6 +1,6 @@ --- title: View Component Columns -weight: 14 +weight: 15 --- View Component columns let you specify a component name and attributes and provide attributes to the View Component. This will render the View Component in it's entirety. diff --git a/docs/column-types/wire_link_column.md b/docs/column-types/wire_link_column.md index 9abf15aac..253544cd0 100644 --- a/docs/column-types/wire_link_column.md +++ b/docs/column-types/wire_link_column.md @@ -1,6 +1,6 @@ --- title: Wire Link Column (beta) -weight: 15 +weight: 16 --- WireLink columns provide a way to display Wired Links in your table without having to use `format()` or partial views, with or without a Confirmation Message diff --git a/docs/columns/other-column-types.md b/docs/columns/other-column-types.md index c3a8bd154..f12adf6e7 100644 --- a/docs/columns/other-column-types.md +++ b/docs/columns/other-column-types.md @@ -28,6 +28,9 @@ weight: 4
  • Date Columns
  • +
  • + [Icon Columns (Beta)](../column-types/icon_columns) +
  • Image Columns
  • diff --git a/resources/views/includes/columns/icon.blade.php b/resources/views/includes/columns/icon.blade.php new file mode 100644 index 000000000..0f8298c03 --- /dev/null +++ b/resources/views/includes/columns/icon.blade.php @@ -0,0 +1,7 @@ +
    + @svg( + $icon, + $classes, + $attributes, + ) +
    \ No newline at end of file diff --git a/src/Views/Columns/IconColumn.php b/src/Views/Columns/IconColumn.php new file mode 100644 index 000000000..3d37dbc10 --- /dev/null +++ b/src/Views/Columns/IconColumn.php @@ -0,0 +1,43 @@ +label(fn () => null); + } + + $this->html(); + } + + public function getContents(Model $row): null|string|\Illuminate\Support\HtmlString|DataTableConfigurationException|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View + { + $attributeBag = $this->getAttributeBag($row); + + return view($this->getView()) + ->withIsTailwind($this->isTailwind()) + ->withIsBootstrap($this->isBootstrap()) + ->withIcon($this->getIcon($row)) + ->withClasses($attributeBag['class']) + ->withAttributes(collect($attributeBag)->except('class')->toArray()); + } +} diff --git a/src/Views/Traits/Configuration/IconColumnConfiguration.php b/src/Views/Traits/Configuration/IconColumnConfiguration.php new file mode 100644 index 000000000..f52bc9e2e --- /dev/null +++ b/src/Views/Traits/Configuration/IconColumnConfiguration.php @@ -0,0 +1,13 @@ +iconCallback = $callback; + + return $this; + } +} diff --git a/src/Views/Traits/Core/HasAttributes.php b/src/Views/Traits/Core/HasAttributes.php index 76220d4bc..5ddd4653b 100644 --- a/src/Views/Traits/Core/HasAttributes.php +++ b/src/Views/Traits/Core/HasAttributes.php @@ -31,7 +31,7 @@ public function hasAttributesCallback(): bool // TODO: Test public function getAttributeBag(Model $row): ComponentAttributeBag { - return new ComponentAttributeBag($this->hasAttributesCallback() ? app()->call($this->getAttributesCallback(), ['row' => $row]) : []); + return new ComponentAttributeBag($this->hasAttributesCallback() ? app()->call($this->getAttributesCallback(), ['row' => $row, 'value' => $this->getValue($row)]) : []); } /** diff --git a/src/Views/Traits/Helpers/IconColumnHelpers.php b/src/Views/Traits/Helpers/IconColumnHelpers.php new file mode 100644 index 000000000..ceb8f9439 --- /dev/null +++ b/src/Views/Traits/Helpers/IconColumnHelpers.php @@ -0,0 +1,27 @@ +hasIconCallback() ? app()->call($this->getIconCallback(), ['row' => $row, 'value' => $this->getValue($row) ?? '']) : ($this->getValue($row)); + } + + public function getIconCallback(): ?callable + { + return $this->iconCallback; + } + + public function hasIconCallback(): bool + { + return isset($this->iconCallback); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index d930575f7..0bf3aa3e2 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -193,10 +193,10 @@ public function getEnvironmentSetUp($app): void $app['config']->set('view.cache', false); $app['config']->set('view.compiled', realpath(storage_path('framework/views')).'/'.rand(0, 100)); - if (file_exists(__DIR__.'/../database/sqlite.database')) { + if (file_exists(__DIR__.'/../database/database.sqlite')) { $app['config']->set('database.connections.sqlite', [ 'driver' => 'sqlite', - 'database' => __DIR__.'/../database/sqlite.database', + 'database' => __DIR__.'/../database/database.sqlite', 'prefix' => '', ]); } else { diff --git a/tests/Traits/Visuals/Columns/IconColumnVisualsTest.php b/tests/Traits/Visuals/Columns/IconColumnVisualsTest.php new file mode 100644 index 000000000..68d3c80fb --- /dev/null +++ b/tests/Traits/Visuals/Columns/IconColumnVisualsTest.php @@ -0,0 +1,64 @@ +setPrimaryKey('id'); + } + + public function columns(): array + { + return [ + \Rappasoft\LaravelLivewireTables\Views\Column::make('Name')->searchable(), + \Rappasoft\LaravelLivewireTables\Views\Columns\IconColumn::make('Old Age', 'age') + ->setIcon(function (\Rappasoft\LaravelLivewireTables\Tests\Models\Pet $row, int $value) { + if ($value >= 5) { + return 'heroicon-o-check-circle'; + } else { + return 'heroicon-o-x-circle'; + } + }), + ]; + } + + public function filters(): array + { + return []; + } + }) + ->call('setSearch', 'Cartman') + ->assertSeeHtmlInOrder([ + '
    ', + '
    ', + ]) + ->assertDontSeeHtml('') + ->call('setSearch', 'May') + ->assertDontSeeHtml('') + ->assertSeeHtmlInOrder([ + '
    ', + '
    ', + ]); + + } +} diff --git a/tests/Views/Columns/IconColumnTest.php b/tests/Views/Columns/IconColumnTest.php new file mode 100644 index 000000000..3ac423234 --- /dev/null +++ b/tests/Views/Columns/IconColumnTest.php @@ -0,0 +1,108 @@ +assertSame('Icon Column 1', $column->getTitle()); + } + + public function test_can_get_the_column_view(): void + { + $column = IconColumn::make('Icon Column 1', 'favorite_color'); + + $this->assertSame('livewire-tables::includes.columns.icon', $column->getView()); + $column->setView('test-icon-column'); + $this->assertSame('test-icon-column', $column->getView()); + + } + + public function test_can_infer_field_name_from_title_if_no_from(): void + { + $column = IconColumn::make('Icon Column 1'); + + $this->assertNull($column->getField()); + } + + public function test_can_setup_column_correctly(): void + { + $column = IconColumn::make('Icon Column 1') + ->setIcon(function ($row, $value) { + if ($value == 1) { + return 'heroicon-o-check-circle'; + } else { + return 'heroicon-o-x-circle'; + } + }); + + $this->assertNotEmpty($column); + } + + public function test_icons_correctly_via_value(): void + { + $rows = $this->basicTable->getRows(); + $column = IconColumn::make('Old Age', 'age') + ->setIcon(function (Pet $row, int $value) { + if ($value >= 5) { + return 'heroicon-o-check-circle'; + } else { + return 'heroicon-o-x-circle'; + } + }); + + $this->assertSame('heroicon-o-check-circle', $column->getIcon(Pet::where('age', '>', 5)->first())); + $this->assertSame('heroicon-o-x-circle', $column->getIcon(Pet::where('age', '<', 4)->first())); + } + + public function test_icons_correctly_via_row(): void + { + $rows = $this->basicTable->getRows(); + $column = IconColumn::make('Old Age', 'age') + ->setIcon(function (Pet $row) { + if ($row->age >= 7) { + return 'old-icon'; + } else { + return 'young-icon'; + } + }); + + $this->assertSame('old-icon', $column->getIcon(Pet::where('age', '>', 9)->first())); + $this->assertSame('young-icon', $column->getIcon(Pet::where('age', '<', 4)->first())); + } + + public function test_renders_correctly(): void + { + $rows = $this->basicTable->getRows(); + $row1 = $rows->first(); + $column = IconColumn::make('Old Age', 'age') + ->setIcon(function (Pet $row, int $value) { + if ($value >= 5) { + return 'heroicon-o-check-circle'; + } else { + return 'heroicon-o-x-circle'; + } + }); + $youngString = '
    '; + $oldString = '
    '; + $firstLine = str_replace(' ', ' ', str_replace(["\r", "\n"], '', $column->getContents(Pet::where('age', '<', 4)->first()))); + $firstLine = str_replace('> <', '><', $firstLine); + $firstLine = str_replace('> <', '><', $firstLine); + + $this->assertSame($oldString, $firstLine); + + $lastLine = str_replace(' ', ' ', str_replace(["\r", "\n"], '', $column->getContents(Pet::where('age', '>', 5)->first()))); + $lastLine = str_replace('> <', '><', $lastLine); + $lastLine = str_replace('> <', '><', $lastLine); + + $this->assertSame($youngString, $lastLine); + } +}