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

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

427 lines 28.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 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 useBlockProps = wp.blockEditor.useBlockProps;
9 var RichText = wp.blockEditor.RichText;
10 var MediaUpload = wp.blockEditor.MediaUpload;
11 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
12 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
13 var PanelBody = wp.components.PanelBody;
14 var ToggleControl = wp.components.ToggleControl;
15 var RangeControl = wp.components.RangeControl;
16 var SelectControl = wp.components.SelectControl;
17 var TextControl = wp.components.TextControl;
18 var Button = wp.components.Button;
19 var ColorPicker = wp.components.ColorPicker;
20 var Popover = wp.components.Popover;
21
22 var _TypographyControl, _typoCssVars;
23 function getTypographyControl() { return _TypographyControl || (_TypographyControl = window.bkbgTypographyControl); }
24 function getTypoCssVars() { return _typoCssVars || (_typoCssVars = window.bkbgTypoCssVars); }
25
26 var JOB_TYPES = [
27 { label: 'Full‑time', value: 'full-time' },
28 { label: 'Part‑time', value: 'part-time' },
29 { label: 'Contract', value: 'contract' },
30 { label: 'Freelance', value: 'freelance' },
31 { label: 'Internship', value: 'internship' },
32 { label: 'Temporary', value: 'temporary' },
33 ];
34
35 var LOCATION_TYPES = [
36 { label: 'On‑site', value: 'onsite' },
37 { label: 'Remote', value: 'remote' },
38 { label: 'Hybrid', value: 'hybrid' },
39 ];
40
41 var PERIODS = [
42 { label: 'per year', value: 'year' },
43 { label: 'per month', value: 'month' },
44 { label: 'per hour', value: 'hour' },
45 { label: 'per project', value: 'project' },
46 ];
47
48 function jobTypeLabel(v) {
49 var f = JOB_TYPES.find(function (t) { return t.value === v; });
50 return f ? f.label : v;
51 }
52
53 function locationIcon(v) {
54 if (v === 'remote') { return '🌐'; }
55 if (v === 'hybrid') { return '🔀'; }
56 return '📍';
57 }
58
59 /* ── meta pill ──────────────────────────────────────────────────────────── */
60 function Pill(props) {
61 var ls = props.ls;
62 return el('span', {
63 className: ls ? undefined : 'bkjl-pill',
64 style: {
65 display: 'inline-flex', alignItems: 'center', gap: '4px',
66 background: props.bg || '#f3f4f6',
67 color: props.color || '#374151',
68 padding: '3px 10px', borderRadius: '999px',
69 fontSize: ls ? '12px' : undefined,
70 fontWeight: ls ? 600 : undefined,
71 whiteSpace: 'nowrap',
72 }
73 }, props.icon && el('span', null, props.icon), props.label);
74 }
75
76 /* ── card preview used in both edit & save ──────────────────────────────── */
77 function JobCard(props) {
78 var a = props.a;
79 var isEdit = props.isEdit;
80 var ls = props.legacyStyles;
81
82 var skills = (a.skills || '').split(',').map(function (s) { return s.trim(); }).filter(Boolean);
83
84 var cardStyle = {
85 background: a.cardBg,
86 borderRadius: a.cardBorderRadius + 'px',
87 padding: a.cardPadding + 'px',
88 boxShadow: a.showShadow ? '0 4px 24px rgba(0,0,0,0.08)' : 'none',
89 border: a.showBorder ? '1px solid ' + a.borderColor : 'none',
90 position: 'relative',
91 overflow: 'hidden',
92 };
93
94 return el('div', { className: 'bkjl-card', style: cardStyle },
95 /* featured stripe */
96 a.featured && el('div', {
97 className: 'bkjl-featured-stripe',
98 style: { position: 'absolute', top: 0, left: 0, right: 0, height: '4px', background: a.featuredColor }
99 }),
100
101 /* header row */
102 el('div', { className: 'bkjl-header', style: { display: 'flex', alignItems: 'flex-start', gap: '16px', marginBottom: '14px' } },
103 a.showLogo && el('div', { className: 'bkjl-logo-wrap', style: { flexShrink: 0 } },
104 a.logoUrl
105 ? el('img', {
106 src: a.logoUrl, alt: a.logoAlt,
107 style: { width: a.logoSize + 'px', height: a.logoSize + 'px', objectFit: 'contain', borderRadius: '8px', border: '1px solid #e5e7eb', display: 'block' }
108 })
109 : el('div', {
110 style: { width: a.logoSize + 'px', height: a.logoSize + 'px', borderRadius: '8px', background: '#ece9f8', display: 'flex', alignItems: 'center', justifyContent: 'center', color: a.companyColor, fontWeight: 700, fontSize: '20px' }
111 }, (a.company || 'C').charAt(0).toUpperCase())
112 ),
113
114 el('div', { style: { flex: 1, minWidth: 0 } },
115 /* badges row */
116 el('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '6px', alignItems: 'center' } },
117 a.featured && el('span', {
118 className: 'bkjl-badge-featured',
119 style: { background: a.featuredColor, color: a.featuredTextColor, padding: '2px 8px', borderRadius: '4px',
120 fontSize: ls ? '11px' : undefined, fontWeight: ls ? 700 : undefined, letterSpacing: ls ? '.3px' : undefined }
121 }, (a.featuredLabel || 'Featured').toUpperCase()),
122 a.urgent && el('span', {
123 className: 'bkjl-badge-urgent',
124 style: { background: '#fef2f2', color: '#ef4444', border: '1px solid #fca5a5', padding: '2px 8px', borderRadius: '4px',
125 fontSize: ls ? '11px' : undefined, fontWeight: ls ? 700 : undefined }
126 }, 'URGENT')
127 ),
128
129 /* title */
130 isEdit
131 ? el(RichText, {
132 tagName: 'h3', className: 'bkjl-title',
133 value: a.jobTitle,
134 onChange: function (v) { props.setAttr({ jobTitle: v }); },
135 style: { margin: '0 0 4px', color: a.titleColor },
136 placeholder: __('Job Title', 'blockenberg'),
137 })
138 : el(RichText.Content, { tagName: 'h3', className: 'bkjl-title', value: a.jobTitle, style: { margin: '0 0 4px', color: a.titleColor } }),
139
140 /* company */
141 el('p', { className: 'bkjl-company', style: { margin: '0 0 8px', color: a.companyColor, fontWeight: ls ? 600 : undefined, fontSize: ls ? '14px' : undefined } },
142 isEdit
143 ? el(RichText, { tagName: 'span', value: a.company, onChange: function (v) { props.setAttr({ company: v }); }, placeholder: __('Company', 'blockenberg') })
144 : el(RichText.Content, { tagName: 'span', value: a.company }),
145 a.department && el('span', { style: { color: a.metaColor, fontWeight: 400, marginLeft: '6px' } }, '· ' + a.department)
146 ),
147
148 /* meta pills row */
149 el('div', { className: 'bkjl-meta', style: { display: 'flex', flexWrap: 'wrap', gap: '6px' } },
150 el(Pill, { bg: a.jobTypeBg, color: a.jobTypeText, label: jobTypeLabel(a.jobType), ls: ls }),
151 el(Pill, { bg: '#f0fdf4', color: '#16a34a', icon: locationIcon(a.locationType), label: a.location || 'Location', ls: ls }),
152 a.locationType !== 'onsite' && el(Pill, { bg: '#eff6ff', color: '#2563eb', label: a.locationType === 'remote' ? 'Remote' : 'Hybrid', ls: ls }),
153 a.showSalary && a.salaryMin && el(Pill, { bg: '#fef9c3', color: '#854d0e', icon: '💰', label: a.salaryCurrency + a.salaryMin + (a.salaryMax ? '' + a.salaryCurrency + a.salaryMax : '') + ' / ' + a.salaryPeriod, ls: ls })
154 )
155 )
156 ),
157
158 /* divider */
159 a.showDivider && el('hr', { style: { border: 'none', borderTop: '1px solid ' + a.dividerColor, margin: '14px 0' } }),
160
161 /* description */
162 a.showDescription && (
163 isEdit
164 ? el(RichText, {
165 tagName: 'p', className: 'bkjl-desc',
166 value: a.description,
167 onChange: function (v) { props.setAttr({ description: v }); },
168 style: { margin: '0 0 14px', color: a.bodyColor, fontSize: ls ? '14px' : undefined, lineHeight: ls ? 1.65 : undefined },
169 placeholder: __('Job description...', 'blockenberg'),
170 })
171 : el(RichText.Content, { tagName: 'p', className: 'bkjl-desc', value: a.description, style: { margin: '0 0 14px', color: a.bodyColor, fontSize: ls ? '14px' : undefined, lineHeight: ls ? 1.65 : undefined } })
172 ),
173
174 /* skills */
175 a.showSkills && skills.length > 0 && el('div', { className: 'bkjl-skills', style: { display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '18px' } },
176 skills.map(function (s, i) {
177 return el('span', {
178 key: i,
179 className: 'bkjl-skill',
180 style: { background: a.skillBg, color: a.skillText, padding: '3px 10px', borderRadius: '4px',
181 fontSize: ls ? '12px' : undefined, fontWeight: ls ? 500 : undefined }
182 }, s);
183 })
184 ),
185
186 /* footer row */
187 el('div', { className: 'bkjl-footer', style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: '10px' } },
188 el('div', { className: 'bkjl-dates', style: { display: 'flex', gap: '16px', flexWrap: 'wrap' } },
189 a.showPostedDate && a.postedDate && el('span', { className: 'bkjl-posted', style: { color: a.metaColor, fontSize: ls ? '12px' : undefined, display: 'flex', alignItems: 'center', gap: '4px' } }, '🗓 Posted: ' + a.postedDate),
190 a.showDeadline && a.deadline && el('span', { className: 'bkjl-deadline', style: { color: '#ef4444', fontSize: ls ? '12px' : undefined, display: 'flex', alignItems: 'center', gap: '4px' } }, '⏰ Deadline: ' + a.deadline)
191 ),
192 el('div', { className: 'bkjl-cta', style: { display: 'flex', gap: '8px', flexWrap: 'wrap' } },
193 a.showSecondaryBtn && a.secondaryLabel && el('a', {
194 href: isEdit ? undefined : (a.secondaryUrl || '#'),
195 className: 'bkjl-btn-secondary',
196 style: { padding: '9px 20px', borderRadius: a.primaryBtnRadius + 'px', border: '1px solid ' + a.primaryBtnBg, color: a.primaryBtnBg,
197 fontWeight: ls ? 600 : undefined, fontSize: ls ? '14px' : undefined, textDecoration: 'none', display: 'inline-block', transition: 'all .2s ease' }
198 }, a.secondaryLabel),
199 a.showApplyBtn && el('a', {
200 href: isEdit ? undefined : (a.applyUrl || '#'),
201 target: a.applyNewTab && !isEdit ? '_blank' : undefined,
202 rel: a.applyNewTab && !isEdit ? 'noopener noreferrer' : undefined,
203 className: 'bkjl-btn-apply',
204 style: { padding: '9px 22px', borderRadius: a.primaryBtnRadius + 'px', background: a.primaryBtnBg, color: a.primaryBtnText,
205 fontWeight: ls ? 700 : undefined, fontSize: ls ? '14px' : undefined, textDecoration: 'none', display: 'inline-block', transition: 'all .2s ease' }
206 }, a.applyLabel || 'Apply Now')
207 )
208 )
209 );
210 }
211
212 /* ── edit ───────────────────────────────────────────────────────────────── */
213 function Edit(props) {
214 var attributes = props.attributes;
215 var setAttributes = props.setAttributes;
216 var a = attributes;
217
218 var blockProps = useBlockProps((function () {
219 var _tv = getTypoCssVars();
220 var s = {};
221 Object.assign(s,
222 _tv(a.titleTypo, '--bkjl-tt-'),
223 _tv(a.typoCompany, '--bkjl-co-'),
224 _tv(a.typoDesc, '--bkjl-de-'),
225 _tv(a.typoSkill, '--bkjl-sk-'),
226 _tv(a.typoBadge, '--bkjl-ba-'),
227 _tv(a.typoPill, '--bkjl-pi-'),
228 _tv(a.typoMeta, '--bkjl-mt-'),
229 _tv(a.typoBtn, '--bkjl-bt-')
230 );
231 return { style: s };
232 })());
233
234 function setAttr(obj) { setAttributes(obj); }
235
236 return el(Fragment, null,
237 el(InspectorControls, null,
238
239 /* Job Details */
240 el(PanelBody, { title: __('Job Details', 'blockenberg'), initialOpen: true },
241 el(TextControl, { label: __('Job Title', 'blockenberg'), value: a.jobTitle, onChange: function (v) { setAttr({ jobTitle: v }); } }),
242 el(TextControl, { label: __('Company', 'blockenberg'), value: a.company, onChange: function (v) { setAttr({ company: v }); } }),
243 el(TextControl, { label: __('Department', 'blockenberg'), value: a.department, onChange: function (v) { setAttr({ department: v }); } }),
244 el(TextControl, { label: __('Location', 'blockenberg'), value: a.location, onChange: function (v) { setAttr({ location: v }); } }),
245 el(SelectControl, {
246 label: __('Location Type', 'blockenberg'), value: a.locationType, options: LOCATION_TYPES,
247 onChange: function (v) { setAttr({ locationType: v }); }
248 }),
249 el(SelectControl, {
250 label: __('Job Type', 'blockenberg'), value: a.jobType, options: JOB_TYPES,
251 onChange: function (v) { setAttr({ jobType: v }); }
252 })
253 ),
254
255 /* Salary */
256 el(PanelBody, { title: __('Salary', 'blockenberg'), initialOpen: false },
257 el(ToggleControl, { label: __('Show Salary', 'blockenberg'), checked: a.showSalary, onChange: function (v) { setAttr({ showSalary: v }); }, __nextHasNoMarginBottom: true }),
258 a.showSalary && el(Fragment, null,
259 el(TextControl, { label: __('Currency Symbol', 'blockenberg'), value: a.salaryCurrency, onChange: function (v) { setAttr({ salaryCurrency: v }); } }),
260 el(TextControl, { label: __('Min Salary', 'blockenberg'), value: a.salaryMin, onChange: function (v) { setAttr({ salaryMin: v }); } }),
261 el(TextControl, { label: __('Max Salary', 'blockenberg'), value: a.salaryMax, onChange: function (v) { setAttr({ salaryMax: v }); } }),
262 el(SelectControl, {
263 label: __('Period', 'blockenberg'), value: a.salaryPeriod, options: PERIODS,
264 onChange: function (v) { setAttr({ salaryPeriod: v }); }
265 })
266 )
267 ),
268
269 /* Dates */
270 el(PanelBody, { title: __('Dates', 'blockenberg'), initialOpen: false },
271 el(ToggleControl, { label: __('Show Posted Date', 'blockenberg'), checked: a.showPostedDate, onChange: function (v) { setAttr({ showPostedDate: v }); }, __nextHasNoMarginBottom: true }),
272 a.showPostedDate && el(TextControl, { label: __('Posted Date', 'blockenberg'), value: a.postedDate, placeholder: 'e.g. Jan 15, 2026', onChange: function (v) { setAttr({ postedDate: v }); } }),
273 el(ToggleControl, { label: __('Show Deadline', 'blockenberg'), checked: a.showDeadline, onChange: function (v) { setAttr({ showDeadline: v }); }, __nextHasNoMarginBottom: true }),
274 a.showDeadline && el(TextControl, { label: __('Application Deadline', 'blockenberg'), value: a.deadline, placeholder: 'e.g. Feb 28, 2026', onChange: function (v) { setAttr({ deadline: v }); } })
275 ),
276
277 /* Content */
278 el(PanelBody, { title: __('Content', 'blockenberg'), initialOpen: false },
279 el(ToggleControl, { label: __('Show Description', 'blockenberg'), checked: a.showDescription, onChange: function (v) { setAttr({ showDescription: v }); }, __nextHasNoMarginBottom: true }),
280 el(ToggleControl, { label: __('Show Skills', 'blockenberg'), checked: a.showSkills, onChange: function (v) { setAttr({ showSkills: v }); }, __nextHasNoMarginBottom: true }),
281 a.showSkills && el(TextControl, {
282 label: __('Skills (comma-separated)', 'blockenberg'), value: a.skills,
283 placeholder: 'React, Node.js, CSS',
284 onChange: function (v) { setAttr({ skills: v }); }
285 })
286 ),
287
288 /* CTA */
289 el(PanelBody, { title: __('Buttons', 'blockenberg'), initialOpen: false },
290 el(ToggleControl, { label: __('Show Apply Button', 'blockenberg'), checked: a.showApplyBtn, onChange: function (v) { setAttr({ showApplyBtn: v }); }, __nextHasNoMarginBottom: true }),
291 a.showApplyBtn && el(Fragment, null,
292 el(TextControl, { label: __('Apply Label', 'blockenberg'), value: a.applyLabel, onChange: function (v) { setAttr({ applyLabel: v }); } }),
293 el(TextControl, { label: __('Apply URL', 'blockenberg'), value: a.applyUrl, placeholder: 'https://', onChange: function (v) { setAttr({ applyUrl: v }); } }),
294 el(ToggleControl, { label: __('Open in New Tab', 'blockenberg'), checked: a.applyNewTab, onChange: function (v) { setAttr({ applyNewTab: v }); }, __nextHasNoMarginBottom: true })
295 ),
296 el(ToggleControl, { label: __('Show Secondary Button', 'blockenberg'), checked: a.showSecondaryBtn, onChange: function (v) { setAttr({ showSecondaryBtn: v }); }, __nextHasNoMarginBottom: true }),
297 a.showSecondaryBtn && el(Fragment, null,
298 el(TextControl, { label: __('Secondary Label', 'blockenberg'), value: a.secondaryLabel, onChange: function (v) { setAttr({ secondaryLabel: v }); } }),
299 el(TextControl, { label: __('Secondary URL', 'blockenberg'), value: a.secondaryUrl, placeholder: 'https://', onChange: function (v) { setAttr({ secondaryUrl: v }); } })
300 ),
301 el(RangeControl, { label: __('Button Border Radius', 'blockenberg'), value: a.primaryBtnRadius, min: 0, max: 50, onChange: function (v) { setAttr({ primaryBtnRadius: v }); } })
302 ),
303
304 /* Logo */
305 el(PanelBody, { title: __('Company Logo', 'blockenberg'), initialOpen: false },
306 el(ToggleControl, { label: __('Show Logo', 'blockenberg'), checked: a.showLogo, onChange: function (v) { setAttr({ showLogo: v }); }, __nextHasNoMarginBottom: true }),
307 a.showLogo && el(Fragment, null,
308 el(RangeControl, { label: __('Logo Size (px)', 'blockenberg'), value: a.logoSize, min: 32, max: 100, onChange: function (v) { setAttr({ logoSize: v }); } }),
309 el(MediaUploadCheck, null,
310 el(MediaUpload, {
311 onSelect: function (m) { setAttr({ logoUrl: m.url, logoId: m.id, logoAlt: m.alt || '' }); },
312 allowedTypes: ['image'],
313 value: a.logoId,
314 render: function (r) {
315 return el(Fragment, null,
316 a.logoUrl && el('div', { style: { margin: '8px 0' } },
317 el('img', { src: a.logoUrl, style: { width: '64px', height: '64px', objectFit: 'contain', borderRadius: '6px', border: '1px solid #e5e7eb' } })
318 ),
319 el(Button, { onClick: r.open, isSecondary: true, isSmall: true }, a.logoUrl ? __('Change Logo', 'blockenberg') : __('Select Logo', 'blockenberg')),
320 a.logoUrl && el(Button, { onClick: function () { setAttr({ logoUrl: '', logoId: 0, logoAlt: '' }); }, isDestructive: true, isSmall: true, style: { marginLeft: '6px' } }, __('Remove', 'blockenberg'))
321 );
322 }
323 })
324 )
325 )
326 ),
327
328 /* Badges */
329 el(PanelBody, { title: __('Badges', 'blockenberg'), initialOpen: false },
330 el(ToggleControl, { label: __('Featured', 'blockenberg'), checked: a.featured, onChange: function (v) { setAttr({ featured: v }); }, __nextHasNoMarginBottom: true }),
331 a.featured && el(TextControl, { label: __('Featured Label', 'blockenberg'), value: a.featuredLabel, onChange: function (v) { setAttr({ featuredLabel: v }); } }),
332 el(ToggleControl, { label: __('Mark as Urgent', 'blockenberg'), checked: a.urgent, onChange: function (v) { setAttr({ urgent: v }); }, __nextHasNoMarginBottom: true })
333 ),
334
335 /* Card Style */
336 el(PanelBody, { title: __('Card Style', 'blockenberg'), initialOpen: false },
337 el(RangeControl, { label: __('Border Radius (px)', 'blockenberg'), value: a.cardBorderRadius, min: 0, max: 32, onChange: function (v) { setAttr({ cardBorderRadius: v }); } }),
338 el(RangeControl, { label: __('Padding (px)', 'blockenberg'), value: a.cardPadding, min: 12, max: 60, onChange: function (v) { setAttr({ cardPadding: v }); } }),
339 el(ToggleControl, { label: __('Show Shadow', 'blockenberg'), checked: a.showShadow, onChange: function (v) { setAttr({ showShadow: v }); }, __nextHasNoMarginBottom: true }),
340 el(ToggleControl, { label: __('Show Border', 'blockenberg'), checked: a.showBorder, onChange: function (v) { setAttr({ showBorder: v }); }, __nextHasNoMarginBottom: true }),
341 el(ToggleControl, { label: __('Show Divider', 'blockenberg'), checked: a.showDivider, onChange: function (v) { setAttr({ showDivider: v }); }, __nextHasNoMarginBottom: true })
342 ),
343
344 /* Typography */
345 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
346 el(getTypographyControl(), { label: __('Title', 'blockenberg'), value: a.titleTypo, onChange: function (v) { setAttr({ titleTypo: v }); } }),
347 el(getTypographyControl(), { label: __('Company', 'blockenberg'), value: a.typoCompany, onChange: function (v) { setAttr({ typoCompany: v }); } }),
348 el(getTypographyControl(), { label: __('Description', 'blockenberg'), value: a.typoDesc, onChange: function (v) { setAttr({ typoDesc: v }); } }),
349 el(getTypographyControl(), { label: __('Skills', 'blockenberg'), value: a.typoSkill, onChange: function (v) { setAttr({ typoSkill: v }); } }),
350 el(getTypographyControl(), { label: __('Badges', 'blockenberg'), value: a.typoBadge, onChange: function (v) { setAttr({ typoBadge: v }); } }),
351 el(getTypographyControl(), { label: __('Meta Pills', 'blockenberg'), value: a.typoPill, onChange: function (v) { setAttr({ typoPill: v }); } }),
352 el(getTypographyControl(), { label: __('Meta / Dates', 'blockenberg'), value: a.typoMeta, onChange: function (v) { setAttr({ typoMeta: v }); } }),
353 el(getTypographyControl(), { label: __('Buttons', 'blockenberg'), value: a.typoBtn, onChange: function (v) { setAttr({ typoBtn: v }); } })
354 ),
355
356 /* Colors */
357 el(PanelColorSettings, {
358 title: __('Colors', 'blockenberg'),
359 initialOpen: false,
360 colorSettings: [
361 { label: __('Card Background', 'blockenberg'), value: a.cardBg, onChange: function (v) { setAttr({ cardBg: v || '#ffffff' }); } },
362 { label: __('Title', 'blockenberg'), value: a.titleColor, onChange: function (v) { setAttr({ titleColor: v || '#1e1e1e' }); } },
363 { label: __('Company', 'blockenberg'), value: a.companyColor, onChange: function (v) { setAttr({ companyColor: v || '#6c3fb5' }); } },
364 { label: __('Body Text', 'blockenberg'), value: a.bodyColor, onChange: function (v) { setAttr({ bodyColor: v || '#374151' }); } },
365 { label: __('Meta Text', 'blockenberg'), value: a.metaColor, onChange: function (v) { setAttr({ metaColor: v || '#6b7280' }); } },
366 { label: __('Apply Button Bg', 'blockenberg'), value: a.primaryBtnBg, onChange: function (v) { setAttr({ primaryBtnBg: v || '#6c3fb5' }); } },
367 { label: __('Apply Button Text', 'blockenberg'), value: a.primaryBtnText, onChange: function (v) { setAttr({ primaryBtnText: v || '#ffffff' }); } },
368 { label: __('Job Type Badge Bg', 'blockenberg'), value: a.jobTypeBg, onChange: function (v) { setAttr({ jobTypeBg: v || '#ede9fe' }); } },
369 { label: __('Job Type Badge Text', 'blockenberg'), value: a.jobTypeText, onChange: function (v) { setAttr({ jobTypeText: v || '#6c3fb5' }); } },
370 { label: __('Skill Bg', 'blockenberg'), value: a.skillBg, onChange: function (v) { setAttr({ skillBg: v || '#f3f4f6' }); } },
371 { label: __('Skill Text', 'blockenberg'), value: a.skillText, onChange: function (v) { setAttr({ skillText: v || '#374151' }); } },
372 { label: __('Featured Color', 'blockenberg'), value: a.featuredColor, onChange: function (v) { setAttr({ featuredColor: v || '#f59e0b' }); } },
373 { label: __('Border / Divider', 'blockenberg'), value: a.borderColor, onChange: function (v) { setAttr({ borderColor: v || '#e5e7eb' }); } },
374 ]
375 })
376 ),
377
378 el('div', blockProps,
379 el(JobCard, { a: a, isEdit: true, setAttr: setAttributes })
380 )
381 );
382 }
383
384 /* ── save ───────────────────────────────────────────────────────────────── */
385 function Save(props) {
386 var a = props.attributes;
387 var _tv = getTypoCssVars();
388 var s = {};
389 Object.assign(s,
390 _tv(a.titleTypo, '--bkjl-tt-'),
391 _tv(a.typoCompany, '--bkjl-co-'),
392 _tv(a.typoDesc, '--bkjl-de-'),
393 _tv(a.typoSkill, '--bkjl-sk-'),
394 _tv(a.typoBadge, '--bkjl-ba-'),
395 _tv(a.typoPill, '--bkjl-pi-'),
396 _tv(a.typoMeta, '--bkjl-mt-'),
397 _tv(a.typoBtn, '--bkjl-bt-')
398 );
399 var blockProps = wp.blockEditor.useBlockProps.save({ className: 'bkjl-wrap', style: s });
400 return el('div', blockProps,
401 el(JobCard, { a: a, isEdit: false })
402 );
403 }
404
405 /* ── deprecated ─────────────────────────────────────────────────────────── */
406 var deprecated = [
407 {
408 save: function (props) {
409 var a = props.attributes;
410 var _tv = getTypoCssVars();
411 var s = {};
412 Object.assign(s, _tv(a.titleTypo, '--bkjl-tt-'));
413 var blockProps = wp.blockEditor.useBlockProps.save({ className: 'bkjl-wrap', style: s });
414 return el('div', blockProps,
415 el(JobCard, { a: a, isEdit: false, legacyStyles: true })
416 );
417 }
418 }
419 ];
420
421 registerBlockType('blockenberg/job-listing', {
422 edit: Edit,
423 save: Save,
424 deprecated: deprecated,
425 });
426 }() );
427