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

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

590 lines 34.6 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 registerBlockType = wp.blocks.registerBlockType;
6 var __ = wp.i18n.__;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var RichText = wp.blockEditor.RichText;
11 var MediaUpload = wp.blockEditor.MediaUpload;
12 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
13 var PanelBody = wp.components.PanelBody;
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 ToggleControl = wp.components.ToggleControl;
19 var Button = wp.components.Button;
20
21 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
22 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
23
24 var v1Attributes = {
25 "title":{"type":"string","default":"My Reading List"},
26 "showTitle":{"type":"boolean","default":true},
27 "subtitle":{"type":"string","default":"Books and articles I recommend."},
28 "showSubtitle":{"type":"boolean","default":true},
29 "books":{"type":"array","default":[]},
30 "layout":{"type":"string","default":"list"},
31 "columns":{"type":"number","default":3},
32 "showCover":{"type":"boolean","default":true},
33 "showRating":{"type":"boolean","default":true},
34 "showStatus":{"type":"boolean","default":true},
35 "showGenre":{"type":"boolean","default":true},
36 "showYear":{"type":"boolean","default":true},
37 "showDescription":{"type":"boolean","default":true},
38 "showLink":{"type":"boolean","default":true},
39 "linkLabel":{"type":"string","default":"View \u2192"},
40 "filterByStatus":{"type":"boolean","default":false},
41 "accentColor":{"type":"string","default":"#6c3fb5"},
42 "titleColor":{"type":"string","default":"#1e1b4b"},
43 "subtitleColor":{"type":"string","default":"#6b7280"},
44 "bookTitleColor":{"type":"string","default":"#1e1b4b"},
45 "authorColor":{"type":"string","default":"#6c3fb5"},
46 "genreColor":{"type":"string","default":"#6b7280"},
47 "descColor":{"type":"string","default":"#374151"},
48 "starColor":{"type":"string","default":"#f59e0b"},
49 "cardBg":{"type":"string","default":"#ffffff"},
50 "cardBorder":{"type":"string","default":"#e5e7eb"},
51 "linkColor":{"type":"string","default":"#6c3fb5"},
52 "bgColor":{"type":"string","default":""},
53 "titleSize":{"type":"number","default":32},
54 "bookTitleSize":{"type":"number","default":18},
55 "authorSize":{"type":"number","default":13},
56 "descSize":{"type":"number","default":14},
57 "cardRadius":{"type":"number","default":14},
58 "coverHeight":{"type":"number","default":180},
59 "gap":{"type":"number","default":20},
60 "paddingTop":{"type":"number","default":60},
61 "paddingBottom":{"type":"number","default":60}
62 };
63
64 var STATUS_META = {
65 'read': { label: 'Read', bg: '#d1fae5', color: '#065f46' },
66 'reading': { label: 'Currently Reading', bg: '#dbeafe', color: '#1e40af' },
67 'want-to-read': { label: 'Want to Read', bg: '#fef3c7', color: '#92400e' },
68 'recommended': { label: 'Recommended', bg: '#ede9fe', color: '#5b21b6' },
69 'dnf': { label: 'Did Not Finish', bg: '#fee2e2', color: '#991b1b' }
70 };
71
72 function uid() {
73 return 'rl-' + Math.random().toString(36).slice(2, 9);
74 }
75
76 function Stars(rating, color) {
77 return el('span', { className: 'bkbg-rl-stars', 'aria-label': rating + ' out of 5 stars' },
78 [1,2,3,4,5].map(function (i) {
79 return el('span', { key: i, style: { color: i <= rating ? (color || '#f59e0b') : '#d1d5db', fontSize: '14px' } }, i <= rating ? '�
80 ' : '');
81 })
82 );
83 }
84
85 function BookCard(props) {
86 var book = props.book;
87 var attrs = props.attrs;
88 var sm = STATUS_META[book.status] || STATUS_META['want-to-read'];
89 var isGrid = attrs.layout === 'grid';
90
91 var cardStyle = {
92 background: attrs.cardBg || '#ffffff',
93 border: '1px solid ' + (attrs.cardBorder || '#e5e7eb'),
94 borderRadius: attrs.cardRadius + 'px',
95 overflow: 'hidden',
96 display: isGrid ? 'flex' : 'flex',
97 flexDirection: isGrid ? 'column' : 'row',
98 gap: isGrid ? '0' : '16px',
99 alignItems: isGrid ? 'stretch' : 'flex-start'
100 };
101
102 return el('div', { className: 'bkbg-rl-card bkbg-rl-card--' + attrs.layout, style: cardStyle },
103 attrs.showCover && el('div', {
104 className: 'bkbg-rl-cover-wrap',
105 style: {
106 width: isGrid ? '100%' : attrs.coverHeight * 0.67 + 'px',
107 height: isGrid ? attrs.coverHeight + 'px' : undefined,
108 minWidth: isGrid ? undefined : attrs.coverHeight * 0.67 + 'px',
109 flexShrink: 0,
110 background: book.coverUrl ? 'none' : 'linear-gradient(135deg,#6c3fb5,#a78bfa)',
111 overflow: 'hidden',
112 display: 'flex',
113 alignItems: 'center',
114 justifyContent: 'center'
115 }
116 },
117 book.coverUrl
118 ? el('img', { src: book.coverUrl, alt: book.title, style: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' } })
119 : el('span', { style: { color: '#fff', fontSize: '12px', padding: '8px', textAlign: 'center', opacity: 0.7 } }, __('No cover', 'blockenberg'))
120 ),
121 el('div', { className: 'bkbg-rl-body', style: { padding: '16px', flex: 1 } },
122 attrs.showStatus && el('span', {
123 className: 'bkbg-rl-badge',
124 style: { background: sm.bg, color: sm.color, borderRadius: '999px', padding: '2px 10px', fontSize: '11px', fontWeight: 700, display: 'inline-block', marginBottom: '8px' }
125 }, sm.label),
126 el('div', {
127 className: 'bkbg-rl-book-title',
128 style: { color: attrs.bookTitleColor || '#1e1b4b', marginBottom: '4px' }
129 }, book.title || __('Book Title', 'blockenberg')),
130 el('div', {
131 className: 'bkbg-rl-author',
132 style: { color: attrs.authorColor || '#6c3fb5', marginBottom: '6px' }
133 }, book.author || __('Author Name', 'blockenberg')),
134 (attrs.showGenre || attrs.showYear) && el('div', {
135 className: 'bkbg-rl-meta',
136 style: { fontSize: '12px', color: attrs.genreColor || '#6b7280', marginBottom: '6px' }
137 },
138 [attrs.showGenre && book.genre, attrs.showYear && book.year].filter(Boolean).join(' · ')
139 ),
140 attrs.showRating && book.rating > 0 && el('div', { style: { marginBottom: '8px' } }, Stars(book.rating, attrs.starColor)),
141 attrs.showDescription && book.description && el('p', {
142 className: 'bkbg-rl-desc',
143 style: { color: attrs.descColor || '#374151', margin: '0 0 10px' }
144 }, book.description),
145 attrs.showLink && book.url && el('a', {
146 href: book.url,
147 className: 'bkbg-rl-link',
148 style: { color: attrs.linkColor || attrs.accentColor || '#6c3fb5', fontWeight: 600, fontSize: '13px' }
149 }, attrs.linkLabel || 'View →')
150 )
151 );
152 }
153
154 function BookEditor(props) {
155 var book = props.book;
156 var onChange = props.onChange;
157 var onRemove = props.onRemove;
158 var attrs = props.attrs;
159
160 return el(PanelBody, {
161 title: (book.title || __('(untitled)', 'blockenberg')).slice(0, 32),
162 initialOpen: false
163 },
164 el(TextControl, {
165 label: __('Title', 'blockenberg'),
166 value: book.title,
167 onChange: function (v) { onChange({ title: v }); }
168 }),
169 el(TextControl, {
170 label: __('Author', 'blockenberg'),
171 value: book.author,
172 onChange: function (v) { onChange({ author: v }); }
173 }),
174 el(TextControl, {
175 label: __('Genre', 'blockenberg'),
176 value: book.genre,
177 onChange: function (v) { onChange({ genre: v }); }
178 }),
179 el(TextControl, {
180 label: __('Year', 'blockenberg'),
181 value: book.year,
182 onChange: function (v) { onChange({ year: v }); }
183 }),
184 el(RangeControl, {
185 label: __('Rating (stars)', 'blockenberg'),
186 value: book.rating || 0,
187 min: 0, max: 5, step: 1,
188 onChange: function (v) { onChange({ rating: v }); }
189 }),
190 el(SelectControl, {
191 label: __('Status', 'blockenberg'),
192 value: book.status,
193 options: [
194 { label: 'Read', value: 'read' },
195 { label: 'Currently Reading', value: 'reading' },
196 { label: 'Want to Read', value: 'want-to-read' },
197 { label: 'Recommended', value: 'recommended' },
198 { label: 'Did Not Finish', value: 'dnf' }
199 ],
200 onChange: function (v) { onChange({ status: v }); }
201 }),
202 el(TextareaControl, {
203 label: __('Description', 'blockenberg'),
204 value: book.description,
205 rows: 3,
206 onChange: function (v) { onChange({ description: v }); }
207 }),
208 el(TextControl, {
209 label: __('Link URL', 'blockenberg'),
210 value: book.url,
211 type: 'url',
212 onChange: function (v) { onChange({ url: v }); }
213 }),
214 el('div', { style: { marginBottom: '12px' } },
215 el('p', { style: { fontSize: '11px', color: '#757575', margin: '0 0 6px' } }, __('Cover image', 'blockenberg')),
216 el(MediaUploadCheck, null,
217 el(MediaUpload, {
218 onSelect: function (media) { onChange({ coverUrl: media.url, coverId: media.id }); },
219 allowedTypes: ['image'],
220 value: book.coverId,
221 render: function (mediaProps) {
222 return el(Fragment, null,
223 book.coverUrl && el('img', {
224 src: book.coverUrl,
225 style: { width: '80px', height: '120px', objectFit: 'cover', borderRadius: '4px', display: 'block', marginBottom: '6px' }
226 }),
227 el(Button, {
228 isSmall: true,
229 variant: 'secondary',
230 onClick: mediaProps.open
231 }, book.coverUrl ? __('Replace cover', 'blockenberg') : __('Set cover', 'blockenberg')),
232 book.coverUrl && el(Button, {
233 isSmall: true,
234 isDestructive: true,
235 style: { marginLeft: '8px' },
236 onClick: function () { onChange({ coverUrl: '', coverId: 0 }); }
237 }, __('Remove', 'blockenberg'))
238 );
239 }
240 })
241 )
242 ),
243 el(Button, {
244 isDestructive: true, isSmall: true,
245 style: { marginTop: '4px' },
246 onClick: onRemove
247 }, __('Remove book', 'blockenberg'))
248 );
249 }
250
251 registerBlockType('blockenberg/reading-list', {
252 edit: function (props) {
253 var TC = getTypoControl();
254 var attrs = props.attributes;
255 var setAttr = function (obj) { props.setAttributes(obj); };
256 var books = attrs.books || [];
257
258 function addBook() {
259 setAttr({ books: books.concat([{ id: uid(), title: '', author: '', genre: '', year: '', rating: 0, status: 'want-to-read', description: '', coverUrl: '', coverId: 0, url: '' }]) });
260 }
261 function updateBook(id, patch) {
262 setAttr({ books: books.map(function (b) { return b.id === id ? Object.assign({}, b, patch) : b; }) });
263 }
264 function removeBook(id) {
265 setAttr({ books: books.filter(function (b) { return b.id !== id; }) });
266 }
267
268 var wrapStyle = { paddingTop: attrs.paddingTop + 'px', paddingBottom: attrs.paddingBottom + 'px' };
269 if (attrs.bgColor) wrapStyle.background = attrs.bgColor;
270
271 var blockProps = useBlockProps((function() {
272 var _tvFn = getTypoCssVars();
273 var s = Object.assign({}, wrapStyle);
274 if (_tvFn) {
275 Object.assign(s, _tvFn(attrs.titleTypo || {}, '--bkrl-tt-'));
276 Object.assign(s, _tvFn(attrs.bookTitleTypo || {}, '--bkrl-bt-'));
277 Object.assign(s, _tvFn(attrs.metaTypo || {}, '--bkrl-mt-'));
278 }
279 return { style: s };
280 })());
281
282 var listStyle = attrs.layout === 'grid'
283 ? { display: 'grid', gridTemplateColumns: 'repeat(' + attrs.columns + ', 1fr)', gap: attrs.gap + 'px' }
284 : { display: 'flex', flexDirection: 'column', gap: attrs.gap + 'px' };
285
286 return el(Fragment, null,
287 el(InspectorControls, null,
288
289 el(PanelBody, { title: __('Books', 'blockenberg'), initialOpen: true },
290 books.map(function (b) {
291 return el(BookEditor, {
292 key: b.id,
293 book: b,
294 attrs: attrs,
295 onChange: function (patch) { updateBook(b.id, patch); },
296 onRemove: function () { removeBook(b.id); }
297 });
298 }),
299 el(Button, {
300 variant: 'primary', isSmall: true,
301 style: { marginTop: '12px', width: '100%', justifyContent: 'center' },
302 onClick: addBook
303 }, __('+ Add Book', 'blockenberg'))
304 ),
305
306 el(PanelBody, { title: __('Display', 'blockenberg'), initialOpen: false },
307 el(SelectControl, {
308 label: __('Layout', 'blockenberg'),
309 value: attrs.layout,
310 options: [
311 { label: __('List', 'blockenberg'), value: 'list' },
312 { label: __('Grid', 'blockenberg'), value: 'grid' }
313 ],
314 onChange: function (v) { setAttr({ layout: v }); }
315 }),
316 attrs.layout === 'grid' && el(RangeControl, {
317 label: __('Grid columns', 'blockenberg'),
318 value: attrs.columns, min: 2, max: 4,
319 onChange: function (v) { setAttr({ columns: v }); }
320 }),
321 el(RangeControl, {
322 label: __('Gap (px)', 'blockenberg'),
323 value: attrs.gap, min: 8, max: 48,
324 onChange: function (v) { setAttr({ gap: v }); }
325 }),
326 el(RangeControl, {
327 label: __('Cover height (px)', 'blockenberg'),
328 value: attrs.coverHeight, min: 80, max: 320,
329 onChange: function (v) { setAttr({ coverHeight: v }); }
330 }),
331 el(ToggleControl, { label: __('Show cover', 'blockenberg'), checked: attrs.showCover, onChange: function (v) { setAttr({ showCover: v }); }, __nextHasNoMarginBottom: true }),
332 el(ToggleControl, { label: __('Show status badge', 'blockenberg'), checked: attrs.showStatus, onChange: function (v) { setAttr({ showStatus: v }); }, __nextHasNoMarginBottom: true }),
333 el(ToggleControl, { label: __('Show rating stars', 'blockenberg'), checked: attrs.showRating, onChange: function (v) { setAttr({ showRating: v }); }, __nextHasNoMarginBottom: true }),
334 el(ToggleControl, { label: __('Show genre', 'blockenberg'), checked: attrs.showGenre, onChange: function (v) { setAttr({ showGenre: v }); }, __nextHasNoMarginBottom: true }),
335 el(ToggleControl, { label: __('Show year', 'blockenberg'), checked: attrs.showYear, onChange: function (v) { setAttr({ showYear: v }); }, __nextHasNoMarginBottom: true }),
336 el(ToggleControl, { label: __('Show description', 'blockenberg'), checked: attrs.showDescription, onChange: function (v) { setAttr({ showDescription: v }); }, __nextHasNoMarginBottom: true }),
337 el(ToggleControl, { label: __('Show link button', 'blockenberg'), checked: attrs.showLink, onChange: function (v) { setAttr({ showLink: v }); }, __nextHasNoMarginBottom: true }),
338 attrs.showLink && el(TextControl, {
339 label: __('Link label', 'blockenberg'),
340 value: attrs.linkLabel,
341 onChange: function (v) { setAttr({ linkLabel: v }); }
342 })
343 ),
344
345 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
346 TC && el(TC, { label: __('Title', 'blockenberg'), value: attrs.titleTypo || {}, onChange: function(v) { setAttr({ titleTypo: v }); } }),
347 TC && el(TC, { label: __('Book Title', 'blockenberg'), value: attrs.bookTitleTypo || {}, onChange: function(v) { setAttr({ bookTitleTypo: v }); } }),
348 TC && el(TC, { label: __('Author / Description', 'blockenberg'), value: attrs.metaTypo || {}, onChange: function(v) { setAttr({ metaTypo: v }); } }),
349 el(RangeControl, { label: __('Card radius (px)', 'blockenberg'), value: attrs.cardRadius, min: 0, max: 32, onChange: function (v) { setAttr({ cardRadius: v }); } })
350 ),
351
352 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
353 el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: attrs.paddingTop, min: 0, max: 200, onChange: function (v) { setAttr({ paddingTop: v }); } }),
354 el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: attrs.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttr({ paddingBottom: v }); } })
355 ),
356
357 el(PanelColorSettings, {
358 title: __('Colors', 'blockenberg'), initialOpen: false,
359 colorSettings: [
360 { label: __('Accent', 'blockenberg'), value: attrs.accentColor, onChange: function (v) { setAttr({ accentColor: v || '#6c3fb5' }); } },
361 { label: __('Title', 'blockenberg'), value: attrs.titleColor, onChange: function (v) { setAttr({ titleColor: v || '#1e1b4b' }); } },
362 { label: __('Book title', 'blockenberg'), value: attrs.bookTitleColor, onChange: function (v) { setAttr({ bookTitleColor: v || '#1e1b4b' }); } },
363 { label: __('Author', 'blockenberg'), value: attrs.authorColor, onChange: function (v) { setAttr({ authorColor: v || '#6c3fb5' }); } },
364 { label: __('Genre/meta', 'blockenberg'), value: attrs.genreColor, onChange: function (v) { setAttr({ genreColor: v || '#6b7280' }); } },
365 { label: __('Description', 'blockenberg'), value: attrs.descColor, onChange: function (v) { setAttr({ descColor: v || '#374151' }); } },
366 { label: __('Star rating', 'blockenberg'), value: attrs.starColor, onChange: function (v) { setAttr({ starColor: v || '#f59e0b' }); } },
367 { label: __('Card background', 'blockenberg'), value: attrs.cardBg, onChange: function (v) { setAttr({ cardBg: v || '#ffffff' }); } },
368 { label: __('Card border', 'blockenberg'), value: attrs.cardBorder, onChange: function (v) { setAttr({ cardBorder: v || '#e5e7eb' }); } },
369 { label: __('Link color', 'blockenberg'), value: attrs.linkColor, onChange: function (v) { setAttr({ linkColor: v || '#6c3fb5' }); } },
370 { label: __('Block background', 'blockenberg'), value: attrs.bgColor, onChange: function (v) { setAttr({ bgColor: v || '' }); } }
371 ]
372 })
373 ),
374
375 el('div', blockProps,
376 attrs.showTitle && el(RichText, {
377 tagName: 'h2',
378 className: 'bkbg-rl-title',
379 style: { color: attrs.titleColor, margin: '0 0 8px' },
380 value: attrs.title,
381 onChange: function (v) { setAttr({ title: v }); },
382 placeholder: __('Reading List Title…', 'blockenberg')
383 }),
384 attrs.showSubtitle && el(RichText, {
385 tagName: 'p',
386 className: 'bkbg-rl-subtitle',
387 style: { color: attrs.subtitleColor, margin: '0 0 24px' },
388 value: attrs.subtitle,
389 onChange: function (v) { setAttr({ subtitle: v }); },
390 placeholder: __('Optional subtitle…', 'blockenberg')
391 }),
392
393 books.length === 0
394 ? el('p', { style: { color: '#9ca3af', textAlign: 'center', padding: '40px 0' } }, __('Add your first book in the sidebar →', 'blockenberg'))
395 : el('div', { className: 'bkbg-rl-list', style: listStyle },
396 books.map(function (b) {
397 return el(BookCard, { key: b.id, book: b, attrs: attrs });
398 })
399 )
400 )
401 );
402 },
403
404 deprecated: [{
405 attributes: v1Attributes,
406 save: function (props) {
407 var a = props.attributes;
408 var books = a.books || [];
409
410 var wrapStyle = { paddingTop: a.paddingTop + 'px', paddingBottom: a.paddingBottom + 'px' };
411 if (a.bgColor) wrapStyle.background = a.bgColor;
412
413 var blockProps = wp.blockEditor.useBlockProps.save({ style: wrapStyle });
414
415 var listStyle = a.layout === 'grid'
416 ? { display: 'grid', gridTemplateColumns: 'repeat(' + a.columns + ', 1fr)', gap: a.gap + 'px' }
417 : { display: 'flex', flexDirection: 'column', gap: a.gap + 'px' };
418
419 return el('div', blockProps,
420 a.showTitle && el('h2', {
421 className: 'bkbg-rl-title',
422 style: { fontSize: a.titleSize + 'px', color: a.titleColor, margin: '0 0 8px' },
423 dangerouslySetInnerHTML: { __html: a.title }
424 }),
425 a.showSubtitle && el('p', {
426 className: 'bkbg-rl-subtitle',
427 style: { color: a.subtitleColor, margin: '0 0 24px' },
428 dangerouslySetInnerHTML: { __html: a.subtitle }
429 }),
430
431 el('div', {
432 className: 'bkbg-rl-list',
433 'data-opts': JSON.stringify({ layout: a.layout, filterByStatus: a.filterByStatus }),
434 style: listStyle
435 },
436 books.map(function (book) {
437 var sm = STATUS_META[book.status] || STATUS_META['want-to-read'];
438 var isGrid = a.layout === 'grid';
439 return el('div', {
440 key: book.id,
441 className: 'bkbg-rl-card bkbg-rl-card--' + a.layout,
442 'data-status': book.status,
443 style: {
444 background: a.cardBg || '#ffffff',
445 border: '1px solid ' + (a.cardBorder || '#e5e7eb'),
446 borderRadius: a.cardRadius + 'px',
447 overflow: 'hidden',
448 display: 'flex',
449 flexDirection: isGrid ? 'column' : 'row',
450 gap: isGrid ? '0' : '16px',
451 alignItems: isGrid ? 'stretch' : 'flex-start'
452 }
453 },
454 a.showCover && el('div', {
455 className: 'bkbg-rl-cover-wrap',
456 style: {
457 width: isGrid ? '100%' : (a.coverHeight * 0.67) + 'px',
458 height: isGrid ? a.coverHeight + 'px' : undefined,
459 minWidth: isGrid ? undefined : (a.coverHeight * 0.67) + 'px',
460 flexShrink: 0,
461 background: book.coverUrl ? 'none' : 'linear-gradient(135deg,#6c3fb5,#a78bfa)',
462 overflow: 'hidden'
463 }
464 },
465 book.coverUrl
466 ? el('img', { src: book.coverUrl, alt: book.title, loading: 'lazy', style: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' } })
467 : null
468 ),
469 el('div', { className: 'bkbg-rl-body', style: { padding: '16px', flex: 1 } },
470 a.showStatus && el('span', {
471 className: 'bkbg-rl-badge',
472 style: { background: sm.bg, color: sm.color, borderRadius: '999px', padding: '2px 10px', fontSize: '11px', fontWeight: 700, display: 'inline-block', marginBottom: '8px' }
473 }, sm.label),
474 el('div', { className: 'bkbg-rl-book-title', style: { fontSize: a.bookTitleSize + 'px', fontWeight: 700, color: a.bookTitleColor || '#1e1b4b', lineHeight: 1.3, marginBottom: '4px' } }, book.title),
475 el('div', { className: 'bkbg-rl-author', style: { fontSize: a.authorSize + 'px', color: a.authorColor || '#6c3fb5', marginBottom: '6px' } }, book.author),
476 (a.showGenre || a.showYear) && el('div', { className: 'bkbg-rl-meta', style: { fontSize: '12px', color: a.genreColor || '#6b7280', marginBottom: '6px' } },
477 [a.showGenre && book.genre, a.showYear && book.year].filter(Boolean).join(' · ')
478 ),
479 a.showRating && book.rating > 0 && el('div', { className: 'bkbg-rl-stars', style: { marginBottom: '8px' } },
480 [1,2,3,4,5].map(function (i) {
481 return el('span', { key: i, style: { color: i <= book.rating ? (a.starColor || '#f59e0b') : '#d1d5db', fontSize: '14px' } }, i <= book.rating ? '�
482 ' : '');
483 })
484 ),
485 a.showDescription && book.description && el('p', { className: 'bkbg-rl-desc', style: { fontSize: a.descSize + 'px', color: a.descColor || '#374151', lineHeight: 1.6, margin: '0 0 10px' } }, book.description),
486 a.showLink && book.url && el('a', { href: book.url, className: 'bkbg-rl-link', style: { color: a.linkColor || a.accentColor || '#6c3fb5', fontWeight: 600, fontSize: '13px' } }, a.linkLabel || 'View →')
487 )
488 );
489 })
490 )
491 );
492 }
493 }],
494
495 save: function (props) {
496 var a = props.attributes;
497 var books = a.books || [];
498
499 var _tvFn = window.bkbgTypoCssVars;
500 var wrapStyle = { paddingTop: a.paddingTop + 'px', paddingBottom: a.paddingBottom + 'px' };
501 if (a.bgColor) wrapStyle.background = a.bgColor;
502 if (_tvFn) {
503 Object.assign(wrapStyle, _tvFn(a.titleTypo || {}, '--bkrl-tt-'));
504 Object.assign(wrapStyle, _tvFn(a.bookTitleTypo || {}, '--bkrl-bt-'));
505 Object.assign(wrapStyle, _tvFn(a.metaTypo || {}, '--bkrl-mt-'));
506 }
507
508 var blockProps = wp.blockEditor.useBlockProps.save({ style: wrapStyle });
509
510 var listStyle = a.layout === 'grid'
511 ? { display: 'grid', gridTemplateColumns: 'repeat(' + a.columns + ', 1fr)', gap: a.gap + 'px' }
512 : { display: 'flex', flexDirection: 'column', gap: a.gap + 'px' };
513
514 return el('div', blockProps,
515 a.showTitle && el('h2', {
516 className: 'bkbg-rl-title',
517 style: { color: a.titleColor, margin: '0 0 8px' },
518 dangerouslySetInnerHTML: { __html: a.title }
519 }),
520 a.showSubtitle && el('p', {
521 className: 'bkbg-rl-subtitle',
522 style: { color: a.subtitleColor, margin: '0 0 24px' },
523 dangerouslySetInnerHTML: { __html: a.subtitle }
524 }),
525
526 el('div', {
527 className: 'bkbg-rl-list',
528 'data-opts': JSON.stringify({ layout: a.layout, filterByStatus: a.filterByStatus }),
529 style: listStyle
530 },
531 books.map(function (book) {
532 var sm = STATUS_META[book.status] || STATUS_META['want-to-read'];
533 var isGrid = a.layout === 'grid';
534 return el('div', {
535 key: book.id,
536 className: 'bkbg-rl-card bkbg-rl-card--' + a.layout,
537 'data-status': book.status,
538 style: {
539 background: a.cardBg || '#ffffff',
540 border: '1px solid ' + (a.cardBorder || '#e5e7eb'),
541 borderRadius: a.cardRadius + 'px',
542 overflow: 'hidden',
543 display: 'flex',
544 flexDirection: isGrid ? 'column' : 'row',
545 gap: isGrid ? '0' : '16px',
546 alignItems: isGrid ? 'stretch' : 'flex-start'
547 }
548 },
549 a.showCover && el('div', {
550 className: 'bkbg-rl-cover-wrap',
551 style: {
552 width: isGrid ? '100%' : (a.coverHeight * 0.67) + 'px',
553 height: isGrid ? a.coverHeight + 'px' : undefined,
554 minWidth: isGrid ? undefined : (a.coverHeight * 0.67) + 'px',
555 flexShrink: 0,
556 background: book.coverUrl ? 'none' : 'linear-gradient(135deg,#6c3fb5,#a78bfa)',
557 overflow: 'hidden'
558 }
559 },
560 book.coverUrl
561 ? el('img', { src: book.coverUrl, alt: book.title, loading: 'lazy', style: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' } })
562 : null
563 ),
564 el('div', { className: 'bkbg-rl-body', style: { padding: '16px', flex: 1 } },
565 a.showStatus && el('span', {
566 className: 'bkbg-rl-badge',
567 style: { background: sm.bg, color: sm.color, borderRadius: '999px', padding: '2px 10px', fontSize: '11px', fontWeight: 700, display: 'inline-block', marginBottom: '8px' }
568 }, sm.label),
569 el('div', { className: 'bkbg-rl-book-title', style: { color: a.bookTitleColor || '#1e1b4b', marginBottom: '4px' } }, book.title),
570 el('div', { className: 'bkbg-rl-author', style: { color: a.authorColor || '#6c3fb5', marginBottom: '6px' } }, book.author),
571 (a.showGenre || a.showYear) && el('div', { className: 'bkbg-rl-meta', style: { fontSize: '12px', color: a.genreColor || '#6b7280', marginBottom: '6px' } },
572 [a.showGenre && book.genre, a.showYear && book.year].filter(Boolean).join(' · ')
573 ),
574 a.showRating && book.rating > 0 && el('div', { className: 'bkbg-rl-stars', style: { marginBottom: '8px' } },
575 [1,2,3,4,5].map(function (i) {
576 return el('span', { key: i, style: { color: i <= book.rating ? (a.starColor || '#f59e0b') : '#d1d5db', fontSize: '14px' } }, i <= book.rating ? '�
577 ' : '');
578 })
579 ),
580 a.showDescription && book.description && el('p', { className: 'bkbg-rl-desc', style: { color: a.descColor || '#374151', margin: '0 0 10px' } }, book.description),
581 a.showLink && book.url && el('a', { href: book.url, className: 'bkbg-rl-link', style: { color: a.linkColor || a.accentColor || '#6c3fb5', fontWeight: 600, fontSize: '13px' } }, a.linkLabel || 'View →')
582 )
583 );
584 })
585 )
586 );
587 }
588 });
589 }() );
590