diff --git a/src/blocks/TestimonialsBlock.ts b/src/blocks/TestimonialsBlock.ts index 3413a6a..c1f8a13 100644 --- a/src/blocks/TestimonialsBlock.ts +++ b/src/blocks/TestimonialsBlock.ts @@ -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"', + }, + }, ], }, ], diff --git a/src/migrations/20251213_160000_testimonials_slider_v2.ts b/src/migrations/20251213_160000_testimonials_slider_v2.ts new file mode 100644 index 0000000..83e24ef --- /dev/null +++ b/src/migrations/20251213_160000_testimonials_slider_v2.ts @@ -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 { + // 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 { + // 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"); + `) +} diff --git a/src/payload-types.ts b/src/payload-types.ts index c196091..6a308a6 100644 --- a/src/payload-types.ts +++ b/src/payload-types.ts @@ -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 { 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; };