feat: enhance TestimonialsBlock with advanced slider options

Slider Settings:
- Animation types: slide, fade, cards, coverflow, none
- Configurable speed (300-800ms)
- Slides per view (1-3 or auto)
- Gap between slides

Navigation:
- Arrow controls with 5 styles and 4 positions
- Dots/pagination with 5 styles (dots, lines, numbers, progress, fraction)
- Touch swipe and keyboard navigation support

Display Options:
- Show/hide: rating, image, company, source, date
- Text truncation with configurable max length

Styling:
- 5 background options
- 4 card styles (shadow, border, flat, glass)
- 4 quote styles
- Image position and size controls
- Text alignment and spacing

Accessibility:
- ARIA labels (localized)
- Reduced motion preference support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Martin Porwoll 2025-12-13 20:37:35 +00:00
parent 4f6280e09e
commit 8116180955
3 changed files with 753 additions and 62 deletions

View file

@ -2,7 +2,11 @@ import type { Block } from 'payload'
/**
* Testimonials Block
* Zeigt Kundenstimmen aus der Testimonials Collection
*
* Zeigt Kundenstimmen aus der Testimonials Collection mit:
* - Verschiedenen Layouts (Slider, Grid, Masonry, Liste)
* - Erweiterten Slider-Optionen (Animation, Navigation, Autoplay)
* - Flexiblen Anzeigeoptionen
*/
export const TestimonialsBlock: Block = {
slug: 'testimonials-block',
@ -11,6 +15,7 @@ export const TestimonialsBlock: Block = {
plural: 'Testimonials',
},
fields: [
// Überschrift & Untertitel
{
name: 'title',
type: 'text',
@ -24,6 +29,8 @@ export const TestimonialsBlock: Block = {
label: 'Untertitel',
localized: true,
},
// Layout-Auswahl
{
name: 'layout',
type: 'select',
@ -48,10 +55,12 @@ export const TestimonialsBlock: Block = {
{ label: '4 Spalten', value: '4' },
],
admin: {
condition: (data, siblingData) =>
condition: (_, siblingData) =>
siblingData?.layout === 'grid' || siblingData?.layout === 'masonry',
},
},
// Testimonial-Auswahl
{
name: 'displayMode',
type: 'select',
@ -70,7 +79,7 @@ export const TestimonialsBlock: Block = {
hasMany: true,
label: 'Testimonials auswählen',
admin: {
condition: (data, siblingData) => siblingData?.displayMode === 'selected',
condition: (_, siblingData) => siblingData?.displayMode === 'selected',
},
},
{
@ -81,64 +90,402 @@ export const TestimonialsBlock: Block = {
max: 20,
label: 'Maximale Anzahl',
admin: {
condition: (data, siblingData) => siblingData?.displayMode === 'all',
condition: (_, siblingData) => siblingData?.displayMode === 'all',
},
},
// Anzeige-Optionen
{
name: 'showRating',
type: 'checkbox',
defaultValue: true,
label: 'Sterne-Bewertung anzeigen',
name: 'displayOptions',
type: 'group',
label: 'Anzeige-Optionen',
fields: [
{
name: 'showRating',
type: 'checkbox',
defaultValue: true,
label: 'Sterne-Bewertung anzeigen',
},
{
name: 'showImage',
type: 'checkbox',
defaultValue: true,
label: 'Foto anzeigen',
},
{
name: 'showCompany',
type: 'checkbox',
defaultValue: true,
label: 'Unternehmen anzeigen',
},
{
name: 'showSource',
type: 'checkbox',
defaultValue: false,
label: 'Quelle anzeigen',
},
{
name: 'showDate',
type: 'checkbox',
defaultValue: false,
label: 'Datum anzeigen',
},
{
name: 'truncateText',
type: 'checkbox',
defaultValue: false,
label: 'Text kürzen',
admin: {
description: 'Lange Testimonials werden abgeschnitten mit "Mehr lesen"',
},
},
{
name: 'maxLength',
type: 'number',
defaultValue: 200,
min: 100,
max: 500,
label: 'Max. Zeichenanzahl',
admin: {
condition: (_, siblingData) => siblingData?.truncateText,
},
},
],
},
// Slider-Einstellungen (nur bei layout=slider)
{
name: 'showImage',
type: 'checkbox',
defaultValue: true,
label: 'Foto anzeigen',
},
{
name: 'showCompany',
type: 'checkbox',
defaultValue: true,
label: 'Unternehmen anzeigen',
},
{
name: 'showSource',
type: 'checkbox',
defaultValue: false,
label: 'Quelle anzeigen',
},
{
name: 'autoplay',
type: 'checkbox',
defaultValue: true,
label: 'Automatisch wechseln',
name: 'slider',
type: 'group',
label: 'Slider-Einstellungen',
admin: {
condition: (data, siblingData) => siblingData?.layout === 'slider',
condition: (_, siblingData) => siblingData?.layout === 'slider',
},
fields: [
// Animation
{
name: 'effect',
type: 'select',
defaultValue: 'slide',
label: 'Animationstyp',
options: [
{ label: 'Schieben (Slide)', value: 'slide' },
{ label: 'Überblenden (Fade)', value: 'fade' },
{ label: 'Karten (Cards)', value: 'cards' },
{ label: 'Coverflow', value: 'coverflow' },
{ label: 'Keine Animation', value: 'none' },
],
},
{
name: 'speed',
type: 'select',
defaultValue: '500',
label: 'Animationsdauer',
options: [
{ label: 'Schnell (300ms)', value: '300' },
{ label: 'Normal (500ms)', value: '500' },
{ label: 'Langsam (800ms)', value: '800' },
],
},
// Anzahl sichtbarer Slides
{
name: 'perView',
type: 'select',
defaultValue: '1',
label: 'Sichtbare Testimonials',
options: [
{ label: '1 (Vollbild)', value: '1' },
{ label: '2', value: '2' },
{ label: '3', value: '3' },
{ label: 'Auto (responsive)', value: 'auto' },
],
admin: {
description: 'Anzahl gleichzeitig sichtbarer Testimonials',
},
},
{
name: 'gap',
type: 'select',
defaultValue: '24',
label: 'Abstand zwischen Slides',
options: [
{ label: 'Kein Abstand', value: '0' },
{ label: 'Klein (16px)', value: '16' },
{ label: 'Normal (24px)', value: '24' },
{ label: 'Groß (32px)', value: '32' },
{ label: 'Sehr groß (48px)', value: '48' },
],
},
// Autoplay
{
name: 'auto',
type: 'checkbox',
defaultValue: true,
label: 'Autoplay aktivieren',
},
{
name: 'delay',
type: 'select',
defaultValue: '5000',
label: 'Intervall',
options: [
{ label: '3 Sekunden', value: '3000' },
{ label: '4 Sekunden', value: '4000' },
{ label: '5 Sekunden', value: '5000' },
{ label: '6 Sekunden', value: '6000' },
{ label: '8 Sekunden', value: '8000' },
{ label: '10 Sekunden', value: '10000' },
],
admin: {
condition: (_, siblingData) => siblingData?.auto,
},
},
{
name: 'hoverPause',
type: 'checkbox',
defaultValue: true,
label: 'Bei Hover pausieren',
admin: {
condition: (_, siblingData) => siblingData?.auto,
},
},
// Loop
{
name: 'loop',
type: 'checkbox',
defaultValue: true,
label: 'Endlosschleife',
},
// Zentrierung
{
name: 'centered',
type: 'checkbox',
defaultValue: false,
label: 'Aktiven Slide zentrieren',
admin: {
description: 'Der aktive Slide wird in der Mitte angezeigt',
},
},
],
},
// Navigation
{
name: 'autoplaySpeed',
type: 'number',
defaultValue: 5000,
min: 2000,
max: 15000,
label: 'Wechselintervall (ms)',
name: 'nav',
type: 'group',
label: 'Navigation',
admin: {
condition: (data, siblingData) =>
siblingData?.layout === 'slider' && siblingData?.autoplay,
condition: (_, siblingData) => siblingData?.layout === 'slider',
},
fields: [
// Pfeile
{
name: 'arrows',
type: 'checkbox',
defaultValue: true,
label: 'Pfeile anzeigen',
},
{
name: 'arrowStyle',
type: 'select',
defaultValue: 'default',
label: 'Pfeil-Stil',
options: [
{ label: 'Standard (Kreis)', value: 'default' },
{ label: 'Minimal', value: 'minimal' },
{ label: 'Eckig', value: 'square' },
{ label: 'Nur bei Hover', value: 'hover' },
{ label: 'Außerhalb', value: 'outside' },
],
admin: {
condition: (_, siblingData) => siblingData?.arrows,
},
},
{
name: 'arrowPos',
type: 'select',
defaultValue: 'sides',
label: 'Pfeil-Position',
options: [
{ label: 'Seitlich', value: 'sides' },
{ label: 'Unten links', value: 'bl' },
{ label: 'Unten rechts', value: 'br' },
{ label: 'Unten zentriert', value: 'bc' },
],
admin: {
condition: (_, siblingData) => siblingData?.arrows,
},
},
// Dots/Pagination
{
name: 'dots',
type: 'checkbox',
defaultValue: true,
label: 'Punkte anzeigen',
},
{
name: 'dotStyle',
type: 'select',
defaultValue: 'dots',
label: 'Punkte-Stil',
options: [
{ label: 'Punkte (rund)', value: 'dots' },
{ label: 'Striche', value: 'lines' },
{ label: 'Nummern', value: 'numbers' },
{ label: 'Fortschritt', value: 'progress' },
{ label: 'Fraktion (1/5)', value: 'fraction' },
],
admin: {
condition: (_, siblingData) => siblingData?.dots,
},
},
{
name: 'dotPos',
type: 'select',
defaultValue: 'bottom',
label: 'Punkte-Position',
options: [
{ label: 'Unten', value: 'bottom' },
{ label: 'Unten links', value: 'bl' },
{ label: 'Unten rechts', value: 'br' },
],
admin: {
condition: (_, siblingData) => siblingData?.dots,
},
},
// Touch & Keyboard
{
name: 'swipe',
type: 'checkbox',
defaultValue: true,
label: 'Touch-Swipe aktivieren',
},
{
name: 'keys',
type: 'checkbox',
defaultValue: true,
label: 'Tastaturnavigation',
},
],
},
// Darstellung
{
name: 'backgroundColor',
type: 'select',
defaultValue: 'light',
label: 'Hintergrund',
options: [
{ label: 'Weiß', value: 'white' },
{ label: 'Hell (Grau)', value: 'light' },
{ label: 'Dunkel', value: 'dark' },
{ label: 'Akzentfarbe', value: 'accent' },
name: 'style',
type: 'group',
label: 'Darstellung',
fields: [
{
name: 'bg',
type: 'select',
defaultValue: 'light',
label: 'Hintergrund',
options: [
{ label: 'Weiß', value: 'white' },
{ label: 'Hell (Grau)', value: 'light' },
{ label: 'Dunkel', value: 'dark' },
{ label: 'Akzentfarbe', value: 'accent' },
{ label: 'Transparent', value: 'none' },
],
},
{
name: 'card',
type: 'select',
defaultValue: 'shadow',
label: 'Karten-Stil',
options: [
{ label: 'Karte mit Schatten', value: 'shadow' },
{ label: 'Karte mit Rahmen', value: 'border' },
{ label: 'Flach (kein Rand)', value: 'flat' },
{ label: 'Glassmorphism', value: 'glass' },
],
},
{
name: 'quote',
type: 'select',
defaultValue: 'icon',
label: 'Zitat-Stil',
options: [
{ label: 'Mit Icon', value: 'icon' },
{ label: 'Anführungszeichen', value: 'quotes' },
{ label: 'Ohne', value: 'none' },
{ label: 'Groß', value: 'large' },
],
},
{
name: 'imgPos',
type: 'select',
defaultValue: 'top',
label: 'Bild-Position',
options: [
{ label: 'Oben', value: 'top' },
{ label: 'Links', value: 'left' },
{ label: 'Unten', value: 'bottom' },
{ label: 'Hintergrund', value: 'bg' },
],
},
{
name: 'imgSize',
type: 'select',
defaultValue: 'md',
label: 'Bild-Größe',
options: [
{ label: 'Klein (48px)', value: 'sm' },
{ label: 'Mittel (64px)', value: 'md' },
{ label: 'Groß (80px)', value: 'lg' },
{ label: 'Sehr groß (96px)', value: 'xl' },
],
},
{
name: 'align',
type: 'select',
defaultValue: 'center',
label: 'Text-Ausrichtung',
options: [
{ label: 'Links', value: 'left' },
{ label: 'Zentriert', value: 'center' },
{ label: 'Rechts', value: 'right' },
],
},
{
name: 'spacing',
type: 'select',
defaultValue: 'normal',
label: 'Innenabstand',
options: [
{ label: 'Kompakt', value: 'sm' },
{ label: 'Normal', value: 'normal' },
{ label: 'Großzügig', value: 'lg' },
],
},
],
},
// Accessibility (nur für Slider)
{
name: 'a11y',
type: 'group',
label: 'Barrierefreiheit',
admin: {
condition: (_, siblingData) => siblingData?.layout === 'slider',
},
fields: [
{
name: 'label',
type: 'text',
defaultValue: 'Kundenstimmen',
label: 'ARIA Label',
localized: true,
},
{
name: 'reducedMotion',
type: 'checkbox',
defaultValue: true,
label: 'Reduzierte Bewegung respektieren',
admin: {
description: 'Autoplay deaktivieren bei "prefers-reduced-motion"',
},
},
],
},
],

View file

@ -0,0 +1,250 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
/**
* Migration: Testimonials Block Slider Enhancement
*
* Erweitert den TestimonialsBlock um:
* - Slider-Einstellungen (Animation, Geschwindigkeit, sichtbare Slides)
* - Navigation (Pfeile, Dots, Swipe, Keyboard)
* - Darstellungsoptionen (Hintergrund, Kartendesign, Zitate, Bilder)
* - Barrierefreiheit (ARIA Label, Reduced Motion)
*
* Da die Tabelle leer ist, wird sie komplett neu erstellt.
*/
export async function up({ db }: MigrateUpArgs): Promise<void> {
// Drop existing tables and enums (keine Daten vorhanden)
await db.execute(sql`
DROP TABLE IF EXISTS "pages_blocks_testimonials_block_selected_testimonials" CASCADE;
DROP TABLE IF EXISTS "pages_blocks_testimonials_block_locales" CASCADE;
DROP TABLE IF EXISTS "pages_blocks_testimonials_block" CASCADE;
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_layout";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_columns";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_display_mode";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_background_color";
`)
// Create new enums
await db.execute(sql`
CREATE TYPE "enum_pages_blocks_testimonials_block_layout" AS ENUM('slider', 'grid', 'single', 'masonry', 'list');
CREATE TYPE "enum_pages_blocks_testimonials_block_columns" AS ENUM('2', '3', '4');
CREATE TYPE "enum_pages_blocks_testimonials_block_display_mode" AS ENUM('all', 'selected');
-- Slider settings
CREATE TYPE "enum_pages_blocks_testimonials_block_slider_effect" AS ENUM('slide', 'fade', 'cards', 'coverflow', 'none');
CREATE TYPE "enum_pages_blocks_testimonials_block_slider_speed" AS ENUM('300', '500', '800');
CREATE TYPE "enum_pages_blocks_testimonials_block_slider_per_view" AS ENUM('1', '2', '3', 'auto');
CREATE TYPE "enum_pages_blocks_testimonials_block_slider_gap" AS ENUM('0', '16', '24', '32', '48');
CREATE TYPE "enum_pages_blocks_testimonials_block_slider_delay" AS ENUM('3000', '4000', '5000', '6000', '8000', '10000');
-- Navigation
CREATE TYPE "enum_pages_blocks_testimonials_block_nav_arrow_style" AS ENUM('default', 'minimal', 'square', 'hover', 'outside');
CREATE TYPE "enum_pages_blocks_testimonials_block_nav_arrow_pos" AS ENUM('sides', 'bl', 'br', 'bc');
CREATE TYPE "enum_pages_blocks_testimonials_block_nav_dot_style" AS ENUM('dots', 'lines', 'numbers', 'progress', 'fraction');
CREATE TYPE "enum_pages_blocks_testimonials_block_nav_dot_pos" AS ENUM('bottom', 'bl', 'br');
-- Style
CREATE TYPE "enum_pages_blocks_testimonials_block_style_bg" AS ENUM('white', 'light', 'dark', 'accent', 'none');
CREATE TYPE "enum_pages_blocks_testimonials_block_style_card" AS ENUM('shadow', 'border', 'flat', 'glass');
CREATE TYPE "enum_pages_blocks_testimonials_block_style_quote" AS ENUM('icon', 'quotes', 'none', 'large');
CREATE TYPE "enum_pages_blocks_testimonials_block_style_img_pos" AS ENUM('top', 'left', 'bottom', 'bg');
CREATE TYPE "enum_pages_blocks_testimonials_block_style_img_size" AS ENUM('sm', 'md', 'lg', 'xl');
CREATE TYPE "enum_pages_blocks_testimonials_block_style_align" AS ENUM('left', 'center', 'right');
CREATE TYPE "enum_pages_blocks_testimonials_block_style_spacing" AS ENUM('sm', 'normal', 'lg');
`)
// Create main table
await db.execute(sql`
CREATE TABLE "pages_blocks_testimonials_block" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
-- Basic settings
"layout" "enum_pages_blocks_testimonials_block_layout" DEFAULT 'slider',
"columns" "enum_pages_blocks_testimonials_block_columns" DEFAULT '3',
"display_mode" "enum_pages_blocks_testimonials_block_display_mode" DEFAULT 'all',
"limit" numeric DEFAULT 6,
-- Display options
"display_options_show_rating" boolean DEFAULT true,
"display_options_show_image" boolean DEFAULT true,
"display_options_show_company" boolean DEFAULT true,
"display_options_show_source" boolean DEFAULT false,
"display_options_show_date" boolean DEFAULT false,
"display_options_truncate_text" boolean DEFAULT false,
"display_options_max_length" numeric DEFAULT 200,
-- Slider settings
"slider_effect" "enum_pages_blocks_testimonials_block_slider_effect" DEFAULT 'slide',
"slider_speed" "enum_pages_blocks_testimonials_block_slider_speed" DEFAULT '500',
"slider_per_view" "enum_pages_blocks_testimonials_block_slider_per_view" DEFAULT '1',
"slider_gap" "enum_pages_blocks_testimonials_block_slider_gap" DEFAULT '24',
"slider_auto" boolean DEFAULT true,
"slider_delay" "enum_pages_blocks_testimonials_block_slider_delay" DEFAULT '5000',
"slider_hover_pause" boolean DEFAULT true,
"slider_loop" boolean DEFAULT true,
"slider_centered" boolean DEFAULT false,
-- Navigation
"nav_arrows" boolean DEFAULT true,
"nav_arrow_style" "enum_pages_blocks_testimonials_block_nav_arrow_style" DEFAULT 'default',
"nav_arrow_pos" "enum_pages_blocks_testimonials_block_nav_arrow_pos" DEFAULT 'sides',
"nav_dots" boolean DEFAULT true,
"nav_dot_style" "enum_pages_blocks_testimonials_block_nav_dot_style" DEFAULT 'dots',
"nav_dot_pos" "enum_pages_blocks_testimonials_block_nav_dot_pos" DEFAULT 'bottom',
"nav_swipe" boolean DEFAULT true,
"nav_keys" boolean DEFAULT true,
-- Style
"style_bg" "enum_pages_blocks_testimonials_block_style_bg" DEFAULT 'light',
"style_card" "enum_pages_blocks_testimonials_block_style_card" DEFAULT 'shadow',
"style_quote" "enum_pages_blocks_testimonials_block_style_quote" DEFAULT 'icon',
"style_img_pos" "enum_pages_blocks_testimonials_block_style_img_pos" DEFAULT 'top',
"style_img_size" "enum_pages_blocks_testimonials_block_style_img_size" DEFAULT 'md',
"style_align" "enum_pages_blocks_testimonials_block_style_align" DEFAULT 'center',
"style_spacing" "enum_pages_blocks_testimonials_block_style_spacing" DEFAULT 'normal',
-- Accessibility
"a11y_reduced_motion" boolean DEFAULT true,
"block_name" varchar
);
`)
// Create locales table
await db.execute(sql`
CREATE TABLE "pages_blocks_testimonials_block_locales" (
"title" varchar DEFAULT 'Das sagen unsere Kunden',
"subtitle" varchar,
"a11y_label" varchar DEFAULT 'Kundenstimmen',
"id" serial PRIMARY KEY NOT NULL,
"_locale" "_locales" NOT NULL,
"_parent_id" varchar NOT NULL
);
`)
// Create relationships table for selected testimonials
await db.execute(sql`
CREATE TABLE "pages_blocks_testimonials_block_selected_testimonials" (
"_order" integer NOT NULL,
"_parent_id" varchar NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"testimonials_id" integer
);
`)
// Add foreign keys and indexes
await db.execute(sql`
ALTER TABLE "pages_blocks_testimonials_block"
ADD CONSTRAINT "pages_blocks_testimonials_block_parent_id_fk"
FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "pages_blocks_testimonials_block_locales"
ADD CONSTRAINT "pages_blocks_testimonials_block_locales_parent_id_fk"
FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_testimonials_block"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "pages_blocks_testimonials_block_selected_testimonials"
ADD CONSTRAINT "pages_blocks_testimonials_block_sel_test_parent_id_fk"
FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_testimonials_block"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "pages_blocks_testimonials_block_selected_testimonials"
ADD CONSTRAINT "pages_blocks_testimonials_block_sel_test_testimonials_id_fk"
FOREIGN KEY ("testimonials_id") REFERENCES "public"."testimonials"("id") ON DELETE set null ON UPDATE no action;
CREATE INDEX "pages_blocks_testimonials_block_order_idx" ON "pages_blocks_testimonials_block" USING btree ("_order");
CREATE INDEX "pages_blocks_testimonials_block_parent_id_idx" ON "pages_blocks_testimonials_block" USING btree ("_parent_id");
CREATE INDEX "pages_blocks_testimonials_block_path_idx" ON "pages_blocks_testimonials_block" USING btree ("_path");
CREATE UNIQUE INDEX "pages_blocks_testimonials_block_locales_locale_parent_id_uniq"
ON "pages_blocks_testimonials_block_locales" USING btree ("_locale", "_parent_id");
CREATE INDEX "pages_blocks_testimonials_block_sel_test_order_idx"
ON "pages_blocks_testimonials_block_selected_testimonials" USING btree ("_order");
CREATE INDEX "pages_blocks_testimonials_block_sel_test_parent_id_idx"
ON "pages_blocks_testimonials_block_selected_testimonials" USING btree ("_parent_id");
`)
}
export async function down({ db }: MigrateDownArgs): Promise<void> {
// Drop new tables
await db.execute(sql`
DROP TABLE IF EXISTS "pages_blocks_testimonials_block_selected_testimonials" CASCADE;
DROP TABLE IF EXISTS "pages_blocks_testimonials_block_locales" CASCADE;
DROP TABLE IF EXISTS "pages_blocks_testimonials_block" CASCADE;
`)
// Drop new enums
await db.execute(sql`
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_layout";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_columns";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_display_mode";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_slider_effect";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_slider_speed";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_slider_per_view";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_slider_gap";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_slider_delay";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_nav_arrow_style";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_nav_arrow_pos";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_nav_dot_style";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_nav_dot_pos";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_style_bg";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_style_card";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_style_quote";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_style_img_pos";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_style_img_size";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_style_align";
DROP TYPE IF EXISTS "enum_pages_blocks_testimonials_block_style_spacing";
`)
// Recreate original structure
await db.execute(sql`
CREATE TYPE "enum_pages_blocks_testimonials_block_layout" AS ENUM('slider', 'grid', 'single', 'masonry', 'list');
CREATE TYPE "enum_pages_blocks_testimonials_block_columns" AS ENUM('2', '3', '4');
CREATE TYPE "enum_pages_blocks_testimonials_block_display_mode" AS ENUM('all', 'selected');
CREATE TYPE "enum_pages_blocks_testimonials_block_background_color" AS ENUM('white', 'light', 'dark', 'accent');
CREATE TABLE "pages_blocks_testimonials_block" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"layout" "enum_pages_blocks_testimonials_block_layout" DEFAULT 'slider',
"columns" "enum_pages_blocks_testimonials_block_columns" DEFAULT '3',
"display_mode" "enum_pages_blocks_testimonials_block_display_mode" DEFAULT 'all',
"limit" numeric DEFAULT 6,
"show_rating" boolean DEFAULT true,
"show_image" boolean DEFAULT true,
"show_company" boolean DEFAULT true,
"show_source" boolean DEFAULT false,
"autoplay" boolean DEFAULT true,
"autoplay_speed" numeric DEFAULT 5000,
"background_color" "enum_pages_blocks_testimonials_block_background_color" DEFAULT 'light',
"block_name" varchar
);
CREATE TABLE "pages_blocks_testimonials_block_locales" (
"title" varchar DEFAULT 'Das sagen unsere Kunden',
"subtitle" varchar,
"id" serial PRIMARY KEY NOT NULL,
"_locale" "_locales" NOT NULL,
"_parent_id" varchar NOT NULL
);
ALTER TABLE "pages_blocks_testimonials_block"
ADD CONSTRAINT "pages_blocks_testimonials_block_parent_id_fk"
FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "pages_blocks_testimonials_block_locales"
ADD CONSTRAINT "pages_blocks_testimonials_block_locales_parent_id_fk"
FOREIGN KEY ("_parent_id") REFERENCES "public"."pages_blocks_testimonials_block"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "pages_blocks_testimonials_block_order_idx" ON "pages_blocks_testimonials_block" USING btree ("_order");
CREATE INDEX "pages_blocks_testimonials_block_parent_id_idx" ON "pages_blocks_testimonials_block" USING btree ("_parent_id");
CREATE INDEX "pages_blocks_testimonials_block_path_idx" ON "pages_blocks_testimonials_block" USING btree ("_path");
CREATE UNIQUE INDEX "pages_blocks_testimonials_block_locales_locale_parent_id_uniq"
ON "pages_blocks_testimonials_block_locales" USING btree ("_locale", "_parent_id");
`)
}

View file

@ -720,13 +720,61 @@ export interface Page {
displayMode?: ('all' | 'selected') | null;
selectedTestimonials?: (number | Testimonial)[] | null;
limit?: number | null;
showRating?: boolean | null;
showImage?: boolean | null;
showCompany?: boolean | null;
showSource?: boolean | null;
autoplay?: boolean | null;
autoplaySpeed?: number | null;
backgroundColor?: ('white' | 'light' | 'dark' | 'accent') | null;
displayOptions?: {
showRating?: boolean | null;
showImage?: boolean | null;
showCompany?: boolean | null;
showSource?: boolean | null;
showDate?: boolean | null;
/**
* Lange Testimonials werden abgeschnitten mit "Mehr lesen"
*/
truncateText?: boolean | null;
maxLength?: number | null;
};
slider?: {
effect?: ('slide' | 'fade' | 'cards' | 'coverflow' | 'none') | null;
speed?: ('300' | '500' | '800') | null;
/**
* Anzahl gleichzeitig sichtbarer Testimonials
*/
perView?: ('1' | '2' | '3' | 'auto') | null;
gap?: ('0' | '16' | '24' | '32' | '48') | null;
auto?: boolean | null;
delay?: ('3000' | '4000' | '5000' | '6000' | '8000' | '10000') | null;
hoverPause?: boolean | null;
loop?: boolean | null;
/**
* Der aktive Slide wird in der Mitte angezeigt
*/
centered?: boolean | null;
};
nav?: {
arrows?: boolean | null;
arrowStyle?: ('default' | 'minimal' | 'square' | 'hover' | 'outside') | null;
arrowPos?: ('sides' | 'bl' | 'br' | 'bc') | null;
dots?: boolean | null;
dotStyle?: ('dots' | 'lines' | 'numbers' | 'progress' | 'fraction') | null;
dotPos?: ('bottom' | 'bl' | 'br') | null;
swipe?: boolean | null;
keys?: boolean | null;
};
style?: {
bg?: ('white' | 'light' | 'dark' | 'accent' | 'none') | null;
card?: ('shadow' | 'border' | 'flat' | 'glass') | null;
quote?: ('icon' | 'quotes' | 'none' | 'large') | null;
imgPos?: ('top' | 'left' | 'bottom' | 'bg') | null;
imgSize?: ('sm' | 'md' | 'lg' | 'xl') | null;
align?: ('left' | 'center' | 'right') | null;
spacing?: ('sm' | 'normal' | 'lg') | null;
};
a11y?: {
label?: string | null;
/**
* Autoplay deaktivieren bei "prefers-reduced-motion"
*/
reducedMotion?: boolean | null;
};
id?: string | null;
blockName?: string | null;
blockType: 'testimonials-block';
@ -3531,13 +3579,59 @@ export interface PagesSelect<T extends boolean = true> {
displayMode?: T;
selectedTestimonials?: T;
limit?: T;
showRating?: T;
showImage?: T;
showCompany?: T;
showSource?: T;
autoplay?: T;
autoplaySpeed?: T;
backgroundColor?: T;
displayOptions?:
| T
| {
showRating?: T;
showImage?: T;
showCompany?: T;
showSource?: T;
showDate?: T;
truncateText?: T;
maxLength?: T;
};
slider?:
| T
| {
effect?: T;
speed?: T;
perView?: T;
gap?: T;
auto?: T;
delay?: T;
hoverPause?: T;
loop?: T;
centered?: T;
};
nav?:
| T
| {
arrows?: T;
arrowStyle?: T;
arrowPos?: T;
dots?: T;
dotStyle?: T;
dotPos?: T;
swipe?: T;
keys?: T;
};
style?:
| T
| {
bg?: T;
card?: T;
quote?: T;
imgPos?: T;
imgSize?: T;
align?: T;
spacing?: T;
};
a11y?:
| T
| {
label?: T;
reducedMotion?: T;
};
id?: T;
blockName?: T;
};