Implemented a block editor for changing the layout of the page

This commit is contained in:
2026-04-04 01:17:05 +02:00
parent 0800f7664f
commit ff58e82497
41 changed files with 2706 additions and 298 deletions

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('page_blocks', function (Blueprint $table) {
$table->id();
$table->foreignId('preregistration_page_id')->constrained()->cascadeOnDelete();
$table->string('type');
$table->json('content');
$table->integer('sort_order')->default(0);
$table->boolean('is_visible')->default(true);
$table->timestamps();
$table->index(['preregistration_page_id', 'sort_order']);
});
}
public function down(): void
{
Schema::dropIfExists('page_blocks');
}
};

View File

@@ -0,0 +1,117 @@
<?php
declare(strict_types=1);
use App\Models\PageBlock;
use App\Models\PreregistrationPage;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
DB::transaction(function (): void {
PreregistrationPage::query()->orderBy('id')->get()->each(function (PreregistrationPage $page): void {
if ($page->blocks()->exists()) {
return;
}
$sort = 0;
$heroContent = [
'headline' => $page->heading,
'subheadline' => $page->intro_text ?? '',
'eyebrow_text' => '',
'eyebrow_style' => 'badge',
'logo_max_height' => 80,
'background_image' => $page->background_image,
'logo_image' => $page->logo_image,
'overlay_color' => '#000000',
'overlay_opacity' => 50,
'text_alignment' => 'center',
];
PageBlock::query()->create([
'preregistration_page_id' => $page->id,
'type' => 'hero',
'content' => $heroContent,
'sort_order' => $sort++,
'is_visible' => true,
]);
if ($page->start_date->isFuture()) {
PageBlock::query()->create([
'preregistration_page_id' => $page->id,
'type' => 'countdown',
'content' => [
'target_datetime' => $page->start_date->toIso8601String(),
'title' => 'De pre-registratie opent over:',
'expired_action' => 'reload',
'style' => 'large',
'show_labels' => true,
'labels' => [
'days' => 'dagen',
'hours' => 'uren',
'minutes' => 'minuten',
'seconds' => 'seconden',
],
],
'sort_order' => $sort++,
'is_visible' => true,
]);
}
$formContent = [
'title' => 'Registreer nu',
'description' => '',
'button_label' => 'Registreer nu!',
'button_color' => '#F47B20',
'button_text_color' => '#FFFFFF',
'fields' => [
'first_name' => [
'enabled' => true,
'required' => true,
'label' => 'Voornaam',
'placeholder' => 'Je voornaam',
],
'last_name' => [
'enabled' => true,
'required' => true,
'label' => 'Achternaam',
'placeholder' => 'Je achternaam',
],
'email' => [
'enabled' => true,
'required' => true,
'label' => 'E-mailadres',
'placeholder' => 'je@email.nl',
],
'phone' => [
'enabled' => (bool) $page->phone_enabled,
'required' => false,
'label' => 'Mobiel',
'placeholder' => '+31 6 12345678',
],
],
'show_field_icons' => true,
'privacy_text' => 'Door je te registreren ga je akkoord met onze privacyverklaring.',
'privacy_url' => '',
];
PageBlock::query()->create([
'preregistration_page_id' => $page->id,
'type' => 'form',
'content' => $formContent,
'sort_order' => $sort++,
'is_visible' => true,
]);
});
});
}
public function down(): void
{
PageBlock::query()->delete();
}
};

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Run only after verifying block-based editor and public pages in production.
* Uncomment the Schema::table bodies when ready to drop legacy columns.
*/
return new class extends Migration
{
public function up(): void
{
// Schema::table('preregistration_pages', function (Blueprint $table) {
// $table->dropColumn([
// 'heading',
// 'intro_text',
// 'phone_enabled',
// 'background_image',
// 'logo_image',
// ]);
// });
}
public function down(): void
{
// Schema::table('preregistration_pages', function (Blueprint $table) {
// $table->string('heading')->after('title');
// $table->text('intro_text')->nullable()->after('heading');
// $table->boolean('phone_enabled')->default(false)->after('end_date');
// $table->string('background_image')->nullable()->after('phone_enabled');
// $table->string('logo_image')->nullable()->after('background_image');
// });
}
};

View File

@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
use App\Models\PageBlock;
use App\Models\PreregistrationPage;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('preregistration_pages', function (Blueprint $table) {
$table->string('background_overlay_color', 7)->default('#000000')->after('background_image');
$table->unsignedTinyInteger('background_overlay_opacity')->default(50)->after('background_overlay_color');
$table->string('post_submit_redirect_url')->nullable()->after('ticketshop_url');
});
PreregistrationPage::query()->orderBy('id')->each(function (PreregistrationPage $page): void {
$page->load(['blocks' => fn ($q) => $q->orderBy('sort_order')]);
$hero = $page->blocks->firstWhere('type', 'hero');
if ($hero === null) {
return;
}
/** @var array<string, mixed> $c */
$c = is_array($hero->content) ? $hero->content : [];
$pageUpdates = [];
if (($page->background_image === null || $page->background_image === '')
&& isset($c['background_image']) && is_string($c['background_image']) && $c['background_image'] !== '') {
$pageUpdates['background_image'] = $c['background_image'];
}
$oc = $c['overlay_color'] ?? null;
if (is_string($oc) && preg_match('/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/', $oc) === 1) {
$pageUpdates['background_overlay_color'] = $oc;
}
$oo = $c['overlay_opacity'] ?? null;
if (is_numeric($oo)) {
$pageUpdates['background_overlay_opacity'] = max(0, min(100, (int) $oo));
}
if ($pageUpdates !== []) {
$page->update($pageUpdates);
}
$logoPath = $c['logo_image'] ?? null;
unset(
$c['logo_image'],
$c['logo_max_height'],
$c['background_image'],
$c['overlay_color'],
$c['overlay_opacity'],
);
$hero->update(['content' => $c]);
if (is_string($logoPath) && $logoPath !== '') {
PageBlock::query()
->where('preregistration_page_id', $page->id)
->where('sort_order', '>=', 1)
->increment('sort_order');
PageBlock::query()->create([
'preregistration_page_id' => $page->id,
'type' => 'image',
'content' => [
'image' => $logoPath,
'link_url' => '',
'alt' => '',
'max_width_px' => 240,
'text_alignment' => 'center',
],
'sort_order' => 1,
'is_visible' => true,
]);
}
});
}
public function down(): void
{
Schema::table('preregistration_pages', function (Blueprint $table) {
$table->dropColumn([
'background_overlay_color',
'background_overlay_opacity',
'post_submit_redirect_url',
]);
});
}
};