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 / chapter-navigation / index.js

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

207 lines 17.5 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 PanelColorSettings = wp.blockEditor.PanelColorSettings;
8 var PanelBody = wp.components.PanelBody;
9 var ToggleControl = wp.components.ToggleControl;
10 var RangeControl = wp.components.RangeControl;
11 var SelectControl = wp.components.SelectControl;
12 var TextControl = wp.components.TextControl;
13 var Button = wp.components.Button;
14
15 function getTypographyControl() { return (window.bkbgTypographyControl || function () { return null; }); }
16 function getTypoCssVars() { return (window.bkbgTypoCssVars || function () { return {}; }); }
17 function _tv(typo, prefix) { var fn = getTypoCssVars(); return fn(typo || {}, prefix); }
18
19 registerBlockType('blockenberg/chapter-navigation', {
20 edit: function (props) {
21 var attr = props.attributes;
22 var set = props.setAttributes;
23
24 var blockProps = useBlockProps({ style: Object.assign({ padding: attr.paddingTop + 'px 0 ' + attr.paddingBottom + 'px' }, _tv(attr.typoTitle, '--bkbg-cnv-tt-')) });
25
26 var progress = Math.round((attr.currentPart / attr.totalParts) * 100);
27
28 function updateChapter(idx, key, value) {
29 var arr = attr.chapters.map(function (c, i) {
30 if (i !== idx) return c;
31 var copy = Object.assign({}, c);
32 copy[key] = value;
33 return copy;
34 });
35 set({ chapters: arr });
36 }
37
38 var wrapStyle = { background: attr.bgColor, border: '1px solid ' + attr.borderColor, borderRadius: attr.borderRadius + 'px', overflow: 'hidden', boxShadow: '0 2px 8px rgba(0,0,0,.06)' };
39 if (attr.style === 'banner') {
40 wrapStyle = { background: attr.bgColor, borderLeft: '4px solid ' + attr.accentColor, borderTop: '1px solid ' + attr.borderColor, borderBottom: '1px solid ' + attr.borderColor, borderRight: '1px solid ' + attr.borderColor, borderRadius: attr.borderRadius + 'px', overflow: 'hidden' };
41 }
42 if (attr.style === 'minimal') {
43 wrapStyle = { borderTop: '2px solid ' + attr.accentColor, paddingTop: '16px' };
44 }
45
46 var controls = el(InspectorControls, {},
47 el(PanelBody, { title: __('Series Info', 'blockenberg'), initialOpen: true },
48 el(TextControl, { label: __('Series Title', 'blockenberg'), value: attr.seriesTitle, __nextHasNoMarginBottom: true, onChange: function (v) { set({ seriesTitle: v }); } }),
49 el('div', { style: { marginTop: '8px' } },
50 el(TextControl, { label: __('Current Chapter Title', 'blockenberg'), value: attr.currentTitle, __nextHasNoMarginBottom: true, onChange: function (v) { set({ currentTitle: v }); } })
51 ),
52 el('div', { style: { marginTop: '8px' } },
53 el(TextControl, { label: __('Part Label', 'blockenberg'), value: attr.partLabel, __nextHasNoMarginBottom: true, onChange: function (v) { set({ partLabel: v }); } })
54 ),
55 el('div', { style: { marginTop: '8px', display: 'flex', gap: '8px' } },
56 el('div', { style: { flex: 1 } },
57 el(RangeControl, { label: __('Current Part', 'blockenberg'), value: attr.currentPart, min: 1, max: attr.totalParts, __nextHasNoMarginBottom: true, onChange: function (v) { set({ currentPart: v }); } })
58 ),
59 el('div', { style: { flex: 1 } },
60 el(RangeControl, { label: __('Total Parts', 'blockenberg'), value: attr.totalParts, min: 1, max: 50, __nextHasNoMarginBottom: true, onChange: function (v) { set({ totalParts: v }); } })
61 )
62 )
63 ),
64 el(PanelBody, { title: __('Prev / Next', 'blockenberg'), initialOpen: false },
65 el(TextControl, { label: __('Previous Chapter Title', 'blockenberg'), value: attr.prevTitle, __nextHasNoMarginBottom: true, onChange: function (v) { set({ prevTitle: v }); } }),
66 el('div', { style: { marginTop: '8px' } },
67 el(TextControl, { label: __('Previous URL', 'blockenberg'), value: attr.prevUrl, placeholder: 'https://...', __nextHasNoMarginBottom: true, onChange: function (v) { set({ prevUrl: v }); } })
68 ),
69 el('div', { style: { marginTop: '12px' } },
70 el(TextControl, { label: __('Next Chapter Title', 'blockenberg'), value: attr.nextTitle, __nextHasNoMarginBottom: true, onChange: function (v) { set({ nextTitle: v }); } })
71 ),
72 el('div', { style: { marginTop: '8px' } },
73 el(TextControl, { label: __('Next URL', 'blockenberg'), value: attr.nextUrl, placeholder: 'https://...', __nextHasNoMarginBottom: true, onChange: function (v) { set({ nextUrl: v }); } })
74 )
75 ),
76 el(PanelBody, { title: __('Chapter List', 'blockenberg'), initialOpen: false },
77 el(ToggleControl, { label: __('Show All Chapters List', 'blockenberg'), checked: attr.showChapterList, __nextHasNoMarginBottom: true, onChange: function (v) { set({ showChapterList: v }); } }),
78 el('div', { style: { marginTop: '8px' } },
79 el(ToggleControl, { label: __('Open List by Default', 'blockenberg'), checked: attr.chapterListOpen, __nextHasNoMarginBottom: true, onChange: function (v) { set({ chapterListOpen: v }); } })
80 ),
81 el('div', { style: { marginTop: '12px' } },
82 (attr.chapters || []).map(function (ch, idx) {
83 return el('div', { key: idx, style: { marginBottom: '8px', padding: '8px', background: '#f8fafc', borderRadius: '4px', border: '1px solid #e2e8f0' } },
84 el('strong', { style: { fontSize: '11px', color: '#6366f1' } }, (idx + 1) + '.'),
85 el('div', { style: { marginTop: '4px' } },
86 el(TextControl, { label: '', value: ch.title, placeholder: 'Chapter title', __nextHasNoMarginBottom: true, onChange: function (v) { updateChapter(idx, 'title', v); } })
87 ),
88 el('div', { style: { marginTop: '4px' } },
89 el(TextControl, { label: '', value: ch.url, placeholder: 'URL (https://...)', __nextHasNoMarginBottom: true, onChange: function (v) { updateChapter(idx, 'url', v); } })
90 ),
91 el(Button, { variant: 'link', isDestructive: true, style: { fontSize: '11px' }, onClick: function () { set({ chapters: attr.chapters.filter(function (_, i) { return i !== idx; }) }); } }, __('Remove', 'blockenberg'))
92 );
93 })
94 ),
95 el(Button, { variant: 'secondary', style: { marginTop: '8px' }, onClick: function () { set({ chapters: (attr.chapters || []).concat([{ title: 'New Chapter', url: '' }]) }); } }, __('+ Add Chapter', 'blockenberg'))
96 ),
97 el(PanelBody, { title: __('Style & Layout', 'blockenberg'), initialOpen: false },
98 el(SelectControl, {
99 label: __('Style', 'blockenberg'), value: attr.style, __nextHasNoMarginBottom: true,
100 options: [{ label: 'Card (bordered box)', value: 'card' }, { label: 'Banner (left accent)', value: 'banner' }, { label: 'Minimal (top line)', value: 'minimal' }],
101 onChange: function (v) { set({ style: v }); }
102 }),
103 el('div', { style: { marginTop: '12px' } },
104 el(ToggleControl, { label: __('Show Progress Bar', 'blockenberg'), checked: attr.showProgress, __nextHasNoMarginBottom: true, onChange: function (v) { set({ showProgress: v }); } })
105 ),
106 el('div', { style: { marginTop: '4px' } },
107 el(ToggleControl, { label: __('Open Links in New Tab', 'blockenberg'), checked: attr.openInNewTab, __nextHasNoMarginBottom: true, onChange: function (v) { set({ openInNewTab: v }); } })
108 ),
109 el('div', { style: { marginTop: '12px' } },
110 el(RangeControl, { label: __('Border Radius', 'blockenberg'), value: attr.borderRadius, min: 0, max: 24, __nextHasNoMarginBottom: true, onChange: function (v) { set({ borderRadius: v }); } })
111 )
112 ),
113 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
114 el(RangeControl, { label: __('Padding Top', 'blockenberg'), value: attr.paddingTop, min: 0, max: 120, __nextHasNoMarginBottom: true, onChange: function (v) { set({ paddingTop: v }); } }),
115 el('div', { style: { marginTop: '12px' } },
116 el(RangeControl, { label: __('Padding Bottom', 'blockenberg'), value: attr.paddingBottom, min: 0, max: 120, __nextHasNoMarginBottom: true, onChange: function (v) { set({ paddingBottom: v }); } })
117 )
118 ),
119 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
120 el(getTypographyControl(), { label: __('Current Title', 'blockenberg'), value: attr.typoTitle, onChange: function (v) { set({ typoTitle: v }); } }),
121 el(RangeControl, { label: __('Series Title Size (px)', 'blockenberg'), value: attr.seriesTitleFontSize, min: 10, max: 20, __nextHasNoMarginBottom: true, onChange: function (v) { set({ seriesTitleFontSize: v }); } }),
122 el(RangeControl, { label: __('Nav Button Size (px)', 'blockenberg'), value: attr.navFontSize, min: 10, max: 20, __nextHasNoMarginBottom: true, onChange: function (v) { set({ navFontSize: v }); } }),
123 el(RangeControl, { label: __('Chapter List Size (px)', 'blockenberg'), value: attr.chapterListFontSize, min: 10, max: 20, __nextHasNoMarginBottom: true, onChange: function (v) { set({ chapterListFontSize: v }); } })
124 ),
125 el(PanelColorSettings, {
126 title: __('Colors', 'blockenberg'), initialOpen: false,
127 colorSettings: [
128 { label: __('Background', 'blockenberg'), value: attr.bgColor, onChange: function (v) { set({ bgColor: v || '#ffffff' }); } },
129 { label: __('Border', 'blockenberg'), value: attr.borderColor, onChange: function (v) { set({ borderColor: v || '#e2e8f0' }); } },
130 { label: __('Accent', 'blockenberg'), value: attr.accentColor, onChange: function (v) { set({ accentColor: v || '#6366f1' }); } },
131 { label: __('Series Title', 'blockenberg'), value: attr.seriesTitleColor, onChange: function (v) { set({ seriesTitleColor: v || '#374151' }); } },
132 { label: __('Current Title', 'blockenberg'), value: attr.currentTitleColor, onChange: function (v) { set({ currentTitleColor: v || '#111827' }); } },
133 { label: __('Progress Bar BG', 'blockenberg'), value: attr.progressBg, onChange: function (v) { set({ progressBg: v || '#e2e8f0' }); } },
134 { label: __('Progress Fill', 'blockenberg'), value: attr.progressFill, onChange: function (v) { set({ progressFill: v || '#6366f1' }); } },
135 { label: __('Nav Button BG', 'blockenberg'), value: attr.btnBg, onChange: function (v) { set({ btnBg: v || '#f1f5f9' }); } },
136 { label: __('Nav Button Text', 'blockenberg'), value: attr.btnColor, onChange: function (v) { set({ btnColor: v || '#374151' }); } },
137 { label: __('Pill BG', 'blockenberg'), value: attr.pillBg, onChange: function (v) { set({ pillBg: v || '#eef2ff' }); } },
138 { label: __('Pill Text', 'blockenberg'), value: attr.pillColor, onChange: function (v) { set({ pillColor: v || '#4f46e5' }); } },
139 { label: __('Chapter List BG', 'blockenberg'), value: attr.chapterListBg, onChange: function (v) { set({ chapterListBg: v || '#f8fafc' }); } },
140 { label: __('Active Chapter BG', 'blockenberg'), value: attr.activeChapterBg, onChange: function (v) { set({ activeChapterBg: v || '#eef2ff' }); } },
141 { label: __('Active Chapter Text', 'blockenberg'), value: attr.activeChapterColor, onChange: function (v) { set({ activeChapterColor: v || '#4f46e5' }); } }
142 ]
143 })
144 );
145
146 /* ── Editor preview ── */
147 var header = el('div', { style: { padding: '16px 20px', borderBottom: attr.style !== 'minimal' ? '1px solid ' + attr.borderColor : 'none' } },
148 el('div', { style: { display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '6px', flexWrap: 'wrap' } },
149 el('span', { style: { background: attr.pillBg, color: attr.pillColor, padding: '3px 10px', borderRadius: '20px', fontSize: '12px', fontWeight: 600 } }, attr.partLabel + ' ' + attr.currentPart + ' of ' + attr.totalParts),
150 el('span', { style: { color: attr.seriesTitleColor, fontSize: attr.seriesTitleFontSize + 'px' } }, attr.seriesTitle)
151 ),
152 el('div', { className: 'bkbg-cnv-current-title', style: { color: attr.currentTitleColor } }, attr.currentTitle),
153 attr.showProgress && el('div', { style: { marginTop: '10px' } },
154 el('div', { style: { background: attr.progressBg, borderRadius: '4px', height: '6px', overflow: 'hidden' } },
155 el('div', { style: { background: attr.progressFill, width: progress + '%', height: '100%', borderRadius: '4px', transition: 'width .3s' } })
156 ),
157 el('div', { style: { fontSize: '11px', color: attr.seriesTitleColor, marginTop: '4px' } }, progress + '% through the series')
158 )
159 );
160
161 var navRow = el('div', { style: { display: 'flex', gap: '10px', padding: '14px 20px', flexWrap: 'wrap' } },
162 attr.prevTitle && el('a', { href: '#', style: { flex: 1, minWidth: '160px', background: attr.btnBg, color: attr.btnColor, padding: '10px 14px', borderRadius: '6px', fontSize: attr.navFontSize + 'px', textDecoration: 'none', display: 'flex', flexDirection: 'column', gap: '2px' } },
163 el('span', { style: { fontSize: '11px', opacity: 0.7 } }, '← Previous'),
164 el('span', { style: { fontWeight: 600 } }, attr.prevTitle)
165 ),
166 attr.nextTitle && el('a', { href: '#', style: { flex: 1, minWidth: '160px', background: attr.accentColor, color: '#fff', padding: '10px 14px', borderRadius: '6px', fontSize: attr.navFontSize + 'px', textDecoration: 'none', display: 'flex', flexDirection: 'column', gap: '2px', textAlign: 'right' } },
167 el('span', { style: { fontSize: '11px', opacity: 0.8 } }, 'Next →'),
168 el('span', { style: { fontWeight: 600 } }, attr.nextTitle)
169 )
170 );
171
172 var chapterList = attr.showChapterList && el('details', { open: attr.chapterListOpen || true, style: { borderTop: '1px solid ' + attr.borderColor } },
173 el('summary', { style: { padding: '12px 20px', cursor: 'pointer', fontSize: '13px', fontWeight: 600, color: attr.seriesTitleColor, listStyle: 'none', display: 'flex', alignItems: 'center', justifyContent: 'space-between', background: attr.chapterListBg } },
174 el('span', {}, 'All ' + attr.totalParts + ' chapters'),
175 el('span', { style: { fontSize: '16px' } }, '')
176 ),
177 el('ol', { style: { margin: 0, padding: '8px 0', listStyle: 'none', background: attr.chapterListBg } },
178 (attr.chapters || []).map(function (ch, i) {
179 var isActive = (i + 1) === attr.currentPart;
180 return el('li', { key: i, style: { padding: '8px 20px 8px 44px', position: 'relative', background: isActive ? attr.activeChapterBg : 'transparent', fontSize: attr.chapterListFontSize + 'px' } },
181 el('span', { style: { position: 'absolute', left: '20px', fontWeight: 700, color: isActive ? attr.activeChapterColor : attr.seriesTitleColor } }, i + 1 + '.'),
182 el('span', { style: { color: isActive ? attr.activeChapterColor : attr.seriesTitleColor, fontWeight: isActive ? 600 : 400 } }, ch.title),
183 isActive && el('span', { style: { marginLeft: '8px', fontSize: '11px', padding: '1px 7px', background: attr.accentColor, color: '#fff', borderRadius: '10px' } }, 'Current')
184 );
185 })
186 )
187 );
188
189 return el('div', blockProps,
190 controls,
191 el('div', { style: wrapStyle },
192 header,
193 navRow,
194 chapterList
195 )
196 );
197 },
198 save: function (props) {
199 var attr = props.attributes;
200 var useBlockProps = wp.blockEditor.useBlockProps;
201 return el('div', useBlockProps.save(),
202 el('div', { className: 'bkbg-cnv-app', 'data-opts': JSON.stringify(attr) })
203 );
204 }
205 });
206 }() );
207