PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / quote-collection / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/quote-collection/index.js

179 lines 12.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = wp.element.createElement;
3 var __ = wp.i18n.__;
4 var registerBlockType = wp.blocks.registerBlockType;
5 var InspectorControls = wp.blockEditor.InspectorControls;
6 var useBlockProps = wp.blockEditor.useBlockProps;
7 var RichText = wp.blockEditor.RichText;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var PanelBody = wp.components.PanelBody;
10 var ToggleControl = wp.components.ToggleControl;
11 var RangeControl = wp.components.RangeControl;
12 var SelectControl = wp.components.SelectControl;
13 var TextControl = wp.components.TextControl;
14 var Button = wp.components.Button;
15 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
16 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
17
18 var LAYOUT_OPTIONS = [
19 { value: 'grid', label: 'Grid' },
20 { value: 'list', label: 'List (single column)' },
21 { value: 'masonry', label: 'Masonry (CSS columns)' }
22 ];
23
24 var STYLE_OPTIONS = [
25 { value: 'classic', label: 'Classic (large quote mark)' },
26 { value: 'minimal', label: 'Minimal (no border)' },
27 { value: 'highlight', label: 'Highlight (accent left border)' },
28 { value: 'card', label: 'Card (shadow + border)' }
29 ];
30
31 function emptyQuote() { return { text: '', author: '', role: '', source: '' }; }
32
33 registerBlockType('blockenberg/quote-collection', {
34 edit: function (props) {
35 var attr = props.attributes;
36 var set = props.setAttributes;
37 var quotes = attr.quotes || [emptyQuote()];
38 var TC = getTypoControl();
39
40 var blockProps = useBlockProps({ style: { background: attr.bgColor, paddingTop: attr.paddingTop + 'px', paddingBottom: attr.paddingBottom + 'px' } });
41
42 function updateQuote(idx, field, val) {
43 set({ quotes: quotes.map(function (q, i) {
44 if (i !== idx) return q;
45 var patch = {}; patch[field] = val;
46 return Object.assign({}, q, patch);
47 }) });
48 }
49
50 var gridStyle = {};
51 if (attr.layout === 'grid') {
52 gridStyle = { display: 'grid', gridTemplateColumns: 'repeat(' + attr.columns + ', 1fr)', gap: attr.gap + 'px' };
53 } else if (attr.layout === 'list') {
54 gridStyle = { display: 'flex', flexDirection: 'column', gap: attr.gap + 'px' };
55 } else if (attr.layout === 'masonry') {
56 gridStyle = { columnCount: attr.columns, columnGap: attr.gap + 'px' };
57 }
58
59 function cardStyle() {
60 var s = {
61 background: attr.cardBg,
62 borderRadius: attr.cardRadius + 'px',
63 padding: '20px 22px',
64 position: 'relative',
65 overflow: 'hidden',
66 boxSizing: 'border-box'
67 };
68 if (attr.quoteStyle === 'classic') {
69 s.border = '1px solid ' + attr.cardBorder;
70 } else if (attr.quoteStyle === 'minimal') {
71 /* no extra border */
72 } else if (attr.quoteStyle === 'highlight') {
73 s.borderLeft = '4px solid ' + attr.accentColor;
74 s.border = '1px solid ' + attr.cardBorder;
75 } else if (attr.quoteStyle === 'card') {
76 s.border = '1px solid ' + attr.cardBorder;
77 s.boxShadow = '0 4px 12px rgba(0,0,0,0.08)';
78 }
79 return s;
80 }
81
82 var controls = el(InspectorControls, {},
83 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: true },
84 el(SelectControl, { label: __('Layout', 'blockenberg'), value: attr.layout, options: LAYOUT_OPTIONS, __nextHasNoMarginBottom: true, onChange: function (v) { set({ layout: v }); } }),
85 el('div', { style: { marginTop: '10px' } },
86 el(RangeControl, { label: __('Columns', 'blockenberg'), value: attr.columns, min: 1, max: 4, __nextHasNoMarginBottom: true, onChange: function (v) { set({ columns: v }); } })
87 ),
88 el('div', { style: { marginTop: '10px' } },
89 el(RangeControl, { label: __('Gap', 'blockenberg'), value: attr.gap, min: 0, max: 60, __nextHasNoMarginBottom: true, onChange: function (v) { set({ gap: v }); } })
90 ),
91 el('div', { style: { marginTop: '8px' } },
92 el(SelectControl, { label: __('Card Style', 'blockenberg'), value: attr.quoteStyle, options: STYLE_OPTIONS, __nextHasNoMarginBottom: true, onChange: function (v) { set({ quoteStyle: v }); } })
93 ),
94 el('div', { style: { marginTop: '8px' } },
95 el(RangeControl, { label: __('Card Radius', 'blockenberg'), value: attr.cardRadius, min: 0, max: 30, __nextHasNoMarginBottom: true, onChange: function (v) { set({ cardRadius: v }); } })
96 ),
97 el('div', { style: { marginTop: '8px' } },
98 el(ToggleControl, { label: __('Show Decorative Quote Mark', 'blockenberg'), checked: attr.showQuoteMark, __nextHasNoMarginBottom: true, onChange: function (v) { set({ showQuoteMark: v }); } })
99 )
100 ),
101 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
102 TC && el(TC, { label: __('Quote Text', 'blockenberg'), value: attr.quoteTypo || {}, onChange: function (v) { set({ quoteTypo: v }); } }),
103 TC && el(TC, { label: __('Author', 'blockenberg'), value: attr.authorTypo || {}, onChange: function (v) { set({ authorTypo: v }); } })
104 ),
105 el(PanelBody, { title: __('Section Header', 'blockenberg'), initialOpen: false },
106 el(ToggleControl, { label: __('Show Section Header', 'blockenberg'), checked: attr.showHeader, __nextHasNoMarginBottom: true, onChange: function (v) { set({ showHeader: v }); } }),
107 attr.showHeader && el('div', { style: { marginTop: '8px' } },
108 el(TextControl, { label: __('Title', 'blockenberg'), value: attr.sectionTitle, __nextHasNoMarginBottom: true, onChange: function (v) { set({ sectionTitle: v }); } })
109 ),
110 attr.showHeader && el('div', { style: { marginTop: '8px' } },
111 el(TextControl, { label: __('Subtitle', 'blockenberg'), value: attr.sectionSubtitle, __nextHasNoMarginBottom: true, onChange: function (v) { set({ sectionSubtitle: v }); } })
112 )
113 ),
114 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
115 el(RangeControl, { label: __('Padding Top', 'blockenberg'), value: attr.paddingTop, min: 0, max: 120, __nextHasNoMarginBottom: true, onChange: function (v) { set({ paddingTop: v }); } }),
116 el('div', { style: { marginTop: '10px' } },
117 el(RangeControl, { label: __('Padding Bottom', 'blockenberg'), value: attr.paddingBottom, min: 0, max: 120, __nextHasNoMarginBottom: true, onChange: function (v) { set({ paddingBottom: v }); } })
118 )
119 ),
120 el(PanelColorSettings, {
121 title: __('Colors', 'blockenberg'), initialOpen: false,
122 colorSettings: [
123 { label: __('Section Background', 'blockenberg'), value: attr.bgColor, onChange: function (v) { set({ bgColor: v || '#f8f9fa' }); } },
124 { label: __('Card Background', 'blockenberg'), value: attr.cardBg, onChange: function (v) { set({ cardBg: v || '#ffffff' }); } },
125 { label: __('Card Border', 'blockenberg'), value: attr.cardBorder, onChange: function (v) { set({ cardBorder: v || '#e9ecef' }); } },
126 { label: __('Accent', 'blockenberg'), value: attr.accentColor, onChange: function (v) { set({ accentColor: v || '#6366f1' }); } },
127 { label: __('Quote Mark Decoration', 'blockenberg'), value: attr.quoteMarkColor, onChange: function (v) { set({ quoteMarkColor: v || '#e0e7ff' }); } },
128 { label: __('Quote Text', 'blockenberg'), value: attr.quoteColor, onChange: function (v) { set({ quoteColor: v || '#111827' }); } },
129 { label: __('Author Name', 'blockenberg'), value: attr.authorColor, onChange: function (v) { set({ authorColor: v || '#374151' }); } },
130 { label: __('Author Role', 'blockenberg'), value: attr.roleColor, onChange: function (v) { set({ roleColor: v || '#9ca3af' }); } },
131 { label: __('Section Title', 'blockenberg'), value: attr.titleColor, onChange: function (v) { set({ titleColor: v || '#111827' }); } },
132 { label: __('Section Subtitle', 'blockenberg'), value: attr.subtitleColor, onChange: function (v) { set({ subtitleColor: v || '#6b7280' }); } }
133 ]
134 })
135 );
136
137 var header = attr.showHeader && el('div', { style: { textAlign: 'center', marginBottom: '28px' } },
138 attr.sectionTitle && el('h2', { style: { margin: '0 0 6px', fontSize: '26px', fontWeight: 800, color: attr.titleColor } }, attr.sectionTitle),
139 attr.sectionSubtitle && el('p', { style: { margin: 0, fontSize: '15px', color: attr.subtitleColor } }, attr.sectionSubtitle)
140 );
141
142 var quoteCards = el('div', { style: gridStyle },
143 quotes.map(function (q, idx) {
144 return el('div', { key: idx, style: Object.assign({ marginBottom: attr.layout === 'masonry' ? attr.gap + 'px' : 0 }, cardStyle()) },
145 attr.showQuoteMark && el('div', { style: { fontSize: '64px', fontFamily: 'Georgia, serif', lineHeight: 0.8, color: attr.quoteMarkColor, marginBottom: '8px', userSelect: 'none', pointerEvents: 'none' } }, '"'),
146 el(RichText, { tagName: 'p', value: q.text, allowedFormats: ['core/bold', 'core/italic'], placeholder: __('Quote text\u2026', 'blockenberg'), className: 'bkbg-qcl-text', style: { margin: '0 0 14px', color: attr.quoteColor, fontStyle: attr.quoteStyle === 'classic' ? 'italic' : 'normal' }, onChange: function (v) { updateQuote(idx, 'text', v); } }),
147 el(TextControl, { value: q.author, label: '', placeholder: __('Author name', 'blockenberg'), __nextHasNoMarginBottom: true, className: 'bkbg-qcl-author', style: { color: attr.authorColor }, onChange: function (v) { updateQuote(idx, 'author', v); } }),
148 el(TextControl, { value: q.role, label: '', placeholder: __('Role / Title', 'blockenberg'), __nextHasNoMarginBottom: true, style: { fontSize: '12px', color: attr.roleColor }, onChange: function (v) { updateQuote(idx, 'role', v); } }),
149 el(TextControl, { value: q.source, label: '', placeholder: __('Source (optional)', 'blockenberg'), __nextHasNoMarginBottom: true, style: { fontSize: '11px', color: attr.roleColor }, onChange: function (v) { updateQuote(idx, 'source', v); } }),
150 el('div', { style: { marginTop: '10px', textAlign: 'right' } },
151 el(Button, { isSmall: true, isDestructive: true, variant: 'tertiary', onClick: function () { set({ quotes: quotes.filter(function (_, i) { return i !== idx; }) }); } }, '× Remove')
152 )
153 );
154 })
155 );
156
157 return el('div', blockProps,
158 controls,
159 el('div', { style: { maxWidth: '100%' } },
160 header,
161 quoteCards,
162 el('div', { style: { marginTop: '14px', textAlign: 'center' } },
163 el(Button, { variant: 'primary', isSmall: true, onClick: function () {
164 set({ quotes: quotes.concat([emptyQuote()]) });
165 } }, '+ Add Quote')
166 )
167 )
168 );
169 },
170 save: function (props) {
171 var attr = props.attributes;
172 var useBlockProps = wp.blockEditor.useBlockProps;
173 return el('div', useBlockProps.save(),
174 el('div', { className: 'bkbg-qcl-app', 'data-opts': JSON.stringify(attr) })
175 );
176 }
177 });
178 }() );
179