From 01577613da3efc9e1f3538a1436a6686e0852f21 Mon Sep 17 00:00:00 2001 From: Andreas Farah Date: Mon, 8 Jun 2026 14:27:41 +0200 Subject: [PATCH 1/9] refactor: block and field type registries --- config/kompass.php | 144 ++++++++++++++ .../block-controls/advanced.blade.php | 12 ++ .../block-controls/alignment.blade.php | 14 ++ .../components/block-controls/color.blade.php | 5 + .../block-controls/container-layout.blade.php | 65 ++++++ .../block-controls/gallery.blade.php | 30 +++ .../block-controls/layout-grid.blade.php | 13 ++ .../block-controls/layout.blade.php | 38 ++++ .../components/block-controls/link.blade.php | 5 + .../components/blocks-datafield.blade.php | 33 +--- .../components/blocks/palette-tile.blade.php | 20 ++ .../views/components/blocksgroup.blade.php | 14 +- resources/views/components/nav-item.blade.php | 120 +----------- .../views/components/nav-itemgroup.blade.php | 159 +-------------- .../views/livewire/datafield-item.blade.php | 2 +- .../views/livewire/pages/pages-show.blade.php | 60 +----- .../views/livewire/posts/posts-show.blade.php | 34 +--- src/Blocks/BlockTypeRegistry.php | 185 ++++++++++++++++++ src/Blocks/FieldTypeRegistry.php | 78 ++++++++ src/Helpers/helpers.php | 22 +++ src/KompassServiceProvider.php | 5 + src/Livewire/PagesData.php | 33 +--- src/Livewire/PostsData.php | 40 +--- src/Models/Blockfields.php | 23 +-- src/Models/Blocktemplates.php | 10 +- 25 files changed, 688 insertions(+), 476 deletions(-) create mode 100644 resources/views/components/block-controls/advanced.blade.php create mode 100644 resources/views/components/block-controls/alignment.blade.php create mode 100644 resources/views/components/block-controls/color.blade.php create mode 100644 resources/views/components/block-controls/container-layout.blade.php create mode 100644 resources/views/components/block-controls/gallery.blade.php create mode 100644 resources/views/components/block-controls/layout-grid.blade.php create mode 100644 resources/views/components/block-controls/layout.blade.php create mode 100644 resources/views/components/block-controls/link.blade.php create mode 100644 resources/views/components/blocks/palette-tile.blade.php create mode 100644 src/Blocks/BlockTypeRegistry.php create mode 100644 src/Blocks/FieldTypeRegistry.php diff --git a/config/kompass.php b/config/kompass.php index 46afaf42..9486fc2f 100644 --- a/config/kompass.php +++ b/config/kompass.php @@ -195,4 +195,148 @@ ], ], + /* + |-------------------------------------------------------------------------- + | Block Types (single source of truth) + |-------------------------------------------------------------------------- + | + | Built-in block types consumed by Secondnetwork\Kompass\Blocks\BlockTypeRegistry. + | Each entry feeds the add-block palette, the default datafields created on + | add, the builder styling, the edit-control list and the frontend component + | name. User-defined Blocktemplates rows are merged in at runtime; built-ins + | win on a type collision. Available control keys map to the anonymous Blade + | components under resources/views/components/block-controls/*. + | + */ + + 'block_types' => [ + 'wysiwyg' => [ + 'label' => 'Textblock', + 'icon' => 'blockquote', + 'component' => 'blocks.wysiwyg', + 'container' => false, + 'default_fields' => [['type' => 'wysiwyg', 'order' => '1']], + 'styling' => ['rail' => 'border-l-slate-400', 'badge' => 'bg-slate-500', 'bar' => 'bg-base-200', 'accent' => 'text-slate-500'], + 'controls' => ['layout', 'alignment', 'link', 'color', 'advanced'], + 'palette' => true, + 'palette_image' => 'icons-blocks/default.png', + 'palette_border' => 'border-blue-600', + ], + 'group' => [ + 'label' => 'Layout Block', + 'icon' => '', + 'component' => 'blocks.group', + 'container' => true, + 'default_fields' => [], + 'styling' => ['rail' => 'border-l-indigo-500', 'badge' => 'bg-indigo-500', 'bar' => 'bg-indigo-500/10', 'accent' => 'text-indigo-600'], + 'controls' => ['container-layout', 'layout-grid', 'color', 'advanced'], + 'palette' => true, + 'palette_image' => 'icons-blocks/group.png', + 'palette_border' => 'border-purple-600', + ], + 'accordiongroup' => [ + 'label' => 'Accordion', + 'icon' => '', + 'component' => 'blocks.accordiongroup', + 'container' => true, + 'default_fields' => [], + 'styling' => ['rail' => 'border-l-emerald-500', 'badge' => 'bg-emerald-500', 'bar' => 'bg-emerald-500/10', 'accent' => 'text-emerald-600'], + 'controls' => ['container-layout', 'layout-grid', 'color', 'advanced'], + 'palette' => true, + 'palette_image' => 'icons-blocks/accordiongroup.png', + 'palette_border' => 'border-purple-600', + ], + 'button' => [ + 'label' => 'Button', + 'icon' => 'box-model-2', + 'component' => 'blocks.button', + 'container' => false, + 'default_fields' => [['type' => 'link', 'order' => '1']], + 'styling' => ['rail' => 'border-l-slate-400', 'badge' => 'bg-slate-500', 'bar' => 'bg-base-200', 'accent' => 'text-slate-500'], + 'controls' => ['layout', 'color', 'advanced'], + 'palette' => true, + 'palette_image' => 'icons-blocks/button.png', + 'palette_border' => 'border-blue-600', + ], + 'video' => [ + 'label' => 'Video', + 'icon' => 'video', + 'component' => 'blocks.video', + 'container' => false, + 'default_fields' => [], + 'styling' => ['rail' => 'border-l-red-600', 'badge' => 'bg-slate-500', 'bar' => 'bg-slate-600/10', 'accent' => 'text-red-600'], + 'controls' => ['layout', 'color', 'advanced'], + 'palette' => true, + 'palette_image' => 'icons-blocks/videoplayer.png', + 'palette_border' => 'border-blue-600', + ], + 'gallery' => [ + 'label' => 'Images and Gallery', + 'icon' => 'photo', + 'component' => 'blocks.gallery', + 'container' => false, + 'default_fields' => [], + 'styling' => ['rail' => 'border-l-blue-500', 'badge' => 'bg-blue-500', 'bar' => 'bg-blue-500/10', 'accent' => 'text-blue-600'], + 'controls' => ['layout', 'gallery', 'color', 'advanced'], + 'palette' => true, + 'palette_image' => 'icons-blocks/gallery.png', + 'palette_image_class' => 'rounded', + 'palette_border' => 'border-blue-600', + ], + 'anchormenu' => [ + 'label' => 'Anchor menu', + 'icon' => '', + 'component' => 'blocks.anchormenu', + 'container' => false, + 'default_fields' => [['name' => 'Name Anchormenu', 'type' => 'text', 'order' => '1']], + 'styling' => ['rail' => 'border-l-slate-400', 'badge' => 'bg-slate-500', 'bar' => 'bg-base-200', 'accent' => 'text-slate-500'], + 'controls' => ['layout', 'color', 'advanced'], + 'palette' => false, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Field Types (datafields) + |-------------------------------------------------------------------------- + | + | Datafield types consumed by Secondnetwork\Kompass\Blocks\FieldTypeRegistry. + | display_component = anonymous Blade component (under kompass::) used to + | render the saved value in the builder; edit_widget = the interactive editor + | widget (input|image|oembed|editor); select=false hides it from the + | field-type picker. + | + */ + + 'field_types' => [ + 'text' => ['label' => 'Text', 'icon' => 'tabler-letter-case', 'display_component' => 'block.text', 'edit_widget' => 'input'], + 'wysiwyg' => ['label' => 'WYSIWYG Editor', 'icon' => 'tabler-blockquote', 'display_component' => 'block.wysiwyg', 'edit_widget' => 'editor'], + 'image' => ['label' => 'Image', 'icon' => 'tabler-photo', 'display_component' => 'block.image', 'edit_widget' => 'image'], + 'link' => ['label' => 'Link', 'icon' => 'tabler-link', 'display_component' => 'block.link', 'edit_widget' => 'input'], + 'true_false' => ['label' => 'true/false', 'icon' => 'tabler-toggle-left', 'display_component' => 'block.true_false', 'edit_widget' => 'input'], + 'file' => ['label' => 'File', 'icon' => 'tabler-file-zip', 'display_component' => 'block.file', 'edit_widget' => 'input'], + 'color' => ['label' => 'Color', 'icon' => 'tabler-palette', 'display_component' => 'block.color', 'edit_widget' => 'input'], + 'oembed' => ['label' => 'Video embed', 'icon' => 'tabler-brand-youtube', 'display_component' => 'block.text', 'edit_widget' => 'oembed', 'select' => false], + ], + + /* + |-------------------------------------------------------------------------- + | Setting Field Types + |-------------------------------------------------------------------------- + | + | Distinct vocabulary used by the global settings field-type picker + | (components/elements/global.blade.php). Kept separate from field_types + | because its ids (rich_text_box, switch) drive a different render switch. + | + */ + + 'setting_field_types' => [ + 'text' => ['label' => 'Text', 'icon' => 'tabler-letter-case'], + 'rich_text_box' => ['label' => 'Rich Textbox', 'icon' => 'tabler-blockquote'], + 'image' => ['label' => 'Image', 'icon' => 'tabler-photo'], + 'link' => ['label' => 'Link', 'icon' => 'tabler-link'], + 'switch' => ['label' => 'true or false', 'icon' => 'tabler-toggle-left'], + 'file' => ['label' => 'File', 'icon' => 'tabler-file-zip'], + ], + ]; diff --git a/resources/views/components/block-controls/advanced.blade.php b/resources/views/components/block-controls/advanced.blade.php new file mode 100644 index 00000000..add18df1 --- /dev/null +++ b/resources/views/components/block-controls/advanced.blade.php @@ -0,0 +1,12 @@ +@props(['itemblocks']) + + +
+ {{ __('Classname') }} + +
+
+ {{ __('ID') }} + +
+
diff --git a/resources/views/components/block-controls/alignment.blade.php b/resources/views/components/block-controls/alignment.blade.php new file mode 100644 index 00000000..b331060c --- /dev/null +++ b/resources/views/components/block-controls/alignment.blade.php @@ -0,0 +1,14 @@ +@props(['itemblocks']) + +@php $alignment = $itemblocks->alignment ?? ''; @endphp + + +
+ @foreach (['align-left' => 'tabler-align-left', 'align-center' => 'tabler-align-center', 'align-right' => 'tabler-align-right'] as $alignValue => $iconName) + + @svg($iconName, $alignment == $alignValue ? 'stroke-blue-500' : '') + + @endforeach +
+
diff --git a/resources/views/components/block-controls/color.blade.php b/resources/views/components/block-controls/color.blade.php new file mode 100644 index 00000000..3c39e4e2 --- /dev/null +++ b/resources/views/components/block-controls/color.blade.php @@ -0,0 +1,5 @@ +@props(['itemblocks']) + + + + diff --git a/resources/views/components/block-controls/container-layout.blade.php b/resources/views/components/block-controls/container-layout.blade.php new file mode 100644 index 00000000..c189cfd3 --- /dev/null +++ b/resources/views/components/block-controls/container-layout.blade.php @@ -0,0 +1,65 @@ +@props(['itemblocks']) + +@php + $type = $itemblocks->type ?? ''; + $layout = $itemblocks->layout ?? ''; +@endphp + +{{-- Container (group / accordiongroup) layout: only shown at top level. --}} +@if ($itemblocks->subgroup == null) + +
+ {{ __('Width') }} +
+ + + + + + + + + +
+
+ + @if ($type == 'group') + @php + $alignOptions = [ + '' => ['icon' => 'tabler-layout-align-top', 'label' => 'Top'], + 'items-center' => ['icon' => 'tabler-layout-align-middle', 'label' => 'Middle'], + 'items-end' => ['icon' => 'tabler-layout-align-bottom', 'label' => 'Bottom'], + ]; + $currentAlign = $itemblocks->getMeta('align') ?? ''; + $currentOrder = $itemblocks->getMeta('order') ?? ''; + @endphp +
+ {{ __('Align') }} +
+ @foreach ($alignOptions as $alignValue => $alignData) + + @svg($alignData['icon'], $currentAlign == $alignValue ? 'stroke-blue-500' : '') + + @endforeach +
+
+
+ {{ __('Mobile reverse') }} +
+ + @svg('tabler-layout-off', empty($currentOrder) ? 'stroke-blue-500' : '') + + + @svg('tabler-reorder', $currentOrder == 'reverse' ? 'stroke-blue-500' : '') + +
+
+ @endif +
+@endif diff --git a/resources/views/components/block-controls/gallery.blade.php b/resources/views/components/block-controls/gallery.blade.php new file mode 100644 index 00000000..399e7c80 --- /dev/null +++ b/resources/views/components/block-controls/gallery.blade.php @@ -0,0 +1,30 @@ +@props(['itemblocks']) + +@php $slider = $itemblocks->slider ?? ''; @endphp + + +
+ {{ __('Slider') }} +
+ + + + + + +
+
+
+ {{ __('Image Grid') }} +
+ @foreach ([1, 2, 3, 4, 5] as $num) + + @svg('tabler-square-number-'.$num, $itemblocks->grid == (string) $num ? 'stroke-blue-500' : '') + + @endforeach +
+
+
diff --git a/resources/views/components/block-controls/layout-grid.blade.php b/resources/views/components/block-controls/layout-grid.blade.php new file mode 100644 index 00000000..bc82490e --- /dev/null +++ b/resources/views/components/block-controls/layout-grid.blade.php @@ -0,0 +1,13 @@ +@props(['itemblocks']) + +{{-- Container column grid (group / accordiongroup). --}} + +
+ @foreach ([1, 2, 3, 4, 5] as $gridNumber) + + @svg('tabler-square-number-'.$gridNumber, $itemblocks->layoutgrid == $gridNumber ? 'stroke-blue-500' : '') + + @endforeach +
+
diff --git a/resources/views/components/block-controls/layout.blade.php b/resources/views/components/block-controls/layout.blade.php new file mode 100644 index 00000000..82862c71 --- /dev/null +++ b/resources/views/components/block-controls/layout.blade.php @@ -0,0 +1,38 @@ +@props(['itemblocks']) + +@php $layout = $itemblocks->layout ?? ''; @endphp + +{{-- Module layout: Col Span when nested in a group, otherwise Width. --}} + + @if (! ($itemblocks->subgroup == null)) +
+ {{ __('Col Span') }} +
+ @foreach ([1, 2, 3, 4, 5] as $num) + + @svg('tabler-square-number-'.$num, $itemblocks->layoutgrid == (string) $num ? 'stroke-blue-500' : '') + + @endforeach +
+
+ @else +
+ {{ __('Width') }} +
+ + + + + + + + + +
+
+ @endif +
diff --git a/resources/views/components/block-controls/link.blade.php b/resources/views/components/block-controls/link.blade.php new file mode 100644 index 00000000..22213e73 --- /dev/null +++ b/resources/views/components/block-controls/link.blade.php @@ -0,0 +1,5 @@ +@props(['itemblocks']) + + + + diff --git a/resources/views/components/blocks-datafield.blade.php b/resources/views/components/blocks-datafield.blade.php index 97086a77..6223abe8 100644 --- a/resources/views/components/blocks-datafield.blade.php +++ b/resources/views/components/blocks-datafield.blade.php @@ -20,38 +20,7 @@ @default @foreach ($itemblocks->datafield as $item)
- @switch($item['type']) - @case('true_false') - - @break - - @case('image') - - @break - - @case('wysiwyg') - - @break - - @case('buttom') - - @break - - @case('link') - - @break - - @case('file') - - @break - - @case('color') - - @break - - @default - - @endswitch +
@endforeach @endswitch diff --git a/resources/views/components/blocks/palette-tile.blade.php b/resources/views/components/blocks/palette-tile.blade.php new file mode 100644 index 00000000..ca0cfff0 --- /dev/null +++ b/resources/views/components/blocks/palette-tile.blade.php @@ -0,0 +1,20 @@ +@props(['entry']) + +{{-- One add-block palette tile. $entry comes from block_registry()->palette(). --}} +
+ + @if (! empty($entry['image'])) + + @elseif (! empty($entry['icon_svg'])) +
+
+
+ @svg(str_starts_with($entry['icon_svg'], 'tabler-') ? $entry['icon_svg'] : 'tabler-' . $entry['icon_svg'], 'text-blue-500 flex justify-center items-end w-full h-full') +
+
+
+ @endif + + {{ $entry['name'] }} +
diff --git a/resources/views/components/blocksgroup.blade.php b/resources/views/components/blocksgroup.blade.php index ddfd693d..d8809b9b 100644 --- a/resources/views/components/blocksgroup.blade.php +++ b/resources/views/components/blocksgroup.blade.php @@ -6,18 +6,12 @@ ]) @php - $isContainer = in_array($itemblocks->type, ['group', 'accordiongroup']); + $isContainer = block_registry()->isContainer($itemblocks->type); $hasChildren = $itemblocks->children->isNotEmpty(); $showNest = $isContainer || $hasChildren; - // Divi-style colour coding by hierarchy: layout = indigo, accordion = emerald, module = slate. - $style = match ($itemblocks->type) { - 'group' => ['rail' => 'border-l-indigo-500', 'badge' => 'bg-indigo-500', 'bar' => 'bg-indigo-500/10', 'accent' => 'text-indigo-600'], - 'accordiongroup' => ['rail' => 'border-l-emerald-500', 'badge' => 'bg-emerald-500', 'bar' => 'bg-emerald-500/10', 'accent' => 'text-emerald-600'], - 'video' => ['rail' => 'border-l-red-600', 'badge' => 'bg-slate-500', 'bar' => 'bg-slate-600/10', 'accent' => 'text-red-600'], - 'gallery' => ['rail' => 'border-l-blue-500', 'badge' => 'bg-blue-500', 'bar' => 'bg-blue-500/10', 'accent' => 'text-blue-600'], - default => ['rail' => 'border-l-slate-400', 'badge' => 'bg-slate-500', 'bar' => 'bg-base-200', 'accent' => 'text-slate-500'], - }; + // Colour coding by block type, resolved from the central block-type registry. + $style = block_registry()->styling($itemblocks->type); // Per-block custom colour (set via the block settings offcanvas). When present it // overrides the type-based palette above via inline styles (a custom hex can't be a Tailwind class). @@ -90,7 +84,7 @@ class="shrink-0 mr-1 {{ $accentClass }} transition-transform duration-200" {{-- Right: actions --}}
- @if ($itemblocks->type == 'group' || $itemblocks->type == 'accordiongroup') + @if ($isContainer) {{-- Inline icons: visible when container >= 380px --}}