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

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

408 lines 28.8 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 Fragment = wp.element.Fragment;
4 var useState = wp.element.useState;
5 var __ = wp.i18n.__;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var MediaUpload = wp.blockEditor.MediaUpload;
9 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
10 var useBlockProps = wp.blockEditor.useBlockProps;
11 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
12 var PanelBody = wp.components.PanelBody;
13 var ToggleControl = wp.components.ToggleControl;
14 var RangeControl = wp.components.RangeControl;
15 var SelectControl = wp.components.SelectControl;
16 var TextControl = wp.components.TextControl;
17 var TextareaControl = wp.components.TextareaControl;
18 var Button = wp.components.Button;
19
20 var _tc; function getTypoControl(){ return _tc || (_tc = (window.bkbgTypographyControl || function(){return null})); }
21 var _tv; function getTypoCssVars(){ return _tv || (_tv = (window.bkbgTypoCssVars || function(){return {}})); }
22
23 var LAYOUT_OPTIONS = [
24 { label: 'Classic (single column)', value: 'classic' },
25 { label: 'Sidebar (header left, content right)', value: 'sidebar' },
26 { label: 'Modern (header full-width, two-col bottom)', value: 'modern' },
27 ];
28
29 function updateItem(arr, idx, field, val) {
30 return arr.map(function (item, i) {
31 if (i !== idx) return item;
32 var p = {}; p[field] = val;
33 return Object.assign({}, item, p);
34 });
35 }
36
37 function SectionHeading(title, accentColor) {
38 return el('div', {
39 style: {
40 display: 'flex', alignItems: 'center', gap: 10,
41 marginBottom: 16, paddingBottom: 8,
42 }
43 },
44 el('span', {
45 style: {
46 display: 'inline-block', width: 3, height: 18,
47 background: accentColor, borderRadius: 2, flexShrink: 0,
48 }
49 }),
50 el('h3', {
51 style: {
52 margin: 0, fontSize: 13, fontWeight: 700,
53 textTransform: 'uppercase', letterSpacing: '0.08em',
54 color: '#374151',
55 }
56 }, title)
57 );
58 }
59
60 function ExperiencePreview(exp, a) {
61 return el('div', {
62 style: {
63 display: 'flex', gap: 16, paddingBottom: 20,
64 borderBottom: '1px solid ' + a.dividerColor,
65 marginBottom: 20,
66 }
67 },
68 // Timeline dot
69 el('div', { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 0 } },
70 el('div', {
71 style: {
72 width: 12, height: 12, borderRadius: '50%',
73 background: a.accentColor, flexShrink: 0, marginTop: 3,
74 }
75 }),
76 el('div', { style: { width: 2, flexGrow: 1, background: a.dividerColor, marginTop: 4 } })
77 ),
78 el('div', { style: { flexGrow: 1 } },
79 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', flexWrap: 'wrap', gap: 4 } },
80 el('div', null,
81 el('div', { style: { fontWeight: 700, fontSize: 15, color: a.sectionHeadingColor } }, exp.role),
82 el('div', { style: { fontSize: 13, color: a.accentColor, fontWeight: 600 } }, exp.company + (exp.location ? ' · ' + exp.location : ''))
83 ),
84 el('div', { style: { fontSize: 12, color: a.subtextColor, whiteSpace: 'nowrap' } },
85 exp.startDate + '' + (exp.isCurrent ? 'Present' : exp.endDate)
86 )
87 ),
88 exp.description && el('p', { className: 'bkbg-rv-exp-desc', style: { margin: '8px 0 0', color: a.textColor } }, exp.description)
89 )
90 );
91 }
92
93 function EducationPreview(edu, a) {
94 return el('div', {
95 style: { paddingBottom: 16, borderBottom: '1px solid ' + a.dividerColor, marginBottom: 16 }
96 },
97 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' } },
98 el('div', null,
99 el('div', { style: { fontWeight: 700, fontSize: 15, color: a.sectionHeadingColor } }, edu.degree),
100 el('div', { style: { fontSize: 13, color: a.accentColor, fontWeight: 500 } }, edu.institution)
101 ),
102 el('div', { style: { fontSize: 12, color: a.subtextColor } }, edu.startYear + (edu.endYear && edu.endYear !== edu.startYear ? '' + edu.endYear : ''))
103 ),
104 edu.description && el('p', { className: 'bkbg-rv-edu-desc', style: { margin: '6px 0 0', color: a.textColor } }, edu.description)
105 );
106 }
107
108 registerBlockType('blockenberg/resume', {
109 title: __('Resume / CV', 'blockenberg'),
110 icon: 'id-alt',
111 category: 'bkbg-business',
112 description: __('Professional CV/resume with experience, education, and skills.', 'blockenberg'),
113
114 edit: function (props) {
115 var a = props.attributes;
116 var set = props.setAttributes;
117 var panelSt = useState('experience');
118 var activePanel = panelSt[0];
119 var setActivePanel = panelSt[1];
120
121 var blockProps = useBlockProps((function(){
122 var _tv = getTypoCssVars();
123 var s = { background: a.bgColor || undefined };
124 Object.assign(s, _tv(a.nameTypo, '--bkrv-nm-'));
125 Object.assign(s, _tv(a.bodyTypo, '--bkrv-bt-'));
126 return { style: s };
127 })());
128
129 var container = {
130 maxWidth: a.maxWidth + 'px',
131 margin: '0 auto',
132 border: '1px solid ' + a.dividerColor,
133 borderRadius: a.borderRadius + 'px',
134 overflow: 'hidden',
135 background: a.bgColor,
136 };
137
138 return el(Fragment, null,
139 el(InspectorControls, null,
140
141 // Sections toggle
142 el(PanelBody, { title: 'Sections', initialOpen: true },
143 el(ToggleControl, { label: 'Show photo', checked: a.showPhoto, onChange: function (v) { set({ showPhoto: v }); }, __nextHasNoMarginBottom: true }),
144 el('div', { style: { height: 8 } }),
145 el(ToggleControl, { label: 'Show summary', checked: a.showSummary, onChange: function (v) { set({ showSummary: v }); }, __nextHasNoMarginBottom: true }),
146 el('div', { style: { height: 8 } }),
147 el(ToggleControl, { label: 'Show experience', checked: a.showExperience, onChange: function (v) { set({ showExperience: v }); }, __nextHasNoMarginBottom: true }),
148 el('div', { style: { height: 8 } }),
149 el(ToggleControl, { label: 'Show education', checked: a.showEducation, onChange: function (v) { set({ showEducation: v }); }, __nextHasNoMarginBottom: true }),
150 el('div', { style: { height: 8 } }),
151 el(ToggleControl, { label: 'Show skills', checked: a.showSkills, onChange: function (v) { set({ showSkills: v }); }, __nextHasNoMarginBottom: true }),
152 el('div', { style: { height: 8 } }),
153 el(ToggleControl, { label: 'Show contact info', checked: a.showContact, onChange: function (v) { set({ showContact: v }); }, __nextHasNoMarginBottom: true })
154 ),
155
156 // Header / Identity
157 el(PanelBody, { title: 'Header Info', initialOpen: false },
158 el(TextControl, { label: 'Full name', value: a.name, onChange: function (v) { set({ name: v }); }, __nextHasNoMarginBottom: true }),
159 el('div', { style: { height: 8 } }),
160 el(TextControl, { label: 'Job title', value: a.jobTitle, onChange: function (v) { set({ jobTitle: v }); }, __nextHasNoMarginBottom: true }),
161 el('div', { style: { height: 8 } }),
162 a.showSummary && el(Fragment, null,
163 el(TextControl, { label: 'Summary title', value: a.summaryTitle, onChange: function (v) { set({ summaryTitle: v }); }, __nextHasNoMarginBottom: true }),
164 el('div', { style: { height: 8 } }),
165 el(TextareaControl, { label: 'Summary text', value: a.summary, rows: 4, onChange: function (v) { set({ summary: v }); }, __nextHasNoMarginBottom: true }),
166 el('div', { style: { height: 8 } })
167 ),
168 el(TextControl, { label: 'Email', value: a.email, onChange: function (v) { set({ email: v }); }, __nextHasNoMarginBottom: true }),
169 el('div', { style: { height: 8 } }),
170 el(TextControl, { label: 'Phone', value: a.phone, onChange: function (v) { set({ phone: v }); }, __nextHasNoMarginBottom: true }),
171 el('div', { style: { height: 8 } }),
172 el(TextControl, { label: 'Location', value: a.location, onChange: function (v) { set({ location: v }); }, __nextHasNoMarginBottom: true }),
173 el('div', { style: { height: 8 } }),
174 el(TextControl, { label: 'Website', value: a.website, onChange: function (v) { set({ website: v }); }, __nextHasNoMarginBottom: true }),
175 el('div', { style: { height: 10 } }),
176 a.showPhoto && el(Fragment, null,
177 el('div', { style: { fontSize: 11, fontWeight: 600, textTransform: 'uppercase', color: '#6b7280', marginBottom: 6 } }, 'Photo'),
178 el(MediaUploadCheck, null,
179 el(MediaUpload, {
180 onSelect: function (m) { set({ photoUrl: m.url, photoId: m.id }); },
181 allowedTypes: ['image'],
182 value: a.photoId,
183 render: function (ref) {
184 return el(Button, { onClick: ref.open, variant: a.photoUrl ? 'secondary' : 'primary', __nextHasNoMarginBottom: true }, a.photoUrl ? 'Change Photo' : 'Upload Photo');
185 }
186 })
187 ),
188 a.photoUrl && el(Button, { isDestructive: true, variant: 'link', onClick: function () { set({ photoUrl: '', photoId: 0 }); }, __nextHasNoMarginBottom: true }, 'Remove Photo')
189 )
190 ),
191
192 // Experience
193 a.showExperience && el(PanelBody, { title: 'Experience (' + a.experience.length + ')', initialOpen: false },
194 el(TextControl, { label: 'Section title', value: a.experienceTitle, onChange: function (v) { set({ experienceTitle: v }); }, __nextHasNoMarginBottom: true }),
195 el('div', { style: { height: 10 } }),
196 a.experience.map(function (exp, i) {
197 return el('div', {
198 key: i,
199 style: { border: '1px solid #e5e7eb', borderRadius: 8, padding: 10, marginBottom: 8, background: '#fafafa' }
200 },
201 el('div', { style: { fontWeight: 600, fontSize: 12, color: '#374151', marginBottom: 6 } }, (i + 1) + '. ' + (exp.role || 'Role')),
202 el(TextControl, { label: 'Role / Position', value: exp.role, onChange: function (v) { set({ experience: updateItem(a.experience, i, 'role', v) }); }, __nextHasNoMarginBottom: true }),
203 el('div', { style: { height: 6 } }),
204 el(TextControl, { label: 'Company', value: exp.company, onChange: function (v) { set({ experience: updateItem(a.experience, i, 'company', v) }); }, __nextHasNoMarginBottom: true }),
205 el('div', { style: { height: 6 } }),
206 el(TextControl, { label: 'Location', value: exp.location, onChange: function (v) { set({ experience: updateItem(a.experience, i, 'location', v) }); }, __nextHasNoMarginBottom: true }),
207 el('div', { style: { height: 6 } }),
208 el(TextControl, { label: 'Start date', value: exp.startDate, placeholder: 'Jan 2021', onChange: function (v) { set({ experience: updateItem(a.experience, i, 'startDate', v) }); }, __nextHasNoMarginBottom: true }),
209 el('div', { style: { height: 6 } }),
210 el(ToggleControl, { label: 'Current position', checked: exp.isCurrent, onChange: function (v) { set({ experience: updateItem(a.experience, i, 'isCurrent', v) }); }, __nextHasNoMarginBottom: true }),
211 !exp.isCurrent && el(Fragment, null,
212 el('div', { style: { height: 6 } }),
213 el(TextControl, { label: 'End date', value: exp.endDate, placeholder: 'Dec 2023', onChange: function (v) { set({ experience: updateItem(a.experience, i, 'endDate', v) }); }, __nextHasNoMarginBottom: true })
214 ),
215 el('div', { style: { height: 6 } }),
216 el(TextareaControl, { label: 'Description', value: exp.description, rows: 3, onChange: function (v) { set({ experience: updateItem(a.experience, i, 'description', v) }); }, __nextHasNoMarginBottom: true }),
217 el('div', { style: { height: 6 } }),
218 el(Button, { isDestructive: true, variant: 'link', size: 'small', onClick: function () { set({ experience: a.experience.filter(function (_, idx) { return idx !== i; }) }); }, __nextHasNoMarginBottom: true }, 'Remove')
219 );
220 }),
221 el(Button, { variant: 'secondary', onClick: function () { set({ experience: a.experience.concat([{ role: 'Job Title', company: 'Company Name', startDate: '', endDate: '', isCurrent: false, location: '', description: '' }]) }); }, style: { width: '100%', justifyContent: 'center' }, __nextHasNoMarginBottom: true }, '+ Add Experience')
222 ),
223
224 // Education
225 a.showEducation && el(PanelBody, { title: 'Education (' + a.education.length + ')', initialOpen: false },
226 el(TextControl, { label: 'Section title', value: a.educationTitle, onChange: function (v) { set({ educationTitle: v }); }, __nextHasNoMarginBottom: true }),
227 el('div', { style: { height: 10 } }),
228 a.education.map(function (edu, i) {
229 return el('div', {
230 key: i,
231 style: { border: '1px solid #e5e7eb', borderRadius: 8, padding: 10, marginBottom: 8, background: '#fafafa' }
232 },
233 el(TextControl, { label: 'Degree / Qualification', value: edu.degree, onChange: function (v) { set({ education: updateItem(a.education, i, 'degree', v) }); }, __nextHasNoMarginBottom: true }),
234 el('div', { style: { height: 6 } }),
235 el(TextControl, { label: 'Institution', value: edu.institution, onChange: function (v) { set({ education: updateItem(a.education, i, 'institution', v) }); }, __nextHasNoMarginBottom: true }),
236 el('div', { style: { height: 6 } }),
237 el(TextControl, { label: 'Start year', value: edu.startYear, onChange: function (v) { set({ education: updateItem(a.education, i, 'startYear', v) }); }, __nextHasNoMarginBottom: true }),
238 el('div', { style: { height: 6 } }),
239 el(TextControl, { label: 'End year', value: edu.endYear, onChange: function (v) { set({ education: updateItem(a.education, i, 'endYear', v) }); }, __nextHasNoMarginBottom: true }),
240 el('div', { style: { height: 6 } }),
241 el(TextareaControl, { label: 'Description (optional)', value: edu.description, rows: 2, onChange: function (v) { set({ education: updateItem(a.education, i, 'description', v) }); }, __nextHasNoMarginBottom: true }),
242 el('div', { style: { height: 6 } }),
243 el(Button, { isDestructive: true, variant: 'link', size: 'small', onClick: function () { set({ education: a.education.filter(function (_, idx) { return idx !== i; }) }); }, __nextHasNoMarginBottom: true }, 'Remove')
244 );
245 }),
246 el(Button, { variant: 'secondary', onClick: function () { set({ education: a.education.concat([{ degree: 'Degree', institution: 'University', startYear: '', endYear: '', description: '' }]) }); }, style: { width: '100%', justifyContent: 'center' }, __nextHasNoMarginBottom: true }, '+ Add Education')
247 ),
248
249 // Skills
250 a.showSkills && el(PanelBody, { title: 'Skills', initialOpen: false },
251 el(TextControl, { label: 'Section title', value: a.skillsTitle, onChange: function (v) { set({ skillsTitle: v }); }, __nextHasNoMarginBottom: true }),
252 el('div', { style: { height: 10 } }),
253 a.skills.map(function (skill, i) {
254 return el('div', {
255 key: i,
256 style: { border: '1px solid #e5e7eb', borderRadius: 8, padding: 10, marginBottom: 8, background: '#fafafa' }
257 },
258 el(TextControl, { label: 'Category', value: skill.category, onChange: function (v) { set({ skills: updateItem(a.skills, i, 'category', v) }); }, __nextHasNoMarginBottom: true }),
259 el('div', { style: { height: 6 } }),
260 el(TextareaControl, { label: 'Skills (comma-separated)', value: skill.items, rows: 2, onChange: function (v) { set({ skills: updateItem(a.skills, i, 'items', v) }); }, __nextHasNoMarginBottom: true }),
261 el('div', { style: { height: 6 } }),
262 el(Button, { isDestructive: true, variant: 'link', size: 'small', onClick: function () { set({ skills: a.skills.filter(function (_, idx) { return idx !== i; }) }); }, __nextHasNoMarginBottom: true }, 'Remove')
263 );
264 }),
265 el(Button, { variant: 'secondary', onClick: function () { set({ skills: a.skills.concat([{ category: 'Category', items: '' }]) }); }, style: { width: '100%', justifyContent: 'center' }, __nextHasNoMarginBottom: true }, '+ Add Skill Group')
266 ),
267
268 // Layout
269 el(PanelBody, { title: 'Layout', initialOpen: false },
270 el(SelectControl, { label: 'Layout', value: a.layout, options: LAYOUT_OPTIONS, onChange: function (v) { set({ layout: v }); }, __nextHasNoMarginBottom: true }),
271 el('div', { style: { height: 10 } }),
272 el(RangeControl, { label: 'Max width (px)', value: a.maxWidth, min: 500, max: 1200, onChange: function (v) { set({ maxWidth: v }); }, __nextHasNoMarginBottom: true }),
273 el('div', { style: { height: 10 } }),
274 el(RangeControl, { label: 'Container padding (px)', value: a.containerPadding, min: 16, max: 64, onChange: function (v) { set({ containerPadding: v }); }, __nextHasNoMarginBottom: true }),
275 el('div', { style: { height: 10 } }),
276 el(RangeControl, { label: 'Border radius (px)', value: a.borderRadius, min: 0, max: 24, onChange: function (v) { set({ borderRadius: v }); }, __nextHasNoMarginBottom: true }),
277 el('div', { style: { height: 10 } }),
278 el(RangeControl, { label: 'Avatar size (px)', value: a.avatarSize, min: 48, max: 140, onChange: function (v) { set({ avatarSize: v }); }, __nextHasNoMarginBottom: true }),
279 el('div', { style: { height: 10 } }),
280 el(RangeControl, { label: 'Section gap (px)', value: a.sectionGap, min: 16, max: 60, onChange: function (v) { set({ sectionGap: v }); }, __nextHasNoMarginBottom: true })
281 ),
282
283 // Typography
284 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
285 (function(){ var TC = getTypoControl(); return TC ? el(TC, { label: __('Name', 'blockenberg'), value: a.nameTypo, onChange: function(v){ set({nameTypo:v}); } }) : null; })(),
286 (function(){ var TC = getTypoControl(); return TC ? el(TC, { label: __('Body Text', 'blockenberg'), value: a.bodyTypo, onChange: function(v){ set({bodyTypo:v}); } }) : null; })()
287 ),
288 el(PanelColorSettings, {
289 title: 'Colors',
290 initialOpen: false,
291 colorSettings: [
292 { label: 'Accent Color', value: a.accentColor, onChange: function (v) { set({ accentColor: v || '#6366f1' }); } },
293 { label: 'Card Background', value: a.bgColor, onChange: function (v) { set({ bgColor: v || '#ffffff' }); } },
294 { label: 'Header Background', value: a.headerBg, onChange: function (v) { set({ headerBg: v || '#f8fafc' }); } },
295 { label: 'Heading Color', value: a.sectionHeadingColor, onChange: function (v) { set({ sectionHeadingColor: v || '#111827' }); } },
296 { label: 'Body Text', value: a.textColor, onChange: function (v) { set({ textColor: v || '#374151' }); } },
297 { label: 'Subtext / Meta', value: a.subtextColor, onChange: function (v) { set({ subtextColor: v || '#6b7280' }); } },
298 { label: 'Skill Tag Background', value: a.tagBg, onChange: function (v) { set({ tagBg: v || '#f1f5f9' }); } },
299 { label: 'Skill Tag Text', value: a.tagColor, onChange: function (v) { set({ tagColor: v || '#475569' }); } },
300 { label: 'Divider Color', value: a.dividerColor, onChange: function (v) { set({ dividerColor: v || '#e5e7eb' }); } },
301 { label: 'Timeline Dot', value: a.timelineDotColor, onChange: function (v) { set({ timelineDotColor: v || '#6366f1' }); } },
302 ]
303 })
304 ),
305
306 // ── Editor Preview ──
307 el('div', blockProps,
308 el('div', { style: container },
309
310 // Header
311 el('div', { className: 'bkbg-rv-header',
312 style: {
313 background: a.headerBg,
314 padding: a.containerPadding + 'px',
315 display: 'flex',
316 alignItems: 'flex-start',
317 gap: 20,
318 borderBottom: '1px solid ' + a.dividerColor,
319 }
320 },
321 a.showPhoto && el('div', {
322 style: {
323 width: a.avatarSize + 'px',
324 height: a.avatarSize + 'px',
325 borderRadius: '50%',
326 background: a.accentColor,
327 flexShrink: 0,
328 overflow: 'hidden',
329 display: 'flex',
330 alignItems: 'center',
331 justifyContent: 'center',
332 color: '#fff',
333 fontSize: Math.round(a.avatarSize * 0.38) + 'px',
334 fontWeight: 700,
335 }
336 }, a.photoUrl
337 ? el('img', { src: a.photoUrl, alt: a.name, style: { width: '100%', height: '100%', objectFit: 'cover' } })
338 : (a.name || 'A').split(' ').map(function (w) { return w[0]; }).slice(0, 2).join('')
339 ),
340 el('div', { style: { flexGrow: 1 } },
341 el('h2', { className: 'bkbg-rv-name', style: { margin: '0 0 4px', color: a.sectionHeadingColor } }, a.name),
342 el('p', { style: { margin: '0 0 12px', fontSize: 16, color: a.accentColor, fontWeight: 600 } }, a.jobTitle),
343 a.showContact && el('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '6px 16px', fontSize: 13, color: a.subtextColor } },
344 a.email && el('span', null, '' + a.email),
345 a.phone && el('span', null, '📞 ' + a.phone),
346 a.location && el('span', null, '📍 ' + a.location),
347 a.website && el('span', null, '🌐 ' + a.website)
348 )
349 )
350 ),
351
352 // Body
353 el('div', { style: { padding: a.containerPadding + 'px' } },
354
355 // Summary
356 a.showSummary && el('div', { style: { marginBottom: a.sectionGap + 'px' } },
357 SectionHeading(a.summaryTitle, a.accentColor),
358 el('p', { className: 'bkbg-rv-summary', style: { margin: 0, color: a.textColor } }, a.summary)
359 ),
360
361 // Experience
362 a.showExperience && el('div', { style: { marginBottom: a.sectionGap + 'px' } },
363 SectionHeading(a.experienceTitle, a.accentColor),
364 a.experience.map(function (exp, i) { return el(Fragment, { key: i }, ExperiencePreview(exp, a)); })
365 ),
366
367 // Education
368 a.showEducation && el('div', { style: { marginBottom: a.sectionGap + 'px' } },
369 SectionHeading(a.educationTitle, a.accentColor),
370 a.education.map(function (edu, i) { return el(Fragment, { key: i }, EducationPreview(edu, a)); })
371 ),
372
373 // Skills
374 a.showSkills && el('div', null,
375 SectionHeading(a.skillsTitle, a.accentColor),
376 a.skills.map(function (skill, i) {
377 return el('div', { key: i, style: { marginBottom: 14 } },
378 el('div', { style: { fontSize: 13, fontWeight: 700, color: a.sectionHeadingColor, marginBottom: 8, textTransform: 'uppercase', letterSpacing: '0.05em' } }, skill.category),
379 el('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 6 } },
380 (skill.items || '').split(',').map(function (item, j) {
381 var t = item.trim();
382 if (!t) return null;
383 return el('span', {
384 key: j,
385 style: {
386 background: a.tagBg, color: a.tagColor,
387 borderRadius: 99, padding: '3px 10px', fontSize: 13,
388 }
389 }, t);
390 })
391 )
392 );
393 })
394 )
395 )
396 )
397 )
398 );
399 },
400
401 save: function (props) {
402 return el('div', useBlockProps.save(),
403 el('div', { className: 'bkbg-rv-app', 'data-opts': JSON.stringify(props.attributes) })
404 );
405 }
406 });
407 }() );
408