Skip to content

Commit 5de8f7a

Browse files
committed
feat: reordarable action
1 parent 46255e1 commit 5de8f7a

File tree

6 files changed

+152
-18
lines changed

6 files changed

+152
-18
lines changed

database/migrations/create_page_builder_blocks_table.php.stub

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ return new class extends Migration
1111
Schema::create('page_builder_blocks', function (Blueprint $table) {
1212
$table->uuid('id')->primary();
1313
$table->string('block_type');
14+
$table->unsignedTinyInteger('order');
1415
$table->morphs('page_builder_blockable');
1516
$table->json('data')->nullable();
1617
$table->timestamps();

resources/views/forms/page-builder.blade.php

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
@php
22
$blocks = $getBlocks();
33
$state = $getState();
4+
$statePath = $getStatePath();
5+
$reorderActionName = $getReorderActionName();
46
$selectBlockAction = $getAction($getSelectBlockActionName());
7+
$reorderAction = $getAction($reorderActionName);
8+
$reorderAction = $reorderAction([]);
9+
$reorderActionIsVisible = $reorderAction->isVisible();
510
@endphp
611

712

813
<x-dynamic-component :component="$getFieldWrapperView()" :hintActions="[$selectBlockAction]" :field="$field">
914
@if (count($blocks) && $state)
1015
<ul>
11-
<x-filament::grid class="items-start gap-4">
16+
<x-filament::grid
17+
:wire:end.stop="'mountFormComponentAction(\'' . $statePath . '\', \'' . $reorderActionName . '\', { items: $event.target.sortable.toArray() })'"
18+
x-sortable class="items-start gap-4">
1219
@foreach ($state as $item)
1320
@php
1421
$deleteAction = $getAction($getDeleteActionName());
@@ -18,18 +25,22 @@
1825
$editAction = $editAction(['item' => $item, 'index' => $loop->index]);
1926
$editActionIsVisible = $editAction->isVisible();
2027
@endphp
21-
<li
28+
<li x-sortable-item="{{ $item['id'] }}"
2229
class="fi-fo-repeater-item divide-y divide-gray-100 rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 dark:divide-white/10 dark:bg-white/5 dark:ring-white/10">
23-
<div
24-
class ='fi-fo-repeater-item-header flex items-center gap-x-3 overflow-hidden px-4 py-3 justify-between'>
25-
{{ $item['block_type']::getBlockLabel($item, $loop->index) }}
26-
<div class="flex gap-x-4 items-center">
27-
@if ($deleteActionIsVisible)
28-
{{ $renderDeleteActionButton($item['id'], $loop->index) }}
29-
@endif
30-
@if ($editActionIsVisible)
31-
{{ $renderEditActionButton($item['id'], $loop->index) }}
32-
@endif
30+
<div class ='fi-fo-repeater-item-header flex items-center gap-x-3 overflow-hidden px-4 py-3 '>
31+
@if ($reorderActionIsVisible)
32+
{{ $renderReorderActionButton($item['id'], $loop->index) }}
33+
@endif
34+
<div class="flex justify-between w-full items-center">
35+
{{ $item['block_type']::getBlockLabel($item, $loop->index) }}
36+
<div class="flex gap-x-4 items-center">
37+
@if ($deleteActionIsVisible)
38+
{{ $renderDeleteActionButton($item['id'], $loop->index) }}
39+
@endif
40+
@if ($editActionIsVisible)
41+
{{ $renderEditActionButton($item['id'], $loop->index) }}
42+
@endif
43+
</div>
3344
</div>
3445
</div>
3546
</li>

src/Components/Forms/Actions/CreatePageBuilderBlockAction.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,18 @@ protected function setUp(): void
6666

6767
$this->action(function ($arguments, $data, $action, PageBuilder $component) {
6868
$blockType = $arguments['block_type'];
69-
$block = app($component->getModel())->{$component->relationship}()->make([
69+
$state = $component->getState() ?? [];
70+
71+
$block = app($component->getModel())->{$component->relationship}()->make([
7072
'block_type' => $blockType,
7173
'data' => $data['data'],
74+
'order' => count($state) + 1,
7275
]);
76+
7377
$block->id = $block->newUniqueId();
7478

7579
$component->state([
76-
...$component->getState() ?? [],
80+
...$state,
7781
$block->toArray(),
7882
]);
7983

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace RedberryProducts\PageBuilderPlugin\Components\Forms\Actions;
4+
5+
use Filament\Forms\Components\Actions\Action;
6+
use RedberryProducts\PageBuilderPlugin\Components\Forms\PageBuilder;
7+
8+
class ReoraderPageBuilderBlockAction extends Action
9+
{
10+
public static function getDefaultName(): ?string
11+
{
12+
return 'reorder-page-builder-block';
13+
}
14+
15+
protected function setUp(): void
16+
{
17+
parent::setUp();
18+
19+
$this->action(function ($arguments, PageBuilder $component) {
20+
$flippedArray = array_flip($arguments['items']);
21+
22+
$state = $component->getState();
23+
24+
$newState = [];
25+
$originalIds = array_column($state, 'id');
26+
foreach ($flippedArray as $item => $index) {
27+
$newState[$index] = [
28+
...$state[array_search($item, $originalIds)],
29+
'order' => $index,
30+
];
31+
}
32+
33+
$component->state($newState);
34+
});
35+
}
36+
}

src/Components/Forms/PageBuilder.php

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
use RedberryProducts\PageBuilderPlugin\Components\Forms\Actions\CreatePageBuilderBlockAction;
1717
use RedberryProducts\PageBuilderPlugin\Components\Forms\Actions\DeletePageBuilderBlockAction;
1818
use RedberryProducts\PageBuilderPlugin\Components\Forms\Actions\EditPageBuilderBlockAction;
19+
use RedberryProducts\PageBuilderPlugin\Components\Forms\Actions\ReoraderPageBuilderBlockAction;
1920
use RedberryProducts\PageBuilderPlugin\Components\Forms\Actions\SelectBlockAction;
2021

2122
// TODO: make this reorder-able
2223
class PageBuilder extends Field
2324
{
2425
public ?string $relationship = null;
2526

27+
public bool|Closure $reorderable = false;
28+
2629
protected ?Closure $renderDeleteActionButtonUsing = null;
2730

2831
protected ?Closure $modifyDeleteActionUsing = null;
@@ -35,6 +38,10 @@ class PageBuilder extends Field
3538

3639
protected ?Closure $renderEditActionButtonUsing = null;
3740

41+
protected ?Closure $modifyReorderActionUsing = null;
42+
43+
protected ?Closure $renderReorderActionButtonUsing = null;
44+
3845
public array | Closure $blocks = [];
3946

4047
public string $view = 'page-builder-plugin::forms.page-builder';
@@ -52,9 +59,25 @@ protected function setUp(): void
5259
fn (self $component): Action => $component->getEditAction(),
5360
fn (self $component): Action => $component->getSelectBlockAction(),
5461
fn (self $component): Action => $component->getCreateAction(),
62+
fn (self $component): Action => $component->getReorderAction(),
5563
]);
5664
}
5765

66+
public function getReorderAction(): Action
67+
{
68+
$action = ReoraderPageBuilderBlockAction::make($this->getReorderActionName())
69+
->hidden(!$this->getReorderable())
70+
->disabled($this->isDisabled());
71+
72+
if ($this->modifyReorderActionUsing) {
73+
$action = $this->evaluate($this->modifyReorderActionUsing, [
74+
'action' => $action,
75+
]);
76+
}
77+
78+
return $action;
79+
}
80+
5881
public function getCreateAction(): Action
5982
{
6083
$action = CreatePageBuilderBlockAction::make($this->getCreateActionName())
@@ -167,6 +190,31 @@ public function renderEditActionButton(string $item, $index)
167190
return view('filament::components.button.index', $attributes);
168191
}
169192

193+
public function renderReorderActionButton(string $item, $index)
194+
{
195+
$reorderAction = $this->getReorderAction();
196+
197+
$attributes = [
198+
'icon' => 'heroicon-o-arrows-up-down',
199+
'disabled' => $reorderAction->isDisabled(),
200+
'color' => 'gray',
201+
'attributes' => collect([
202+
'x-sortable-handle' => 'x-sortable-handle',
203+
'x-on:click.stop' => 'x-on:click.stop',
204+
])
205+
];
206+
207+
if ($this->renderReorderActionButtonUsing) {
208+
return $this->evaluate($this->renderReorderActionButtonUsing, [
209+
'action' => $reorderAction,
210+
'item' => $item,
211+
'index' => $index,
212+
]);
213+
}
214+
215+
return view('filament::components.icon-button', $attributes);
216+
}
217+
170218
public function deleteActionButton(Closure $renderDeleteActionButtonUsing)
171219
{
172220
$this->renderDeleteActionButtonUsing = $renderDeleteActionButtonUsing;
@@ -181,6 +229,13 @@ public function editActionButton(Closure $renderEditActionButtonUsing)
181229
return $this;
182230
}
183231

232+
public function reorderActionButton(Closure $renderReorderActionButtonUsing)
233+
{
234+
$this->renderReorderActionButtonUsing = $renderReorderActionButtonUsing;
235+
236+
return $this;
237+
}
238+
184239
public function getDeleteActionName(): string
185240
{
186241
return 'delete';
@@ -196,6 +251,11 @@ public function getCreateActionName(): string
196251
return 'create';
197252
}
198253

254+
public function getReorderActionName(): string
255+
{
256+
return 'reorder';
257+
}
258+
199259
public function getSelectBlockActionName(): string
200260
{
201261
return 'select-block';
@@ -225,6 +285,14 @@ public function createAction(
225285
return $this;
226286
}
227287

288+
public function reorderAction(
289+
Closure $modifyReorderActionUsing,
290+
) {
291+
$this->modifyReorderActionUsing = $modifyReorderActionUsing;
292+
293+
return $this;
294+
}
295+
228296
public function blocks(
229297
array | Closure $blocks,
230298
) {
@@ -233,6 +301,19 @@ public function blocks(
233301
return $this;
234302
}
235303

304+
public function reorderable(
305+
bool | Closure $reorderable = true,
306+
) {
307+
$this->reorderable = $reorderable;
308+
309+
return $this;
310+
}
311+
312+
public function getReorderable(): bool
313+
{
314+
return (bool) $this->evaluate($this->reorderable);
315+
}
316+
236317
#[Computed(true)]
237318
public function getBlocks(): array
238319
{
@@ -263,6 +344,7 @@ public function relationship(
263344
$this->loadStateFromRelationshipsUsing(function ($record, PageBuilder $component) {
264345
/** @var Collection */
265346
$blocks = $this->getConstrainAppliedQuery($record)
347+
->orderBy('order')
266348
->get();
267349

268350
$component->state($blocks->toArray());
@@ -281,11 +363,10 @@ public function relationship(
281363

282364
$record->{$this->relationship}()->upsert(array_map(function ($item) {
283365
return [
284-
'id' => $item['id'] ?? null,
285-
'block_type' => $item['block_type'],
366+
...$item,
286367
'data' => json_encode($item['data'] ?? []),
287368
];
288-
}, $state), uniqueBy: ['id'], update: ['data']);
369+
}, $state), uniqueBy: ['id'], update: ['data', 'order']);
289370

290371
DB::commit();
291372

@@ -297,7 +378,7 @@ public function relationship(
297378
->danger()
298379
->send();
299380

300-
throw new Halt;
381+
throw new Halt();
301382
}
302383

303384
});

src/Contracts/BaseBlock.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Illuminate\Support\Facades\Storage;
88
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
99

10+
// TODO: this should not be in contracts...
1011
abstract class BaseBlock
1112
{
1213
use EvaluatesClosures;

0 commit comments

Comments
 (0)