| 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 RichText = wp.blockEditor.RichText; |
| 8 |
var PanelColorSettings = wp.blockEditor.PanelColorSettings; |
| 9 |
var PanelBody = wp.components.PanelBody; |
| 10 |
var ToggleControl = wp.components.ToggleControl; |
| 11 |
var RangeControl = wp.components.RangeControl; |
| 12 |
var SelectControl = wp.components.SelectControl; |
| 13 |
var TextControl = wp.components.TextControl; |
| 14 |
var Button = wp.components.Button; |
| 15 |
|
| 16 |
var _tc, _tv; |
| 17 |
function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); } |
| 18 |
function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); } |
| 19 |
|
| 20 |
var IP = function () { return window.bkbgIconPicker; }; |
| 21 |
|
| 22 |
var LEVELS = [ |
| 23 |
{ value: 'beginner', label: '🟢 Beginner' }, |
| 24 |
{ value: 'intermediate', label: '🟡 Intermediate' }, |
| 25 |
{ value: 'advanced', label: '🔴 Advanced' }, |
| 26 |
{ value: 'all', label: '🔵 All Levels' } |
| 27 |
]; |
| 28 |
|
| 29 |
var BULLET_OPTIONS = [ |
| 30 |
{ value: 'check', label: '� |
| 31 |
Checkmark' }, |
| 32 |
{ value: 'arrow', label: '→ Arrow' }, |
| 33 |
{ value: 'circle', label: '● Circle' }, |
| 34 |
{ value: 'star', label: '� |
| 35 |
Star' }, |
| 36 |
{ value: 'custom', label: 'Custom' } |
| 37 |
]; |
| 38 |
|
| 39 |
var BULLETS = { check: '✓', arrow: '→', circle: '●', star: '� |
| 40 |
' }; |
| 41 |
|
| 42 |
function getBullet(attr) { |
| 43 |
return attr.bulletStyle === 'custom' ? (attr.customBullet || '✓') : (BULLETS[attr.bulletStyle] || '✓'); |
| 44 |
} |
| 45 |
|
| 46 |
function getLevelLabel(val) { |
| 47 |
var found = LEVELS.find(function (l) { return l.value === val; }); |
| 48 |
return found ? found.label : val; |
| 49 |
} |
| 50 |
|
| 51 |
registerBlockType('blockenberg/lesson-objectives', { |
| 52 |
edit: function (props) { |
| 53 |
var attr = props.attributes; |
| 54 |
var set = props.setAttributes; |
| 55 |
|
| 56 |
var blockProps = useBlockProps((function () { |
| 57 |
var _tvFn = getTypoCssVars(); |
| 58 |
var s = { padding: attr.paddingTop + 'px 0 ' + attr.paddingBottom + 'px' }; |
| 59 |
if (_tvFn) { |
| 60 |
Object.assign(s, _tvFn(attr.headingTypo, '--bkbg-lob-h-')); |
| 61 |
Object.assign(s, _tvFn(attr.objectiveTypo, '--bkbg-lob-o-')); |
| 62 |
} |
| 63 |
return { style: s }; |
| 64 |
})()); |
| 65 |
var bullet = getBullet(attr); |
| 66 |
|
| 67 |
function updateObjective(idx, val) { |
| 68 |
var arr = (attr.objectives || []).map(function (o, i) { |
| 69 |
return i === idx ? { text: val } : o; |
| 70 |
}); |
| 71 |
set({ objectives: arr }); |
| 72 |
} |
| 73 |
|
| 74 |
var wrapStyle = { |
| 75 |
background: attr.bgColor, |
| 76 |
border: '1px solid ' + attr.borderColor, |
| 77 |
borderRadius: attr.borderRadius + 'px', |
| 78 |
padding: '20px 24px', |
| 79 |
boxSizing: 'border-box' |
| 80 |
}; |
| 81 |
if (attr.style === 'left-border') { |
| 82 |
wrapStyle.borderLeft = '4px solid ' + attr.accentColor; |
| 83 |
} else if (attr.style === 'top-border') { |
| 84 |
wrapStyle.borderTop = '4px solid ' + attr.accentColor; |
| 85 |
wrapStyle.borderRadius = '0 0 ' + attr.borderRadius + 'px ' + attr.borderRadius + 'px'; |
| 86 |
} else if (attr.style === 'minimal') { |
| 87 |
wrapStyle.background = 'transparent'; |
| 88 |
wrapStyle.border = 'none'; |
| 89 |
wrapStyle.padding = '0'; |
| 90 |
} |
| 91 |
|
| 92 |
/* Header row */ |
| 93 |
var header = el('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '16px', flexWrap: 'wrap', gap: '8px' } }, |
| 94 |
el('div', { style: { display: 'flex', alignItems: 'center', gap: '10px' } }, |
| 95 |
attr.showIcon && el('span', { className: 'bkbg-lob-icon', style: { fontSize: '24px', lineHeight: 1 } }, IP().buildEditorIcon(attr.headingIconType, attr.headingIcon, attr.headingIconDashicon, attr.headingIconImageUrl, attr.headingIconDashiconColor)), |
| 96 |
el(RichText, { tagName: 'h3', className: 'bkbg-lob-heading', value: attr.heading, allowedFormats: [], placeholder: __('What You\'ll Learn', 'blockenberg'), style: { margin: 0, color: attr.headingColor }, onChange: function (v) { set({ heading: v }); } }) |
| 97 |
), |
| 98 |
el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' } }, |
| 99 |
attr.showLevel && el('span', { style: { background: attr.levelBg, color: attr.levelColor, fontSize: '11px', padding: '3px 9px', borderRadius: '20px', fontWeight: 600 } }, getLevelLabel(attr.level)), |
| 100 |
attr.showReadTime && attr.readTime && el('span', { style: { fontSize: '12px', color: attr.metaColor } }, '⏱ ' + attr.readTime) |
| 101 |
) |
| 102 |
); |
| 103 |
|
| 104 |
/* Objectives grid */ |
| 105 |
var cols = attr.columns > 1 ? 'repeat(' + attr.columns + ', 1fr)' : '1fr'; |
| 106 |
var listEl = el('div', { style: { display: 'grid', gridTemplateColumns: cols, gap: '10px' } }, |
| 107 |
(attr.objectives || []).map(function (obj, i) { |
| 108 |
return el('div', { key: i, style: { display: 'flex', alignItems: 'flex-start', gap: '10px' } }, |
| 109 |
el('span', { style: { background: attr.bulletBg, color: attr.bulletColor, width: '24px', height: '24px', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '13px', fontWeight: 700, flexShrink: 0, marginTop: '1px' } }, bullet), |
| 110 |
el(RichText, { tagName: 'p', className: 'bkbg-lob-text', value: obj.text, allowedFormats: ['core/bold', 'core/italic'], placeholder: __('Objective…', 'blockenberg'), style: { margin: 0, color: attr.textColor }, onChange: function (v) { updateObjective(i, v); } }) |
| 111 |
); |
| 112 |
}) |
| 113 |
); |
| 114 |
|
| 115 |
var controls = el(InspectorControls, {}, |
| 116 |
el(PanelBody, { title: __('Objectives', 'blockenberg'), initialOpen: true }, |
| 117 |
(attr.objectives || []).map(function (obj, idx) { |
| 118 |
return el('div', { key: idx, style: { display: 'flex', gap: '4px', marginBottom: '6px', alignItems: 'center' } }, |
| 119 |
el('div', { style: { flex: 1 } }, |
| 120 |
el(TextControl, { label: '', value: obj.text, placeholder: 'Objective…', __nextHasNoMarginBottom: true, onChange: function (v) { updateObjective(idx, v); } }) |
| 121 |
), |
| 122 |
el(Button, { variant: 'link', isDestructive: true, onClick: function () { set({ objectives: (attr.objectives || []).filter(function (_, i) { return i !== idx; }) }); } }, '✕') |
| 123 |
); |
| 124 |
}), |
| 125 |
el(Button, { variant: 'secondary', style: { marginTop: '4px' }, onClick: function () { set({ objectives: (attr.objectives || []).concat([{ text: '' }]) }); } }, __('+ Add Objective', 'blockenberg')) |
| 126 |
), |
| 127 |
el(PanelBody, { title: __('Header & Meta', 'blockenberg'), initialOpen: false }, |
| 128 |
el(IP().IconPickerControl, IP().iconPickerProps(attr, set, { charAttr: 'headingIcon', typeAttr: 'headingIconType', dashiconAttr: 'headingIconDashicon', imageUrlAttr: 'headingIconImageUrl', colorAttr: 'headingIconDashiconColor' })), |
| 129 |
el('div', { style: { marginTop: '8px' } }, |
| 130 |
el(ToggleControl, { label: __('Show Icon', 'blockenberg'), checked: attr.showIcon, __nextHasNoMarginBottom: true, onChange: function (v) { set({ showIcon: v }); } }) |
| 131 |
), |
| 132 |
el('div', { style: { marginTop: '12px' } }, |
| 133 |
el(ToggleControl, { label: __('Show Level Badge', 'blockenberg'), checked: attr.showLevel, __nextHasNoMarginBottom: true, onChange: function (v) { set({ showLevel: v }); } }) |
| 134 |
), |
| 135 |
attr.showLevel && el('div', { style: { marginTop: '8px' } }, |
| 136 |
el(SelectControl, { |
| 137 |
label: __('Level', 'blockenberg'), value: attr.level, __nextHasNoMarginBottom: true, |
| 138 |
options: LEVELS.map(function (l) { return { label: l.label, value: l.value }; }), |
| 139 |
onChange: function (v) { set({ level: v }); } |
| 140 |
}) |
| 141 |
), |
| 142 |
el('div', { style: { marginTop: '12px' } }, |
| 143 |
el(ToggleControl, { label: __('Show Read Time', 'blockenberg'), checked: attr.showReadTime, __nextHasNoMarginBottom: true, onChange: function (v) { set({ showReadTime: v }); } }) |
| 144 |
), |
| 145 |
attr.showReadTime && el('div', { style: { marginTop: '8px' } }, |
| 146 |
el(TextControl, { label: __('Read Time', 'blockenberg'), value: attr.readTime, placeholder: '12 min read', __nextHasNoMarginBottom: true, onChange: function (v) { set({ readTime: v }); } }) |
| 147 |
) |
| 148 |
), |
| 149 |
el(PanelBody, { title: __('Style', 'blockenberg'), initialOpen: false }, |
| 150 |
el(SelectControl, { |
| 151 |
label: __('Style', 'blockenberg'), value: attr.style, __nextHasNoMarginBottom: true, |
| 152 |
options: [{ label: 'Card (bordered)', value: 'card' }, { label: 'Left Border', value: 'left-border' }, { label: 'Top Border', value: 'top-border' }, { label: 'Minimal', value: 'minimal' }], |
| 153 |
onChange: function (v) { set({ style: v }); } |
| 154 |
}), |
| 155 |
el('div', { style: { marginTop: '12px' } }, |
| 156 |
el(SelectControl, { |
| 157 |
label: __('Bullet Style', 'blockenberg'), value: attr.bulletStyle, __nextHasNoMarginBottom: true, |
| 158 |
options: BULLET_OPTIONS, |
| 159 |
onChange: function (v) { set({ bulletStyle: v }); } |
| 160 |
}) |
| 161 |
), |
| 162 |
attr.bulletStyle === 'custom' && el('div', { style: { marginTop: '8px' } }, |
| 163 |
el(TextControl, { label: __('Custom Bullet', 'blockenberg'), value: attr.customBullet, __nextHasNoMarginBottom: true, onChange: function (v) { set({ customBullet: v }); } }) |
| 164 |
), |
| 165 |
el('div', { style: { marginTop: '12px' } }, |
| 166 |
el(RangeControl, { label: __('Columns', 'blockenberg'), value: attr.columns, min: 1, max: 3, __nextHasNoMarginBottom: true, onChange: function (v) { set({ columns: v }); } }) |
| 167 |
), |
| 168 |
el('div', { style: { marginTop: '12px' } }, |
| 169 |
el(RangeControl, { label: __('Border Radius', 'blockenberg'), value: attr.borderRadius, min: 0, max: 20, __nextHasNoMarginBottom: true, onChange: function (v) { set({ borderRadius: v }); } }) |
| 170 |
), |
| 171 |
el('div', { style: { marginTop: '12px' } }, |
| 172 |
el(RangeControl, { label: __('Padding Top', 'blockenberg'), value: attr.paddingTop, min: 0, max: 120, __nextHasNoMarginBottom: true, onChange: function (v) { set({ paddingTop: v }); } }) |
| 173 |
), |
| 174 |
el('div', { style: { marginTop: '12px' } }, |
| 175 |
el(RangeControl, { label: __('Padding Bottom', 'blockenberg'), value: attr.paddingBottom, min: 0, max: 120, __nextHasNoMarginBottom: true, onChange: function (v) { set({ paddingBottom: v }); } }) |
| 176 |
) |
| 177 |
), |
| 178 |
el(PanelColorSettings, { |
| 179 |
title: __('Colors', 'blockenberg'), initialOpen: false, |
| 180 |
colorSettings: [ |
| 181 |
{ label: __('Background', 'blockenberg'), value: attr.bgColor, onChange: function (v) { set({ bgColor: v || '#f0fdf4' }); } }, |
| 182 |
{ label: __('Border', 'blockenberg'), value: attr.borderColor, onChange: function (v) { set({ borderColor: v || '#86efac' }); } }, |
| 183 |
{ label: __('Accent', 'blockenberg'), value: attr.accentColor, onChange: function (v) { set({ accentColor: v || '#16a34a' }); } }, |
| 184 |
{ label: __('Heading', 'blockenberg'), value: attr.headingColor, onChange: function (v) { set({ headingColor: v || '#14532d' }); } }, |
| 185 |
{ label: __('Bullet BG', 'blockenberg'), value: attr.bulletBg, onChange: function (v) { set({ bulletBg: v || '#dcfce7' }); } }, |
| 186 |
{ label: __('Bullet Icon', 'blockenberg'), value: attr.bulletColor, onChange: function (v) { set({ bulletColor: v || '#16a34a' }); } }, |
| 187 |
{ label: __('Item Text', 'blockenberg'), value: attr.textColor, onChange: function (v) { set({ textColor: v || '#166534' }); } }, |
| 188 |
{ label: __('Meta Text', 'blockenberg'), value: attr.metaColor, onChange: function (v) { set({ metaColor: v || '#4b7a5a' }); } }, |
| 189 |
{ label: __('Level Badge BG', 'blockenberg'), value: attr.levelBg, onChange: function (v) { set({ levelBg: v || '#16a34a' }); } }, |
| 190 |
{ label: __('Level Badge Text', 'blockenberg'), value: attr.levelColor, onChange: function (v) { set({ levelColor: v || '#ffffff' }); } } |
| 191 |
] |
| 192 |
}), |
| 193 |
el(PanelBody, { title: 'Typography', initialOpen: false }, |
| 194 |
getTypoControl() && el(getTypoControl(), { label: __('Heading'), value: attr.headingTypo || {}, onChange: function (v) { set({ headingTypo: v }); } }), |
| 195 |
getTypoControl() && el(getTypoControl(), { label: __('Objective'), value: attr.objectiveTypo || {}, onChange: function (v) { set({ objectiveTypo: v }); } }) |
| 196 |
), |
| 197 |
|
| 198 |
); |
| 199 |
|
| 200 |
return el('div', blockProps, |
| 201 |
controls, |
| 202 |
el('div', { style: wrapStyle }, |
| 203 |
header, |
| 204 |
listEl, |
| 205 |
el('div', { style: { marginTop: '16px', paddingTop: '14px', borderTop: '1px solid ' + attr.borderColor, display: 'flex', justifyContent: 'flex-end' } }, |
| 206 |
el(Button, { variant: 'secondary', onClick: function () { set({ objectives: (attr.objectives || []).concat([{ text: '' }]) }); } }, __('+ Add Objective', 'blockenberg')) |
| 207 |
) |
| 208 |
) |
| 209 |
); |
| 210 |
}, |
| 211 |
save: function (props) { |
| 212 |
var attr = props.attributes; |
| 213 |
var useBlockProps = wp.blockEditor.useBlockProps; |
| 214 |
return el('div', useBlockProps.save(), |
| 215 |
el('div', { className: 'bkbg-lob-app', 'data-opts': JSON.stringify(attr) }) |
| 216 |
); |
| 217 |
} |
| 218 |
}); |
| 219 |
}() ); |
| 220 |
|