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 / word-frequency / index.js

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

180 lines 11.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 const el = window.wp.element.createElement;
3 const { registerBlockType } = window.wp.blocks;
4 const { InspectorControls, useBlockProps, PanelColorSettings } = window.wp.blockEditor;
5 const { PanelBody, RangeControl, ToggleControl, TextControl, Button, ColorPicker, Popover } = window.wp.components;
6 const { __ } = window.wp.i18n;
7 const { useState } = window.wp.element;
8
9 /* ── Typography helpers (lazy) ──────────────────────────────────── */
10 var _tc, _tvf;
11 Object.defineProperty(window, '__bkwfr_tc', { get: function () { return _tc || (_tc = window.bkbgTypographyControl); } });
12 Object.defineProperty(window, '__bkwfr_tvf', { get: function () { return _tvf || (_tvf = window.bkbgTypoCssVars); } });
13 function getTypoControl(label, typoObj, setAttributes, attrName) {
14 var fn = window.__bkwfr_tc;
15 return fn ? fn({ label: label, value: typoObj || {}, onChange: function (v) { var o = {}; o[attrName] = v; setAttributes(o); } }) : null;
16 }
17 function getTypoCssVars(a) {
18 var fn = window.__bkwfr_tvf;
19 var s = {};
20 if (fn) {
21 Object.assign(s, fn(a.titleTypo || {}, '--bkwfr-tt-'));
22 Object.assign(s, fn(a.labelTypo || {}, '--bkwfr-lb-'));
23 Object.assign(s, fn(a.valueTypo || {}, '--bkwfr-vl-'));
24 }
25 return s;
26 }
27
28 // ── Render bar chart ──────────────────────────────────────────────────────
29 function renderChart( a ) {
30 const sorted = a.sortDesc
31 ? [ ...( a.words || [] ) ].sort( ( x, y ) => ( y.count || 0 ) - ( x.count || 0 ) )
32 : [ ...( a.words || [] ) ];
33
34 const maxCount = Math.max( ...sorted.map( w => w.count || 0 ), 1 );
35
36 return el( 'div', { className: 'bkbg-wf-bars', style: { background: a.bgColor || '#ffffff', padding: '4px 0' } },
37 sorted.map( ( word, i ) => {
38 const count = word.count || 0;
39 const pct = ( ( count / maxCount ) * 100 ).toFixed( 1 );
40 const label = a.showPercent ? pct + '%' : String( count );
41
42 return el( 'div', { key: i, className: 'bkbg-wf-row' },
43
44 // Rank badge
45 a.showRank && el( 'span', {
46 className: 'bkbg-wf-rank',
47 style: { color: word.color || '#4f46e5' }
48 }, String( i + 1 ) ),
49
50 // Word label
51 a.showLabels && el( 'span', {
52 className: 'bkbg-wf-label',
53 style: { width: a.labelWidth + 'px', color: a.textColor }
54 }, word.word || '' ),
55
56 // Bar track + fill
57 el( 'div', { className: 'bkbg-wf-track', style: { background: a.trackColor || '#f3f4f6', height: a.barHeight + 'px' } },
58 el( 'div', {
59 className: 'bkbg-wf-fill',
60 style: {
61 width: pct + '%',
62 height: '100%',
63 background: word.color || '#4f46e5',
64 borderRadius: a.barRadius + 'px',
65 transition: 'width 0.6s ease',
66 }
67 } )
68 ),
69
70 // Value label
71 a.showValues && el( 'span', {
72 className: 'bkbg-wf-val',
73 style: { color: a.textColor }
74 }, label ),
75
76 );
77 } )
78 );
79 }
80
81 // ── Helpers ───────────────────────────────────────────────────────────────
82 function updWord( setAttributes, words, idx, field, val ) {
83 const next = words.map( ( w, i ) => i === idx ? { ...w, [field]: val } : w );
84 setAttributes( { words: next } );
85 }
86
87 // ── Block registration ──────────────────────────────────────────────────── /* ── colour-swatch + popover ── */
88 function BkbgColorSwatch(p) {
89 var st = useState(false), open = st[0], setOpen = st[1];
90 return el('div', { style:{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'4px 0', gap:'8px' } },
91 el('span', { style:{ fontSize:'12px', color:'#1e1e1e', flex:1, lineHeight:1.4 } }, p.label),
92 el('div', { style:{ position:'relative', flexShrink:0 } },
93 el('button', { type:'button', title: p.value||'none', onClick: function(){ setOpen(!open); },
94 style:{ width:'28px', height:'28px', borderRadius:'4px', border: open ? '2px solid #007cba' : '2px solid #ddd', cursor:'pointer', padding:0, display:'block', background: p.value||'#ffffff', flexShrink:0 } }),
95 open && el(Popover, { position:'bottom left', onClose: function(){ setOpen(false); } },
96 el('div', { style:{ padding:'8px' }, onMouseDown: function(e){ e.stopPropagation(); } },
97 el('div', { style:{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:'6px' } },
98 el('strong', { style:{ fontSize:'12px' } }, p.label),
99 el(Button, { icon:'no-alt', isSmall:true, onClick: function(){ setOpen(false); } })
100 ),
101 el(ColorPicker, { color: p.value, enableAlpha:true, onChange: p.onChange })
102 )
103 )
104 )
105 );
106 }
107 registerBlockType( 'blockenberg/word-frequency', {
108 edit: function ( props ) {
109 const { attributes: a, setAttributes } = props;
110 const blockProps = useBlockProps( { className: 'bkbg-word-frequency-wrap', style: getTypoCssVars( a ) } );
111
112 return el( 'div', blockProps,
113 el( InspectorControls, {},
114
115 el( PanelBody, { title: __( 'Chart Settings', 'blockenberg' ), initialOpen: true },
116 el( TextControl, { label: __( 'Title', 'blockenberg' ), value: a.title, onChange: v => setAttributes( { title: v } ) } ),
117 el( ToggleControl, { label: __( 'Show Title', 'blockenberg' ), checked: a.showTitle, onChange: v => setAttributes( { showTitle: v } ) } ),
118 el( ToggleControl, { label: __( 'Show Values', 'blockenberg' ), checked: a.showValues, onChange: v => setAttributes( { showValues: v } ) } ),
119 el( ToggleControl, { label: __( 'Show As Percent', 'blockenberg' ), checked: a.showPercent, onChange: v => setAttributes( { showPercent: v } ) } ),
120 el( ToggleControl, { label: __( 'Show Rank Numbers', 'blockenberg' ), checked: a.showRank, onChange: v => setAttributes( { showRank: v } ) } ),
121 el( ToggleControl, { label: __( 'Show Labels', 'blockenberg' ), checked: a.showLabels, onChange: v => setAttributes( { showLabels: v } ) } ),
122 el( ToggleControl, { label: __( 'Sort High → Low', 'blockenberg' ), checked: a.sortDesc, onChange: v => setAttributes( { sortDesc: v } ) } ),
123 ),
124
125 el( PanelBody, { title: __( 'Appearance', 'blockenberg' ), initialOpen: false },
126 el( RangeControl, { label: __( 'Bar Height', 'blockenberg' ), value: a.barHeight, onChange: v => setAttributes( { barHeight: v } ), min: 16, max: 80 } ),
127 el( RangeControl, { label: __( 'Row Gap', 'blockenberg' ), value: a.barGap, onChange: v => setAttributes( { barGap: v } ), min: 0, max: 30 } ),
128 el( RangeControl, { label: __( 'Bar Radius', 'blockenberg' ), value: a.barRadius, onChange: v => setAttributes( { barRadius: v } ), min: 0, max: 20 } ),
129 el( RangeControl, { label: __( 'Label Column Width', 'blockenberg' ), value: a.labelWidth, onChange: v => setAttributes( { labelWidth: v } ), min: 60, max: 300 } ),
130 ),
131
132
133 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
134 getTypoControl( 'Title', a.titleTypo, setAttributes, 'titleTypo' ),
135 getTypoControl( 'Label', a.labelTypo, setAttributes, 'labelTypo' ),
136 getTypoControl( 'Value', a.valueTypo, setAttributes, 'valueTypo' )
137 ),
138 el( PanelColorSettings, {
139 title: __( 'Colors', 'blockenberg' ),
140 initialOpen: false,
141 colorSettings: [
142 { label: __( 'Background', 'blockenberg' ), value: a.bgColor, onChange: v => setAttributes( { bgColor: v || '#ffffff' } ) },
143 { label: __( 'Track Color', 'blockenberg' ), value: a.trackColor, onChange: v => setAttributes( { trackColor: v || '#f3f4f6' } ) },
144 { label: __( 'Title Color', 'blockenberg' ), value: a.titleColor, onChange: v => setAttributes( { titleColor: v || '#111827' } ) },
145 { label: __( 'Text Color', 'blockenberg' ), value: a.textColor, onChange: v => setAttributes( { textColor: v || '#374151' } ) },
146 ]
147 } ),
148
149 el( PanelBody, { title: __( 'Data', 'blockenberg' ), initialOpen: false },
150 el( Button, {
151 variant: 'secondary', style: { marginBottom: 10 },
152 onClick: () => setAttributes( { words: [ ...a.words, { word: 'New Item', count: 10, color: '#6b7280' } ] } )
153 }, __( '+ Add Item', 'blockenberg' ) ),
154
155 a.words.map( ( word, i ) =>
156 el( PanelBody, { key: i, title: ( word.word || `Item ${ i + 1 }` ) + ` (${ word.count })`, initialOpen: false },
157 el( TextControl, { label: __( 'Label', 'blockenberg' ), value: word.word, onChange: v => updWord( setAttributes, a.words, i, 'word', v ) } ),
158 el( RangeControl, { label: __( 'Value / Count', 'blockenberg' ), value: word.count, onChange: v => updWord( setAttributes, a.words, i, 'count', v ), min: 0, max: 10000 } ),
159 el( BkbgColorSwatch, { label: __( 'Color', 'blockenberg' ), value: word.color, onChange: v => updWord( setAttributes, a.words, i, 'color', v ) } ),
160 el( Button, { isDestructive: true, isSmall: true, onClick: () => setAttributes( { words: a.words.filter( ( _, x ) => x !== i ) } ) }, __( 'Remove', 'blockenberg' ) ),
161 )
162 ),
163 ),
164 ),
165
166 a.showTitle && a.title && el( 'h3', { className: 'bkbg-wf-title', style: { color: a.titleColor } }, a.title ),
167 renderChart( a ),
168 );
169 },
170
171 save: function ( { attributes: a } ) {
172 const blockProps = useBlockProps.save( { className: 'bkbg-word-frequency-wrap', style: getTypoCssVars( a ) } );
173 return el( 'div', blockProps,
174 a.showTitle && a.title ? el( 'h3', { className: 'bkbg-wf-title', style: { color: a.titleColor } }, a.title ) : null,
175 renderChart( a ),
176 );
177 },
178 } );
179 }() );
180