diff options
author | Sam Light <samlight1994@gmail.com> | 2025-03-27 10:53:34 +0000 |
---|---|---|
committer | Sam Light <samlight1994@gmail.com> | 2025-03-27 10:53:34 +0000 |
commit | 1f81ce361cb454b1655d6e2a7ac031bc1e3b2ede (patch) | |
tree | 1307ebad02e2a9644613d496e3d3ec87ed2cdfb9 | |
parent | 56a180f139699b3ee1eec566b6a98105576f804a (diff) |
Seperating toolbar into its own class and views
-rw-r--r-- | resources/views/table.blade.php | 39 | ||||
-rw-r--r-- | resources/views/toolbar.blade.php | 17 | ||||
-rw-r--r-- | resources/views/toolbar/column-select.blade.php | 16 | ||||
-rw-r--r-- | resources/views/toolbar/page-size.blade.php | 5 | ||||
-rw-r--r-- | resources/views/toolbar/search.blade.php | 3 | ||||
-rw-r--r-- | src/Columns/Column.php | 19 | ||||
-rw-r--r-- | src/TableComponent.php | 78 | ||||
-rw-r--r-- | src/Toolbar.php | 88 | ||||
-rw-r--r-- | src/Toolbar/ColumnSelect.php | 17 | ||||
-rw-r--r-- | src/Toolbar/Filter.php | 8 | ||||
-rw-r--r-- | src/Toolbar/Item.php | 32 | ||||
-rw-r--r-- | src/Toolbar/PageSize.php | 19 | ||||
-rw-r--r-- | src/Toolbar/Search.php | 25 | ||||
-rw-r--r-- | workbench/app/Livewire/CategoriesTable.php | 3 | ||||
-rw-r--r-- | workbench/app/Livewire/OrdersTable.php | 3 | ||||
-rw-r--r-- | workbench/app/Livewire/ProductsTable.php | 17 | ||||
-rw-r--r-- | workbench/app/Livewire/Table.php | 16 | ||||
-rw-r--r-- | workbench/resources/views/components/layouts/app.blade.php | 1 |
18 files changed, 324 insertions, 82 deletions
diff --git a/resources/views/table.blade.php b/resources/views/table.blade.php index 783255e..bcefe57 100644 --- a/resources/views/table.blade.php +++ b/resources/views/table.blade.php @@ -1,42 +1,5 @@ <div> - @if($searchable || $showColumnSelect || $showPageSizeSelect) - <div class="table-controls pb-2 d-flex justify-content-between align-items-center"> - <div> - @if($searchable) - <input class="form-control border-secondary" type="search" - wire:model.live.debounce.{{ $searchDebounce}}="search" - placeholder="{{ __('Search') }}..." /> - @endif - </div> - <div class="d-flex gap-3"> - @if($showColumnSelect) - <div class="dropdown"> - <button type="button" class="btn btn-outline-secondary border-secondary" - data-bs-toggle="dropdown" aria-expanded="false" - data-bs-auto-close="outside"> - {{ __('Columns') }} - </button> - <div class="dropdown-menu p-4"> - @foreach($allColumns->filter(fn($c) => $c->getShowInSelect()) as $column) - <label class="d-block"> - <input type="checkbox" wire:model.live="activeColumns" - value="{{ $column->name }}" /> - {{ $column->getTitle() }} - </label> - @endforeach - </div> - </div> - @endif - @if($showPageSizeSelect) - <select wire:model.live="pageSize" class="form-select border-secondary"> - @foreach($pageSizes as $size) - <option value="{{ $size }}">{{ $size }}</option> - @endforeach - </select> - @endif - </div> - </div> - @endif + {{ $toolbar?->render() }} <table class="table"> <colgroup> @foreach($columns as $column) diff --git a/resources/views/toolbar.blade.php b/resources/views/toolbar.blade.php new file mode 100644 index 0000000..fee00b4 --- /dev/null +++ b/resources/views/toolbar.blade.php @@ -0,0 +1,17 @@ +<div class="table-controls pb-2 d-flex justify-content-between align-items-center"> + <div class="d-flex gap-3"> + @foreach ($startItems as $item) + {{ $item->render() }} + @endforeach + </div> + <div class="d-flex gap-3"> + @foreach ($midItems as $item) + {{ $item->render() }} + @endforeach + </div> + <div class="d-flex gap-3"> + @foreach ($endItems as $item) + {{ $item->render() }} + @endforeach + </div> +</div> diff --git a/resources/views/toolbar/column-select.blade.php b/resources/views/toolbar/column-select.blade.php new file mode 100644 index 0000000..6fa7474 --- /dev/null +++ b/resources/views/toolbar/column-select.blade.php @@ -0,0 +1,16 @@ +<div class="dropdown"> + <button type="button" class="btn btn-outline-secondary border-secondary" + data-bs-toggle="dropdown" aria-expanded="false" + data-bs-auto-close="outside"> + {{ __('Columns') }} + </button> + <div class="dropdown-menu p-4"> + @foreach($allColumns->filter(fn($c) => $c->getShowInSelect()) as $column) + <label class="d-block"> + <input type="checkbox" wire:model.live="activeColumns" + value="{{ $column->name }}" /> + {{ $column->getTitle() }} + </label> + @endforeach + </div> +</div> diff --git a/resources/views/toolbar/page-size.blade.php b/resources/views/toolbar/page-size.blade.php new file mode 100644 index 0000000..cc35ff4 --- /dev/null +++ b/resources/views/toolbar/page-size.blade.php @@ -0,0 +1,5 @@ +<select wire:model.live="pageSize" class="form-select border-secondary"> + @foreach($pageSizes as $size) + <option value="{{ $size }}">{{ $size }}</option> + @endforeach +</select> diff --git a/resources/views/toolbar/search.blade.php b/resources/views/toolbar/search.blade.php new file mode 100644 index 0000000..04fd000 --- /dev/null +++ b/resources/views/toolbar/search.blade.php @@ -0,0 +1,3 @@ +<input class="form-control border-secondary" type="search" + wire:model.live.debounce.{{ $debounce }}="search" + placeholder="{{ __('Search') }}..." /> diff --git a/src/Columns/Column.php b/src/Columns/Column.php index 94e386f..895708f 100644 --- a/src/Columns/Column.php +++ b/src/Columns/Column.php @@ -28,24 +28,24 @@ class Column { $this->showInSelect = $this->title !== null; } - public static function make(string $name, ?string $title = null) : static + public static function make(string $name, ?string $title = null): static { return new static($name, $title); } - public function setTable(TableComponent $table) : void + public function setTable(TableComponent $table): void { $this->table = $table; } - public function getTitle() + public function getTitle(): string { return $this->title; } - private function defaultSlot(Model $row) + private function defaultSlot(Model $row): string { - return $row->{$this->name}; + return (string) $row->{$this->name}; } public function slot(callable $fn) : static @@ -77,22 +77,23 @@ class Column { return $this; } - public function showInSelect($show = true) + public function showInSelect($show = true): static { $this->showInSelect = $show; + return $this; } - public function getShowInSelect() + public function getShowInSelect(): bool { return $this->showInSelect; } - protected function getContent(Model $row) + protected function getContent(Model $row): string { return $this->slotFn?->call($this, $row, $this) ?? $this->defaultSlot($row); } - public function view(Model $row) + public function view(Model $row): HtmlString { $attributes = $this->tdAttributesFn?->call($this, $row) ?? []; $attributes = (new ComponentAttributeBag($attributes))->toHtml(); diff --git a/src/TableComponent.php b/src/TableComponent.php index b8fae6a..0a55d5e 100644 --- a/src/TableComponent.php +++ b/src/TableComponent.php @@ -9,6 +9,7 @@ use Livewire\Attributes\Url; use Illuminate\Pagination\Paginator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Str; +use Illuminate\Support\Collection; use Exception; @@ -18,35 +19,65 @@ abstract class TableComponent extends Component // Config protected $paginationTheme = 'bootstrap'; - protected bool $searchable = true; - protected int $searchMinLength = 2; - protected int $searchDebounce = 250; - protected bool $showPageSizeSelect = true; - protected bool $showColumnSelect = true; - - protected array $pageSizes = [10, 25, 50]; - protected $model = null; + protected int $defaultPageSize = 10; // Properties + #[Url] public string $search = ''; #[Url] - public int $pageSize = 0; + public int $pageSize; public array $activeColumns = []; - public function __construct() + public function mount() { - $this->pageSize = $this->pageSizes[0] ?? 0; + $this->setDefaultActiveColumns(); + $this->setDefaultPageSize(); } - public function mount() + protected function setDefaultPageSize(): void + { + if (!isset($this->pageSize)) { + $this->pageSize = $this->defaultPageSize; + } + } + + protected function setDefaultActiveColumns(): void { foreach($this->getColumns() as $column) { $this->activeColumns[] = $column->name; } } + protected function isSearching(): bool + { + $search = $this->getToolbar()->getSearch(); + return $search !== null && Str::length($this->search) >= $search->getMinLength(); + } + + public function updatedSearch(): void + { + if ($this->isSearching()) { + $this->resetPage(); + } + } + + protected function toolbar(): ?Toolbar + { + return null; + } + + private ?Toolbar $toolbarCache; + + protected function getToolbar(): ?Toolbar + { + if (!isset($this->_toolbar)) { + $this->toolbar = $this->toolbar(); + } + return $this->toolbar; + } + protected function query() : Builder { if($this->model === null) { @@ -60,25 +91,19 @@ abstract class TableComponent extends Component protected function search(Builder $builder, string $search) : void {} - protected function filters() : array - { - return []; - } - protected function buildQuery() : Builder { $query = $this->query(); - if($this->searchable && (Str::length($this->search) >= $this->searchMinLength)) { + if ($this->isSearching()) { $this->search($query, $this->search); } return $query; } - private $columnsCache = null; - - protected function getColumns() + private ?Collection $columnsCache = null; + public function getColumns() { if($this->columnsCache === null) { $this->columnsCache = collect($this->columns())->each( @@ -94,17 +119,12 @@ abstract class TableComponent extends Component $data = $this->buildQuery()->paginate($this->pageSize); $allColumns = $this->getColumns(); $columns = $allColumns->filter(fn($c) => in_array($c->name,$this->activeColumns)); + $toolbar = $this->toolbar(); Paginator::defaultView('laralight-tables::pagination'); - return view('laralight-tables::table', [ - 'searchable' => $this->searchable, - 'searchDebounce' => $this->searchDebounce, - 'showPageSizeSelect' => $this->showPageSizeSelect, - 'showColumnSelect' => $this->showColumnSelect, - 'pageSizes' => $this->pageSizes, - ] + compact( - 'data', 'allColumns', 'columns' + return view('laralight-tables::table', compact( + 'data', 'allColumns', 'columns', 'toolbar', )); } } diff --git a/src/Toolbar.php b/src/Toolbar.php new file mode 100644 index 0000000..2db39f5 --- /dev/null +++ b/src/Toolbar.php @@ -0,0 +1,88 @@ +<?php + +namespace Lightscale\LaralightTables; + +use Lightscale\LaralightTables\Toolbar\Item as ToolbarItem; +use Lightscale\LaralightTables\Toolbar\Search as SearchItem; +use Lightscale\LaralightTables\Toolbar\PageSize as PageSizeItem; +use Lightscale\LaralightTables\Toolbar\Filter as FitlerItem; + +use Illuminate\View\View; +use Illuminate\Support\Collection; + +class Toolbar +{ + protected ?SearchItem $searchItem = null; + protected ?PageSizeItem $pageSizeItem = null; + + protected Collection $startItems; + protected Collection $midItems; + protected Collection $endItems; + + public function __construct( + private TableComponent $table + ) + { + $this->startItems = collect(); + $this->midItems = collect(); + $this->endItems = collect(); + } + + private function addItem(Collection $list, ToolbarItem $item): static + { + $item->setToolbar($this); + + if ($item instanceof FilterItem) { + $this->filterItems->push($item); + } + else if ($item instanceof PageSizeItem) { + $this->pageSizeItem = $item; + } + else if ($item instanceof SearchItem) { + $this->searchItem = $item; + } + + $list->push($item); + return $this; + } + + public function addStartItem(ToolbarItem $item): static + { + return $this->addItem($this->startItems, $item); + } + + public function addMidItem(ToolbarItem $item): static + { + return $this->addItem($this->midItems, $item); + } + + public function addEndItem(ToolbarItem $item): static + { + return $this->addItem($this->endItems, $item); + } + + public function getTable(): TableComponent + { + return $this->table; + } + + public function getSearch(): ?SearchItem + { + return $this->searchItem; + } + + public function getPageSize(): ?PageSizeItem + { + return $this->pageSizeItem; + } + + public function render(): View + { + return view('laralight-tables::toolbar', [ + 'startItems' => $this->startItems, + 'midItems' => $this->midItems, + 'endItems' => $this->endItems, + ]); + } + +} diff --git a/src/Toolbar/ColumnSelect.php b/src/Toolbar/ColumnSelect.php new file mode 100644 index 0000000..a70c49a --- /dev/null +++ b/src/Toolbar/ColumnSelect.php @@ -0,0 +1,17 @@ +<?php + +namespace Lightscale\LaralightTables\Toolbar; + +use Illuminate\View\View; + +class ColumnSelect extends Item +{ + public function __construct() {} + + public function render(): View + { + return view('laralight-tables::toolbar.column-select', [ + 'allColumns' => $this->getTable()->getColumns() + ]); + } +} diff --git a/src/Toolbar/Filter.php b/src/Toolbar/Filter.php new file mode 100644 index 0000000..ebda2c6 --- /dev/null +++ b/src/Toolbar/Filter.php @@ -0,0 +1,8 @@ +<?php + +namespace Lightscale\LaralightTables\Toolbar; + +abstract class Filter extends Item +{ + +} diff --git a/src/Toolbar/Item.php b/src/Toolbar/Item.php new file mode 100644 index 0000000..168f877 --- /dev/null +++ b/src/Toolbar/Item.php @@ -0,0 +1,32 @@ +<?php + +namespace Lightscale\LaralightTables\Toolbar; + +use Lightscale\LaralightTables\TableComponent; +use Lightscale\LaralightTables\Toolbar; + +use Illuminate\View\View; +use Illuminate\Support\HtmlString; + +abstract class Item +{ + private Toolbar $toolbar; + + public function setToolbar(Toolbar $toolbar): void + { + $this->toolbar = $toolbar; + } + + public function getToolbar(): Toolbar + { + return $this->toolbar; + } + + public function getTable(): TableComponent + { + return $this->getToolbar()->getTable(); + } + + abstract public function render(): View|HtmlString|string|null; + +} diff --git a/src/Toolbar/PageSize.php b/src/Toolbar/PageSize.php new file mode 100644 index 0000000..9c2821a --- /dev/null +++ b/src/Toolbar/PageSize.php @@ -0,0 +1,19 @@ +<?php + +namespace Lightscale\LaralightTables\Toolbar; + +use Illuminate\View\View; + +class PageSize extends Item +{ + public function __construct( + private array $pageSizes = [10, 25, 50], + ) {} + + public function render(): View + { + return view('laralight-tables::toolbar.page-size', [ + 'pageSizes' => $this->pageSizes, + ]); + } +} diff --git a/src/Toolbar/Search.php b/src/Toolbar/Search.php new file mode 100644 index 0000000..0b0dc37 --- /dev/null +++ b/src/Toolbar/Search.php @@ -0,0 +1,25 @@ +<?php + +namespace Lightscale\LaralightTables\Toolbar; + +use Illuminate\View\View; + +class Search extends Item +{ + public function __construct( + protected int $debounce = 250, + protected int $minLength = 2, + ) {} + + public function getMinLength(): int + { + return $this->minLength; + } + + public function render(): View + { + return view('laralight-tables::toolbar.search', [ + 'debounce' => $this->debounce, + ]); + } +} diff --git a/workbench/app/Livewire/CategoriesTable.php b/workbench/app/Livewire/CategoriesTable.php index 92287b9..14cd5a8 100644 --- a/workbench/app/Livewire/CategoriesTable.php +++ b/workbench/app/Livewire/CategoriesTable.php @@ -4,10 +4,9 @@ namespace Workbench\App\Livewire; use Workbench\App\Models\Product; -use Lightscale\LaralightTables\TableComponent; use Lightscale\LaralightTables\Columns\Column; -class CategoriesTable extends TableComponent +class CategoriesTable extends Table { protected $model = Product::class; diff --git a/workbench/app/Livewire/OrdersTable.php b/workbench/app/Livewire/OrdersTable.php index 97ef195..bb909a3 100644 --- a/workbench/app/Livewire/OrdersTable.php +++ b/workbench/app/Livewire/OrdersTable.php @@ -4,10 +4,9 @@ namespace Workbench\App\Livewire; use Workbench\App\Models\Product; -use Lightscale\LaralightTables\TableComponent; use Lightscale\LaralightTables\Columns\Column; -class OrdersTable extends TableComponent +class OrdersTable extends Table { protected $model = Product::class; diff --git a/workbench/app/Livewire/ProductsTable.php b/workbench/app/Livewire/ProductsTable.php index 3b327d9..e3fefc3 100644 --- a/workbench/app/Livewire/ProductsTable.php +++ b/workbench/app/Livewire/ProductsTable.php @@ -4,15 +4,28 @@ namespace Workbench\App\Livewire; use Workbench\App\Models\Product; -use Lightscale\LaralightTables\TableComponent; use Lightscale\LaralightTables\Columns\Column; +use Lightscale\LaralightTables\Toolbar; +use Lightscale\LaralightTables\Toolbar\Search; +use Lightscale\LaralightTables\Toolbar\PageSize; +use Lightscale\LaralightTables\Toolbar\ColumnSelect; use Illuminate\Database\Eloquent\Builder; -class ProductsTable extends TableComponent +class ProductsTable extends Table { protected $model = Product::class; + public function toolbar(): Toolbar + { + return parent::toolbar() + ->addStartItem(new Search()) + ->addEndItem(new PageSize()) + ->addEndItem(new ColumnSelect()); + + return $toolbar; + } + protected function search(Builder $q, string $s): void { $q->search($s); diff --git a/workbench/app/Livewire/Table.php b/workbench/app/Livewire/Table.php new file mode 100644 index 0000000..5bffaed --- /dev/null +++ b/workbench/app/Livewire/Table.php @@ -0,0 +1,16 @@ +<?php + +namespace Workbench\App\Livewire; + +use Lightscale\LaralightTables\TableComponent; +use Lightscale\LaralightTables\Toolbar; + +abstract class Table extends TableComponent +{ + + public function toolbar(): Toolbar + { + return new Toolbar($this); + } + +} diff --git a/workbench/resources/views/components/layouts/app.blade.php b/workbench/resources/views/components/layouts/app.blade.php index 68016cd..599f5c4 100644 --- a/workbench/resources/views/components/layouts/app.blade.php +++ b/workbench/resources/views/components/layouts/app.blade.php @@ -38,6 +38,7 @@ </div> </div> </header> + <div class="container"> {{ $slot }} </div> |