PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.11
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.11
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 / text-path / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.11, at blocks/text-path/index.js

239 lines 12.6 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 useBlockProps = wp.blockEditor.useBlockProps;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
8 var PanelBody = wp.components.PanelBody;
9 var TextControl = wp.components.TextControl;
10 var ToggleControl = wp.components.ToggleControl;
11 var RangeControl = wp.components.RangeControl;
12 var SelectControl = wp.components.SelectControl;
13
14 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
15 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
16 var _tvf = function (typo, prefix) { var fn = getTypoCssVars(); return fn ? fn(typo, prefix) : {}; };
17
18 /* ── Build SVG path string ── */
19 function buildPath(attr) {
20 var W = attr.svgWidth, H = attr.svgHeight;
21 var type = attr.pathType;
22
23 if (type === 'arc') {
24 var r = attr.arcRadius;
25 var cx = W / 2;
26 var cy = attr.arcDirection === 'top' ? r + 20 : H - r - 20;
27 // Large arc from left to right
28 var x1 = cx - r, x2 = cx + r;
29 var sweep = attr.arcDirection === 'top' ? 1 : 0;
30 return 'M ' + x1 + ' ' + cy + ' A ' + r + ' ' + r + ' 0 0 ' + sweep + ' ' + x2 + ' ' + cy;
31 }
32
33 if (type === 'wave') {
34 var amp = attr.waveAmplitude;
35 var freq = attr.waveFrequency;
36 var midY = H / 2;
37 var step = W / (freq * 2);
38 var d = 'M 0 ' + midY;
39 for (var i = 0; i < freq * 2; i++) {
40 var cpX = step * (i + 0.5);
41 var cpY = i % 2 === 0 ? midY - amp : midY + amp;
42 var eX = step * (i + 1);
43 var eY = midY;
44 d += ' Q ' + cpX + ' ' + cpY + ' ' + eX + ' ' + eY;
45 }
46 return d;
47 }
48
49 if (type === 'circle') {
50 var cr = Math.min(W, H) / 2 - 20;
51 var ccx = W / 2, ccy = H / 2;
52 return 'M ' + (ccx - cr) + ' ' + ccy +
53 ' A ' + cr + ' ' + cr + ' 0 1 1 ' + (ccx + cr) + ' ' + ccy +
54 ' A ' + cr + ' ' + cr + ' 0 1 1 ' + (ccx - cr) + ' ' + ccy;
55 }
56
57 if (type === 'scurve') {
58 var midX = W / 2, sH = H;
59 return 'M 0 ' + (sH * 0.7) + ' C ' + (midX * 0.5) + ' ' + (sH * 0.7) + ' ' + (midX * 0.5) + ' ' + (sH * 0.3) + ' ' + midX + ' ' + (sH * 0.5) + ' S ' + (midX + midX * 0.5) + ' ' + (sH * 0.8) + ' ' + W + ' ' + (sH * 0.3);
60 }
61
62 return 'M 0 ' + (H / 2) + ' L ' + W + ' ' + (H / 2);
63 }
64
65 /* ── Build SVG preview ── */
66 function buildSVGPreview(attr) {
67 var W = attr.svgWidth, H = attr.svgHeight;
68 var pathId = 'bkbg-tp-path-preview';
69 var pathD = buildPath(attr);
70
71 var pathEl = el('path', {
72 id: pathId,
73 d: pathD,
74 fill: 'none',
75 stroke: attr.showPath ? attr.pathStrokeColor : 'none',
76 strokeWidth: attr.showPath ? attr.pathStrokeWidth : 0
77 });
78
79 var textOnPath = el('text', {
80 fill: attr.textColor
81 },
82 el('textPath', {
83 href: '#' + pathId,
84 startOffset: attr.startOffset + '%',
85 textAnchor: attr.textAnchor
86 }, attr.text)
87 );
88
89 return el('svg', {
90 viewBox: '0 0 ' + W + ' ' + H,
91 width: '100%',
92 height: H + 'px',
93 xmlns: 'http://www.w3.org/2000/svg',
94 style: { display: 'block', maxWidth: W + 'px', margin: '0 auto' }
95 }, pathEl, textOnPath);
96 }
97
98 registerBlockType('blockenberg/text-path', {
99 edit: function (props) {
100 var attr = props.attributes;
101 var setAttr = props.setAttributes;
102 var blockProps = useBlockProps((function () {
103 var s = { background: attr.sectionBg || undefined, textAlign: attr.align2 || 'center' };
104 Object.assign(s, _tvf(attr.titleTypo, '--bktp-tt-'));
105 return { style: s };
106 })());
107
108 var inspector = el(InspectorControls, {},
109 /* Text & Path */
110 el(PanelBody, { title: __('Text & Path', 'blockenberg'), initialOpen: true },
111 el(TextControl, {
112 label: __('Text', 'blockenberg'),
113 value: attr.text,
114 onChange: function (v) { setAttr({ text: v }); },
115 help: __('Add • or | between repetitions for circular paths.', 'blockenberg'),
116 __nextHasNoMarginBottom: true
117 }),
118 el('div', { style: { marginTop: '12px' } }),
119 el(SelectControl, {
120 label: __('Path Shape', 'blockenberg'),
121 value: attr.pathType,
122 options: [
123 { label: 'Arc (Bow)', value: 'arc' },
124 { label: 'Wave', value: 'wave' },
125 { label: 'Circle', value: 'circle' },
126 { label: 'S-Curve', value: 'scurve' }
127 ],
128 onChange: function (v) { setAttr({ pathType: v }); },
129 __nextHasNoMarginBottom: true
130 }),
131 el('div', { style: { marginTop: '8px' } }),
132 attr.pathType === 'arc' && el('div', {},
133 el(RangeControl, { label: __('Arc Radius (px)', 'blockenberg'), value: attr.arcRadius, min: 50, max: 600, onChange: function (v) { setAttr({ arcRadius: v }); }, __nextHasNoMarginBottom: true }),
134 el('div', { style: { marginTop: '8px' } }),
135 el(SelectControl, {
136 label: __('Arc Direction', 'blockenberg'),
137 value: attr.arcDirection,
138 options: [{ label: 'Bow Up (text on top)', value: 'top' }, { label: 'Bow Down (text underneath)', value: 'bottom' }],
139 onChange: function (v) { setAttr({ arcDirection: v }); },
140 __nextHasNoMarginBottom: true
141 })
142 ),
143 attr.pathType === 'wave' && el('div', {},
144 el(RangeControl, { label: __('Wave Amplitude (px)', 'blockenberg'), value: attr.waveAmplitude, min: 5, max: 120, onChange: function (v) { setAttr({ waveAmplitude: v }); }, __nextHasNoMarginBottom: true }),
145 el('div', { style: { marginTop: '8px' } }),
146 el(RangeControl, { label: __('Wave Frequency', 'blockenberg'), value: attr.waveFrequency, min: 1, max: 6, onChange: function (v) { setAttr({ waveFrequency: v }); }, __nextHasNoMarginBottom: true })
147 ),
148 el('div', { style: { marginTop: '8px' } }),
149 el(RangeControl, { label: __('SVG Width (px)', 'blockenberg'), value: attr.svgWidth, min: 300, max: 1400, onChange: function (v) { setAttr({ svgWidth: v }); }, __nextHasNoMarginBottom: true }),
150 el('div', { style: { marginTop: '8px' } }),
151 el(RangeControl, { label: __('SVG Height (px)', 'blockenberg'), value: attr.svgHeight, min: 80, max: 600, onChange: function (v) { setAttr({ svgHeight: v }); }, __nextHasNoMarginBottom: true }),
152 el('div', { style: { marginTop: '8px' } }),
153 el(RangeControl, { label: __('Text Start Offset (%)', 'blockenberg'), value: attr.startOffset, min: 0, max: 100, onChange: function (v) { setAttr({ startOffset: v }); }, __nextHasNoMarginBottom: true }),
154 el('div', { style: { marginTop: '8px' } }),
155 el(SelectControl, {
156 label: __('Text Anchor', 'blockenberg'),
157 value: attr.textAnchor,
158 options: [{ label: 'Start', value: 'start' }, { label: 'Middle', value: 'middle' }, { label: 'End', value: 'end' }],
159 onChange: function (v) { setAttr({ textAnchor: v }); },
160 __nextHasNoMarginBottom: true
161 })
162 ),
163 /* Typography */
164 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
165 getTypoControl() && getTypoControl()({
166 label: __('Text', 'blockenberg'),
167 value: attr.titleTypo || {},
168 onChange: function (v) { setAttr({ titleTypo: v }); }
169 }),
170 el('div', { style: { marginTop: '8px' } }),
171 el(SelectControl, {
172 label: __('Alignment', 'blockenberg'),
173 value: attr.align2,
174 options: [{ label: 'Left', value: 'left' }, { label: 'Center', value: 'center' }, { label: 'Right', value: 'right' }],
175 onChange: function (v) { setAttr({ align2: v }); },
176 __nextHasNoMarginBottom: true
177 })
178 ),
179 /* Path Stroke */
180 el(PanelBody, { title: __('Path Stroke', 'blockenberg'), initialOpen: false },
181 el(ToggleControl, { label: __('Show Path Line', 'blockenberg'), checked: attr.showPath, onChange: function (v) { setAttr({ showPath: v }); }, __nextHasNoMarginBottom: true }),
182 attr.showPath && el('div', {},
183 el('div', { style: { marginTop: '8px' } }),
184 el(RangeControl, { label: __('Stroke Width (px)', 'blockenberg'), value: attr.pathStrokeWidth, min: 1, max: 10, onChange: function (v) { setAttr({ pathStrokeWidth: v }); }, __nextHasNoMarginBottom: true })
185 )
186 ),
187 /* Animation */
188 el(PanelBody, { title: __('Animation', 'blockenberg'), initialOpen: false },
189 el(ToggleControl, { label: __('Animate Text Along Path', 'blockenberg'), checked: attr.animate, onChange: function (v) { setAttr({ animate: v }); }, __nextHasNoMarginBottom: true }),
190 attr.animate && el('div', {},
191 el('div', { style: { marginTop: '8px' } }),
192 el(RangeControl, { label: __('Animation Duration (s)', 'blockenberg'), value: attr.animateDuration, min: 2, max: 60, onChange: function (v) { setAttr({ animateDuration: v }); }, __nextHasNoMarginBottom: true }),
193 el('div', { style: { marginTop: '8px' } }),
194 el(SelectControl, {
195 label: __('Repeat', 'blockenberg'),
196 value: attr.repeatCount,
197 options: [{ label: 'Infinite', value: 'indefinite' }, { label: '', value: '1' }, { label: '', value: '2' }, { label: '', value: '3' }],
198 onChange: function (v) { setAttr({ repeatCount: v }); },
199 __nextHasNoMarginBottom: true
200 })
201 )
202 ),
203 /* Colors */
204 el(PanelColorSettings, {
205 title: __('Colors', 'blockenberg'),
206 initialOpen: false,
207 colorSettings: [
208 { label: __('Text Color', 'blockenberg'), value: attr.textColor, onChange: function (v) { setAttr({ textColor: v || '#0f172a' }); } },
209 { label: __('Path Stroke Color', 'blockenberg'), value: attr.pathStrokeColor, onChange: function (v) { setAttr({ pathStrokeColor: v || '#e2e8f0' }); } },
210 { label: __('Section Background', 'blockenberg'), value: attr.sectionBg, onChange: function (v) { setAttr({ sectionBg: v || '' }); } }
211 ]
212 })
213 );
214
215 return el('div', blockProps,
216 inspector,
217 el('div', { className: 'bkbg-tp-wrap', style: { textAlign: attr.align2 || 'center' } },
218 buildSVGPreview(attr)
219 )
220 );
221 },
222
223 save: function (props) {
224 var attr = props.attributes;
225 var blockProps = useBlockProps.save((function () {
226 var s = {};
227 Object.assign(s, _tvf(attr.titleTypo, '--bktp-tt-'));
228 return { style: s };
229 })());
230 return el('div', blockProps,
231 el('div', {
232 className: 'bkbg-tp-app',
233 'data-opts': JSON.stringify(attr)
234 })
235 );
236 }
237 });
238 }() );
239