Version Description
- Fix focus bug on Testimonial block title.
Download this release
Release Info
Developer | atomicblocks |
Plugin | Atomic Blocks – Gutenberg Blocks Collection |
Version | 1.2.8 |
Comparing to | |
See all releases |
Code changes from version 1.2.7 to 1.2.8
- README.md +3 -0
- README.txt +4 -2
- atomicblocks.php +1 -1
- dist/blocks.build.js +1 -1
- src/blocks.js +16 -0
- src/blocks/block-accordion/components/accordion.js +41 -0
- src/blocks/block-accordion/components/icons.js +18 -0
- src/blocks/block-accordion/components/inspector.js +62 -0
- src/blocks/block-accordion/index.js +137 -0
- src/blocks/block-accordion/styles/editor.scss +11 -0
- src/blocks/block-accordion/styles/style.scss +52 -0
- src/blocks/block-author-profile/components/avatar.js +33 -0
- src/blocks/block-author-profile/components/icons.js +14 -0
- src/blocks/block-author-profile/components/inspector.js +181 -0
- src/blocks/block-author-profile/components/profile.js +42 -0
- src/blocks/block-author-profile/components/social.js +75 -0
- src/blocks/block-author-profile/index.js +317 -0
- src/blocks/block-author-profile/styles/editor.scss +33 -0
- src/blocks/block-author-profile/styles/style.scss +210 -0
- src/blocks/block-button/components/button.js +36 -0
- src/blocks/block-button/components/icons.js +18 -0
- src/blocks/block-button/components/inspector.js +128 -0
- src/blocks/block-button/index.js +187 -0
- src/blocks/block-button/styles/editor.scss +19 -0
- src/blocks/block-button/styles/style.scss +81 -0
- src/blocks/block-container/components/container.js +44 -0
- src/blocks/block-container/components/inspector.js +187 -0
- src/blocks/block-container/index.js +270 -0
- src/blocks/block-container/styles/editor.scss +31 -0
- src/blocks/block-container/styles/style.scss +103 -0
- src/blocks/block-cta/components/cta.js +39 -0
- src/blocks/block-cta/components/inspector.js +235 -0
- src/blocks/block-cta/index.js +406 -0
- src/blocks/block-cta/styles/editor.scss +31 -0
- src/blocks/block-cta/styles/style.scss +310 -0
- src/blocks/block-drop-cap/components/dropcap.js +42 -0
- src/blocks/block-drop-cap/components/icons.js +14 -0
- src/blocks/block-drop-cap/components/inspector.js +69 -0
- src/blocks/block-drop-cap/index.js +140 -0
- src/blocks/block-drop-cap/styles/editor.scss +55 -0
- src/blocks/block-drop-cap/styles/style.scss +79 -0
- src/blocks/block-layout-split/components/icons.js +14 -0
- src/blocks/block-layout-split/components/inspector.js +88 -0
- src/blocks/block-layout-split/components/profile.js +43 -0
- src/blocks/block-layout-split/components/social.js +75 -0
- src/blocks/block-layout-split/index.js +286 -0
- src/blocks/block-layout-split/styles/editor.scss +33 -0
- src/blocks/block-layout-split/styles/style.scss +59 -0
- src/blocks/block-notice/components/button.js +41 -0
- src/blocks/block-notice/components/icons.js +18 -0
- src/blocks/block-notice/components/inspector.js +125 -0
- src/blocks/block-notice/components/notice.js +49 -0
- src/blocks/block-notice/index.js +228 -0
- src/blocks/block-notice/styles/editor.scss +11 -0
- src/blocks/block-notice/styles/style.scss +78 -0
- src/blocks/block-post-grid/edit.js +298 -0
- src/blocks/block-post-grid/index.js +54 -0
- src/blocks/block-post-grid/styles/editor.scss +14 -0
- src/blocks/block-post-grid/styles/style.scss +171 -0
- src/blocks/block-sharing/components/inspector.js +169 -0
- src/blocks/block-sharing/components/sharing.js +38 -0
- src/blocks/block-sharing/index.js +179 -0
- src/blocks/block-sharing/styles/editor.scss +7 -0
- src/blocks/block-sharing/styles/style.scss +167 -0
- src/blocks/block-spacer/components/icons.js +18 -0
- src/blocks/block-spacer/components/inspector.js +112 -0
- src/blocks/block-spacer/components/spacer.js +42 -0
- src/blocks/block-spacer/index.js +138 -0
- src/blocks/block-spacer/styles/editor.scss +66 -0
- src/blocks/block-spacer/styles/style.scss +55 -0
- src/blocks/block-testimonial/components/icons.js +14 -0
- src/blocks/block-testimonial/components/inspector.js +109 -0
- src/blocks/block-testimonial/components/testimonial.js +44 -0
- src/blocks/block-testimonial/index.js +282 -0
- src/blocks/block-testimonial/styles/editor.scss +30 -0
- src/blocks/block-testimonial/styles/style.scss +155 -0
- src/common.scss +158 -0
- src/utils/helper.js +18 -0
README.md
CHANGED
@@ -74,6 +74,9 @@ Yes, you will need to install the [Gutenberg plugin](https://wordpress.org/plugi
|
|
74 |
|
75 |
## Changelog
|
76 |
|
|
|
|
|
|
|
77 |
**1.2.7**
|
78 |
* Fix the URLInput on the Button block.
|
79 |
|
74 |
|
75 |
## Changelog
|
76 |
|
77 |
+
**1.2.8**
|
78 |
+
* Fix focus bug on Testimonial block title.
|
79 |
+
|
80 |
**1.2.7**
|
81 |
* Fix the URLInput on the Button block.
|
82 |
|
README.txt
CHANGED
@@ -4,7 +4,7 @@ Donate link: https://atomicblocks.com
|
|
4 |
Tags: gutenberg, blocks, page builder, gutenberg blocks, editor, atomicblocks, builder, wordpress 5.0, options
|
5 |
Requires at least: 4.7
|
6 |
Tested up to: 4.9.5
|
7 |
-
Stable tag: 1.2.
|
8 |
Requires PHP: 5.2.4
|
9 |
License: GPLv2 or later
|
10 |
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
@@ -96,10 +96,12 @@ Yes, you will need to install the [Gutenberg plugin](https://wordpress.org/plugi
|
|
96 |
|
97 |
== Changelog ==
|
98 |
|
|
|
|
|
|
|
99 |
= 1.2.7 =
|
100 |
* Fix URLInput on the Button block.
|
101 |
|
102 |
-
|
103 |
= 1.2.6 =
|
104 |
* Remove unnecessary state from blocks.
|
105 |
* Improve call to decodeEntities.
|
4 |
Tags: gutenberg, blocks, page builder, gutenberg blocks, editor, atomicblocks, builder, wordpress 5.0, options
|
5 |
Requires at least: 4.7
|
6 |
Tested up to: 4.9.5
|
7 |
+
Stable tag: 1.2.8
|
8 |
Requires PHP: 5.2.4
|
9 |
License: GPLv2 or later
|
10 |
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
96 |
|
97 |
== Changelog ==
|
98 |
|
99 |
+
= 1.2.8 =
|
100 |
+
* Fix focus bug on Testimonial block title.
|
101 |
+
|
102 |
= 1.2.7 =
|
103 |
* Fix URLInput on the Button block.
|
104 |
|
|
|
105 |
= 1.2.6 =
|
106 |
* Remove unnecessary state from blocks.
|
107 |
* Improve call to decodeEntities.
|
atomicblocks.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
* Description: A beautiful collection of handy Gutenberg blocks to help you get started with the new WordPress editor.
|
6 |
* Author: atomicblocks
|
7 |
* Author URI: http://arraythemes.com
|
8 |
-
* Version: 1.2.
|
9 |
* License: GPL2+
|
10 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
11 |
*
|
5 |
* Description: A beautiful collection of handy Gutenberg blocks to help you get started with the new WordPress editor.
|
6 |
* Author: atomicblocks
|
7 |
* Author URI: http://arraythemes.com
|
8 |
+
* Version: 1.2.8
|
9 |
* License: GPL2+
|
10 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
11 |
*
|
dist/blocks.build.js
CHANGED
@@ -2060,7 +2060,7 @@ eval("Object.defineProperty(__webpack_exports__, \"__esModule\", { value: true }
|
|
2060 |
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
2061 |
|
2062 |
"use strict";
|
2063 |
-
eval("/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_classnames__ = __webpack_require__(/*! classnames */ 1);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_classnames___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_classnames__);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__components_inspector__ = __webpack_require__(/*! ./components/inspector */ 181);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__components_testimonial__ = __webpack_require__(/*! ./components/testimonial */ 182);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__components_icons__ = __webpack_require__(/*! ./components/icons */ 185);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__styles_style_scss__ = __webpack_require__(/*! ./styles/style.scss */ 186);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__styles_style_scss___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4__styles_style_scss__);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__styles_editor_scss__ = __webpack_require__(/*! ./styles/editor.scss */ 187);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__styles_editor_scss___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5__styles_editor_scss__);\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\n/**\n * BLOCK: Atomic Blocks Testimonial\n */\n\n// Import block dependencies and components\n\n\n\n\n\n// Import CSS\n\n\n\n// Internationalization\nvar __ = wp.i18n.__;\n\n// Extend component\n\nvar Component = wp.element.Component;\n\n// Register block\n\nvar registerBlockType = wp.blocks.registerBlockType;\n\n// Register editor components\n\nvar _wp$editor = wp.editor,\n RichText = _wp$editor.RichText,\n AlignmentToolbar = _wp$editor.AlignmentToolbar,\n BlockControls = _wp$editor.BlockControls,\n BlockAlignmentToolbar = _wp$editor.BlockAlignmentToolbar,\n MediaUpload = _wp$editor.MediaUpload;\n\n// Register components\n\nvar _wp$components = wp.components,\n Button = _wp$components.Button,\n SelectControl = _wp$components.SelectControl;\n\nvar ABTestimonialBlock = function (_Component) {\n\t_inherits(ABTestimonialBlock, _Component);\n\n\tfunction ABTestimonialBlock() {\n\t\t_classCallCheck(this, ABTestimonialBlock);\n\n\t\treturn _possibleConstructorReturn(this, (ABTestimonialBlock.__proto__ || Object.getPrototypeOf(ABTestimonialBlock)).apply(this, arguments));\n\t}\n\n\t_createClass(ABTestimonialBlock, [{\n\t\tkey: 'render',\n\t\tvalue: function render() {\n\t\t\tvar _this2 = this;\n\n\t\t\t// Setup the attributes\n\t\t\tvar _props = this.props,\n\t\t\t _props$attributes = _props.attributes,\n\t\t\t testimonialName = _props$attributes.testimonialName,\n\t\t\t testimonialTitle = _props$attributes.testimonialTitle,\n\t\t\t testimonialContent = _props$attributes.testimonialContent,\n\t\t\t testimonialAlignment = _props$attributes.testimonialAlignment,\n\t\t\t testimonialImgURL = _props$attributes.testimonialImgURL,\n\t\t\t testimonialImgID = _props$attributes.testimonialImgID,\n\t\t\t testimonialBackgroundColor = _props$attributes.testimonialBackgroundColor,\n\t\t\t testimonialTextColor = _props$attributes.testimonialTextColor,\n\t\t\t testimonialFontSize = _props$attributes.testimonialFontSize,\n\t\t\t testimonialCiteAlign = _props$attributes.testimonialCiteAlign,\n\t\t\t attributes = _props.attributes,\n\t\t\t isSelected = _props.isSelected,\n\t\t\t editable = _props.editable,\n\t\t\t className = _props.className,\n\t\t\t setAttributes = _props.setAttributes;\n\n\n\t\t\tvar onSelectImage = function onSelectImage(img) {\n\t\t\t\tsetAttributes({\n\t\t\t\t\ttestimonialImgID: img.id,\n\t\t\t\t\ttestimonialImgURL: img.url\n\t\t\t\t});\n\t\t\t};\n\n\t\t\treturn [\n\t\t\t// Show the alignment toolbar on focus\n\t\t\twp.element.createElement(\n\t\t\t\tBlockControls,\n\t\t\t\t{ key: 'controls' },\n\t\t\t\twp.element.createElement(AlignmentToolbar, {\n\t\t\t\t\tvalue: testimonialAlignment,\n\t\t\t\t\tonChange: function onChange(value) {\n\t\t\t\t\t\treturn setAttributes({ testimonialAlignment: value });\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t),\n\t\t\t// Show the block controls on focus\n\t\t\twp.element.createElement(__WEBPACK_IMPORTED_MODULE_1__components_inspector__[\"a\" /* default */], Object.assign({ setAttributes: setAttributes }, this.props)),\n\t\t\t// Show the block markup in the editor\n\t\t\twp.element.createElement(\n\t\t\t\t__WEBPACK_IMPORTED_MODULE_2__components_testimonial__[\"a\" /* default */],\n\t\t\t\tthis.props,\n\t\t\t\twp.element.createElement(RichText, {\n\t\t\t\t\ttagName: 'div',\n\t\t\t\t\tmultiline: 'p',\n\t\t\t\t\tplaceholder: __('Add testimonial text...'),\n\t\t\t\t\tkeepPlaceholderOnFocus: true,\n\t\t\t\t\tvalue: testimonialContent,\n\t\t\t\t\tformattingControls: ['bold', 'italic', 'strikethrough', 'link'],\n\t\t\t\t\tclassName: __WEBPACK_IMPORTED_MODULE_0_classnames___default()('ab-testimonial-text'),\n\t\t\t\t\tstyle: {\n\t\t\t\t\t\ttextAlign: testimonialAlignment\n\t\t\t\t\t},\n\t\t\t\t\tonChange: function onChange(value) {\n\t\t\t\t\t\treturn setAttributes({ testimonialContent: value });\n\t\t\t\t\t},\n\t\t\t\t\tinlineToolbar: true\n\t\t\t\t}),\n\t\t\t\twp.element.createElement(\n\t\t\t\t\t'div',\n\t\t\t\t\t{ 'class': 'ab-testimonial-info' },\n\t\t\t\t\twp.element.createElement(\n\t\t\t\t\t\t'div',\n\t\t\t\t\t\t{ 'class': 'ab-testimonial-avatar-wrap' },\n\t\t\t\t\t\twp.element.createElement(\n\t\t\t\t\t\t\t'div',\n\t\t\t\t\t\t\t{ 'class': 'ab-testimonial-image-wrap' },\n\t\t\t\t\t\t\twp.element.createElement(MediaUpload, {\n\t\t\t\t\t\t\t\tbuttonProps: {\n\t\t\t\t\t\t\t\t\tclassName: 'change-image'\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tonSelect: function onSelect(img) {\n\t\t\t\t\t\t\t\t\treturn setAttributes({\n\t\t\t\t\t\t\t\t\t\ttestimonialImgID: img.id,\n\t\t\t\t\t\t\t\t\t\ttestimonialImgURL: img.url\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\ttype: 'image',\n\t\t\t\t\t\t\t\tvalue: testimonialImgID,\n\t\t\t\t\t\t\t\trender: function render(_ref) {\n\t\t\t\t\t\t\t\t\tvar open = _ref.open;\n\t\t\t\t\t\t\t\t\treturn wp.element.createElement(\n\t\t\t\t\t\t\t\t\t\tButton,\n\t\t\t\t\t\t\t\t\t\t{ onClick: open },\n\t\t\t\t\t\t\t\t\t\t!testimonialImgID ? __WEBPACK_IMPORTED_MODULE_3__components_icons__[\"a\" /* default */].upload : wp.element.createElement('img', {\n\t\t\t\t\t\t\t\t\t\t\t'class': 'ab-testimonial-avatar',\n\t\t\t\t\t\t\t\t\t\t\tsrc: testimonialImgURL,\n\t\t\t\t\t\t\t\t\t\t\talt: 'avatar'\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t)\n\t\t\t\t\t),\n\t\t\t\t\twp.element.createElement(RichText, {\n\t\t\t\t\t\ttagName: 'h2',\n\t\t\t\t\t\tplaceholder: __('Add name'),\n\t\t\t\t\t\tkeepPlaceholderOnFocus: true,\n\t\t\t\t\t\tvalue: testimonialName,\n\t\t\t\t\t\tclassName: 'ab-testimonial-name',\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tcolor: testimonialTextColor\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonChange: function onChange(value) {\n\t\t\t\t\t\t\treturn _this2.props.setAttributes({ testimonialName: value });\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t\twp.element.createElement(RichText, {\n\t\t\t\t\t\ttagName: 'h5',\n\t\t\t\t\t\tplaceholder: __('Add title'),\n\t\t\t\t\t\tkeepPlaceholderOnFocus: true,\n\t\t\t\t\t\tvalue: testimonialTitle,\n\t\t\t\t\t\tclassName: 'ab-testimonial-title',\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tcolor: testimonialTextColor\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonChange: function onChange(value) {\n\t\t\t\t\t\t\treturn _this2.props.setAttributes({ testimonialTitle: value });\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t)];\n\t\t}\n\t}]);\n\n\treturn ABTestimonialBlock;\n}(Component);\n\n// Register the block\n\n\nregisterBlockType('atomic-blocks/ab-testimonial', {\n\ttitle: __('AB Testimonial'),\n\tdescription: __('Add a user testimonial with a name and title.'),\n\ticon: 'format-quote',\n\tcategory: 'atomic-blocks',\n\tkeywords: [__('testimonial'), __('quote'), __('atomic')],\n\tattributes: {\n\t\ttestimonialName: {\n\t\t\ttype: 'string',\n\t\t\tselector: '.ab-testimonial-name'\n\t\t},\n\t\ttestimonialTitle: {\n\t\t\ttype: 'string',\n\t\t\tselector: '.ab-testimonial-title'\n\t\t},\n\t\ttestimonialContent: {\n\t\t\ttype: 'array',\n\t\t\tselector: '.ab-testimonial-text',\n\t\t\tsource: 'children'\n\t\t},\n\t\ttestimonialAlignment: {\n\t\t\ttype: 'string'\n\t\t},\n\t\ttestimonialImgURL: {\n\t\t\ttype: 'string',\n\t\t\tsource: 'attribute',\n\t\t\tattribute: 'src',\n\t\t\tselector: 'img'\n\t\t},\n\t\ttestimonialImgID: {\n\t\t\ttype: 'number'\n\t\t},\n\t\ttestimonialBackgroundColor: {\n\t\t\ttype: 'string',\n\t\t\tdefault: '#f2f2f2'\n\t\t},\n\t\ttestimonialTextColor: {\n\t\t\ttype: 'string',\n\t\t\tdefault: '#32373c'\n\t\t},\n\t\ttestimonialFontSize: {\n\t\t\ttype: 'number',\n\t\t\tdefault: 18\n\t\t},\n\t\ttestimonialCiteAlign: {\n\t\t\ttype: 'string',\n\t\t\tdefault: 'left-aligned'\n\t\t}\n\t},\n\n\t// Render the block components\n\tedit: ABTestimonialBlock,\n\n\t// Save the attributes and markup\n\tsave: function save(props) {\n\n\t\t// Setup the attributes\n\t\tvar _props$attributes2 = props.attributes,\n\t\t testimonialName = _props$attributes2.testimonialName,\n\t\t testimonialTitle = _props$attributes2.testimonialTitle,\n\t\t testimonialContent = _props$attributes2.testimonialContent,\n\t\t testimonialAlignment = _props$attributes2.testimonialAlignment,\n\t\t testimonialImgURL = _props$attributes2.testimonialImgURL,\n\t\t testimonialImgID = _props$attributes2.testimonialImgID,\n\t\t testimonialBackgroundColor = _props$attributes2.testimonialBackgroundColor,\n\t\t testimonialTextColor = _props$attributes2.testimonialTextColor,\n\t\t testimonialFontSize = _props$attributes2.testimonialFontSize,\n\t\t testimonialCiteAlign = _props$attributes2.testimonialCiteAlign;\n\n\t\t// Save the block markup for the front end\n\n\t\treturn wp.element.createElement(\n\t\t\t__WEBPACK_IMPORTED_MODULE_2__components_testimonial__[\"a\" /* default */],\n\t\t\tprops,\n\t\t\twp.element.createElement(\n\t\t\t\t'div',\n\t\t\t\t{\n\t\t\t\t\tclassName: __WEBPACK_IMPORTED_MODULE_0_classnames___default()('ab-testimonial-text'),\n\t\t\t\t\tstyle: {\n\t\t\t\t\t\ttextAlign: testimonialAlignment\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\ttestimonialContent\n\t\t\t),\n\t\t\twp.element.createElement(\n\t\t\t\t'div',\n\t\t\t\t{ 'class': 'ab-testimonial-info' },\n\t\t\t\ttestimonialImgURL && !!testimonialImgURL.length && wp.element.createElement(\n\t\t\t\t\t'div',\n\t\t\t\t\t{ 'class': 'ab-testimonial-avatar-wrap' },\n\t\t\t\t\twp.element.createElement(\n\t\t\t\t\t\t'div',\n\t\t\t\t\t\t{ 'class': 'ab-testimonial-image-wrap' },\n\t\t\t\t\t\twp.element.createElement('img', {\n\t\t\t\t\t\t\t'class': 'ab-testimonial-avatar',\n\t\t\t\t\t\t\tsrc: testimonialImgURL,\n\t\t\t\t\t\t\talt: 'avatar'\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\ttestimonialName && !!testimonialName.length && wp.element.createElement(\n\t\t\t\t\t'h2',\n\t\t\t\t\t{ 'class': 'ab-testimonial-name',\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tcolor: testimonialTextColor\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\ttestimonialName\n\t\t\t\t),\n\t\t\t\ttestimonialTitle && !!testimonialTitle.length && wp.element.createElement(\n\t\t\t\t\t'small',\n\t\t\t\t\t{ 'class': 'ab-testimonial-title',\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tcolor: testimonialTextColor\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\ttestimonialTitle\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTgwLmpzIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4vc3JjL2Jsb2Nrcy9ibG9jay10ZXN0aW1vbmlhbC9pbmRleC5qcz9jMzQyIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfY3JlYXRlQ2xhc3MgPSBmdW5jdGlvbiAoKSB7IGZ1bmN0aW9uIGRlZmluZVByb3BlcnRpZXModGFyZ2V0LCBwcm9wcykgeyBmb3IgKHZhciBpID0gMDsgaSA8IHByb3BzLmxlbmd0aDsgaSsrKSB7IHZhciBkZXNjcmlwdG9yID0gcHJvcHNbaV07IGRlc2NyaXB0b3IuZW51bWVyYWJsZSA9IGRlc2NyaXB0b3IuZW51bWVyYWJsZSB8fCBmYWxzZTsgZGVzY3JpcHRvci5jb25maWd1cmFibGUgPSB0cnVlOyBpZiAoXCJ2YWx1ZVwiIGluIGRlc2NyaXB0b3IpIGRlc2NyaXB0b3Iud3JpdGFibGUgPSB0cnVlOyBPYmplY3QuZGVmaW5lUHJvcGVydHkodGFyZ2V0LCBkZXNjcmlwdG9yLmtleSwgZGVzY3JpcHRvcik7IH0gfSByZXR1cm4gZnVuY3Rpb24gKENvbnN0cnVjdG9yLCBwcm90b1Byb3BzLCBzdGF0aWNQcm9wcykgeyBpZiAocHJvdG9Qcm9wcykgZGVmaW5lUHJvcGVydGllcyhDb25zdHJ1Y3Rvci5wcm90b3R5cGUsIHByb3RvUHJvcHMpOyBpZiAoc3RhdGljUHJvcHMpIGRlZmluZVByb3BlcnRpZXMoQ29uc3RydWN0b3IsIHN0YXRpY1Byb3BzKTsgcmV0dXJuIENvbnN0cnVjdG9yOyB9OyB9KCk7XG5cbmZ1bmN0aW9uIF9jbGFzc0NhbGxDaGVjayhpbnN0YW5jZSwgQ29uc3RydWN0b3IpIHsgaWYgKCEoaW5zdGFuY2UgaW5zdGFuY2VvZiBDb25zdHJ1Y3RvcikpIHsgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkNhbm5vdCBjYWxsIGEgY2xhc3MgYXMgYSBmdW5jdGlvblwiKTsgfSB9XG5cbmZ1bmN0aW9uIF9wb3NzaWJsZUNvbnN0cnVjdG9yUmV0dXJuKHNlbGYsIGNhbGwpIHsgaWYgKCFzZWxmKSB7IHRocm93IG5ldyBSZWZlcmVuY2VFcnJvcihcInRoaXMgaGFzbid0IGJlZW4gaW5pdGlhbGlzZWQgLSBzdXBlcigpIGhhc24ndCBiZWVuIGNhbGxlZFwiKTsgfSByZXR1cm4gY2FsbCAmJiAodHlwZW9mIGNhbGwgPT09IFwib2JqZWN0XCIgfHwgdHlwZW9mIGNhbGwgPT09IFwiZnVuY3Rpb25cIikgPyBjYWxsIDogc2VsZjsgfVxuXG5mdW5jdGlvbiBfaW5oZXJpdHMoc3ViQ2xhc3MsIHN1cGVyQ2xhc3MpIHsgaWYgKHR5cGVvZiBzdXBlckNsYXNzICE9PSBcImZ1bmN0aW9uXCIgJiYgc3VwZXJDbGFzcyAhPT0gbnVsbCkgeyB0aHJvdyBuZXcgVHlwZUVycm9yKFwiU3VwZXIgZXhwcmVzc2lvbiBtdXN0IGVpdGhlciBiZSBudWxsIG9yIGEgZnVuY3Rpb24sIG5vdCBcIiArIHR5cGVvZiBzdXBlckNsYXNzKTsgfSBzdWJDbGFzcy5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHN1cGVyQ2xhc3MgJiYgc3VwZXJDbGFzcy5wcm90b3R5cGUsIHsgY29uc3RydWN0b3I6IHsgdmFsdWU6IHN1YkNsYXNzLCBlbnVtZXJhYmxlOiBmYWxzZSwgd3JpdGFibGU6IHRydWUsIGNvbmZpZ3VyYWJsZTogdHJ1ZSB9IH0pOyBpZiAoc3VwZXJDbGFzcykgT2JqZWN0LnNldFByb3RvdHlwZU9mID8gT2JqZWN0LnNldFByb3RvdHlwZU9mKHN1YkNsYXNzLCBzdXBlckNsYXNzKSA6IHN1YkNsYXNzLl9fcHJvdG9fXyA9IHN1cGVyQ2xhc3M7IH1cblxuLyoqXG4gKiBCTE9DSzogQXRvbWljIEJsb2NrcyBUZXN0aW1vbmlhbFxuICovXG5cbi8vIEltcG9ydCBibG9jayBkZXBlbmRlbmNpZXMgYW5kIGNvbXBvbmVudHNcbmltcG9ydCBjbGFzc25hbWVzIGZyb20gJ2NsYXNzbmFtZXMnO1xuaW1wb3J0IEluc3BlY3RvciBmcm9tICcuL2NvbXBvbmVudHMvaW5zcGVjdG9yJztcbmltcG9ydCBUZXN0aW1vbmlhbCBmcm9tICcuL2NvbXBvbmVudHMvdGVzdGltb25pYWwnO1xuaW1wb3J0IGljb25zIGZyb20gJy4vY29tcG9uZW50cy9pY29ucyc7XG5cbi8vIEltcG9ydCBDU1NcbmltcG9ydCAnLi9zdHlsZXMvc3R5bGUuc2Nzcyc7XG5pbXBvcnQgJy4vc3R5bGVzL2VkaXRvci5zY3NzJztcblxuLy8gSW50ZXJuYXRpb25hbGl6YXRpb25cbnZhciBfXyA9IHdwLmkxOG4uX187XG5cbi8vIEV4dGVuZCBjb21wb25lbnRcblxudmFyIENvbXBvbmVudCA9IHdwLmVsZW1lbnQuQ29tcG9uZW50O1xuXG4vLyBSZWdpc3RlciBibG9ja1xuXG52YXIgcmVnaXN0ZXJCbG9ja1R5cGUgPSB3cC5ibG9ja3MucmVnaXN0ZXJCbG9ja1R5cGU7XG5cbi8vIFJlZ2lzdGVyIGVkaXRvciBjb21wb25lbnRzXG5cbnZhciBfd3AkZWRpdG9yID0gd3AuZWRpdG9yLFxuICAgIFJpY2hUZXh0ID0gX3dwJGVkaXRvci5SaWNoVGV4dCxcbiAgICBBbGlnbm1lbnRUb29sYmFyID0gX3dwJGVkaXRvci5BbGlnbm1lbnRUb29sYmFyLFxuICAgIEJsb2NrQ29udHJvbHMgPSBfd3AkZWRpdG9yLkJsb2NrQ29udHJvbHMsXG4gICAgQmxvY2tBbGlnbm1lbnRUb29sYmFyID0gX3dwJGVkaXRvci5CbG9ja0FsaWdubWVudFRvb2xiYXIsXG4gICAgTWVkaWFVcGxvYWQgPSBfd3AkZWRpdG9yLk1lZGlhVXBsb2FkO1xuXG4vLyBSZWdpc3RlciBjb21wb25lbnRzXG5cbnZhciBfd3AkY29tcG9uZW50cyA9IHdwLmNvbXBvbmVudHMsXG4gICAgQnV0dG9uID0gX3dwJGNvbXBvbmVudHMuQnV0dG9uLFxuICAgIFNlbGVjdENvbnRyb2wgPSBfd3AkY29tcG9uZW50cy5TZWxlY3RDb250cm9sO1xuXG52YXIgQUJUZXN0aW1vbmlhbEJsb2NrID0gZnVuY3Rpb24gKF9Db21wb25lbnQpIHtcblx0X2luaGVyaXRzKEFCVGVzdGltb25pYWxCbG9jaywgX0NvbXBvbmVudCk7XG5cblx0ZnVuY3Rpb24gQUJUZXN0aW1vbmlhbEJsb2NrKCkge1xuXHRcdF9jbGFzc0NhbGxDaGVjayh0aGlzLCBBQlRlc3RpbW9uaWFsQmxvY2spO1xuXG5cdFx0cmV0dXJuIF9wb3NzaWJsZUNvbnN0cnVjdG9yUmV0dXJuKHRoaXMsIChBQlRlc3RpbW9uaWFsQmxvY2suX19wcm90b19fIHx8IE9iamVjdC5nZXRQcm90b3R5cGVPZihBQlRlc3RpbW9uaWFsQmxvY2spKS5hcHBseSh0aGlzLCBhcmd1bWVudHMpKTtcblx0fVxuXG5cdF9jcmVhdGVDbGFzcyhBQlRlc3RpbW9uaWFsQmxvY2ssIFt7XG5cdFx0a2V5OiAncmVuZGVyJyxcblx0XHR2YWx1ZTogZnVuY3Rpb24gcmVuZGVyKCkge1xuXHRcdFx0dmFyIF90aGlzMiA9IHRoaXM7XG5cblx0XHRcdC8vIFNldHVwIHRoZSBhdHRyaWJ1dGVzXG5cdFx0XHR2YXIgX3Byb3BzID0gdGhpcy5wcm9wcyxcblx0XHRcdCAgICBfcHJvcHMkYXR0cmlidXRlcyA9IF9wcm9wcy5hdHRyaWJ1dGVzLFxuXHRcdFx0ICAgIHRlc3RpbW9uaWFsTmFtZSA9IF9wcm9wcyRhdHRyaWJ1dGVzLnRlc3RpbW9uaWFsTmFtZSxcblx0XHRcdCAgICB0ZXN0aW1vbmlhbFRpdGxlID0gX3Byb3BzJGF0dHJpYnV0ZXMudGVzdGltb25pYWxUaXRsZSxcblx0XHRcdCAgICB0ZXN0aW1vbmlhbENvbnRlbnQgPSBfcHJvcHMkYXR0cmlidXRlcy50ZXN0aW1vbmlhbENvbnRlbnQsXG5cdFx0XHQgICAgdGVzdGltb25pYWxBbGlnbm1lbnQgPSBfcHJvcHMkYXR0cmlidXRlcy50ZXN0aW1vbmlhbEFsaWdubWVudCxcblx0XHRcdCAgICB0ZXN0aW1vbmlhbEltZ1VSTCA9IF9wcm9wcyRhdHRyaWJ1dGVzLnRlc3RpbW9uaWFsSW1nVVJMLFxuXHRcdFx0ICAgIHRlc3RpbW9uaWFsSW1nSUQgPSBfcHJvcHMkYXR0cmlidXRlcy50ZXN0aW1vbmlhbEltZ0lELFxuXHRcdFx0ICAgIHRlc3RpbW9uaWFsQmFja2dyb3VuZENvbG9yID0gX3Byb3BzJGF0dHJpYnV0ZXMudGVzdGltb25pYWxCYWNrZ3JvdW5kQ29sb3IsXG5cdFx0XHQgICAgdGVzdGltb25pYWxUZXh0Q29sb3IgPSBfcHJvcHMkYXR0cmlidXRlcy50ZXN0aW1vbmlhbFRleHRDb2xvcixcblx0XHRcdCAgICB0ZXN0aW1vbmlhbEZvbnRTaXplID0gX3Byb3BzJGF0dHJpYnV0ZXMudGVzdGltb25pYWxGb250U2l6ZSxcblx0XHRcdCAgICB0ZXN0aW1vbmlhbENpdGVBbGlnbiA9IF9wcm9wcyRhdHRyaWJ1dGVzLnRlc3RpbW9uaWFsQ2l0ZUFsaWduLFxuXHRcdFx0ICAgIGF0dHJpYnV0ZXMgPSBfcHJvcHMuYXR0cmlidXRlcyxcblx0XHRcdCAgICBpc1NlbGVjdGVkID0gX3Byb3BzLmlzU2VsZWN0ZWQsXG5cdFx0XHQgICAgZWRpdGFibGUgPSBfcHJvcHMuZWRpdGFibGUsXG5cdFx0XHQgICAgY2xhc3NOYW1lID0gX3Byb3BzLmNsYXNzTmFtZSxcblx0XHRcdCAgICBzZXRBdHRyaWJ1dGVzID0gX3Byb3BzLnNldEF0dHJpYnV0ZXM7XG5cblxuXHRcdFx0dmFyIG9uU2VsZWN0SW1hZ2UgPSBmdW5jdGlvbiBvblNlbGVjdEltYWdlKGltZykge1xuXHRcdFx0XHRzZXRBdHRyaWJ1dGVzKHtcblx0XHRcdFx0XHR0ZXN0aW1vbmlhbEltZ0lEOiBpbWcuaWQsXG5cdFx0XHRcdFx0dGVzdGltb25pYWxJbWdVUkw6IGltZy51cmxcblx0XHRcdFx0fSk7XG5cdFx0XHR9O1xuXG5cdFx0XHRyZXR1cm4gW1xuXHRcdFx0Ly8gU2hvdyB0aGUgYWxpZ25tZW50IHRvb2xiYXIgb24gZm9jdXNcblx0XHRcdHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudChcblx0XHRcdFx0QmxvY2tDb250cm9scyxcblx0XHRcdFx0eyBrZXk6ICdjb250cm9scycgfSxcblx0XHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KEFsaWdubWVudFRvb2xiYXIsIHtcblx0XHRcdFx0XHR2YWx1ZTogdGVzdGltb25pYWxBbGlnbm1lbnQsXG5cdFx0XHRcdFx0b25DaGFuZ2U6IGZ1bmN0aW9uIG9uQ2hhbmdlKHZhbHVlKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gc2V0QXR0cmlidXRlcyh7IHRlc3RpbW9uaWFsQWxpZ25tZW50OiB2YWx1ZSB9KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0pXG5cdFx0XHQpLFxuXHRcdFx0Ly8gU2hvdyB0aGUgYmxvY2sgY29udHJvbHMgb24gZm9jdXNcblx0XHRcdHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudChJbnNwZWN0b3IsIE9iamVjdC5hc3NpZ24oeyBzZXRBdHRyaWJ1dGVzOiBzZXRBdHRyaWJ1dGVzIH0sIHRoaXMucHJvcHMpKSxcblx0XHRcdC8vIFNob3cgdGhlIGJsb2NrIG1hcmt1cCBpbiB0aGUgZWRpdG9yXG5cdFx0XHR3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRcdFRlc3RpbW9uaWFsLFxuXHRcdFx0XHR0aGlzLnByb3BzLFxuXHRcdFx0XHR3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoUmljaFRleHQsIHtcblx0XHRcdFx0XHR0YWdOYW1lOiAnZGl2Jyxcblx0XHRcdFx0XHRtdWx0aWxpbmU6ICdwJyxcblx0XHRcdFx0XHRwbGFjZWhvbGRlcjogX18oJ0FkZCB0ZXN0aW1vbmlhbCB0ZXh0Li4uJyksXG5cdFx0XHRcdFx0a2VlcFBsYWNlaG9sZGVyT25Gb2N1czogdHJ1ZSxcblx0XHRcdFx0XHR2YWx1ZTogdGVzdGltb25pYWxDb250ZW50LFxuXHRcdFx0XHRcdGZvcm1hdHRpbmdDb250cm9sczogWydib2xkJywgJ2l0YWxpYycsICdzdHJpa2V0aHJvdWdoJywgJ2xpbmsnXSxcblx0XHRcdFx0XHRjbGFzc05hbWU6IGNsYXNzbmFtZXMoJ2FiLXRlc3RpbW9uaWFsLXRleHQnKSxcblx0XHRcdFx0XHRzdHlsZToge1xuXHRcdFx0XHRcdFx0dGV4dEFsaWduOiB0ZXN0aW1vbmlhbEFsaWdubWVudFxuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0b25DaGFuZ2U6IGZ1bmN0aW9uIG9uQ2hhbmdlKHZhbHVlKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gc2V0QXR0cmlidXRlcyh7IHRlc3RpbW9uaWFsQ29udGVudDogdmFsdWUgfSk7XG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRpbmxpbmVUb29sYmFyOiB0cnVlXG5cdFx0XHRcdH0pLFxuXHRcdFx0XHR3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRcdFx0J2RpdicsXG5cdFx0XHRcdFx0eyAnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtaW5mbycgfSxcblx0XHRcdFx0XHR3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRcdFx0XHQnZGl2Jyxcblx0XHRcdFx0XHRcdHsgJ2NsYXNzJzogJ2FiLXRlc3RpbW9uaWFsLWF2YXRhci13cmFwJyB9LFxuXHRcdFx0XHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFxuXHRcdFx0XHRcdFx0XHQnZGl2Jyxcblx0XHRcdFx0XHRcdFx0eyAnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtaW1hZ2Utd3JhcCcgfSxcblx0XHRcdFx0XHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KE1lZGlhVXBsb2FkLCB7XG5cdFx0XHRcdFx0XHRcdFx0YnV0dG9uUHJvcHM6IHtcblx0XHRcdFx0XHRcdFx0XHRcdGNsYXNzTmFtZTogJ2NoYW5nZS1pbWFnZSdcblx0XHRcdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0XHRcdG9uU2VsZWN0OiBmdW5jdGlvbiBvblNlbGVjdChpbWcpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybiBzZXRBdHRyaWJ1dGVzKHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGVzdGltb25pYWxJbWdJRDogaW1nLmlkLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHR0ZXN0aW1vbmlhbEltZ1VSTDogaW1nLnVybFxuXHRcdFx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdFx0XHR0eXBlOiAnaW1hZ2UnLFxuXHRcdFx0XHRcdFx0XHRcdHZhbHVlOiB0ZXN0aW1vbmlhbEltZ0lELFxuXHRcdFx0XHRcdFx0XHRcdHJlbmRlcjogZnVuY3Rpb24gcmVuZGVyKF9yZWYpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHZhciBvcGVuID0gX3JlZi5vcGVuO1xuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudChcblx0XHRcdFx0XHRcdFx0XHRcdFx0QnV0dG9uLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHR7IG9uQ2xpY2s6IG9wZW4gfSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0IXRlc3RpbW9uaWFsSW1nSUQgPyBpY29ucy51cGxvYWQgOiB3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoJ2ltZycsIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtYXZhdGFyJyxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRzcmM6IHRlc3RpbW9uaWFsSW1nVVJMLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGFsdDogJ2F2YXRhcidcblx0XHRcdFx0XHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9KVxuXHRcdFx0XHRcdFx0KVxuXHRcdFx0XHRcdCksXG5cdFx0XHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFJpY2hUZXh0LCB7XG5cdFx0XHRcdFx0XHR0YWdOYW1lOiAnaDInLFxuXHRcdFx0XHRcdFx0cGxhY2Vob2xkZXI6IF9fKCdBZGQgbmFtZScpLFxuXHRcdFx0XHRcdFx0a2VlcFBsYWNlaG9sZGVyT25Gb2N1czogdHJ1ZSxcblx0XHRcdFx0XHRcdHZhbHVlOiB0ZXN0aW1vbmlhbE5hbWUsXG5cdFx0XHRcdFx0XHRjbGFzc05hbWU6ICdhYi10ZXN0aW1vbmlhbC1uYW1lJyxcblx0XHRcdFx0XHRcdHN0eWxlOiB7XG5cdFx0XHRcdFx0XHRcdGNvbG9yOiB0ZXN0aW1vbmlhbFRleHRDb2xvclxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdG9uQ2hhbmdlOiBmdW5jdGlvbiBvbkNoYW5nZSh2YWx1ZSkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gX3RoaXMyLnByb3BzLnNldEF0dHJpYnV0ZXMoeyB0ZXN0aW1vbmlhbE5hbWU6IHZhbHVlIH0pO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0pLFxuXHRcdFx0XHRcdHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudChSaWNoVGV4dCwge1xuXHRcdFx0XHRcdFx0dGFnTmFtZTogJ2g1Jyxcblx0XHRcdFx0XHRcdHBsYWNlaG9sZGVyOiBfXygnQWRkIHRpdGxlJyksXG5cdFx0XHRcdFx0XHRrZWVwUGxhY2Vob2xkZXJPbkZvY3VzOiB0cnVlLFxuXHRcdFx0XHRcdFx0dmFsdWU6IHRlc3RpbW9uaWFsVGl0bGUsXG5cdFx0XHRcdFx0XHRjbGFzc05hbWU6ICdhYi10ZXN0aW1vbmlhbC10aXRsZScsXG5cdFx0XHRcdFx0XHRzdHlsZToge1xuXHRcdFx0XHRcdFx0XHRjb2xvcjogdGVzdGltb25pYWxUZXh0Q29sb3Jcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRvbkNoYW5nZTogZnVuY3Rpb24gb25DaGFuZ2UodmFsdWUpIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIF90aGlzMi5wcm9wcy5zZXRBdHRyaWJ1dGVzKHsgdGVzdGltb25pYWxUaXRsZTogdmFsdWUgfSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSlcblx0XHRcdFx0KVxuXHRcdFx0KV07XG5cdFx0fVxuXHR9XSk7XG5cblx0cmV0dXJuIEFCVGVzdGltb25pYWxCbG9jaztcbn0oQ29tcG9uZW50KTtcblxuLy8gUmVnaXN0ZXIgdGhlIGJsb2NrXG5cblxucmVnaXN0ZXJCbG9ja1R5cGUoJ2F0b21pYy1ibG9ja3MvYWItdGVzdGltb25pYWwnLCB7XG5cdHRpdGxlOiBfXygnQUIgVGVzdGltb25pYWwnKSxcblx0ZGVzY3JpcHRpb246IF9fKCdBZGQgYSB1c2VyIHRlc3RpbW9uaWFsIHdpdGggYSBuYW1lIGFuZCB0aXRsZS4nKSxcblx0aWNvbjogJ2Zvcm1hdC1xdW90ZScsXG5cdGNhdGVnb3J5OiAnYXRvbWljLWJsb2NrcycsXG5cdGtleXdvcmRzOiBbX18oJ3Rlc3RpbW9uaWFsJyksIF9fKCdxdW90ZScpLCBfXygnYXRvbWljJyldLFxuXHRhdHRyaWJ1dGVzOiB7XG5cdFx0dGVzdGltb25pYWxOYW1lOiB7XG5cdFx0XHR0eXBlOiAnc3RyaW5nJyxcblx0XHRcdHNlbGVjdG9yOiAnLmFiLXRlc3RpbW9uaWFsLW5hbWUnXG5cdFx0fSxcblx0XHR0ZXN0aW1vbmlhbFRpdGxlOiB7XG5cdFx0XHR0eXBlOiAnc3RyaW5nJyxcblx0XHRcdHNlbGVjdG9yOiAnLmFiLXRlc3RpbW9uaWFsLXRpdGxlJ1xuXHRcdH0sXG5cdFx0dGVzdGltb25pYWxDb250ZW50OiB7XG5cdFx0XHR0eXBlOiAnYXJyYXknLFxuXHRcdFx0c2VsZWN0b3I6ICcuYWItdGVzdGltb25pYWwtdGV4dCcsXG5cdFx0XHRzb3VyY2U6ICdjaGlsZHJlbidcblx0XHR9LFxuXHRcdHRlc3RpbW9uaWFsQWxpZ25tZW50OiB7XG5cdFx0XHR0eXBlOiAnc3RyaW5nJ1xuXHRcdH0sXG5cdFx0dGVzdGltb25pYWxJbWdVUkw6IHtcblx0XHRcdHR5cGU6ICdzdHJpbmcnLFxuXHRcdFx0c291cmNlOiAnYXR0cmlidXRlJyxcblx0XHRcdGF0dHJpYnV0ZTogJ3NyYycsXG5cdFx0XHRzZWxlY3RvcjogJ2ltZydcblx0XHR9LFxuXHRcdHRlc3RpbW9uaWFsSW1nSUQ6IHtcblx0XHRcdHR5cGU6ICdudW1iZXInXG5cdFx0fSxcblx0XHR0ZXN0aW1vbmlhbEJhY2tncm91bmRDb2xvcjoge1xuXHRcdFx0dHlwZTogJ3N0cmluZycsXG5cdFx0XHRkZWZhdWx0OiAnI2YyZjJmMidcblx0XHR9LFxuXHRcdHRlc3RpbW9uaWFsVGV4dENvbG9yOiB7XG5cdFx0XHR0eXBlOiAnc3RyaW5nJyxcblx0XHRcdGRlZmF1bHQ6ICcjMzIzNzNjJ1xuXHRcdH0sXG5cdFx0dGVzdGltb25pYWxGb250U2l6ZToge1xuXHRcdFx0dHlwZTogJ251bWJlcicsXG5cdFx0XHRkZWZhdWx0OiAxOFxuXHRcdH0sXG5cdFx0dGVzdGltb25pYWxDaXRlQWxpZ246IHtcblx0XHRcdHR5cGU6ICdzdHJpbmcnLFxuXHRcdFx0ZGVmYXVsdDogJ2xlZnQtYWxpZ25lZCdcblx0XHR9XG5cdH0sXG5cblx0Ly8gUmVuZGVyIHRoZSBibG9jayBjb21wb25lbnRzXG5cdGVkaXQ6IEFCVGVzdGltb25pYWxCbG9jayxcblxuXHQvLyBTYXZlIHRoZSBhdHRyaWJ1dGVzIGFuZCBtYXJrdXBcblx0c2F2ZTogZnVuY3Rpb24gc2F2ZShwcm9wcykge1xuXG5cdFx0Ly8gU2V0dXAgdGhlIGF0dHJpYnV0ZXNcblx0XHR2YXIgX3Byb3BzJGF0dHJpYnV0ZXMyID0gcHJvcHMuYXR0cmlidXRlcyxcblx0XHQgICAgdGVzdGltb25pYWxOYW1lID0gX3Byb3BzJGF0dHJpYnV0ZXMyLnRlc3RpbW9uaWFsTmFtZSxcblx0XHQgICAgdGVzdGltb25pYWxUaXRsZSA9IF9wcm9wcyRhdHRyaWJ1dGVzMi50ZXN0aW1vbmlhbFRpdGxlLFxuXHRcdCAgICB0ZXN0aW1vbmlhbENvbnRlbnQgPSBfcHJvcHMkYXR0cmlidXRlczIudGVzdGltb25pYWxDb250ZW50LFxuXHRcdCAgICB0ZXN0aW1vbmlhbEFsaWdubWVudCA9IF9wcm9wcyRhdHRyaWJ1dGVzMi50ZXN0aW1vbmlhbEFsaWdubWVudCxcblx0XHQgICAgdGVzdGltb25pYWxJbWdVUkwgPSBfcHJvcHMkYXR0cmlidXRlczIudGVzdGltb25pYWxJbWdVUkwsXG5cdFx0ICAgIHRlc3RpbW9uaWFsSW1nSUQgPSBfcHJvcHMkYXR0cmlidXRlczIudGVzdGltb25pYWxJbWdJRCxcblx0XHQgICAgdGVzdGltb25pYWxCYWNrZ3JvdW5kQ29sb3IgPSBfcHJvcHMkYXR0cmlidXRlczIudGVzdGltb25pYWxCYWNrZ3JvdW5kQ29sb3IsXG5cdFx0ICAgIHRlc3RpbW9uaWFsVGV4dENvbG9yID0gX3Byb3BzJGF0dHJpYnV0ZXMyLnRlc3RpbW9uaWFsVGV4dENvbG9yLFxuXHRcdCAgICB0ZXN0aW1vbmlhbEZvbnRTaXplID0gX3Byb3BzJGF0dHJpYnV0ZXMyLnRlc3RpbW9uaWFsRm9udFNpemUsXG5cdFx0ICAgIHRlc3RpbW9uaWFsQ2l0ZUFsaWduID0gX3Byb3BzJGF0dHJpYnV0ZXMyLnRlc3RpbW9uaWFsQ2l0ZUFsaWduO1xuXG5cdFx0Ly8gU2F2ZSB0aGUgYmxvY2sgbWFya3VwIGZvciB0aGUgZnJvbnQgZW5kXG5cblx0XHRyZXR1cm4gd3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFxuXHRcdFx0VGVzdGltb25pYWwsXG5cdFx0XHRwcm9wcyxcblx0XHRcdHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudChcblx0XHRcdFx0J2RpdicsXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRjbGFzc05hbWU6IGNsYXNzbmFtZXMoJ2FiLXRlc3RpbW9uaWFsLXRleHQnKSxcblx0XHRcdFx0XHRzdHlsZToge1xuXHRcdFx0XHRcdFx0dGV4dEFsaWduOiB0ZXN0aW1vbmlhbEFsaWdubWVudFxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSxcblx0XHRcdFx0dGVzdGltb25pYWxDb250ZW50XG5cdFx0XHQpLFxuXHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFxuXHRcdFx0XHQnZGl2Jyxcblx0XHRcdFx0eyAnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtaW5mbycgfSxcblx0XHRcdFx0dGVzdGltb25pYWxJbWdVUkwgJiYgISF0ZXN0aW1vbmlhbEltZ1VSTC5sZW5ndGggJiYgd3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFxuXHRcdFx0XHRcdCdkaXYnLFxuXHRcdFx0XHRcdHsgJ2NsYXNzJzogJ2FiLXRlc3RpbW9uaWFsLWF2YXRhci13cmFwJyB9LFxuXHRcdFx0XHRcdHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudChcblx0XHRcdFx0XHRcdCdkaXYnLFxuXHRcdFx0XHRcdFx0eyAnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtaW1hZ2Utd3JhcCcgfSxcblx0XHRcdFx0XHRcdHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudCgnaW1nJywge1xuXHRcdFx0XHRcdFx0XHQnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtYXZhdGFyJyxcblx0XHRcdFx0XHRcdFx0c3JjOiB0ZXN0aW1vbmlhbEltZ1VSTCxcblx0XHRcdFx0XHRcdFx0YWx0OiAnYXZhdGFyJ1xuXHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0XHQpXG5cdFx0XHRcdCksXG5cdFx0XHRcdHRlc3RpbW9uaWFsTmFtZSAmJiAhIXRlc3RpbW9uaWFsTmFtZS5sZW5ndGggJiYgd3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFxuXHRcdFx0XHRcdCdoMicsXG5cdFx0XHRcdFx0eyAnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtbmFtZScsXG5cdFx0XHRcdFx0XHRzdHlsZToge1xuXHRcdFx0XHRcdFx0XHRjb2xvcjogdGVzdGltb25pYWxUZXh0Q29sb3Jcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdHRlc3RpbW9uaWFsTmFtZVxuXHRcdFx0XHQpLFxuXHRcdFx0XHR0ZXN0aW1vbmlhbFRpdGxlICYmICEhdGVzdGltb25pYWxUaXRsZS5sZW5ndGggJiYgd3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFxuXHRcdFx0XHRcdCdzbWFsbCcsXG5cdFx0XHRcdFx0eyAnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtdGl0bGUnLFxuXHRcdFx0XHRcdFx0c3R5bGU6IHtcblx0XHRcdFx0XHRcdFx0Y29sb3I6IHRlc3RpbW9uaWFsVGV4dENvbG9yXG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0XHR0ZXN0aW1vbmlhbFRpdGxlXG5cdFx0XHRcdClcblx0XHRcdClcblx0XHQpO1xuXHR9XG59KTtcblxuXG4vLy8vLy8vLy8vLy8vLy8vLy9cbi8vIFdFQlBBQ0sgRk9PVEVSXG4vLyAuL3NyYy9ibG9ja3MvYmxvY2stdGVzdGltb25pYWwvaW5kZXguanNcbi8vIG1vZHVsZSBpZCA9IDE4MFxuLy8gbW9kdWxlIGNodW5rcyA9IDAiXSwibWFwcGluZ3MiOiJBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///180\n");
|
2064 |
|
2065 |
/***/ }),
|
2066 |
/* 181 */
|
2060 |
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
2061 |
|
2062 |
"use strict";
|
2063 |
+
eval("/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_classnames__ = __webpack_require__(/*! classnames */ 1);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_classnames___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_classnames__);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__components_inspector__ = __webpack_require__(/*! ./components/inspector */ 181);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__components_testimonial__ = __webpack_require__(/*! ./components/testimonial */ 182);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__components_icons__ = __webpack_require__(/*! ./components/icons */ 185);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__styles_style_scss__ = __webpack_require__(/*! ./styles/style.scss */ 186);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__styles_style_scss___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4__styles_style_scss__);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__styles_editor_scss__ = __webpack_require__(/*! ./styles/editor.scss */ 187);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__styles_editor_scss___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5__styles_editor_scss__);\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\n/**\n * BLOCK: Atomic Blocks Testimonial\n */\n\n// Import block dependencies and components\n\n\n\n\n\n// Import CSS\n\n\n\n// Internationalization\nvar __ = wp.i18n.__;\n\n// Extend component\n\nvar Component = wp.element.Component;\n\n// Register block\n\nvar registerBlockType = wp.blocks.registerBlockType;\n\n// Register editor components\n\nvar _wp$editor = wp.editor,\n RichText = _wp$editor.RichText,\n AlignmentToolbar = _wp$editor.AlignmentToolbar,\n BlockControls = _wp$editor.BlockControls,\n BlockAlignmentToolbar = _wp$editor.BlockAlignmentToolbar,\n MediaUpload = _wp$editor.MediaUpload;\n\n// Register components\n\nvar _wp$components = wp.components,\n Button = _wp$components.Button,\n SelectControl = _wp$components.SelectControl;\n\nvar ABTestimonialBlock = function (_Component) {\n\t_inherits(ABTestimonialBlock, _Component);\n\n\tfunction ABTestimonialBlock() {\n\t\t_classCallCheck(this, ABTestimonialBlock);\n\n\t\treturn _possibleConstructorReturn(this, (ABTestimonialBlock.__proto__ || Object.getPrototypeOf(ABTestimonialBlock)).apply(this, arguments));\n\t}\n\n\t_createClass(ABTestimonialBlock, [{\n\t\tkey: 'render',\n\t\tvalue: function render() {\n\t\t\tvar _this2 = this;\n\n\t\t\t// Setup the attributes\n\t\t\tvar _props = this.props,\n\t\t\t _props$attributes = _props.attributes,\n\t\t\t testimonialName = _props$attributes.testimonialName,\n\t\t\t testimonialTitle = _props$attributes.testimonialTitle,\n\t\t\t testimonialContent = _props$attributes.testimonialContent,\n\t\t\t testimonialAlignment = _props$attributes.testimonialAlignment,\n\t\t\t testimonialImgURL = _props$attributes.testimonialImgURL,\n\t\t\t testimonialImgID = _props$attributes.testimonialImgID,\n\t\t\t testimonialBackgroundColor = _props$attributes.testimonialBackgroundColor,\n\t\t\t testimonialTextColor = _props$attributes.testimonialTextColor,\n\t\t\t testimonialFontSize = _props$attributes.testimonialFontSize,\n\t\t\t testimonialCiteAlign = _props$attributes.testimonialCiteAlign,\n\t\t\t attributes = _props.attributes,\n\t\t\t isSelected = _props.isSelected,\n\t\t\t editable = _props.editable,\n\t\t\t className = _props.className,\n\t\t\t setAttributes = _props.setAttributes;\n\n\n\t\t\tvar onSelectImage = function onSelectImage(img) {\n\t\t\t\tsetAttributes({\n\t\t\t\t\ttestimonialImgID: img.id,\n\t\t\t\t\ttestimonialImgURL: img.url\n\t\t\t\t});\n\t\t\t};\n\n\t\t\treturn [\n\t\t\t// Show the alignment toolbar on focus\n\t\t\twp.element.createElement(\n\t\t\t\tBlockControls,\n\t\t\t\t{ key: 'controls' },\n\t\t\t\twp.element.createElement(AlignmentToolbar, {\n\t\t\t\t\tvalue: testimonialAlignment,\n\t\t\t\t\tonChange: function onChange(value) {\n\t\t\t\t\t\treturn setAttributes({ testimonialAlignment: value });\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t),\n\t\t\t// Show the block controls on focus\n\t\t\twp.element.createElement(__WEBPACK_IMPORTED_MODULE_1__components_inspector__[\"a\" /* default */], Object.assign({ setAttributes: setAttributes }, this.props)),\n\t\t\t// Show the block markup in the editor\n\t\t\twp.element.createElement(\n\t\t\t\t__WEBPACK_IMPORTED_MODULE_2__components_testimonial__[\"a\" /* default */],\n\t\t\t\tthis.props,\n\t\t\t\twp.element.createElement(RichText, {\n\t\t\t\t\ttagName: 'div',\n\t\t\t\t\tmultiline: 'p',\n\t\t\t\t\tplaceholder: __('Add testimonial text...'),\n\t\t\t\t\tkeepPlaceholderOnFocus: true,\n\t\t\t\t\tvalue: testimonialContent,\n\t\t\t\t\tformattingControls: ['bold', 'italic', 'strikethrough', 'link'],\n\t\t\t\t\tclassName: __WEBPACK_IMPORTED_MODULE_0_classnames___default()('ab-testimonial-text'),\n\t\t\t\t\tstyle: {\n\t\t\t\t\t\ttextAlign: testimonialAlignment\n\t\t\t\t\t},\n\t\t\t\t\tonChange: function onChange(value) {\n\t\t\t\t\t\treturn setAttributes({ testimonialContent: value });\n\t\t\t\t\t},\n\t\t\t\t\tinlineToolbar: true\n\t\t\t\t}),\n\t\t\t\twp.element.createElement(\n\t\t\t\t\t'div',\n\t\t\t\t\t{ 'class': 'ab-testimonial-info' },\n\t\t\t\t\twp.element.createElement(\n\t\t\t\t\t\t'div',\n\t\t\t\t\t\t{ 'class': 'ab-testimonial-avatar-wrap' },\n\t\t\t\t\t\twp.element.createElement(\n\t\t\t\t\t\t\t'div',\n\t\t\t\t\t\t\t{ 'class': 'ab-testimonial-image-wrap' },\n\t\t\t\t\t\t\twp.element.createElement(MediaUpload, {\n\t\t\t\t\t\t\t\tbuttonProps: {\n\t\t\t\t\t\t\t\t\tclassName: 'change-image'\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tonSelect: function onSelect(img) {\n\t\t\t\t\t\t\t\t\treturn setAttributes({\n\t\t\t\t\t\t\t\t\t\ttestimonialImgID: img.id,\n\t\t\t\t\t\t\t\t\t\ttestimonialImgURL: img.url\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\ttype: 'image',\n\t\t\t\t\t\t\t\tvalue: testimonialImgID,\n\t\t\t\t\t\t\t\trender: function render(_ref) {\n\t\t\t\t\t\t\t\t\tvar open = _ref.open;\n\t\t\t\t\t\t\t\t\treturn wp.element.createElement(\n\t\t\t\t\t\t\t\t\t\tButton,\n\t\t\t\t\t\t\t\t\t\t{ onClick: open },\n\t\t\t\t\t\t\t\t\t\t!testimonialImgID ? __WEBPACK_IMPORTED_MODULE_3__components_icons__[\"a\" /* default */].upload : wp.element.createElement('img', {\n\t\t\t\t\t\t\t\t\t\t\t'class': 'ab-testimonial-avatar',\n\t\t\t\t\t\t\t\t\t\t\tsrc: testimonialImgURL,\n\t\t\t\t\t\t\t\t\t\t\talt: 'avatar'\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t)\n\t\t\t\t\t),\n\t\t\t\t\twp.element.createElement(RichText, {\n\t\t\t\t\t\ttagName: 'h2',\n\t\t\t\t\t\tplaceholder: __('Add name'),\n\t\t\t\t\t\tkeepPlaceholderOnFocus: true,\n\t\t\t\t\t\tvalue: testimonialName,\n\t\t\t\t\t\tclassName: 'ab-testimonial-name',\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tcolor: testimonialTextColor\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonChange: function onChange(value) {\n\t\t\t\t\t\t\treturn _this2.props.setAttributes({ testimonialName: value });\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t\twp.element.createElement(RichText, {\n\t\t\t\t\t\ttagName: 'small',\n\t\t\t\t\t\tplaceholder: __('Add title'),\n\t\t\t\t\t\tkeepPlaceholderOnFocus: true,\n\t\t\t\t\t\tvalue: testimonialTitle,\n\t\t\t\t\t\tclassName: 'ab-testimonial-title',\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tcolor: testimonialTextColor\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonChange: function onChange(value) {\n\t\t\t\t\t\t\treturn _this2.props.setAttributes({ testimonialTitle: value });\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t)];\n\t\t}\n\t}]);\n\n\treturn ABTestimonialBlock;\n}(Component);\n\n// Register the block\n\n\nregisterBlockType('atomic-blocks/ab-testimonial', {\n\ttitle: __('AB Testimonial'),\n\tdescription: __('Add a user testimonial with a name and title.'),\n\ticon: 'format-quote',\n\tcategory: 'atomic-blocks',\n\tkeywords: [__('testimonial'), __('quote'), __('atomic')],\n\tattributes: {\n\t\ttestimonialName: {\n\t\t\ttype: 'string',\n\t\t\tselector: '.ab-testimonial-name'\n\t\t},\n\t\ttestimonialTitle: {\n\t\t\ttype: 'array',\n\t\t\tselector: '.ab-testimonial-title',\n\t\t\tsource: 'children'\n\t\t},\n\t\ttestimonialContent: {\n\t\t\ttype: 'array',\n\t\t\tselector: '.ab-testimonial-text',\n\t\t\tsource: 'children'\n\t\t},\n\t\ttestimonialAlignment: {\n\t\t\ttype: 'string'\n\t\t},\n\t\ttestimonialImgURL: {\n\t\t\ttype: 'string',\n\t\t\tsource: 'attribute',\n\t\t\tattribute: 'src',\n\t\t\tselector: 'img'\n\t\t},\n\t\ttestimonialImgID: {\n\t\t\ttype: 'number'\n\t\t},\n\t\ttestimonialBackgroundColor: {\n\t\t\ttype: 'string',\n\t\t\tdefault: '#f2f2f2'\n\t\t},\n\t\ttestimonialTextColor: {\n\t\t\ttype: 'string',\n\t\t\tdefault: '#32373c'\n\t\t},\n\t\ttestimonialFontSize: {\n\t\t\ttype: 'number',\n\t\t\tdefault: 18\n\t\t},\n\t\ttestimonialCiteAlign: {\n\t\t\ttype: 'string',\n\t\t\tdefault: 'left-aligned'\n\t\t}\n\t},\n\n\t// Render the block components\n\tedit: ABTestimonialBlock,\n\n\t// Save the attributes and markup\n\tsave: function save(props) {\n\n\t\t// Setup the attributes\n\t\tvar _props$attributes2 = props.attributes,\n\t\t testimonialName = _props$attributes2.testimonialName,\n\t\t testimonialTitle = _props$attributes2.testimonialTitle,\n\t\t testimonialContent = _props$attributes2.testimonialContent,\n\t\t testimonialAlignment = _props$attributes2.testimonialAlignment,\n\t\t testimonialImgURL = _props$attributes2.testimonialImgURL,\n\t\t testimonialImgID = _props$attributes2.testimonialImgID,\n\t\t testimonialBackgroundColor = _props$attributes2.testimonialBackgroundColor,\n\t\t testimonialTextColor = _props$attributes2.testimonialTextColor,\n\t\t testimonialFontSize = _props$attributes2.testimonialFontSize,\n\t\t testimonialCiteAlign = _props$attributes2.testimonialCiteAlign;\n\n\t\t// Save the block markup for the front end\n\n\t\treturn wp.element.createElement(\n\t\t\t__WEBPACK_IMPORTED_MODULE_2__components_testimonial__[\"a\" /* default */],\n\t\t\tprops,\n\t\t\twp.element.createElement(\n\t\t\t\t'div',\n\t\t\t\t{\n\t\t\t\t\tclassName: __WEBPACK_IMPORTED_MODULE_0_classnames___default()('ab-testimonial-text'),\n\t\t\t\t\tstyle: {\n\t\t\t\t\t\ttextAlign: testimonialAlignment\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\ttestimonialContent\n\t\t\t),\n\t\t\twp.element.createElement(\n\t\t\t\t'div',\n\t\t\t\t{ 'class': 'ab-testimonial-info' },\n\t\t\t\ttestimonialImgURL && !!testimonialImgURL.length && wp.element.createElement(\n\t\t\t\t\t'div',\n\t\t\t\t\t{ 'class': 'ab-testimonial-avatar-wrap' },\n\t\t\t\t\twp.element.createElement(\n\t\t\t\t\t\t'div',\n\t\t\t\t\t\t{ 'class': 'ab-testimonial-image-wrap' },\n\t\t\t\t\t\twp.element.createElement('img', {\n\t\t\t\t\t\t\t'class': 'ab-testimonial-avatar',\n\t\t\t\t\t\t\tsrc: testimonialImgURL,\n\t\t\t\t\t\t\talt: 'avatar'\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\ttestimonialName && !!testimonialName.length && wp.element.createElement(\n\t\t\t\t\t'h2',\n\t\t\t\t\t{ 'class': 'ab-testimonial-name',\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tcolor: testimonialTextColor\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\ttestimonialName\n\t\t\t\t),\n\t\t\t\ttestimonialTitle && !!testimonialTitle.length && wp.element.createElement(\n\t\t\t\t\t'small',\n\t\t\t\t\t{ 'class': 'ab-testimonial-title',\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tcolor: testimonialTextColor\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\ttestimonialTitle\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTgwLmpzIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4vc3JjL2Jsb2Nrcy9ibG9jay10ZXN0aW1vbmlhbC9pbmRleC5qcz9jMzQyIl0sInNvdXJjZXNDb250ZW50IjpbInZhciBfY3JlYXRlQ2xhc3MgPSBmdW5jdGlvbiAoKSB7IGZ1bmN0aW9uIGRlZmluZVByb3BlcnRpZXModGFyZ2V0LCBwcm9wcykgeyBmb3IgKHZhciBpID0gMDsgaSA8IHByb3BzLmxlbmd0aDsgaSsrKSB7IHZhciBkZXNjcmlwdG9yID0gcHJvcHNbaV07IGRlc2NyaXB0b3IuZW51bWVyYWJsZSA9IGRlc2NyaXB0b3IuZW51bWVyYWJsZSB8fCBmYWxzZTsgZGVzY3JpcHRvci5jb25maWd1cmFibGUgPSB0cnVlOyBpZiAoXCJ2YWx1ZVwiIGluIGRlc2NyaXB0b3IpIGRlc2NyaXB0b3Iud3JpdGFibGUgPSB0cnVlOyBPYmplY3QuZGVmaW5lUHJvcGVydHkodGFyZ2V0LCBkZXNjcmlwdG9yLmtleSwgZGVzY3JpcHRvcik7IH0gfSByZXR1cm4gZnVuY3Rpb24gKENvbnN0cnVjdG9yLCBwcm90b1Byb3BzLCBzdGF0aWNQcm9wcykgeyBpZiAocHJvdG9Qcm9wcykgZGVmaW5lUHJvcGVydGllcyhDb25zdHJ1Y3Rvci5wcm90b3R5cGUsIHByb3RvUHJvcHMpOyBpZiAoc3RhdGljUHJvcHMpIGRlZmluZVByb3BlcnRpZXMoQ29uc3RydWN0b3IsIHN0YXRpY1Byb3BzKTsgcmV0dXJuIENvbnN0cnVjdG9yOyB9OyB9KCk7XG5cbmZ1bmN0aW9uIF9jbGFzc0NhbGxDaGVjayhpbnN0YW5jZSwgQ29uc3RydWN0b3IpIHsgaWYgKCEoaW5zdGFuY2UgaW5zdGFuY2VvZiBDb25zdHJ1Y3RvcikpIHsgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkNhbm5vdCBjYWxsIGEgY2xhc3MgYXMgYSBmdW5jdGlvblwiKTsgfSB9XG5cbmZ1bmN0aW9uIF9wb3NzaWJsZUNvbnN0cnVjdG9yUmV0dXJuKHNlbGYsIGNhbGwpIHsgaWYgKCFzZWxmKSB7IHRocm93IG5ldyBSZWZlcmVuY2VFcnJvcihcInRoaXMgaGFzbid0IGJlZW4gaW5pdGlhbGlzZWQgLSBzdXBlcigpIGhhc24ndCBiZWVuIGNhbGxlZFwiKTsgfSByZXR1cm4gY2FsbCAmJiAodHlwZW9mIGNhbGwgPT09IFwib2JqZWN0XCIgfHwgdHlwZW9mIGNhbGwgPT09IFwiZnVuY3Rpb25cIikgPyBjYWxsIDogc2VsZjsgfVxuXG5mdW5jdGlvbiBfaW5oZXJpdHMoc3ViQ2xhc3MsIHN1cGVyQ2xhc3MpIHsgaWYgKHR5cGVvZiBzdXBlckNsYXNzICE9PSBcImZ1bmN0aW9uXCIgJiYgc3VwZXJDbGFzcyAhPT0gbnVsbCkgeyB0aHJvdyBuZXcgVHlwZUVycm9yKFwiU3VwZXIgZXhwcmVzc2lvbiBtdXN0IGVpdGhlciBiZSBudWxsIG9yIGEgZnVuY3Rpb24sIG5vdCBcIiArIHR5cGVvZiBzdXBlckNsYXNzKTsgfSBzdWJDbGFzcy5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHN1cGVyQ2xhc3MgJiYgc3VwZXJDbGFzcy5wcm90b3R5cGUsIHsgY29uc3RydWN0b3I6IHsgdmFsdWU6IHN1YkNsYXNzLCBlbnVtZXJhYmxlOiBmYWxzZSwgd3JpdGFibGU6IHRydWUsIGNvbmZpZ3VyYWJsZTogdHJ1ZSB9IH0pOyBpZiAoc3VwZXJDbGFzcykgT2JqZWN0LnNldFByb3RvdHlwZU9mID8gT2JqZWN0LnNldFByb3RvdHlwZU9mKHN1YkNsYXNzLCBzdXBlckNsYXNzKSA6IHN1YkNsYXNzLl9fcHJvdG9fXyA9IHN1cGVyQ2xhc3M7IH1cblxuLyoqXG4gKiBCTE9DSzogQXRvbWljIEJsb2NrcyBUZXN0aW1vbmlhbFxuICovXG5cbi8vIEltcG9ydCBibG9jayBkZXBlbmRlbmNpZXMgYW5kIGNvbXBvbmVudHNcbmltcG9ydCBjbGFzc25hbWVzIGZyb20gJ2NsYXNzbmFtZXMnO1xuaW1wb3J0IEluc3BlY3RvciBmcm9tICcuL2NvbXBvbmVudHMvaW5zcGVjdG9yJztcbmltcG9ydCBUZXN0aW1vbmlhbCBmcm9tICcuL2NvbXBvbmVudHMvdGVzdGltb25pYWwnO1xuaW1wb3J0IGljb25zIGZyb20gJy4vY29tcG9uZW50cy9pY29ucyc7XG5cbi8vIEltcG9ydCBDU1NcbmltcG9ydCAnLi9zdHlsZXMvc3R5bGUuc2Nzcyc7XG5pbXBvcnQgJy4vc3R5bGVzL2VkaXRvci5zY3NzJztcblxuLy8gSW50ZXJuYXRpb25hbGl6YXRpb25cbnZhciBfXyA9IHdwLmkxOG4uX187XG5cbi8vIEV4dGVuZCBjb21wb25lbnRcblxudmFyIENvbXBvbmVudCA9IHdwLmVsZW1lbnQuQ29tcG9uZW50O1xuXG4vLyBSZWdpc3RlciBibG9ja1xuXG52YXIgcmVnaXN0ZXJCbG9ja1R5cGUgPSB3cC5ibG9ja3MucmVnaXN0ZXJCbG9ja1R5cGU7XG5cbi8vIFJlZ2lzdGVyIGVkaXRvciBjb21wb25lbnRzXG5cbnZhciBfd3AkZWRpdG9yID0gd3AuZWRpdG9yLFxuICAgIFJpY2hUZXh0ID0gX3dwJGVkaXRvci5SaWNoVGV4dCxcbiAgICBBbGlnbm1lbnRUb29sYmFyID0gX3dwJGVkaXRvci5BbGlnbm1lbnRUb29sYmFyLFxuICAgIEJsb2NrQ29udHJvbHMgPSBfd3AkZWRpdG9yLkJsb2NrQ29udHJvbHMsXG4gICAgQmxvY2tBbGlnbm1lbnRUb29sYmFyID0gX3dwJGVkaXRvci5CbG9ja0FsaWdubWVudFRvb2xiYXIsXG4gICAgTWVkaWFVcGxvYWQgPSBfd3AkZWRpdG9yLk1lZGlhVXBsb2FkO1xuXG4vLyBSZWdpc3RlciBjb21wb25lbnRzXG5cbnZhciBfd3AkY29tcG9uZW50cyA9IHdwLmNvbXBvbmVudHMsXG4gICAgQnV0dG9uID0gX3dwJGNvbXBvbmVudHMuQnV0dG9uLFxuICAgIFNlbGVjdENvbnRyb2wgPSBfd3AkY29tcG9uZW50cy5TZWxlY3RDb250cm9sO1xuXG52YXIgQUJUZXN0aW1vbmlhbEJsb2NrID0gZnVuY3Rpb24gKF9Db21wb25lbnQpIHtcblx0X2luaGVyaXRzKEFCVGVzdGltb25pYWxCbG9jaywgX0NvbXBvbmVudCk7XG5cblx0ZnVuY3Rpb24gQUJUZXN0aW1vbmlhbEJsb2NrKCkge1xuXHRcdF9jbGFzc0NhbGxDaGVjayh0aGlzLCBBQlRlc3RpbW9uaWFsQmxvY2spO1xuXG5cdFx0cmV0dXJuIF9wb3NzaWJsZUNvbnN0cnVjdG9yUmV0dXJuKHRoaXMsIChBQlRlc3RpbW9uaWFsQmxvY2suX19wcm90b19fIHx8IE9iamVjdC5nZXRQcm90b3R5cGVPZihBQlRlc3RpbW9uaWFsQmxvY2spKS5hcHBseSh0aGlzLCBhcmd1bWVudHMpKTtcblx0fVxuXG5cdF9jcmVhdGVDbGFzcyhBQlRlc3RpbW9uaWFsQmxvY2ssIFt7XG5cdFx0a2V5OiAncmVuZGVyJyxcblx0XHR2YWx1ZTogZnVuY3Rpb24gcmVuZGVyKCkge1xuXHRcdFx0dmFyIF90aGlzMiA9IHRoaXM7XG5cblx0XHRcdC8vIFNldHVwIHRoZSBhdHRyaWJ1dGVzXG5cdFx0XHR2YXIgX3Byb3BzID0gdGhpcy5wcm9wcyxcblx0XHRcdCAgICBfcHJvcHMkYXR0cmlidXRlcyA9IF9wcm9wcy5hdHRyaWJ1dGVzLFxuXHRcdFx0ICAgIHRlc3RpbW9uaWFsTmFtZSA9IF9wcm9wcyRhdHRyaWJ1dGVzLnRlc3RpbW9uaWFsTmFtZSxcblx0XHRcdCAgICB0ZXN0aW1vbmlhbFRpdGxlID0gX3Byb3BzJGF0dHJpYnV0ZXMudGVzdGltb25pYWxUaXRsZSxcblx0XHRcdCAgICB0ZXN0aW1vbmlhbENvbnRlbnQgPSBfcHJvcHMkYXR0cmlidXRlcy50ZXN0aW1vbmlhbENvbnRlbnQsXG5cdFx0XHQgICAgdGVzdGltb25pYWxBbGlnbm1lbnQgPSBfcHJvcHMkYXR0cmlidXRlcy50ZXN0aW1vbmlhbEFsaWdubWVudCxcblx0XHRcdCAgICB0ZXN0aW1vbmlhbEltZ1VSTCA9IF9wcm9wcyRhdHRyaWJ1dGVzLnRlc3RpbW9uaWFsSW1nVVJMLFxuXHRcdFx0ICAgIHRlc3RpbW9uaWFsSW1nSUQgPSBfcHJvcHMkYXR0cmlidXRlcy50ZXN0aW1vbmlhbEltZ0lELFxuXHRcdFx0ICAgIHRlc3RpbW9uaWFsQmFja2dyb3VuZENvbG9yID0gX3Byb3BzJGF0dHJpYnV0ZXMudGVzdGltb25pYWxCYWNrZ3JvdW5kQ29sb3IsXG5cdFx0XHQgICAgdGVzdGltb25pYWxUZXh0Q29sb3IgPSBfcHJvcHMkYXR0cmlidXRlcy50ZXN0aW1vbmlhbFRleHRDb2xvcixcblx0XHRcdCAgICB0ZXN0aW1vbmlhbEZvbnRTaXplID0gX3Byb3BzJGF0dHJpYnV0ZXMudGVzdGltb25pYWxGb250U2l6ZSxcblx0XHRcdCAgICB0ZXN0aW1vbmlhbENpdGVBbGlnbiA9IF9wcm9wcyRhdHRyaWJ1dGVzLnRlc3RpbW9uaWFsQ2l0ZUFsaWduLFxuXHRcdFx0ICAgIGF0dHJpYnV0ZXMgPSBfcHJvcHMuYXR0cmlidXRlcyxcblx0XHRcdCAgICBpc1NlbGVjdGVkID0gX3Byb3BzLmlzU2VsZWN0ZWQsXG5cdFx0XHQgICAgZWRpdGFibGUgPSBfcHJvcHMuZWRpdGFibGUsXG5cdFx0XHQgICAgY2xhc3NOYW1lID0gX3Byb3BzLmNsYXNzTmFtZSxcblx0XHRcdCAgICBzZXRBdHRyaWJ1dGVzID0gX3Byb3BzLnNldEF0dHJpYnV0ZXM7XG5cblxuXHRcdFx0dmFyIG9uU2VsZWN0SW1hZ2UgPSBmdW5jdGlvbiBvblNlbGVjdEltYWdlKGltZykge1xuXHRcdFx0XHRzZXRBdHRyaWJ1dGVzKHtcblx0XHRcdFx0XHR0ZXN0aW1vbmlhbEltZ0lEOiBpbWcuaWQsXG5cdFx0XHRcdFx0dGVzdGltb25pYWxJbWdVUkw6IGltZy51cmxcblx0XHRcdFx0fSk7XG5cdFx0XHR9O1xuXG5cdFx0XHRyZXR1cm4gW1xuXHRcdFx0Ly8gU2hvdyB0aGUgYWxpZ25tZW50IHRvb2xiYXIgb24gZm9jdXNcblx0XHRcdHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudChcblx0XHRcdFx0QmxvY2tDb250cm9scyxcblx0XHRcdFx0eyBrZXk6ICdjb250cm9scycgfSxcblx0XHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KEFsaWdubWVudFRvb2xiYXIsIHtcblx0XHRcdFx0XHR2YWx1ZTogdGVzdGltb25pYWxBbGlnbm1lbnQsXG5cdFx0XHRcdFx0b25DaGFuZ2U6IGZ1bmN0aW9uIG9uQ2hhbmdlKHZhbHVlKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gc2V0QXR0cmlidXRlcyh7IHRlc3RpbW9uaWFsQWxpZ25tZW50OiB2YWx1ZSB9KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0pXG5cdFx0XHQpLFxuXHRcdFx0Ly8gU2hvdyB0aGUgYmxvY2sgY29udHJvbHMgb24gZm9jdXNcblx0XHRcdHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudChJbnNwZWN0b3IsIE9iamVjdC5hc3NpZ24oeyBzZXRBdHRyaWJ1dGVzOiBzZXRBdHRyaWJ1dGVzIH0sIHRoaXMucHJvcHMpKSxcblx0XHRcdC8vIFNob3cgdGhlIGJsb2NrIG1hcmt1cCBpbiB0aGUgZWRpdG9yXG5cdFx0XHR3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRcdFRlc3RpbW9uaWFsLFxuXHRcdFx0XHR0aGlzLnByb3BzLFxuXHRcdFx0XHR3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoUmljaFRleHQsIHtcblx0XHRcdFx0XHR0YWdOYW1lOiAnZGl2Jyxcblx0XHRcdFx0XHRtdWx0aWxpbmU6ICdwJyxcblx0XHRcdFx0XHRwbGFjZWhvbGRlcjogX18oJ0FkZCB0ZXN0aW1vbmlhbCB0ZXh0Li4uJyksXG5cdFx0XHRcdFx0a2VlcFBsYWNlaG9sZGVyT25Gb2N1czogdHJ1ZSxcblx0XHRcdFx0XHR2YWx1ZTogdGVzdGltb25pYWxDb250ZW50LFxuXHRcdFx0XHRcdGZvcm1hdHRpbmdDb250cm9sczogWydib2xkJywgJ2l0YWxpYycsICdzdHJpa2V0aHJvdWdoJywgJ2xpbmsnXSxcblx0XHRcdFx0XHRjbGFzc05hbWU6IGNsYXNzbmFtZXMoJ2FiLXRlc3RpbW9uaWFsLXRleHQnKSxcblx0XHRcdFx0XHRzdHlsZToge1xuXHRcdFx0XHRcdFx0dGV4dEFsaWduOiB0ZXN0aW1vbmlhbEFsaWdubWVudFxuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0b25DaGFuZ2U6IGZ1bmN0aW9uIG9uQ2hhbmdlKHZhbHVlKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gc2V0QXR0cmlidXRlcyh7IHRlc3RpbW9uaWFsQ29udGVudDogdmFsdWUgfSk7XG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRpbmxpbmVUb29sYmFyOiB0cnVlXG5cdFx0XHRcdH0pLFxuXHRcdFx0XHR3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRcdFx0J2RpdicsXG5cdFx0XHRcdFx0eyAnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtaW5mbycgfSxcblx0XHRcdFx0XHR3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRcdFx0XHQnZGl2Jyxcblx0XHRcdFx0XHRcdHsgJ2NsYXNzJzogJ2FiLXRlc3RpbW9uaWFsLWF2YXRhci13cmFwJyB9LFxuXHRcdFx0XHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFxuXHRcdFx0XHRcdFx0XHQnZGl2Jyxcblx0XHRcdFx0XHRcdFx0eyAnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtaW1hZ2Utd3JhcCcgfSxcblx0XHRcdFx0XHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KE1lZGlhVXBsb2FkLCB7XG5cdFx0XHRcdFx0XHRcdFx0YnV0dG9uUHJvcHM6IHtcblx0XHRcdFx0XHRcdFx0XHRcdGNsYXNzTmFtZTogJ2NoYW5nZS1pbWFnZSdcblx0XHRcdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0XHRcdG9uU2VsZWN0OiBmdW5jdGlvbiBvblNlbGVjdChpbWcpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybiBzZXRBdHRyaWJ1dGVzKHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGVzdGltb25pYWxJbWdJRDogaW1nLmlkLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHR0ZXN0aW1vbmlhbEltZ1VSTDogaW1nLnVybFxuXHRcdFx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdFx0XHR0eXBlOiAnaW1hZ2UnLFxuXHRcdFx0XHRcdFx0XHRcdHZhbHVlOiB0ZXN0aW1vbmlhbEltZ0lELFxuXHRcdFx0XHRcdFx0XHRcdHJlbmRlcjogZnVuY3Rpb24gcmVuZGVyKF9yZWYpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHZhciBvcGVuID0gX3JlZi5vcGVuO1xuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudChcblx0XHRcdFx0XHRcdFx0XHRcdFx0QnV0dG9uLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHR7IG9uQ2xpY2s6IG9wZW4gfSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0IXRlc3RpbW9uaWFsSW1nSUQgPyBpY29ucy51cGxvYWQgOiB3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoJ2ltZycsIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtYXZhdGFyJyxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRzcmM6IHRlc3RpbW9uaWFsSW1nVVJMLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGFsdDogJ2F2YXRhcidcblx0XHRcdFx0XHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9KVxuXHRcdFx0XHRcdFx0KVxuXHRcdFx0XHRcdCksXG5cdFx0XHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFJpY2hUZXh0LCB7XG5cdFx0XHRcdFx0XHR0YWdOYW1lOiAnaDInLFxuXHRcdFx0XHRcdFx0cGxhY2Vob2xkZXI6IF9fKCdBZGQgbmFtZScpLFxuXHRcdFx0XHRcdFx0a2VlcFBsYWNlaG9sZGVyT25Gb2N1czogdHJ1ZSxcblx0XHRcdFx0XHRcdHZhbHVlOiB0ZXN0aW1vbmlhbE5hbWUsXG5cdFx0XHRcdFx0XHRjbGFzc05hbWU6ICdhYi10ZXN0aW1vbmlhbC1uYW1lJyxcblx0XHRcdFx0XHRcdHN0eWxlOiB7XG5cdFx0XHRcdFx0XHRcdGNvbG9yOiB0ZXN0aW1vbmlhbFRleHRDb2xvclxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdG9uQ2hhbmdlOiBmdW5jdGlvbiBvbkNoYW5nZSh2YWx1ZSkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gX3RoaXMyLnByb3BzLnNldEF0dHJpYnV0ZXMoeyB0ZXN0aW1vbmlhbE5hbWU6IHZhbHVlIH0pO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0pLFxuXHRcdFx0XHRcdHdwLmVsZW1lbnQuY3JlYXRlRWxlbWVudChSaWNoVGV4dCwge1xuXHRcdFx0XHRcdFx0dGFnTmFtZTogJ3NtYWxsJyxcblx0XHRcdFx0XHRcdHBsYWNlaG9sZGVyOiBfXygnQWRkIHRpdGxlJyksXG5cdFx0XHRcdFx0XHRrZWVwUGxhY2Vob2xkZXJPbkZvY3VzOiB0cnVlLFxuXHRcdFx0XHRcdFx0dmFsdWU6IHRlc3RpbW9uaWFsVGl0bGUsXG5cdFx0XHRcdFx0XHRjbGFzc05hbWU6ICdhYi10ZXN0aW1vbmlhbC10aXRsZScsXG5cdFx0XHRcdFx0XHRzdHlsZToge1xuXHRcdFx0XHRcdFx0XHRjb2xvcjogdGVzdGltb25pYWxUZXh0Q29sb3Jcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRvbkNoYW5nZTogZnVuY3Rpb24gb25DaGFuZ2UodmFsdWUpIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIF90aGlzMi5wcm9wcy5zZXRBdHRyaWJ1dGVzKHsgdGVzdGltb25pYWxUaXRsZTogdmFsdWUgfSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSlcblx0XHRcdFx0KVxuXHRcdFx0KV07XG5cdFx0fVxuXHR9XSk7XG5cblx0cmV0dXJuIEFCVGVzdGltb25pYWxCbG9jaztcbn0oQ29tcG9uZW50KTtcblxuLy8gUmVnaXN0ZXIgdGhlIGJsb2NrXG5cblxucmVnaXN0ZXJCbG9ja1R5cGUoJ2F0b21pYy1ibG9ja3MvYWItdGVzdGltb25pYWwnLCB7XG5cdHRpdGxlOiBfXygnQUIgVGVzdGltb25pYWwnKSxcblx0ZGVzY3JpcHRpb246IF9fKCdBZGQgYSB1c2VyIHRlc3RpbW9uaWFsIHdpdGggYSBuYW1lIGFuZCB0aXRsZS4nKSxcblx0aWNvbjogJ2Zvcm1hdC1xdW90ZScsXG5cdGNhdGVnb3J5OiAnYXRvbWljLWJsb2NrcycsXG5cdGtleXdvcmRzOiBbX18oJ3Rlc3RpbW9uaWFsJyksIF9fKCdxdW90ZScpLCBfXygnYXRvbWljJyldLFxuXHRhdHRyaWJ1dGVzOiB7XG5cdFx0dGVzdGltb25pYWxOYW1lOiB7XG5cdFx0XHR0eXBlOiAnc3RyaW5nJyxcblx0XHRcdHNlbGVjdG9yOiAnLmFiLXRlc3RpbW9uaWFsLW5hbWUnXG5cdFx0fSxcblx0XHR0ZXN0aW1vbmlhbFRpdGxlOiB7XG5cdFx0XHR0eXBlOiAnYXJyYXknLFxuXHRcdFx0c2VsZWN0b3I6ICcuYWItdGVzdGltb25pYWwtdGl0bGUnLFxuXHRcdFx0c291cmNlOiAnY2hpbGRyZW4nXG5cdFx0fSxcblx0XHR0ZXN0aW1vbmlhbENvbnRlbnQ6IHtcblx0XHRcdHR5cGU6ICdhcnJheScsXG5cdFx0XHRzZWxlY3RvcjogJy5hYi10ZXN0aW1vbmlhbC10ZXh0Jyxcblx0XHRcdHNvdXJjZTogJ2NoaWxkcmVuJ1xuXHRcdH0sXG5cdFx0dGVzdGltb25pYWxBbGlnbm1lbnQ6IHtcblx0XHRcdHR5cGU6ICdzdHJpbmcnXG5cdFx0fSxcblx0XHR0ZXN0aW1vbmlhbEltZ1VSTDoge1xuXHRcdFx0dHlwZTogJ3N0cmluZycsXG5cdFx0XHRzb3VyY2U6ICdhdHRyaWJ1dGUnLFxuXHRcdFx0YXR0cmlidXRlOiAnc3JjJyxcblx0XHRcdHNlbGVjdG9yOiAnaW1nJ1xuXHRcdH0sXG5cdFx0dGVzdGltb25pYWxJbWdJRDoge1xuXHRcdFx0dHlwZTogJ251bWJlcidcblx0XHR9LFxuXHRcdHRlc3RpbW9uaWFsQmFja2dyb3VuZENvbG9yOiB7XG5cdFx0XHR0eXBlOiAnc3RyaW5nJyxcblx0XHRcdGRlZmF1bHQ6ICcjZjJmMmYyJ1xuXHRcdH0sXG5cdFx0dGVzdGltb25pYWxUZXh0Q29sb3I6IHtcblx0XHRcdHR5cGU6ICdzdHJpbmcnLFxuXHRcdFx0ZGVmYXVsdDogJyMzMjM3M2MnXG5cdFx0fSxcblx0XHR0ZXN0aW1vbmlhbEZvbnRTaXplOiB7XG5cdFx0XHR0eXBlOiAnbnVtYmVyJyxcblx0XHRcdGRlZmF1bHQ6IDE4XG5cdFx0fSxcblx0XHR0ZXN0aW1vbmlhbENpdGVBbGlnbjoge1xuXHRcdFx0dHlwZTogJ3N0cmluZycsXG5cdFx0XHRkZWZhdWx0OiAnbGVmdC1hbGlnbmVkJ1xuXHRcdH1cblx0fSxcblxuXHQvLyBSZW5kZXIgdGhlIGJsb2NrIGNvbXBvbmVudHNcblx0ZWRpdDogQUJUZXN0aW1vbmlhbEJsb2NrLFxuXG5cdC8vIFNhdmUgdGhlIGF0dHJpYnV0ZXMgYW5kIG1hcmt1cFxuXHRzYXZlOiBmdW5jdGlvbiBzYXZlKHByb3BzKSB7XG5cblx0XHQvLyBTZXR1cCB0aGUgYXR0cmlidXRlc1xuXHRcdHZhciBfcHJvcHMkYXR0cmlidXRlczIgPSBwcm9wcy5hdHRyaWJ1dGVzLFxuXHRcdCAgICB0ZXN0aW1vbmlhbE5hbWUgPSBfcHJvcHMkYXR0cmlidXRlczIudGVzdGltb25pYWxOYW1lLFxuXHRcdCAgICB0ZXN0aW1vbmlhbFRpdGxlID0gX3Byb3BzJGF0dHJpYnV0ZXMyLnRlc3RpbW9uaWFsVGl0bGUsXG5cdFx0ICAgIHRlc3RpbW9uaWFsQ29udGVudCA9IF9wcm9wcyRhdHRyaWJ1dGVzMi50ZXN0aW1vbmlhbENvbnRlbnQsXG5cdFx0ICAgIHRlc3RpbW9uaWFsQWxpZ25tZW50ID0gX3Byb3BzJGF0dHJpYnV0ZXMyLnRlc3RpbW9uaWFsQWxpZ25tZW50LFxuXHRcdCAgICB0ZXN0aW1vbmlhbEltZ1VSTCA9IF9wcm9wcyRhdHRyaWJ1dGVzMi50ZXN0aW1vbmlhbEltZ1VSTCxcblx0XHQgICAgdGVzdGltb25pYWxJbWdJRCA9IF9wcm9wcyRhdHRyaWJ1dGVzMi50ZXN0aW1vbmlhbEltZ0lELFxuXHRcdCAgICB0ZXN0aW1vbmlhbEJhY2tncm91bmRDb2xvciA9IF9wcm9wcyRhdHRyaWJ1dGVzMi50ZXN0aW1vbmlhbEJhY2tncm91bmRDb2xvcixcblx0XHQgICAgdGVzdGltb25pYWxUZXh0Q29sb3IgPSBfcHJvcHMkYXR0cmlidXRlczIudGVzdGltb25pYWxUZXh0Q29sb3IsXG5cdFx0ICAgIHRlc3RpbW9uaWFsRm9udFNpemUgPSBfcHJvcHMkYXR0cmlidXRlczIudGVzdGltb25pYWxGb250U2l6ZSxcblx0XHQgICAgdGVzdGltb25pYWxDaXRlQWxpZ24gPSBfcHJvcHMkYXR0cmlidXRlczIudGVzdGltb25pYWxDaXRlQWxpZ247XG5cblx0XHQvLyBTYXZlIHRoZSBibG9jayBtYXJrdXAgZm9yIHRoZSBmcm9udCBlbmRcblxuXHRcdHJldHVybiB3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRUZXN0aW1vbmlhbCxcblx0XHRcdHByb3BzLFxuXHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFxuXHRcdFx0XHQnZGl2Jyxcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGNsYXNzTmFtZTogY2xhc3NuYW1lcygnYWItdGVzdGltb25pYWwtdGV4dCcpLFxuXHRcdFx0XHRcdHN0eWxlOiB7XG5cdFx0XHRcdFx0XHR0ZXh0QWxpZ246IHRlc3RpbW9uaWFsQWxpZ25tZW50XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9LFxuXHRcdFx0XHR0ZXN0aW1vbmlhbENvbnRlbnRcblx0XHRcdCksXG5cdFx0XHR3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRcdCdkaXYnLFxuXHRcdFx0XHR7ICdjbGFzcyc6ICdhYi10ZXN0aW1vbmlhbC1pbmZvJyB9LFxuXHRcdFx0XHR0ZXN0aW1vbmlhbEltZ1VSTCAmJiAhIXRlc3RpbW9uaWFsSW1nVVJMLmxlbmd0aCAmJiB3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRcdFx0J2RpdicsXG5cdFx0XHRcdFx0eyAnY2xhc3MnOiAnYWItdGVzdGltb25pYWwtYXZhdGFyLXdyYXAnIH0sXG5cdFx0XHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KFxuXHRcdFx0XHRcdFx0J2RpdicsXG5cdFx0XHRcdFx0XHR7ICdjbGFzcyc6ICdhYi10ZXN0aW1vbmlhbC1pbWFnZS13cmFwJyB9LFxuXHRcdFx0XHRcdFx0d3AuZWxlbWVudC5jcmVhdGVFbGVtZW50KCdpbWcnLCB7XG5cdFx0XHRcdFx0XHRcdCdjbGFzcyc6ICdhYi10ZXN0aW1vbmlhbC1hdmF0YXInLFxuXHRcdFx0XHRcdFx0XHRzcmM6IHRlc3RpbW9uaWFsSW1nVVJMLFxuXHRcdFx0XHRcdFx0XHRhbHQ6ICdhdmF0YXInXG5cdFx0XHRcdFx0XHR9KVxuXHRcdFx0XHRcdClcblx0XHRcdFx0KSxcblx0XHRcdFx0dGVzdGltb25pYWxOYW1lICYmICEhdGVzdGltb25pYWxOYW1lLmxlbmd0aCAmJiB3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRcdFx0J2gyJyxcblx0XHRcdFx0XHR7ICdjbGFzcyc6ICdhYi10ZXN0aW1vbmlhbC1uYW1lJyxcblx0XHRcdFx0XHRcdHN0eWxlOiB7XG5cdFx0XHRcdFx0XHRcdGNvbG9yOiB0ZXN0aW1vbmlhbFRleHRDb2xvclxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0dGVzdGltb25pYWxOYW1lXG5cdFx0XHRcdCksXG5cdFx0XHRcdHRlc3RpbW9uaWFsVGl0bGUgJiYgISF0ZXN0aW1vbmlhbFRpdGxlLmxlbmd0aCAmJiB3cC5lbGVtZW50LmNyZWF0ZUVsZW1lbnQoXG5cdFx0XHRcdFx0J3NtYWxsJyxcblx0XHRcdFx0XHR7ICdjbGFzcyc6ICdhYi10ZXN0aW1vbmlhbC10aXRsZScsXG5cdFx0XHRcdFx0XHRzdHlsZToge1xuXHRcdFx0XHRcdFx0XHRjb2xvcjogdGVzdGltb25pYWxUZXh0Q29sb3Jcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdHRlc3RpbW9uaWFsVGl0bGVcblx0XHRcdFx0KVxuXHRcdFx0KVxuXHRcdCk7XG5cdH1cbn0pO1xuXG5cbi8vLy8vLy8vLy8vLy8vLy8vL1xuLy8gV0VCUEFDSyBGT09URVJcbi8vIC4vc3JjL2Jsb2Nrcy9ibG9jay10ZXN0aW1vbmlhbC9pbmRleC5qc1xuLy8gbW9kdWxlIGlkID0gMTgwXG4vLyBtb2R1bGUgY2h1bmtzID0gMCJdLCJtYXBwaW5ncyI6IkFBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///180\n");
|
2064 |
|
2065 |
/***/ }),
|
2066 |
/* 181 */
|
src/blocks.js
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Import the blocks
|
3 |
+
*/
|
4 |
+
|
5 |
+
import './blocks/block-testimonial/index.js';
|
6 |
+
import './blocks/block-author-profile/index.js';
|
7 |
+
import './blocks/block-notice/index.js';
|
8 |
+
import './blocks/block-drop-cap/index.js';
|
9 |
+
import './blocks/block-button/index.js';
|
10 |
+
import './blocks/block-spacer/index.js';
|
11 |
+
import './blocks/block-accordion/index.js';
|
12 |
+
import './blocks/block-cta/index.js';
|
13 |
+
import './blocks/block-sharing/index.js';
|
14 |
+
import './blocks/block-post-grid/index.js';
|
15 |
+
import './blocks/block-container/index.js';
|
16 |
+
import './blocks/block-layout-split/index.js';
|
src/blocks/block-accordion/components/accordion.js
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Accordion Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Create a Accordion wrapper Component
|
13 |
+
*/
|
14 |
+
export default class Accordion extends Component {
|
15 |
+
|
16 |
+
constructor( props ) {
|
17 |
+
super( ...arguments );
|
18 |
+
}
|
19 |
+
|
20 |
+
render() {
|
21 |
+
|
22 |
+
// Setup the attributes
|
23 |
+
const { accordionTitle, accordionText, accordionAlignment, accordionFontSize } = this.props.attributes;
|
24 |
+
|
25 |
+
return (
|
26 |
+
<div
|
27 |
+
style={ {
|
28 |
+
|
29 |
+
} }
|
30 |
+
className={ classnames(
|
31 |
+
this.props.className,
|
32 |
+
accordionAlignment,
|
33 |
+
'ab-block-accordion',
|
34 |
+
'ab-font-size-' + accordionFontSize,
|
35 |
+
) }
|
36 |
+
>
|
37 |
+
{ this.props.children }
|
38 |
+
</div>
|
39 |
+
);
|
40 |
+
}
|
41 |
+
}
|
src/blocks/block-accordion/components/icons.js
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const icons = {};
|
2 |
+
|
3 |
+
icons.upload = <svg width='20px' height='20px' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'>
|
4 |
+
<path d='m77.945 91.453h-72.371c-3.3711 0-5.5742-2.3633-5.5742-5.2422v-55.719c0-3.457 2.1172-6.0703 5.5742-6.0703h44.453v11.051l-38.98-0.003906v45.008h60.977v-17.133l11.988-0.007812v22.875c0 2.8789-2.7812 5.2422-6.0664 5.2422z'
|
5 |
+
/>
|
6 |
+
<path d='m16.543 75.48l23.25-22.324 10.441 9.7773 11.234-14.766 5.5039 10.539 0.039063 16.773z'
|
7 |
+
/>
|
8 |
+
<path d='m28.047 52.992c-3.168 0-5.7422-2.5742-5.7422-5.7461 0-3.1758 2.5742-5.75 5.7422-5.75 3.1797 0 5.7539 2.5742 5.7539 5.75 0 3.1719-2.5742 5.7461-5.7539 5.7461z'
|
9 |
+
/>
|
10 |
+
<path d='m84.043 30.492v22.02h-12.059l-0.015625-22.02h-15.852l21.941-21.945 21.941 21.945z'
|
11 |
+
/>
|
12 |
+
</svg>;
|
13 |
+
|
14 |
+
icons.dismiss = <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns='http://www.w3.org/2000/svg' width="20" height="20" viewBox="0 0 20 20">
|
15 |
+
<path d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zM15 13l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z"></path>
|
16 |
+
</svg>;
|
17 |
+
|
18 |
+
export default icons;
|
src/blocks/block-accordion/components/inspector.js
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
InspectorControls,
|
12 |
+
BlockDescription,
|
13 |
+
ColorPalette,
|
14 |
+
} = wp.editor;
|
15 |
+
|
16 |
+
// Import Inspector components
|
17 |
+
const {
|
18 |
+
Toolbar,
|
19 |
+
Button,
|
20 |
+
PanelBody,
|
21 |
+
PanelRow,
|
22 |
+
PanelColor,
|
23 |
+
RangeControl,
|
24 |
+
ToggleControl,
|
25 |
+
} = wp.components;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Create an Inspector Controls wrapper Component
|
29 |
+
*/
|
30 |
+
export default class Inspector extends Component {
|
31 |
+
|
32 |
+
constructor( props ) {
|
33 |
+
super( ...arguments );
|
34 |
+
}
|
35 |
+
|
36 |
+
render() {
|
37 |
+
|
38 |
+
// Setup the attributes
|
39 |
+
const { accordionTitle, accordionText, accordionFontSize, accordionOpen } = this.props.attributes;
|
40 |
+
|
41 |
+
return (
|
42 |
+
<InspectorControls key="inspector">
|
43 |
+
<PanelBody>
|
44 |
+
<RangeControl
|
45 |
+
label={ __( 'Font Size' ) }
|
46 |
+
value={ accordionFontSize }
|
47 |
+
onChange={ ( value ) => this.props.setAttributes( { accordionFontSize: value } ) }
|
48 |
+
min={ 14 }
|
49 |
+
max={ 24 }
|
50 |
+
step={ 1 }
|
51 |
+
/>
|
52 |
+
|
53 |
+
<ToggleControl
|
54 |
+
label={ __( 'Open by default' ) }
|
55 |
+
checked={ accordionOpen }
|
56 |
+
onChange={ () => this.props.setAttributes( { accordionOpen: ! accordionOpen } ) }
|
57 |
+
/>
|
58 |
+
</PanelBody>
|
59 |
+
</InspectorControls>
|
60 |
+
);
|
61 |
+
}
|
62 |
+
}
|
src/blocks/block-accordion/index.js
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Accordion Block
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import Accordion from './components/accordion';
|
9 |
+
import icons from './components/icons';
|
10 |
+
|
11 |
+
// Import CSS
|
12 |
+
import './styles/style.scss';
|
13 |
+
import './styles/editor.scss';
|
14 |
+
|
15 |
+
// Components
|
16 |
+
const { __ } = wp.i18n;
|
17 |
+
|
18 |
+
// Extend component
|
19 |
+
const { Component } = wp.element;
|
20 |
+
|
21 |
+
// Register block
|
22 |
+
const { registerBlockType } = wp.blocks;
|
23 |
+
|
24 |
+
// Register editor components
|
25 |
+
const {
|
26 |
+
RichText,
|
27 |
+
AlignmentToolbar,
|
28 |
+
BlockControls,
|
29 |
+
BlockAlignmentToolbar,
|
30 |
+
} = wp.editor;
|
31 |
+
|
32 |
+
// Register components
|
33 |
+
const {
|
34 |
+
Button,
|
35 |
+
withFallbackStyles,
|
36 |
+
IconButton,
|
37 |
+
Dashicon,
|
38 |
+
} = wp.components;
|
39 |
+
|
40 |
+
class ABAccordionBlock extends Component {
|
41 |
+
|
42 |
+
render() {
|
43 |
+
|
44 |
+
// Setup the attributes
|
45 |
+
const { attributes: { accordionTitle, accordionText, accordionAlignment, accordionFontSize, accordionOpen }, isSelected, className, setAttributes } = this.props;
|
46 |
+
|
47 |
+
return [
|
48 |
+
// Show the block alignment controls on focus
|
49 |
+
<BlockControls key="controls">
|
50 |
+
<AlignmentToolbar
|
51 |
+
value={ accordionAlignment }
|
52 |
+
onChange={ ( value ) => this.props.setAttributes( { accordionAlignment: value } ) }
|
53 |
+
/>
|
54 |
+
</BlockControls>,
|
55 |
+
// Show the block controls on focus
|
56 |
+
<Inspector
|
57 |
+
{ ...this.props }
|
58 |
+
/>,
|
59 |
+
// Show the button markup in the editor
|
60 |
+
<Accordion { ...this.props }>
|
61 |
+
<RichText
|
62 |
+
tagName="p"
|
63 |
+
placeholder={ __( 'Accordion Title' ) }
|
64 |
+
keepPlaceholderOnFocus
|
65 |
+
value={ accordionTitle }
|
66 |
+
className='ab-accordion-title'
|
67 |
+
onChange={ ( value ) => this.props.setAttributes( { accordionTitle: value } ) }
|
68 |
+
/>
|
69 |
+
|
70 |
+
<RichText
|
71 |
+
tagName="p"
|
72 |
+
placeholder={ __( 'Accordion Text' ) }
|
73 |
+
keepPlaceholderOnFocus
|
74 |
+
value={ accordionText }
|
75 |
+
isSelected={ isSelected }
|
76 |
+
className='ab-accordion-text'
|
77 |
+
onChange={ ( value ) => this.props.setAttributes( { accordionText: value } ) }
|
78 |
+
inlineToolbar
|
79 |
+
/>
|
80 |
+
</Accordion>
|
81 |
+
];
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
// Register the block
|
86 |
+
registerBlockType( 'atomic-blocks/ab-accordion', {
|
87 |
+
title: __( 'AB Accordion' ),
|
88 |
+
description: __( 'Add accordion block with a title and text.' ),
|
89 |
+
icon: 'editor-ul',
|
90 |
+
category: 'atomic-blocks',
|
91 |
+
keywords: [
|
92 |
+
__( 'accordion' ),
|
93 |
+
__( 'list' ),
|
94 |
+
__( 'atomic' ),
|
95 |
+
],
|
96 |
+
attributes: {
|
97 |
+
accordionTitle: {
|
98 |
+
type: 'string',
|
99 |
+
},
|
100 |
+
accordionText: {
|
101 |
+
type: 'array',
|
102 |
+
selector: '.ab-accordion-text',
|
103 |
+
source: 'children',
|
104 |
+
},
|
105 |
+
accordionAlignment: {
|
106 |
+
type: 'string',
|
107 |
+
},
|
108 |
+
accordionFontSize: {
|
109 |
+
type: 'number',
|
110 |
+
default: 18
|
111 |
+
},
|
112 |
+
accordionOpen: {
|
113 |
+
type: 'boolean',
|
114 |
+
default: false
|
115 |
+
},
|
116 |
+
},
|
117 |
+
|
118 |
+
// Render the block components
|
119 |
+
edit: ABAccordionBlock,
|
120 |
+
|
121 |
+
// Save the attributes and markup
|
122 |
+
save: function( props ) {
|
123 |
+
|
124 |
+
// Setup the attributes
|
125 |
+
const { accordionTitle, accordionText, accordionAlignment, accordionFontSize, accordionOpen } = props.attributes;
|
126 |
+
|
127 |
+
// Save the block markup for the front end
|
128 |
+
return (
|
129 |
+
<Accordion { ...props }>
|
130 |
+
<details open={accordionOpen}>
|
131 |
+
<summary class="ab-accordion-title"><p>{ accordionTitle }</p></summary>
|
132 |
+
<p class="ab-accordion-text">{ accordionText }</p>
|
133 |
+
</details>
|
134 |
+
</Accordion>
|
135 |
+
);
|
136 |
+
},
|
137 |
+
} );
|
src/blocks/block-accordion/styles/editor.scss
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-accordion {
|
6 |
+
margin-bottom: 0;
|
7 |
+
}
|
8 |
+
|
9 |
+
.editor-block-list__layout [data-type="atomic-blocks/ab-accordion"] {
|
10 |
+
margin-bottom: 1.2em;
|
11 |
+
}
|
src/blocks/block-accordion/styles/style.scss
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Accordion styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.ab-block-accordion {
|
7 |
+
margin-bottom: 1.2em;
|
8 |
+
|
9 |
+
.ab-accordion-title {
|
10 |
+
background: #f2f2f2;
|
11 |
+
padding: 10px 15px;
|
12 |
+
|
13 |
+
p {
|
14 |
+
display: inline;
|
15 |
+
}
|
16 |
+
}
|
17 |
+
|
18 |
+
.ab-accordion-text {
|
19 |
+
padding: 10px 15px;
|
20 |
+
|
21 |
+
a {
|
22 |
+
color: inherit;
|
23 |
+
box-shadow: 0 -1px 0 inset;
|
24 |
+
text-decoration: none;
|
25 |
+
|
26 |
+
&:hover {
|
27 |
+
color: inherit;
|
28 |
+
box-shadow: 0 -2px 0 inset;
|
29 |
+
}
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
a {
|
34 |
+
color: inherit;
|
35 |
+
box-shadow: 0 -1px 0 inset;
|
36 |
+
text-decoration: none;
|
37 |
+
|
38 |
+
&:hover {
|
39 |
+
color: inherit;
|
40 |
+
box-shadow: 0 -2px 0 inset;
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
.editor-rich-text .editor-rich-text__inline-toolbar {
|
45 |
+
display: block;
|
46 |
+
left: 40%;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
.ab-block-accordion + .ab-block-accordion {
|
51 |
+
margin-top: -.6em;
|
52 |
+
}
|
src/blocks/block-author-profile/components/avatar.js
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Avatar Column Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
import icons from './icons';
|
11 |
+
|
12 |
+
// Import block components
|
13 |
+
const {
|
14 |
+
MediaUpload,
|
15 |
+
} = wp.editor;
|
16 |
+
|
17 |
+
// Create an SocialIcons wrapper Component
|
18 |
+
export default class AvatarColumn extends Component {
|
19 |
+
|
20 |
+
constructor( props ) {
|
21 |
+
super( ...arguments );
|
22 |
+
}
|
23 |
+
|
24 |
+
render() {
|
25 |
+
return (
|
26 |
+
<div class="ab-profile-column ab-profile-avatar-wrap">
|
27 |
+
<div class="ab-profile-image-wrap">
|
28 |
+
{ this.props.children }
|
29 |
+
</div>
|
30 |
+
</div>
|
31 |
+
);
|
32 |
+
}
|
33 |
+
}
|
src/blocks/block-author-profile/components/icons.js
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const icons = {};
|
2 |
+
|
3 |
+
icons.upload = <svg width='32px' height='32px' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'>
|
4 |
+
<path d='m77.945 91.453h-72.371c-3.3711 0-5.5742-2.3633-5.5742-5.2422v-55.719c0-3.457 2.1172-6.0703 5.5742-6.0703h44.453v11.051l-38.98-0.003906v45.008h60.977v-17.133l11.988-0.007812v22.875c0 2.8789-2.7812 5.2422-6.0664 5.2422z'
|
5 |
+
/>
|
6 |
+
<path d='m16.543 75.48l23.25-22.324 10.441 9.7773 11.234-14.766 5.5039 10.539 0.039063 16.773z'
|
7 |
+
/>
|
8 |
+
<path d='m28.047 52.992c-3.168 0-5.7422-2.5742-5.7422-5.7461 0-3.1758 2.5742-5.75 5.7422-5.75 3.1797 0 5.7539 2.5742 5.7539 5.75 0 3.1719-2.5742 5.7461-5.7539 5.7461z'
|
9 |
+
/>
|
10 |
+
<path d='m84.043 30.492v22.02h-12.059l-0.015625-22.02h-15.852l21.941-21.945 21.941 21.945z'
|
11 |
+
/>
|
12 |
+
</svg>;
|
13 |
+
|
14 |
+
export default icons;
|
src/blocks/block-author-profile/components/inspector.js
ADDED
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
InspectorControls,
|
12 |
+
BlockDescription,
|
13 |
+
ColorPalette,
|
14 |
+
} = wp.editor;
|
15 |
+
|
16 |
+
// Import Inspector components
|
17 |
+
const {
|
18 |
+
Panel,
|
19 |
+
PanelBody,
|
20 |
+
PanelRow,
|
21 |
+
PanelColor,
|
22 |
+
RangeControl,
|
23 |
+
SelectControl,
|
24 |
+
TextControl,
|
25 |
+
} = wp.components;
|
26 |
+
|
27 |
+
// Create an Inspector Controls wrapper Component
|
28 |
+
export default class Inspector extends Component {
|
29 |
+
|
30 |
+
constructor( props ) {
|
31 |
+
super( ...arguments );
|
32 |
+
}
|
33 |
+
|
34 |
+
render() {
|
35 |
+
|
36 |
+
// Setup the attributes
|
37 |
+
const { profileName, profileTitle, profileContent, profileAlignment, profileImgURL, profileImgID, profileFontSize, profileBackgroundColor, profileTextColor, profileLinkColor, twitter, facebook, instagram, pinterest, google, youtube, github, email, website, profileAvatarShape } = this.props.attributes;
|
38 |
+
|
39 |
+
// Avatar shape options
|
40 |
+
const profileAvatarShapeOptions = [
|
41 |
+
{ value: 'square', label: __( 'Square' ) },
|
42 |
+
{ value: 'round', label: __( 'Round' ) },
|
43 |
+
];
|
44 |
+
|
45 |
+
return (
|
46 |
+
<InspectorControls key="inspector">
|
47 |
+
<PanelBody>
|
48 |
+
<RangeControl
|
49 |
+
label={ __( 'Font Size' ) }
|
50 |
+
value={ profileFontSize }
|
51 |
+
onChange={ ( value ) => this.props.setAttributes( { profileFontSize: value } ) }
|
52 |
+
min={ 14 }
|
53 |
+
max={ 24 }
|
54 |
+
step={ 1 }
|
55 |
+
/>
|
56 |
+
|
57 |
+
<SelectControl
|
58 |
+
label={ __( 'Avatar Shape' ) }
|
59 |
+
description={ __( 'Choose between a round or square avatar shape.' ) }
|
60 |
+
options={ profileAvatarShapeOptions }
|
61 |
+
value={ profileAvatarShape }
|
62 |
+
onChange={ ( value ) => this.props.setAttributes( { profileAvatarShape: value } ) }
|
63 |
+
/>
|
64 |
+
|
65 |
+
<PanelColor
|
66 |
+
title={ __( 'Background Color' ) }
|
67 |
+
colorValue={ profileBackgroundColor }
|
68 |
+
initialOpen={ false }
|
69 |
+
>
|
70 |
+
<ColorPalette
|
71 |
+
label={ __( 'Background Color' ) }
|
72 |
+
value={ profileBackgroundColor }
|
73 |
+
onChange={ ( value ) => this.props.setAttributes( { profileBackgroundColor: value } ) }
|
74 |
+
/>
|
75 |
+
</PanelColor>
|
76 |
+
|
77 |
+
<PanelColor
|
78 |
+
title={ __( 'Text Color' ) }
|
79 |
+
colorValue={ profileTextColor }
|
80 |
+
initialOpen={ false }
|
81 |
+
>
|
82 |
+
<ColorPalette
|
83 |
+
label={ __( 'Background Color' ) }
|
84 |
+
value={ profileTextColor }
|
85 |
+
onChange={ ( value ) => this.props.setAttributes( { profileTextColor: value } ) }
|
86 |
+
/>
|
87 |
+
</PanelColor>
|
88 |
+
|
89 |
+
<PanelColor
|
90 |
+
title={ __( 'Social Link Color' ) }
|
91 |
+
colorValue={ profileLinkColor }
|
92 |
+
initialOpen={ false }
|
93 |
+
>
|
94 |
+
<ColorPalette
|
95 |
+
label={ __( 'Link Color' ) }
|
96 |
+
value={ profileLinkColor }
|
97 |
+
onChange={ ( value ) => this.props.setAttributes( { profileLinkColor: value } ) }
|
98 |
+
colors={[
|
99 |
+
{ color: '#392F43', name: 'black' },
|
100 |
+
{ color: '#3373dc', name: 'royal blue' },
|
101 |
+
{ color: '#2DBAA3', name: 'teal' },
|
102 |
+
{ color: '#209cef', name: 'sky blue' },
|
103 |
+
{ color: '#2BAD59', name: 'green' },
|
104 |
+
{ color: '#ff3860', name: 'pink' },
|
105 |
+
{ color: '#7941b6', name: 'purple' },
|
106 |
+
{ color: '#F7812B', name: 'orange' },
|
107 |
+
]}
|
108 |
+
/>
|
109 |
+
</PanelColor>
|
110 |
+
</PanelBody>
|
111 |
+
|
112 |
+
<PanelBody title={ __( 'Social Links' ) } initialOpen={ false }>
|
113 |
+
<p>{ __( 'Add links to your social media site and they will appear in the bottom of the profile box.' ) }</p>
|
114 |
+
|
115 |
+
<TextControl
|
116 |
+
label={ __( 'Twitter URL' ) }
|
117 |
+
type="url"
|
118 |
+
value={ twitter }
|
119 |
+
onChange={ ( value ) => this.props.setAttributes( { twitter: value } ) }
|
120 |
+
/>
|
121 |
+
|
122 |
+
<TextControl
|
123 |
+
label={ __( 'Facebook URL' ) }
|
124 |
+
type="url"
|
125 |
+
value={ facebook }
|
126 |
+
onChange={ ( value ) => this.props.setAttributes( { facebook: value } ) }
|
127 |
+
/>
|
128 |
+
|
129 |
+
<TextControl
|
130 |
+
label={ __( 'Instagram URL' ) }
|
131 |
+
type="url"
|
132 |
+
value={ instagram }
|
133 |
+
onChange={ ( value ) => this.props.setAttributes( { instagram: value } ) }
|
134 |
+
/>
|
135 |
+
|
136 |
+
<TextControl
|
137 |
+
label={ __( 'Pinterest URL' ) }
|
138 |
+
type="url"
|
139 |
+
value={ pinterest }
|
140 |
+
onChange={ ( value ) => this.props.setAttributes( { pinterest: value } ) }
|
141 |
+
/>
|
142 |
+
|
143 |
+
<TextControl
|
144 |
+
label={ __( 'Google URL' ) }
|
145 |
+
type="url"
|
146 |
+
value={ google }
|
147 |
+
onChange={ ( value ) => this.props.setAttributes( { google: value } ) }
|
148 |
+
/>
|
149 |
+
|
150 |
+
<TextControl
|
151 |
+
label={ __( 'YouTube URL' ) }
|
152 |
+
type="url"
|
153 |
+
value={ youtube }
|
154 |
+
onChange={ ( value ) => this.props.setAttributes( { youtube: value } ) }
|
155 |
+
/>
|
156 |
+
|
157 |
+
<TextControl
|
158 |
+
label={ __( 'Github URL' ) }
|
159 |
+
type="url"
|
160 |
+
value={ github }
|
161 |
+
onChange={ ( value ) => this.props.setAttributes( { github: value } ) }
|
162 |
+
/>
|
163 |
+
|
164 |
+
<TextControl
|
165 |
+
label={ __( 'Email URL' ) }
|
166 |
+
type="url"
|
167 |
+
value={ email }
|
168 |
+
onChange={ ( value ) => this.props.setAttributes( { email: value } ) }
|
169 |
+
/>
|
170 |
+
|
171 |
+
<TextControl
|
172 |
+
label={ __( 'Website URL' ) }
|
173 |
+
type="url"
|
174 |
+
value={ website }
|
175 |
+
onChange={ ( value ) => this.props.setAttributes( { website: value } ) }
|
176 |
+
/>
|
177 |
+
</PanelBody>
|
178 |
+
</InspectorControls>
|
179 |
+
);
|
180 |
+
}
|
181 |
+
}
|
src/blocks/block-author-profile/components/profile.js
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Profile Box Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
|
11 |
+
// Create a profile box wrapper Component
|
12 |
+
export default class ProfileBox extends Component {
|
13 |
+
|
14 |
+
constructor( props ) {
|
15 |
+
super( ...arguments );
|
16 |
+
}
|
17 |
+
|
18 |
+
render() {
|
19 |
+
|
20 |
+
// Setup the attributes
|
21 |
+
const { profileAlignment, profileImgURL, profileFontSize, profileBackgroundColor, profileTextColor, profileAvatarShape } = this.props.attributes;
|
22 |
+
|
23 |
+
return (
|
24 |
+
<div
|
25 |
+
style={ {
|
26 |
+
backgroundColor: profileBackgroundColor,
|
27 |
+
color: profileTextColor,
|
28 |
+
} }
|
29 |
+
className={ classnames(
|
30 |
+
this.props.className,
|
31 |
+
profileAlignment,
|
32 |
+
profileAvatarShape,
|
33 |
+
{ 'ab-has-avatar': profileImgURL },
|
34 |
+
'ab-font-size-' + profileFontSize,
|
35 |
+
'ab-block-profile',
|
36 |
+
'ab-profile-columns',
|
37 |
+
) }>
|
38 |
+
{ this.props.children }
|
39 |
+
</div>
|
40 |
+
);
|
41 |
+
}
|
42 |
+
}
|
src/blocks/block-author-profile/components/social.js
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Social Media Icons
|
3 |
+
*/
|
4 |
+
const { __ } = wp.i18n;
|
5 |
+
const { Component } = wp.element;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Create an SocialIcons wrapper Component
|
9 |
+
*/
|
10 |
+
export default class SocialIcons extends Component {
|
11 |
+
|
12 |
+
constructor( props ) {
|
13 |
+
super( ...arguments );
|
14 |
+
}
|
15 |
+
|
16 |
+
render() {
|
17 |
+
return (
|
18 |
+
<ul class="ab-social-links">
|
19 |
+
{ this.props.attributes.website && !! this.props.attributes.website.length && (
|
20 |
+
<li>
|
21 |
+
<a href={ this.props.attributes.website } target="_blank">{ __( 'Website' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fas fa-link"></i></a>
|
22 |
+
</li>
|
23 |
+
) }
|
24 |
+
|
25 |
+
{ this.props.attributes.twitter && !! this.props.attributes.twitter.length && (
|
26 |
+
<li>
|
27 |
+
<a href={ this.props.attributes.twitter } target="_blank">{ __( 'Twitter' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-twitter"></i></a>
|
28 |
+
</li>
|
29 |
+
) }
|
30 |
+
|
31 |
+
{ this.props.attributes.facebook && !! this.props.attributes.facebook.length && (
|
32 |
+
<li>
|
33 |
+
<a href={ this.props.attributes.facebook } target="_blank">{ __( 'Facebook' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-facebook-f"></i></a>
|
34 |
+
</li>
|
35 |
+
) }
|
36 |
+
|
37 |
+
{ this.props.attributes.instagram && !! this.props.attributes.instagram.length && (
|
38 |
+
<li>
|
39 |
+
<a href={ this.props.attributes.instagram } target="_blank">{ __( 'Instagram' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-instagram"></i></a>
|
40 |
+
</li>
|
41 |
+
) }
|
42 |
+
|
43 |
+
{ this.props.attributes.pinterest && !! this.props.attributes.pinterest.length && (
|
44 |
+
<li>
|
45 |
+
<a href={ this.props.attributes.pinterest } target="_blank">{ __( 'Pinterest' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-pinterest"></i></a>
|
46 |
+
</li>
|
47 |
+
) }
|
48 |
+
|
49 |
+
{ this.props.attributes.google && !! this.props.attributes.google.length && (
|
50 |
+
<li>
|
51 |
+
<a href={ this.props.attributes.google } target="_blank">{ __( 'Google' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-google"></i></a>
|
52 |
+
</li>
|
53 |
+
) }
|
54 |
+
|
55 |
+
{ this.props.attributes.youtube && !! this.props.attributes.youtube.length && (
|
56 |
+
<li>
|
57 |
+
<a href={ this.props.attributes.youtube } target="_blank">{ __( 'YouTube' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-youtube"></i></a>
|
58 |
+
</li>
|
59 |
+
) }
|
60 |
+
|
61 |
+
{ this.props.attributes.github && !! this.props.attributes.github.length && (
|
62 |
+
<li>
|
63 |
+
<a href={ this.props.attributes.github } target="_blank">{ __( 'Github' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-github"></i></a>
|
64 |
+
</li>
|
65 |
+
) }
|
66 |
+
|
67 |
+
{ this.props.attributes.email && !! this.props.attributes.email.length && (
|
68 |
+
<li>
|
69 |
+
<a href={ this.props.attributes.email } target="_blank">{ __( 'Email' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="far fa-envelope"></i></a>
|
70 |
+
</li>
|
71 |
+
) }
|
72 |
+
</ul>
|
73 |
+
);
|
74 |
+
}
|
75 |
+
}
|
src/blocks/block-author-profile/index.js
ADDED
@@ -0,0 +1,317 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Profile Box
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import ProfileBox from './components/profile';
|
9 |
+
import SocialIcons from './components/social';
|
10 |
+
import AvatarColumn from './components/avatar';
|
11 |
+
import icons from './components/icons';
|
12 |
+
|
13 |
+
// Import styles
|
14 |
+
import './styles/style.scss';
|
15 |
+
import './styles/editor.scss';
|
16 |
+
|
17 |
+
// Internationalization
|
18 |
+
const { __ } = wp.i18n;
|
19 |
+
|
20 |
+
// Extend component
|
21 |
+
const { Component } = wp.element;
|
22 |
+
|
23 |
+
// Register block
|
24 |
+
const { registerBlockType } = wp.blocks;
|
25 |
+
|
26 |
+
// Register components
|
27 |
+
const {
|
28 |
+
RichText,
|
29 |
+
AlignmentToolbar,
|
30 |
+
BlockControls,
|
31 |
+
InspectorControls,
|
32 |
+
MediaUpload,
|
33 |
+
} = wp.editor;
|
34 |
+
|
35 |
+
// Register Inspector components
|
36 |
+
const {
|
37 |
+
Button,
|
38 |
+
} = wp.components;
|
39 |
+
|
40 |
+
const blockAttributes = {
|
41 |
+
profileName: {
|
42 |
+
type: 'string',
|
43 |
+
selector: '.ab-profile-name',
|
44 |
+
},
|
45 |
+
profileTitle: {
|
46 |
+
type: 'string',
|
47 |
+
selector: '.ab-profile-title',
|
48 |
+
},
|
49 |
+
profileContent: {
|
50 |
+
type: 'array',
|
51 |
+
selector: '.ab-profile-text',
|
52 |
+
source: 'children',
|
53 |
+
},
|
54 |
+
profileAlignment: {
|
55 |
+
type: 'string',
|
56 |
+
},
|
57 |
+
profileImgURL: {
|
58 |
+
type: 'string',
|
59 |
+
source: 'attribute',
|
60 |
+
attribute: 'src',
|
61 |
+
selector: 'img',
|
62 |
+
},
|
63 |
+
profileImgID: {
|
64 |
+
type: 'number',
|
65 |
+
},
|
66 |
+
profileBackgroundColor: {
|
67 |
+
type: 'string',
|
68 |
+
default: '#f2f2f2'
|
69 |
+
},
|
70 |
+
profileTextColor: {
|
71 |
+
type: 'string',
|
72 |
+
default: '#32373c'
|
73 |
+
},
|
74 |
+
profileLinkColor: {
|
75 |
+
type: 'string',
|
76 |
+
default: '#392f43'
|
77 |
+
},
|
78 |
+
profileFontSize: {
|
79 |
+
type: 'number',
|
80 |
+
default: 18
|
81 |
+
},
|
82 |
+
profileAvatarShape: {
|
83 |
+
type: 'string',
|
84 |
+
default: 'square',
|
85 |
+
},
|
86 |
+
twitter: {
|
87 |
+
type: 'url',
|
88 |
+
},
|
89 |
+
facebook: {
|
90 |
+
type: 'url',
|
91 |
+
},
|
92 |
+
instagram: {
|
93 |
+
type: 'url',
|
94 |
+
},
|
95 |
+
pinterest: {
|
96 |
+
type: 'url',
|
97 |
+
},
|
98 |
+
google: {
|
99 |
+
type: 'url',
|
100 |
+
},
|
101 |
+
youtube: {
|
102 |
+
type: 'url',
|
103 |
+
},
|
104 |
+
github: {
|
105 |
+
type: 'url',
|
106 |
+
},
|
107 |
+
email: {
|
108 |
+
type: 'url',
|
109 |
+
},
|
110 |
+
website: {
|
111 |
+
type: 'url',
|
112 |
+
},
|
113 |
+
};
|
114 |
+
|
115 |
+
class ABAuthorProfileBlock extends Component {
|
116 |
+
|
117 |
+
render() {
|
118 |
+
|
119 |
+
// Setup the attributes
|
120 |
+
const {
|
121 |
+
attributes: {
|
122 |
+
profileName,
|
123 |
+
profileTitle,
|
124 |
+
profileContent,
|
125 |
+
profileAlignment,
|
126 |
+
profileImgURL,
|
127 |
+
profileImgID,
|
128 |
+
profileFontSize,
|
129 |
+
profileBackgroundColor,
|
130 |
+
profileTextColor,
|
131 |
+
profileLinkColor,
|
132 |
+
twitter,
|
133 |
+
facebook,
|
134 |
+
instagram,
|
135 |
+
pinterest,
|
136 |
+
google,
|
137 |
+
youtube,
|
138 |
+
github,
|
139 |
+
email,
|
140 |
+
website,
|
141 |
+
profileAvatarShape
|
142 |
+
},
|
143 |
+
attributes,
|
144 |
+
isSelected,
|
145 |
+
editable,
|
146 |
+
className,
|
147 |
+
setAttributes
|
148 |
+
} = this.props;
|
149 |
+
|
150 |
+
const onSelectImage = img => {
|
151 |
+
setAttributes( {
|
152 |
+
profileImgID: img.id,
|
153 |
+
profileImgURL: img.url,
|
154 |
+
} );
|
155 |
+
};
|
156 |
+
|
157 |
+
return [
|
158 |
+
// Show the block alignment controls on focus
|
159 |
+
<BlockControls key="controls">
|
160 |
+
<AlignmentToolbar
|
161 |
+
value={ profileAlignment }
|
162 |
+
onChange={ ( value ) => setAttributes( { profileAlignment: value } ) }
|
163 |
+
/>
|
164 |
+
</BlockControls>,
|
165 |
+
// Show the block controls on focus
|
166 |
+
<Inspector
|
167 |
+
{ ...{ setAttributes, ...this.props } }
|
168 |
+
/>,
|
169 |
+
// Show the block markup in the editor
|
170 |
+
<ProfileBox { ...this.props }>
|
171 |
+
<AvatarColumn { ...this.props }>
|
172 |
+
<div class="ab-profile-image-square">
|
173 |
+
<MediaUpload
|
174 |
+
buttonProps={ {
|
175 |
+
className: 'change-image'
|
176 |
+
} }
|
177 |
+
onSelect={ ( img ) => setAttributes(
|
178 |
+
{
|
179 |
+
profileImgID: img.id,
|
180 |
+
profileImgURL: img.url,
|
181 |
+
}
|
182 |
+
) }
|
183 |
+
type="image"
|
184 |
+
value={ profileImgID }
|
185 |
+
render={ ( { open } ) => (
|
186 |
+
<Button onClick={ open }>
|
187 |
+
{ ! profileImgID ? icons.upload : <img
|
188 |
+
class="profile-avatar"
|
189 |
+
src={ profileImgURL }
|
190 |
+
alt="avatar"
|
191 |
+
/> }
|
192 |
+
</Button>
|
193 |
+
) }
|
194 |
+
>
|
195 |
+
</MediaUpload>
|
196 |
+
</div>
|
197 |
+
</AvatarColumn>
|
198 |
+
|
199 |
+
<div
|
200 |
+
className={ classnames(
|
201 |
+
'ab-profile-column ab-profile-content-wrap'
|
202 |
+
) }
|
203 |
+
>
|
204 |
+
<RichText
|
205 |
+
tagName="h2"
|
206 |
+
placeholder={ __( 'Add name' ) }
|
207 |
+
keepPlaceholderOnFocus
|
208 |
+
value={ profileName }
|
209 |
+
className='ab-profile-name'
|
210 |
+
style={ {
|
211 |
+
color: profileTextColor
|
212 |
+
} }
|
213 |
+
onChange={ ( value ) => setAttributes( { profileName: value } ) }
|
214 |
+
/>
|
215 |
+
|
216 |
+
<RichText
|
217 |
+
tagName="p"
|
218 |
+
placeholder={ __( 'Add title' ) }
|
219 |
+
keepPlaceholderOnFocus
|
220 |
+
value={ profileTitle }
|
221 |
+
className='ab-profile-title'
|
222 |
+
style={ {
|
223 |
+
color: profileTextColor
|
224 |
+
} }
|
225 |
+
onChange={ ( value ) => setAttributes( { profileTitle: value } ) }
|
226 |
+
/>
|
227 |
+
|
228 |
+
<RichText
|
229 |
+
tagName="div"
|
230 |
+
className='ab-profile-text'
|
231 |
+
multiline="p"
|
232 |
+
placeholder={ __( 'Add profile text...' ) }
|
233 |
+
keepPlaceholderOnFocus
|
234 |
+
value={ profileContent }
|
235 |
+
formattingControls={ [ 'bold', 'italic', 'strikethrough', 'link' ] }
|
236 |
+
onChange={ ( value ) => setAttributes( { profileContent: value } ) }
|
237 |
+
inlineToolbar
|
238 |
+
/>
|
239 |
+
|
240 |
+
<SocialIcons { ...this.props } />
|
241 |
+
</div>
|
242 |
+
</ProfileBox>
|
243 |
+
];
|
244 |
+
}
|
245 |
+
}
|
246 |
+
|
247 |
+
// Register the block
|
248 |
+
registerBlockType( 'atomic-blocks/ab-profile-box', {
|
249 |
+
title: __( 'AB Profile Box' ),
|
250 |
+
description: __( 'Add a profile box with bio info and social media links.' ),
|
251 |
+
icon: 'admin-users',
|
252 |
+
category: 'atomic-blocks',
|
253 |
+
keywords: [
|
254 |
+
__( 'author' ),
|
255 |
+
__( 'profile' ),
|
256 |
+
__( 'atomic' ),
|
257 |
+
],
|
258 |
+
// Setup the block attributes
|
259 |
+
attributes: blockAttributes,
|
260 |
+
|
261 |
+
// Render the block components
|
262 |
+
edit: ABAuthorProfileBlock,
|
263 |
+
|
264 |
+
// Save the block markup
|
265 |
+
save: function( props ) {
|
266 |
+
|
267 |
+
// Setup the attributes
|
268 |
+
const { profileName, profileTitle, profileContent, profileAlignment, profileImgURL, profileImgID, profileFontSize, profileBackgroundColor, profileTextColor, profileLinkColor, twitter, facebook, instagram, pinterest, google, youtube, github, email, website, profileAvatarShape } = props.attributes;
|
269 |
+
|
270 |
+
return (
|
271 |
+
// Save the block markup for the front end
|
272 |
+
<ProfileBox { ...props }>
|
273 |
+
|
274 |
+
{ profileImgURL && !! profileImgURL.length && (
|
275 |
+
<AvatarColumn { ...props }>
|
276 |
+
<div class="ab-profile-image-square">
|
277 |
+
<img
|
278 |
+
class="ab-profile-avatar"
|
279 |
+
src={ profileImgURL }
|
280 |
+
alt="avatar"
|
281 |
+
/>
|
282 |
+
</div>
|
283 |
+
</AvatarColumn>
|
284 |
+
) }
|
285 |
+
|
286 |
+
<div
|
287 |
+
className={ classnames(
|
288 |
+
'ab-profile-column ab-profile-content-wrap'
|
289 |
+
) }
|
290 |
+
>
|
291 |
+
{ profileName && !! profileName.length && (
|
292 |
+
<h2
|
293 |
+
className='ab-profile-name'
|
294 |
+
style={ {
|
295 |
+
color: profileTextColor
|
296 |
+
} }
|
297 |
+
>{ profileName }</h2>
|
298 |
+
) }
|
299 |
+
{ profileTitle && !! profileTitle.length && (
|
300 |
+
<p
|
301 |
+
className='ab-profile-title'
|
302 |
+
style={ {
|
303 |
+
color: profileTextColor
|
304 |
+
} }
|
305 |
+
>{ profileTitle }</p>
|
306 |
+
) }
|
307 |
+
{ profileContent && !! profileContent.length && (
|
308 |
+
<div className='ab-profile-text'>
|
309 |
+
{ profileContent }
|
310 |
+
</div>
|
311 |
+
) }
|
312 |
+
<SocialIcons { ...props } />
|
313 |
+
</div>
|
314 |
+
</ProfileBox>
|
315 |
+
);
|
316 |
+
},
|
317 |
+
} );
|
src/blocks/block-author-profile/styles/editor.scss
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-profile {
|
6 |
+
margin-bottom: 0;
|
7 |
+
}
|
8 |
+
|
9 |
+
.editor-block-list__layout [data-type="atomic-blocks/ab-profile-box"] {
|
10 |
+
margin-bottom: 1.2em;
|
11 |
+
}
|
12 |
+
|
13 |
+
.ab-profile-image-wrap {
|
14 |
+
svg {
|
15 |
+
pointer-events: none;
|
16 |
+
margin: 0 auto;
|
17 |
+
}
|
18 |
+
|
19 |
+
.components-button:not(:disabled):not([aria-disabled=true]):focus {
|
20 |
+
background: none;
|
21 |
+
box-shadow: none;
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
.ab-profile-content-wrap {
|
26 |
+
h2.editor-rich-text__tinymce {
|
27 |
+
line-height: 1.2;
|
28 |
+
}
|
29 |
+
|
30 |
+
p.editor-rich-text__tinymce {
|
31 |
+
line-height: 1.6;
|
32 |
+
}
|
33 |
+
}
|
src/blocks/block-author-profile/styles/style.scss
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Profile styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.ab-block-profile {
|
7 |
+
background: #f2f2f2;
|
8 |
+
color: #293038;
|
9 |
+
margin: 0 auto;
|
10 |
+
padding: 3%;
|
11 |
+
border-radius: 5px;
|
12 |
+
margin-bottom: 1.2em;
|
13 |
+
display: flex;
|
14 |
+
flex-flow: row wrap;
|
15 |
+
justify-content: space-around;
|
16 |
+
width: 100%;
|
17 |
+
|
18 |
+
.ab-profile-column {
|
19 |
+
display: block;
|
20 |
+
padding: 15px;
|
21 |
+
flex: 3 0 0;
|
22 |
+
|
23 |
+
@media only screen and (max-width: 600px) {
|
24 |
+
flex: auto;
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
.ab-profile-avatar-wrap {
|
29 |
+
position: relative;
|
30 |
+
z-index: 0;
|
31 |
+
flex: 1 0 0;
|
32 |
+
|
33 |
+
@media only screen and (max-width: 600px) {
|
34 |
+
flex: auto;
|
35 |
+
max-width: 210px;
|
36 |
+
margin: 0 auto;
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
.ab-profile-content-wrap {
|
41 |
+
@media only screen and (max-width: 600px) {
|
42 |
+
text-align: center;
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
.ab-profile-text {
|
47 |
+
font-size: 18px;
|
48 |
+
padding-top: 1em;
|
49 |
+
|
50 |
+
a {
|
51 |
+
color: inherit;
|
52 |
+
box-shadow: 0 -1px 0 inset;
|
53 |
+
text-decoration: none;
|
54 |
+
|
55 |
+
&:hover {
|
56 |
+
color: inherit;
|
57 |
+
box-shadow: 0 -2px 0 inset;
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
p {
|
62 |
+
line-height: 1.6;
|
63 |
+
|
64 |
+
&:last-child {
|
65 |
+
margin-bottom: 0;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
.ab-profile-name {
|
71 |
+
font-size: 1.4em;
|
72 |
+
font-weight: bold;
|
73 |
+
line-height: 1.2;
|
74 |
+
margin: 0;
|
75 |
+
}
|
76 |
+
|
77 |
+
.ab-profile-title {
|
78 |
+
opacity: .8;
|
79 |
+
padding-top: 5px;
|
80 |
+
margin-bottom: 0;
|
81 |
+
}
|
82 |
+
|
83 |
+
.ab-profile-image-square {
|
84 |
+
position: absolute;
|
85 |
+
top: 0;
|
86 |
+
left: 0;
|
87 |
+
height: 100%;
|
88 |
+
width: 100%;
|
89 |
+
z-index: 5;
|
90 |
+
}
|
91 |
+
|
92 |
+
.ab-profile-text:empty,
|
93 |
+
.ab-profile-title:empty,
|
94 |
+
.ab-profile-name:empty {
|
95 |
+
display: none;
|
96 |
+
}
|
97 |
+
|
98 |
+
.ab-profile-image-wrap {
|
99 |
+
width: 100%;
|
100 |
+
background: #ddd;
|
101 |
+
position: relative;
|
102 |
+
width: 100%;
|
103 |
+
|
104 |
+
&:before {
|
105 |
+
content: '';
|
106 |
+
display: inline-block;
|
107 |
+
padding-top: 100%;
|
108 |
+
}
|
109 |
+
|
110 |
+
button {
|
111 |
+
position: absolute;
|
112 |
+
left: 0;
|
113 |
+
z-index: 50;
|
114 |
+
padding: 0;
|
115 |
+
height: 100%;
|
116 |
+
width: 100%;
|
117 |
+
}
|
118 |
+
|
119 |
+
button:focus {
|
120 |
+
background: none;
|
121 |
+
border: none;
|
122 |
+
outline: none;
|
123 |
+
box-shadow: none;
|
124 |
+
}
|
125 |
+
|
126 |
+
img {
|
127 |
+
object-fit: cover;
|
128 |
+
height: 100%;
|
129 |
+
width: 100%;
|
130 |
+
position: relative;
|
131 |
+
z-index: 5;
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
.ab-social-links {
|
136 |
+
list-style: none;
|
137 |
+
margin: 0 0 0 0;
|
138 |
+
padding: 5% 0 0 0;
|
139 |
+
font-size: 0;
|
140 |
+
|
141 |
+
&:empty {
|
142 |
+
display: none;
|
143 |
+
}
|
144 |
+
|
145 |
+
li {
|
146 |
+
display: inline-block;
|
147 |
+
margin: 0 8px 0 0;
|
148 |
+
padding: 0;
|
149 |
+
|
150 |
+
a {
|
151 |
+
border: none;
|
152 |
+
|
153 |
+
&:hover {
|
154 |
+
opacity: .9;
|
155 |
+
}
|
156 |
+
}
|
157 |
+
|
158 |
+
i {
|
159 |
+
font-size: 18px;
|
160 |
+
background: #0393e3;
|
161 |
+
color: #fff;
|
162 |
+
padding: 10px;
|
163 |
+
border-radius: 100px;
|
164 |
+
height: 38px;
|
165 |
+
width: 38px;
|
166 |
+
text-align: center;
|
167 |
+
}
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
.right .ab-profile-avatar-wrap {
|
173 |
+
order: 2;
|
174 |
+
}
|
175 |
+
|
176 |
+
.round .ab-profile-image-wrap {
|
177 |
+
border-radius: 500px;
|
178 |
+
overflow: hidden;
|
179 |
+
|
180 |
+
&:before {
|
181 |
+
content: '';
|
182 |
+
display: inline-block;
|
183 |
+
padding-top: 92%;
|
184 |
+
}
|
185 |
+
|
186 |
+
img {
|
187 |
+
border-radius: 500px;
|
188 |
+
}
|
189 |
+
}
|
190 |
+
|
191 |
+
#editor .ab-has-avatar {
|
192 |
+
|
193 |
+
.ab-profile-image-square {
|
194 |
+
&:hover {
|
195 |
+
cursor: pointer;
|
196 |
+
|
197 |
+
img {
|
198 |
+
opacity: .7 !important;
|
199 |
+
}
|
200 |
+
}
|
201 |
+
|
202 |
+
button {
|
203 |
+
top: 0;
|
204 |
+
left: 0;
|
205 |
+
opacity: 1 !important;
|
206 |
+
height: 100%;
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
}
|
src/blocks/block-button/components/button.js
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Button Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Create a Button wrapper Component
|
13 |
+
*/
|
14 |
+
export default class customButton extends Component {
|
15 |
+
|
16 |
+
constructor( props ) {
|
17 |
+
super( ...arguments );
|
18 |
+
}
|
19 |
+
|
20 |
+
render() {
|
21 |
+
|
22 |
+
return (
|
23 |
+
<div
|
24 |
+
style={ {
|
25 |
+
textAlign: this.props.attributes.buttonAlignment,
|
26 |
+
} }
|
27 |
+
className={ classnames(
|
28 |
+
this.props.className,
|
29 |
+
'ab-block-button'
|
30 |
+
) }
|
31 |
+
>
|
32 |
+
{ this.props.children }
|
33 |
+
</div>
|
34 |
+
);
|
35 |
+
}
|
36 |
+
}
|
src/blocks/block-button/components/icons.js
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const icons = {};
|
2 |
+
|
3 |
+
icons.upload = <svg width='20px' height='20px' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'>
|
4 |
+
<path d='m77.945 91.453h-72.371c-3.3711 0-5.5742-2.3633-5.5742-5.2422v-55.719c0-3.457 2.1172-6.0703 5.5742-6.0703h44.453v11.051l-38.98-0.003906v45.008h60.977v-17.133l11.988-0.007812v22.875c0 2.8789-2.7812 5.2422-6.0664 5.2422z'
|
5 |
+
/>
|
6 |
+
<path d='m16.543 75.48l23.25-22.324 10.441 9.7773 11.234-14.766 5.5039 10.539 0.039063 16.773z'
|
7 |
+
/>
|
8 |
+
<path d='m28.047 52.992c-3.168 0-5.7422-2.5742-5.7422-5.7461 0-3.1758 2.5742-5.75 5.7422-5.75 3.1797 0 5.7539 2.5742 5.7539 5.75 0 3.1719-2.5742 5.7461-5.7539 5.7461z'
|
9 |
+
/>
|
10 |
+
<path d='m84.043 30.492v22.02h-12.059l-0.015625-22.02h-15.852l21.941-21.945 21.941 21.945z'
|
11 |
+
/>
|
12 |
+
</svg>;
|
13 |
+
|
14 |
+
icons.dismiss = <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns='http://www.w3.org/2000/svg' width="20" height="20" viewBox="0 0 20 20">
|
15 |
+
<path d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zM15 13l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z"></path>
|
16 |
+
</svg>;
|
17 |
+
|
18 |
+
export default icons;
|
src/blocks/block-button/components/inspector.js
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
InspectorControls,
|
12 |
+
BlockDescription,
|
13 |
+
ColorPalette,
|
14 |
+
} = wp.editor;
|
15 |
+
|
16 |
+
// Import Inspector components
|
17 |
+
const {
|
18 |
+
Toolbar,
|
19 |
+
Button,
|
20 |
+
PanelBody,
|
21 |
+
PanelRow,
|
22 |
+
PanelColor,
|
23 |
+
FormToggle,
|
24 |
+
RangeControl,
|
25 |
+
SelectControl,
|
26 |
+
ToggleControl,
|
27 |
+
} = wp.components;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Create an Inspector Controls wrapper Component
|
31 |
+
*/
|
32 |
+
export default class Inspector extends Component {
|
33 |
+
|
34 |
+
constructor( props ) {
|
35 |
+
super( ...arguments );
|
36 |
+
}
|
37 |
+
|
38 |
+
render() {
|
39 |
+
|
40 |
+
// Setup the attributes
|
41 |
+
const { buttonText, buttonUrl, buttonAlignment, buttonBackgroundColor, buttonTextColor, buttonSize, buttonShape, buttonTarget } = this.props.attributes;
|
42 |
+
|
43 |
+
// Button size values
|
44 |
+
const buttonSizeOptions = [
|
45 |
+
{ value: 'ab-button-size-small', label: __( 'Small' ) },
|
46 |
+
{ value: 'ab-button-size-medium', label: __( 'Medium' ) },
|
47 |
+
{ value: 'ab-button-size-large', label: __( 'Large' ) },
|
48 |
+
{ value: 'ab-button-size-extralarge', label: __( 'Extra Large' ) },
|
49 |
+
];
|
50 |
+
|
51 |
+
// Button shape
|
52 |
+
const buttonShapeOptions = [
|
53 |
+
{ value: 'ab-button-shape-square', label: __( 'Square' ) },
|
54 |
+
{ value: 'ab-button-shape-rounded', label: __( 'Rounded Square' ) },
|
55 |
+
{ value: 'ab-button-shape-circular', label: __( 'Circular' ) },
|
56 |
+
];
|
57 |
+
|
58 |
+
return (
|
59 |
+
<InspectorControls key="inspector">
|
60 |
+
<PanelBody>
|
61 |
+
<ToggleControl
|
62 |
+
label={ __( 'Open link in new window' ) }
|
63 |
+
checked={ buttonTarget }
|
64 |
+
onChange={ () => this.props.setAttributes( { buttonTarget: ! buttonTarget } ) }
|
65 |
+
/>
|
66 |
+
|
67 |
+
<SelectControl
|
68 |
+
label={ __( 'Button Size' ) }
|
69 |
+
value={ buttonSize }
|
70 |
+
options={ buttonSizeOptions.map( ({ value, label }) => ( {
|
71 |
+
value: value,
|
72 |
+
label: label,
|
73 |
+
} ) ) }
|
74 |
+
onChange={ ( value ) => { this.props.setAttributes( { buttonSize: value } ) } }
|
75 |
+
/>
|
76 |
+
|
77 |
+
<SelectControl
|
78 |
+
label={ __( 'Button Shape' ) }
|
79 |
+
value={ buttonShape }
|
80 |
+
options={ buttonShapeOptions.map( ({ value, label }) => ( {
|
81 |
+
value: value,
|
82 |
+
label: label,
|
83 |
+
} ) ) }
|
84 |
+
onChange={ ( value ) => { this.props.setAttributes( { buttonShape: value } ) } }
|
85 |
+
/>
|
86 |
+
|
87 |
+
<PanelColor
|
88 |
+
title={ __( 'Button Color' ) }
|
89 |
+
colorValue={ buttonBackgroundColor }
|
90 |
+
initialOpen={ false }
|
91 |
+
>
|
92 |
+
<ColorPalette
|
93 |
+
label={ __( 'Button Color' ) }
|
94 |
+
value={ buttonBackgroundColor }
|
95 |
+
onChange={ ( value ) => { this.props.setAttributes( { buttonBackgroundColor: value } ) } }
|
96 |
+
colors={[
|
97 |
+
{ color: '#00d1b2', name: 'teal' },
|
98 |
+
{ color: '#3373dc', name: 'royal blue' },
|
99 |
+
{ color: '#209cef', name: 'sky blue' },
|
100 |
+
{ color: '#22d25f', name: 'green' },
|
101 |
+
{ color: '#ffdd57', name: 'yellow' },
|
102 |
+
{ color: '#ff3860', name: 'pink' },
|
103 |
+
{ color: '#7941b6', name: 'purple' },
|
104 |
+
{ color: '#392F43', name: 'black' },
|
105 |
+
]}
|
106 |
+
/>
|
107 |
+
</PanelColor>
|
108 |
+
|
109 |
+
<PanelColor
|
110 |
+
title={ __( 'Button Text Color' ) }
|
111 |
+
colorValue={ buttonTextColor }
|
112 |
+
initialOpen={ false }
|
113 |
+
>
|
114 |
+
<ColorPalette
|
115 |
+
label={ __( 'Button Text Color' ) }
|
116 |
+
value={ buttonTextColor }
|
117 |
+
onChange={ ( value ) => { this.props.setAttributes( { buttonTextColor: value } ) } }
|
118 |
+
colors={[
|
119 |
+
{ color: '#fff', name: 'white' },
|
120 |
+
{ color: '#32373c', name: 'black' },
|
121 |
+
]}
|
122 |
+
/>
|
123 |
+
</PanelColor>
|
124 |
+
</PanelBody>
|
125 |
+
</InspectorControls>
|
126 |
+
);
|
127 |
+
}
|
128 |
+
}
|
src/blocks/block-button/index.js
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Button
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import CustomButton from './components/button';
|
9 |
+
import icons from './components/icons';
|
10 |
+
|
11 |
+
// Import CSS
|
12 |
+
import './styles/style.scss';
|
13 |
+
import './styles/editor.scss';
|
14 |
+
|
15 |
+
// Components
|
16 |
+
const { __ } = wp.i18n;
|
17 |
+
|
18 |
+
// Extend component
|
19 |
+
const { Component } = wp.element;
|
20 |
+
|
21 |
+
// Register block
|
22 |
+
const { registerBlockType } = wp.blocks;
|
23 |
+
|
24 |
+
// Register editor components
|
25 |
+
const {
|
26 |
+
RichText,
|
27 |
+
AlignmentToolbar,
|
28 |
+
BlockControls,
|
29 |
+
BlockAlignmentToolbar,
|
30 |
+
URLInput,
|
31 |
+
} = wp.editor;
|
32 |
+
|
33 |
+
// Register components
|
34 |
+
const {
|
35 |
+
Button,
|
36 |
+
withFallbackStyles,
|
37 |
+
IconButton,
|
38 |
+
Dashicon,
|
39 |
+
} = wp.components;
|
40 |
+
|
41 |
+
class ABButtonBlock extends Component {
|
42 |
+
|
43 |
+
render() {
|
44 |
+
|
45 |
+
// Setup the attributes
|
46 |
+
const { attributes: { buttonText, buttonUrl, buttonAlignment, buttonBackgroundColor, buttonTextColor, buttonSize, buttonShape, buttonTarget }, isSelected, className, setAttributes } = this.props;
|
47 |
+
|
48 |
+
return [
|
49 |
+
// Show the alignment toolbar on focus
|
50 |
+
<BlockControls key="controls">
|
51 |
+
<AlignmentToolbar
|
52 |
+
value={ buttonAlignment }
|
53 |
+
onChange={ ( value ) => {
|
54 |
+
setAttributes( { buttonAlignment: value } );
|
55 |
+
} }
|
56 |
+
/>
|
57 |
+
</BlockControls>,
|
58 |
+
// Show the block controls on focus
|
59 |
+
<Inspector
|
60 |
+
{ ...this.props }
|
61 |
+
/>,
|
62 |
+
// Show the button markup in the editor
|
63 |
+
<CustomButton { ...this.props }>
|
64 |
+
<RichText
|
65 |
+
tagName="span"
|
66 |
+
placeholder={ __( 'Button text...' ) }
|
67 |
+
keepPlaceholderOnFocus
|
68 |
+
value={ buttonText }
|
69 |
+
formattingControls={ [] }
|
70 |
+
className={ classnames(
|
71 |
+
'ab-button',
|
72 |
+
buttonShape,
|
73 |
+
buttonSize,
|
74 |
+
) }
|
75 |
+
style={ {
|
76 |
+
color: buttonTextColor,
|
77 |
+
backgroundColor: buttonBackgroundColor,
|
78 |
+
} }
|
79 |
+
onChange={ (value) => setAttributes( { buttonText: value } ) }
|
80 |
+
/>
|
81 |
+
</CustomButton>,
|
82 |
+
isSelected && (
|
83 |
+
<form
|
84 |
+
key="form-link"
|
85 |
+
className={ `blocks-button__inline-link ab-button-${buttonAlignment}`}
|
86 |
+
onSubmit={ event => event.preventDefault() }
|
87 |
+
style={ {
|
88 |
+
textAlign: buttonAlignment,
|
89 |
+
} }
|
90 |
+
>
|
91 |
+
<Dashicon icon={ 'admin-links' } />
|
92 |
+
<URLInput
|
93 |
+
className="button-url"
|
94 |
+
value={ buttonUrl }
|
95 |
+
onChange={ ( value ) => setAttributes( { buttonUrl: value } ) }
|
96 |
+
/>
|
97 |
+
<IconButton
|
98 |
+
icon="editor-break"
|
99 |
+
label={ __( 'Apply' ) }
|
100 |
+
type="submit"
|
101 |
+
/>
|
102 |
+
</form>
|
103 |
+
)
|
104 |
+
];
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
// Register the block
|
109 |
+
registerBlockType( 'atomic-blocks/ab-button', {
|
110 |
+
title: __( 'AB Button' ),
|
111 |
+
description: __( 'Add a customizable button.' ),
|
112 |
+
icon: 'admin-links',
|
113 |
+
category: 'atomic-blocks',
|
114 |
+
keywords: [
|
115 |
+
__( 'button' ),
|
116 |
+
__( 'link' ),
|
117 |
+
__( 'atomic' ),
|
118 |
+
],
|
119 |
+
attributes: {
|
120 |
+
buttonText: {
|
121 |
+
type: 'string',
|
122 |
+
},
|
123 |
+
buttonUrl: {
|
124 |
+
type: 'string',
|
125 |
+
source: 'attribute',
|
126 |
+
selector: 'a',
|
127 |
+
attribute: 'href',
|
128 |
+
},
|
129 |
+
buttonAlignment: {
|
130 |
+
type: 'string',
|
131 |
+
},
|
132 |
+
buttonBackgroundColor: {
|
133 |
+
type: 'string',
|
134 |
+
default: '#3373dc'
|
135 |
+
},
|
136 |
+
buttonTextColor: {
|
137 |
+
type: 'string',
|
138 |
+
default: '#ffffff'
|
139 |
+
},
|
140 |
+
buttonSize: {
|
141 |
+
type: 'string',
|
142 |
+
default: 'ab-button-size-medium'
|
143 |
+
},
|
144 |
+
buttonShape: {
|
145 |
+
type: 'string',
|
146 |
+
default: 'ab-button-shape-rounded'
|
147 |
+
},
|
148 |
+
buttonTarget: {
|
149 |
+
type: 'boolean',
|
150 |
+
default: false
|
151 |
+
},
|
152 |
+
},
|
153 |
+
|
154 |
+
// Render the block components
|
155 |
+
edit: ABButtonBlock,
|
156 |
+
|
157 |
+
// Save the attributes and markup
|
158 |
+
save: function( props ) {
|
159 |
+
|
160 |
+
// Setup the attributes
|
161 |
+
const { buttonText, buttonUrl, buttonAlignment, buttonBackgroundColor, buttonTextColor, buttonSize, buttonShape, buttonTarget } = props.attributes;
|
162 |
+
|
163 |
+
// Save the block markup for the front end
|
164 |
+
return (
|
165 |
+
<CustomButton { ...props }>
|
166 |
+
{ // Check if there is button text and output
|
167 |
+
buttonText && (
|
168 |
+
<a
|
169 |
+
href={ buttonUrl }
|
170 |
+
target={ buttonTarget ? '_blank' : '_self' }
|
171 |
+
className={ classnames(
|
172 |
+
'ab-button',
|
173 |
+
buttonShape,
|
174 |
+
buttonSize,
|
175 |
+
) }
|
176 |
+
style={ {
|
177 |
+
color: buttonTextColor,
|
178 |
+
backgroundColor: buttonBackgroundColor,
|
179 |
+
} }
|
180 |
+
>
|
181 |
+
{ buttonText }
|
182 |
+
</a>
|
183 |
+
) }
|
184 |
+
</CustomButton>
|
185 |
+
);
|
186 |
+
},
|
187 |
+
} );
|
src/blocks/block-button/styles/editor.scss
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-button {
|
6 |
+
&+ .blocks-button__inline-link .editor-url-input {
|
7 |
+
display: inline-block;
|
8 |
+
width: auto;
|
9 |
+
}
|
10 |
+
|
11 |
+
&+ .blocks-button__inline-link .components-button {
|
12 |
+
display: inline-block;
|
13 |
+
}
|
14 |
+
|
15 |
+
&+ .blocks-button__inline-link svg {
|
16 |
+
vertical-align: middle;
|
17 |
+
margin-right: 8px;
|
18 |
+
}
|
19 |
+
}
|
src/blocks/block-button/styles/style.scss
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Button styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.ab-block-button {
|
7 |
+
margin: 0 0 1.2em 0;
|
8 |
+
position: relative;
|
9 |
+
|
10 |
+
.blocks-rich-text {
|
11 |
+
display: inline-flex;
|
12 |
+
}
|
13 |
+
|
14 |
+
.components-autocomplete {
|
15 |
+
display: inline-block;
|
16 |
+
width: auto;
|
17 |
+
margin: 0 auto;
|
18 |
+
position: relative;
|
19 |
+
}
|
20 |
+
|
21 |
+
.ab-button {
|
22 |
+
text-align: center;
|
23 |
+
font-size: 18px;
|
24 |
+
line-height: 1 !important;
|
25 |
+
background-color: #32373c;
|
26 |
+
border: none;
|
27 |
+
border-radius: 50px;
|
28 |
+
box-shadow: none;
|
29 |
+
color: #fff;
|
30 |
+
cursor: pointer;
|
31 |
+
padding: .6em 1em;
|
32 |
+
text-decoration: none;
|
33 |
+
word-break: break-word;
|
34 |
+
transition: .3s ease;
|
35 |
+
display: inline-block;
|
36 |
+
|
37 |
+
&:hover {
|
38 |
+
box-shadow: inset 0 0 200px rgba(255, 255, 255, 0.15);
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
.ab-button-shape-square {
|
43 |
+
border-radius: 0;
|
44 |
+
}
|
45 |
+
|
46 |
+
.ab-button-shape-rounded {
|
47 |
+
border-radius: 5px;
|
48 |
+
}
|
49 |
+
|
50 |
+
.ab-button-shape-circular {
|
51 |
+
border-radius: 100px;
|
52 |
+
}
|
53 |
+
|
54 |
+
.ab-button-size-small {
|
55 |
+
font-size: 14px;
|
56 |
+
}
|
57 |
+
|
58 |
+
.ab-button-size-medium {
|
59 |
+
font-size: 20px;
|
60 |
+
}
|
61 |
+
|
62 |
+
.ab-button-size-large {
|
63 |
+
font-size: 26px;
|
64 |
+
padding: .8em 1.2em;
|
65 |
+
}
|
66 |
+
|
67 |
+
.ab-button-size-extralarge {
|
68 |
+
font-size: 34px;
|
69 |
+
padding: .8em 1.2em;
|
70 |
+
}
|
71 |
+
}
|
72 |
+
|
73 |
+
.ab-button-right {
|
74 |
+
transform: translateX(-100%);
|
75 |
+
left: 100%;
|
76 |
+
position: relative;
|
77 |
+
}
|
78 |
+
|
79 |
+
.ab-button-center {
|
80 |
+
margin: 0 auto;
|
81 |
+
}
|
src/blocks/block-container/components/container.js
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Container wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Create a Button wrapper Component
|
13 |
+
*/
|
14 |
+
export default class Container extends Component {
|
15 |
+
|
16 |
+
constructor( props ) {
|
17 |
+
super( ...arguments );
|
18 |
+
}
|
19 |
+
|
20 |
+
render() {
|
21 |
+
// Setup the attributes
|
22 |
+
const { attributes: { containerBackgroundColor, containerAlignment, containerPaddingTop, containerPaddingRight, containerPaddingBottom, containerPaddingLeft, containerMarginTop, containerMarginBottom, containerWidth, containerMaxWidth } } = this.props;
|
23 |
+
|
24 |
+
return (
|
25 |
+
<div
|
26 |
+
style={ {
|
27 |
+
backgroundColor: containerBackgroundColor,
|
28 |
+
textAlign: containerAlignment,
|
29 |
+
paddingLeft: `${containerPaddingLeft}%`,
|
30 |
+
paddingRight: `${containerPaddingRight}%`,
|
31 |
+
paddingBottom: `${containerPaddingBottom}%`,
|
32 |
+
paddingTop: `${containerPaddingTop}%`,
|
33 |
+
marginTop: `${containerMarginTop}%`,
|
34 |
+
marginBottom: `${containerMarginBottom}%`,
|
35 |
+
} }
|
36 |
+
className={ classnames(
|
37 |
+
this.props.className,
|
38 |
+
`align${containerWidth}`,
|
39 |
+
'ab-block-container',
|
40 |
+
) }
|
41 |
+
>{ this.props.children }</div>
|
42 |
+
);
|
43 |
+
}
|
44 |
+
}
|
src/blocks/block-container/components/inspector.js
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
InspectorControls,
|
12 |
+
BlockDescription,
|
13 |
+
ColorPalette,
|
14 |
+
MediaUpload,
|
15 |
+
} = wp.editor;
|
16 |
+
|
17 |
+
// Import Inspector components
|
18 |
+
const {
|
19 |
+
Toolbar,
|
20 |
+
Button,
|
21 |
+
PanelBody,
|
22 |
+
PanelRow,
|
23 |
+
PanelColor,
|
24 |
+
FormToggle,
|
25 |
+
RangeControl,
|
26 |
+
SelectControl,
|
27 |
+
ToggleControl,
|
28 |
+
IconButton,
|
29 |
+
} = wp.components;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Create an Inspector Controls wrapper Component
|
33 |
+
*/
|
34 |
+
export default class Inspector extends Component {
|
35 |
+
|
36 |
+
constructor( props ) {
|
37 |
+
super( ...arguments );
|
38 |
+
}
|
39 |
+
|
40 |
+
render() {
|
41 |
+
|
42 |
+
// Setup the attributes
|
43 |
+
const { containerPaddingTop, containerPaddingRight, containerPaddingBottom, containerPaddingLeft, containerMarginTop, containerMarginBottom, containerMaxWidth, containerBackgroundColor, containerDimRatio, containerImgURL, containerImgID, containerImgAlt } = this.props.attributes;
|
44 |
+
const { setAttributes } = this.props;
|
45 |
+
|
46 |
+
const onSelectImage = img => {
|
47 |
+
setAttributes( {
|
48 |
+
containerImgID: img.id,
|
49 |
+
containerImgURL: img.url,
|
50 |
+
containerImgAlt: img.alt,
|
51 |
+
} );
|
52 |
+
};
|
53 |
+
|
54 |
+
const onRemoveImage = () => {
|
55 |
+
setAttributes({
|
56 |
+
containerImgID: null,
|
57 |
+
containerImgURL: null,
|
58 |
+
containerImgAlt: null,
|
59 |
+
});
|
60 |
+
}
|
61 |
+
|
62 |
+
return (
|
63 |
+
<InspectorControls key="inspector">
|
64 |
+
<PanelBody title={ __( 'Container Options' ) } initialOpen={ true }>
|
65 |
+
<RangeControl
|
66 |
+
label={ __( 'Padding Top (%)' ) }
|
67 |
+
value={ containerPaddingTop }
|
68 |
+
onChange={ ( value ) => this.props.setAttributes( { containerPaddingTop: value } ) }
|
69 |
+
min={ 0 }
|
70 |
+
max={ 20 }
|
71 |
+
step={ 1 }
|
72 |
+
/>
|
73 |
+
|
74 |
+
<RangeControl
|
75 |
+
label={ __( 'Padding Bottom (%)' ) }
|
76 |
+
value={ containerPaddingBottom }
|
77 |
+
onChange={ ( value ) => this.props.setAttributes( { containerPaddingBottom: value } ) }
|
78 |
+
min={ 0 }
|
79 |
+
max={ 20 }
|
80 |
+
step={ .5 }
|
81 |
+
/>
|
82 |
+
|
83 |
+
<RangeControl
|
84 |
+
label={ __( 'Padding Left (%)' ) }
|
85 |
+
value={ containerPaddingLeft }
|
86 |
+
onChange={ ( value ) => this.props.setAttributes( { containerPaddingLeft: value } ) }
|
87 |
+
min={ 0 }
|
88 |
+
max={ 20 }
|
89 |
+
step={ 1 }
|
90 |
+
/>
|
91 |
+
|
92 |
+
<RangeControl
|
93 |
+
label={ __( 'Padding Right (%)' ) }
|
94 |
+
value={ containerPaddingRight }
|
95 |
+
onChange={ ( value ) => this.props.setAttributes( { containerPaddingRight: value } ) }
|
96 |
+
min={ 0 }
|
97 |
+
max={ 20 }
|
98 |
+
step={ .5 }
|
99 |
+
/>
|
100 |
+
|
101 |
+
<RangeControl
|
102 |
+
label={ __( 'Margin Top (%)' ) }
|
103 |
+
value={ containerMarginTop }
|
104 |
+
onChange={ ( value ) => this.props.setAttributes( { containerMarginTop: value } ) }
|
105 |
+
min={ 0 }
|
106 |
+
max={ 20 }
|
107 |
+
step={ 1 }
|
108 |
+
/>
|
109 |
+
|
110 |
+
<RangeControl
|
111 |
+
label={ __( 'Margin Bottom (%)' ) }
|
112 |
+
value={ containerMarginBottom }
|
113 |
+
onChange={ ( value ) => this.props.setAttributes( { containerMarginBottom: value } ) }
|
114 |
+
min={ 0 }
|
115 |
+
max={ 20 }
|
116 |
+
step={ .5 }
|
117 |
+
/>
|
118 |
+
|
119 |
+
<RangeControl
|
120 |
+
label={ __( 'Inside Container Max Width (px)' ) }
|
121 |
+
value={ containerMaxWidth }
|
122 |
+
onChange={ ( value ) => this.props.setAttributes( { containerMaxWidth: value } ) }
|
123 |
+
min={ 500 }
|
124 |
+
max={ 1600 }
|
125 |
+
step={ 1 }
|
126 |
+
/>
|
127 |
+
</PanelBody>
|
128 |
+
|
129 |
+
<PanelBody title={ __( 'Background Options' ) } initialOpen={ false }>
|
130 |
+
<p>{ __( 'Select a background image:' ) }</p>
|
131 |
+
<MediaUpload
|
132 |
+
onSelect={ onSelectImage }
|
133 |
+
type="image"
|
134 |
+
value={ containerImgID }
|
135 |
+
render={ ( { open } ) => (
|
136 |
+
<div>
|
137 |
+
<IconButton
|
138 |
+
className="ab-container-inspector-media"
|
139 |
+
label={ __( 'Edit image' ) }
|
140 |
+
icon="format-image"
|
141 |
+
onClick={ open }
|
142 |
+
>
|
143 |
+
{ __( 'Select Image' ) }
|
144 |
+
</IconButton>
|
145 |
+
|
146 |
+
{ containerImgURL && !! containerImgURL.length && (
|
147 |
+
<IconButton
|
148 |
+
className="ab-container-inspector-media"
|
149 |
+
label={ __( 'Remove Image' ) }
|
150 |
+
icon="dismiss"
|
151 |
+
onClick={ onRemoveImage }
|
152 |
+
>
|
153 |
+
{ __( 'Remove' ) }
|
154 |
+
</IconButton>
|
155 |
+
) }
|
156 |
+
</div>
|
157 |
+
) }
|
158 |
+
>
|
159 |
+
</MediaUpload>
|
160 |
+
|
161 |
+
{ containerImgURL && !! containerImgURL.length && (
|
162 |
+
<RangeControl
|
163 |
+
label={ __( 'Image Opacity' ) }
|
164 |
+
value={ containerDimRatio }
|
165 |
+
onChange={ ( value ) => this.props.setAttributes( { containerDimRatio: value } ) }
|
166 |
+
min={ 0 }
|
167 |
+
max={ 100 }
|
168 |
+
step={ 10 }
|
169 |
+
/>
|
170 |
+
) }
|
171 |
+
|
172 |
+
<PanelColor
|
173 |
+
title={ __( 'Background Color' ) }
|
174 |
+
colorValue={ containerBackgroundColor }
|
175 |
+
initialOpen={ false }
|
176 |
+
>
|
177 |
+
<ColorPalette
|
178 |
+
label={ __( 'Background Color' ) }
|
179 |
+
value={ containerBackgroundColor }
|
180 |
+
onChange={ ( value ) => this.props.setAttributes( { containerBackgroundColor: value } ) }
|
181 |
+
/>
|
182 |
+
</PanelColor>
|
183 |
+
</PanelBody>
|
184 |
+
</InspectorControls>
|
185 |
+
);
|
186 |
+
}
|
187 |
+
}
|
src/blocks/block-container/index.js
ADDED
@@ -0,0 +1,270 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Container
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import Container from './components/container';
|
9 |
+
|
10 |
+
// Import CSS
|
11 |
+
import './styles/style.scss';
|
12 |
+
import './styles/editor.scss';
|
13 |
+
|
14 |
+
// Components
|
15 |
+
const { __ } = wp.i18n;
|
16 |
+
|
17 |
+
// Extend component
|
18 |
+
const { Component } = wp.element;
|
19 |
+
|
20 |
+
// Register block
|
21 |
+
const { registerBlockType } = wp.blocks;
|
22 |
+
|
23 |
+
// Register editor components
|
24 |
+
const {
|
25 |
+
AlignmentToolbar,
|
26 |
+
BlockControls,
|
27 |
+
BlockAlignmentToolbar,
|
28 |
+
MediaUpload,
|
29 |
+
RichText,
|
30 |
+
InnerBlocks,
|
31 |
+
} = wp.editor;
|
32 |
+
|
33 |
+
// Register components
|
34 |
+
const {
|
35 |
+
Button,
|
36 |
+
withFallbackStyles,
|
37 |
+
IconButton,
|
38 |
+
Dashicon,
|
39 |
+
withState,
|
40 |
+
Toolbar,
|
41 |
+
} = wp.components;
|
42 |
+
|
43 |
+
const blockAttributes = {
|
44 |
+
containerPaddingTop: {
|
45 |
+
type: 'number',
|
46 |
+
default: 0,
|
47 |
+
},
|
48 |
+
containerPaddingRight: {
|
49 |
+
type: 'number',
|
50 |
+
default: 0,
|
51 |
+
},
|
52 |
+
containerPaddingBottom: {
|
53 |
+
type: 'number',
|
54 |
+
default: 0,
|
55 |
+
},
|
56 |
+
containerPaddingLeft: {
|
57 |
+
type: 'number',
|
58 |
+
default: 0,
|
59 |
+
},
|
60 |
+
containerMarginTop: {
|
61 |
+
type: 'number',
|
62 |
+
default: 0,
|
63 |
+
},
|
64 |
+
containerMarginBottom: {
|
65 |
+
type: 'number',
|
66 |
+
default: 0,
|
67 |
+
},
|
68 |
+
containerWidth: {
|
69 |
+
type: 'string',
|
70 |
+
default: 'center',
|
71 |
+
},
|
72 |
+
containerMaxWidth: {
|
73 |
+
type: 'number',
|
74 |
+
default: 1600,
|
75 |
+
},
|
76 |
+
containerBackgroundColor: {
|
77 |
+
type: 'string',
|
78 |
+
default: '#fff',
|
79 |
+
},
|
80 |
+
containerImgURL: {
|
81 |
+
type: 'string',
|
82 |
+
source: 'attribute',
|
83 |
+
attribute: 'src',
|
84 |
+
selector: 'img',
|
85 |
+
},
|
86 |
+
containerImgID: {
|
87 |
+
type: 'number',
|
88 |
+
},
|
89 |
+
containerImgAlt: {
|
90 |
+
type: 'string',
|
91 |
+
source: 'attribute',
|
92 |
+
attribute: 'alt',
|
93 |
+
selector: 'img',
|
94 |
+
},
|
95 |
+
containerDimRatio: {
|
96 |
+
type: 'number',
|
97 |
+
default: 50,
|
98 |
+
},
|
99 |
+
};
|
100 |
+
|
101 |
+
class ABContainerBlock extends Component {
|
102 |
+
|
103 |
+
render() {
|
104 |
+
|
105 |
+
// Setup the attributes
|
106 |
+
const {
|
107 |
+
attributes: {
|
108 |
+
containerPaddingTop,
|
109 |
+
containerPaddingRight,
|
110 |
+
containerPaddingBottom,
|
111 |
+
containerPaddingLeft,
|
112 |
+
containerMarginTop,
|
113 |
+
containerMarginBottom,
|
114 |
+
containerWidth,
|
115 |
+
containerMaxWidth,
|
116 |
+
containerBackgroundColor,
|
117 |
+
containerImgURL,
|
118 |
+
containerImgID,
|
119 |
+
containerImgAlt,
|
120 |
+
containerDimRatio,
|
121 |
+
},
|
122 |
+
attributes,
|
123 |
+
isSelected,
|
124 |
+
editable,
|
125 |
+
className,
|
126 |
+
setAttributes
|
127 |
+
} = this.props;
|
128 |
+
|
129 |
+
const onSelectImage = img => {
|
130 |
+
setAttributes( {
|
131 |
+
containerImgID: img.id,
|
132 |
+
containerImgURL: img.url,
|
133 |
+
containerImgAlt: img.alt,
|
134 |
+
} );
|
135 |
+
};
|
136 |
+
|
137 |
+
return [
|
138 |
+
// Show the alignment toolbar on focus
|
139 |
+
<BlockControls>
|
140 |
+
<BlockAlignmentToolbar
|
141 |
+
value={ containerWidth }
|
142 |
+
onChange={ containerWidth => setAttributes( { containerWidth } ) }
|
143 |
+
controls={ [ 'center', 'full' ] }
|
144 |
+
/>
|
145 |
+
</BlockControls>,
|
146 |
+
// Show the block controls on focus
|
147 |
+
<Inspector
|
148 |
+
{ ...{ setAttributes, ...this.props } }
|
149 |
+
/>,
|
150 |
+
// Show the container markup in the editor
|
151 |
+
<Container { ...this.props }>
|
152 |
+
<div class="ab-container-inside">
|
153 |
+
{ containerImgURL && !! containerImgURL.length && (
|
154 |
+
<div class="ab-container-image-wrap">
|
155 |
+
<img
|
156 |
+
className={ classnames(
|
157 |
+
'ab-container-image',
|
158 |
+
dimRatioToClass( containerDimRatio ),
|
159 |
+
{
|
160 |
+
'has-background-dim': containerDimRatio !== 0,
|
161 |
+
}
|
162 |
+
) }
|
163 |
+
src={ containerImgURL }
|
164 |
+
alt={ containerImgAlt }
|
165 |
+
/>
|
166 |
+
</div>
|
167 |
+
) }
|
168 |
+
|
169 |
+
<div
|
170 |
+
class="ab-container-content"
|
171 |
+
style={ {
|
172 |
+
maxWidth: `${containerMaxWidth}px`,
|
173 |
+
} }
|
174 |
+
>
|
175 |
+
<InnerBlocks />
|
176 |
+
</div>
|
177 |
+
</div>
|
178 |
+
</Container>
|
179 |
+
];
|
180 |
+
}
|
181 |
+
}
|
182 |
+
|
183 |
+
// Register the block
|
184 |
+
registerBlockType( 'atomic-blocks/ab-container', {
|
185 |
+
title: __( 'AB Container' ),
|
186 |
+
description: __( 'Add a container block to wrap several blocks in a parent container.' ),
|
187 |
+
icon: 'editor-table',
|
188 |
+
category: 'atomic-blocks',
|
189 |
+
keywords: [
|
190 |
+
__( 'container' ),
|
191 |
+
__( 'section' ),
|
192 |
+
__( 'atomic' ),
|
193 |
+
],
|
194 |
+
|
195 |
+
attributes: blockAttributes,
|
196 |
+
|
197 |
+
getEditWrapperProps( { containerWidth } ) {
|
198 |
+
if ( 'left' === containerWidth || 'right' === containerWidth || 'full' === containerWidth ) {
|
199 |
+
return { 'data-align': containerWidth };
|
200 |
+
}
|
201 |
+
},
|
202 |
+
|
203 |
+
// Render the block components
|
204 |
+
edit: ABContainerBlock,
|
205 |
+
|
206 |
+
// Save the attributes and markup
|
207 |
+
save: function( props ) {
|
208 |
+
|
209 |
+
// Setup the attributes
|
210 |
+
const {
|
211 |
+
containerPaddingTop,
|
212 |
+
containerPaddingRight,
|
213 |
+
containerPaddingBottom,
|
214 |
+
containerPaddingLeft,
|
215 |
+
containerMarginTop,
|
216 |
+
containerMarginBottom,
|
217 |
+
containerWidth,
|
218 |
+
containerMaxWidth,
|
219 |
+
containerBackgroundColor,
|
220 |
+
containerImgURL,
|
221 |
+
containerImgID,
|
222 |
+
containerImgAlt,
|
223 |
+
containerDimRatio,
|
224 |
+
} = props.attributes;
|
225 |
+
|
226 |
+
// Save the block markup for the front end
|
227 |
+
return (
|
228 |
+
<Container { ...props }>
|
229 |
+
<div class="ab-container-inside">
|
230 |
+
{ containerImgURL && !! containerImgURL.length && (
|
231 |
+
<div class="ab-container-image-wrap">
|
232 |
+
<img
|
233 |
+
className={ classnames(
|
234 |
+
'ab-container-image',
|
235 |
+
dimRatioToClass( containerDimRatio ),
|
236 |
+
{
|
237 |
+
'has-background-dim': containerDimRatio !== 0,
|
238 |
+
}
|
239 |
+
) }
|
240 |
+
src={ containerImgURL }
|
241 |
+
alt={ containerImgAlt }
|
242 |
+
/>
|
243 |
+
</div>
|
244 |
+
) }
|
245 |
+
|
246 |
+
<div
|
247 |
+
class="ab-container-content"
|
248 |
+
style={ {
|
249 |
+
maxWidth: `${containerMaxWidth}px`,
|
250 |
+
} }
|
251 |
+
>
|
252 |
+
<InnerBlocks.Content />
|
253 |
+
</div>
|
254 |
+
</div>
|
255 |
+
</Container>
|
256 |
+
);
|
257 |
+
},
|
258 |
+
} );
|
259 |
+
|
260 |
+
function dimRatioToClass( ratio ) {
|
261 |
+
return ( ratio === 0 || ratio === 50 ) ?
|
262 |
+
null :
|
263 |
+
'has-background-dim-' + ( 10 * Math.round( ratio / 10 ) );
|
264 |
+
}
|
265 |
+
|
266 |
+
function backgroundImageStyles( url ) {
|
267 |
+
return url ?
|
268 |
+
{ backgroundImage: `url(${ url })` } :
|
269 |
+
undefined;
|
270 |
+
}
|
src/blocks/block-container/styles/editor.scss
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-cta {
|
6 |
+
margin-bottom: 0;
|
7 |
+
}
|
8 |
+
|
9 |
+
.editor-block-list__layout [data-type="atomic-blocks/ab-cta"] {
|
10 |
+
margin-bottom: 1.2em;
|
11 |
+
}
|
12 |
+
|
13 |
+
.ab-cta-button {
|
14 |
+
.blocks-button__inline-link .editor-url-input {
|
15 |
+
display: inline-block;
|
16 |
+
width: auto;
|
17 |
+
}
|
18 |
+
|
19 |
+
.blocks-button__inline-link .components-button {
|
20 |
+
display: inline-block;
|
21 |
+
}
|
22 |
+
|
23 |
+
.blocks-button__inline-link svg {
|
24 |
+
vertical-align: middle;
|
25 |
+
margin-right: 8px;
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
.ab-block-cta h2.editor-rich-text__tinymce.mce-content-body {
|
30 |
+
line-height: 1.2;
|
31 |
+
}
|
src/blocks/block-container/styles/style.scss
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* CTA styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.ab-block-container {
|
7 |
+
margin: 0 0 1.2em 0;
|
8 |
+
position: relative;
|
9 |
+
background: #fff;
|
10 |
+
color: #293038;
|
11 |
+
padding: 0;
|
12 |
+
|
13 |
+
&.alignfull {
|
14 |
+
.editor-block-list__block {
|
15 |
+
max-width: 100%;
|
16 |
+
}
|
17 |
+
}
|
18 |
+
|
19 |
+
&.alignfull .ab-container-inside,
|
20 |
+
&.alignfull .ab-container-inside {
|
21 |
+
@media only screen and (min-width: 768px) {
|
22 |
+
max-width: 100%;
|
23 |
+
margin: 0 auto;
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
&.alignwide .ab-container-inside,
|
28 |
+
&.alignwide .ab-container-inside {
|
29 |
+
@media only screen and (min-width: 768px) {
|
30 |
+
max-width: 80%;
|
31 |
+
margin: 0 auto;
|
32 |
+
}
|
33 |
+
}
|
34 |
+
|
35 |
+
.ab-container-image-wrap {
|
36 |
+
position: absolute;
|
37 |
+
top: 0;
|
38 |
+
right: 0;
|
39 |
+
left: 0;
|
40 |
+
height: 100%;
|
41 |
+
z-index: 0;
|
42 |
+
}
|
43 |
+
|
44 |
+
.ab-container-image {
|
45 |
+
object-fit: cover;
|
46 |
+
height: 100%;
|
47 |
+
width: 100%;
|
48 |
+
transition: .3s ease;
|
49 |
+
}
|
50 |
+
|
51 |
+
.ab-container-content {
|
52 |
+
margin: 0 auto;
|
53 |
+
position: relative;
|
54 |
+
}
|
55 |
+
|
56 |
+
.ab-container-image:not(.has-background-dim) {
|
57 |
+
opacity: 0;
|
58 |
+
}
|
59 |
+
|
60 |
+
.has-background-dim {
|
61 |
+
opacity: .5;
|
62 |
+
}
|
63 |
+
|
64 |
+
.has-background-dim-10 {
|
65 |
+
opacity: .1;
|
66 |
+
}
|
67 |
+
|
68 |
+
.has-background-dim-20 {
|
69 |
+
opacity: .2;
|
70 |
+
}
|
71 |
+
|
72 |
+
.has-background-dim-30 {
|
73 |
+
opacity: .3;
|
74 |
+
}
|
75 |
+
|
76 |
+
.has-background-dim-40 {
|
77 |
+
opacity: .4;
|
78 |
+
}
|
79 |
+
|
80 |
+
.has-background-dim-50 {
|
81 |
+
opacity: .5;
|
82 |
+
}
|
83 |
+
|
84 |
+
.has-background-dim-60 {
|
85 |
+
opacity: .6;
|
86 |
+
}
|
87 |
+
|
88 |
+
.has-background-dim-70 {
|
89 |
+
opacity: .7;
|
90 |
+
}
|
91 |
+
|
92 |
+
.has-background-dim-80 {
|
93 |
+
opacity: .8;
|
94 |
+
}
|
95 |
+
|
96 |
+
.has-background-dim-90 {
|
97 |
+
opacity: .9;
|
98 |
+
}
|
99 |
+
|
100 |
+
.has-background-dim-100 {
|
101 |
+
opacity: 1;
|
102 |
+
}
|
103 |
+
}
|
src/blocks/block-cta/components/cta.js
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* CTA Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Create a CallToAction wrapper Component
|
13 |
+
*/
|
14 |
+
export default class CallToAction extends Component {
|
15 |
+
|
16 |
+
constructor( props ) {
|
17 |
+
super( ...arguments );
|
18 |
+
}
|
19 |
+
|
20 |
+
render() {
|
21 |
+
// Setup the attributes
|
22 |
+
const { attributes: { buttonText, buttonUrl, buttonAlignment, buttonBackgroundColor, buttonTextColor, buttonSize, buttonShape, buttonTarget, ctaTitle, ctaText, ctaTitleFontSize, ctaTextFontSize, ctaWidth, ctaBackgroundColor, ctaTextColor } } = this.props;
|
23 |
+
|
24 |
+
return (
|
25 |
+
<div
|
26 |
+
style={ {
|
27 |
+
backgroundColor: ctaBackgroundColor,
|
28 |
+
textAlign: buttonAlignment,
|
29 |
+
} }
|
30 |
+
className={ classnames(
|
31 |
+
this.props.className,
|
32 |
+
`align${ctaWidth}`,
|
33 |
+
'ab-block-cta',
|
34 |
+
'ab-font-size-' + ctaTextFontSize,
|
35 |
+
) }
|
36 |
+
>{ this.props.children }</div>
|
37 |
+
);
|
38 |
+
}
|
39 |
+
}
|
src/blocks/block-cta/components/inspector.js
ADDED
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
InspectorControls,
|
12 |
+
BlockDescription,
|
13 |
+
ColorPalette,
|
14 |
+
MediaUpload,
|
15 |
+
} = wp.editor;
|
16 |
+
|
17 |
+
// Import Inspector components
|
18 |
+
const {
|
19 |
+
Toolbar,
|
20 |
+
Button,
|
21 |
+
PanelBody,
|
22 |
+
PanelRow,
|
23 |
+
PanelColor,
|
24 |
+
FormToggle,
|
25 |
+
RangeControl,
|
26 |
+
SelectControl,
|
27 |
+
ToggleControl,
|
28 |
+
IconButton,
|
29 |
+
} = wp.components;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Create an Inspector Controls wrapper Component
|
33 |
+
*/
|
34 |
+
export default class Inspector extends Component {
|
35 |
+
|
36 |
+
constructor( props ) {
|
37 |
+
super( ...arguments );
|
38 |
+
}
|
39 |
+
|
40 |
+
render() {
|
41 |
+
|
42 |
+
// Setup the attributes
|
43 |
+
const { buttonText, buttonUrl, buttonAlignment, buttonBackgroundColor, buttonTextColor, buttonSize, buttonShape, buttonTarget, ctaTitle, ctaText, ctaTitleFontSize, ctaTextFontSize, ctaBackgroundColor, ctaTextColor, dimRatio, imgURL, imgID, imgAlt } = this.props.attributes;
|
44 |
+
const { setAttributes } = this.props;
|
45 |
+
|
46 |
+
// Button size values
|
47 |
+
const buttonSizeOptions = [
|
48 |
+
{ value: 'ab-button-size-small', label: __( 'Small' ) },
|
49 |
+
{ value: 'ab-button-size-medium', label: __( 'Medium' ) },
|
50 |
+
{ value: 'ab-button-size-large', label: __( 'Large' ) },
|
51 |
+
{ value: 'ab-button-size-extralarge', label: __( 'Extra Large' ) },
|
52 |
+
];
|
53 |
+
|
54 |
+
// Button shape
|
55 |
+
const buttonShapeOptions = [
|
56 |
+
{ value: 'ab-button-shape-square', label: __( 'Square' ) },
|
57 |
+
{ value: 'ab-button-shape-rounded', label: __( 'Rounded Square' ) },
|
58 |
+
{ value: 'ab-button-shape-circular', label: __( 'Circular' ) },
|
59 |
+
];
|
60 |
+
|
61 |
+
const onSelectImage = img => {
|
62 |
+
setAttributes( {
|
63 |
+
imgID: img.id,
|
64 |
+
imgURL: img.url,
|
65 |
+
imgAlt: img.alt,
|
66 |
+
} );
|
67 |
+
};
|
68 |
+
|
69 |
+
const onRemoveImage = () => {
|
70 |
+
setAttributes({
|
71 |
+
imgID: null,
|
72 |
+
imgURL: null,
|
73 |
+
imgAlt: null,
|
74 |
+
});
|
75 |
+
}
|
76 |
+
|
77 |
+
return (
|
78 |
+
<InspectorControls key="inspector">
|
79 |
+
<PanelBody title={ __( 'Text Options' ) } initialOpen={ true }>
|
80 |
+
<RangeControl
|
81 |
+
label={ __( 'Title Font Size' ) }
|
82 |
+
value={ ctaTitleFontSize }
|
83 |
+
onChange={ ( value ) => this.props.setAttributes( { ctaTitleFontSize: value } ) }
|
84 |
+
min={ 24 }
|
85 |
+
max={ 60 }
|
86 |
+
step={ 2 }
|
87 |
+
/>
|
88 |
+
|
89 |
+
<RangeControl
|
90 |
+
label={ __( 'Text Font Size' ) }
|
91 |
+
value={ ctaTextFontSize }
|
92 |
+
onChange={ ( value ) => this.props.setAttributes( { ctaTextFontSize: value } ) }
|
93 |
+
min={ 14 }
|
94 |
+
max={ 24 }
|
95 |
+
step={ 2 }
|
96 |
+
/>
|
97 |
+
|
98 |
+
<PanelColor
|
99 |
+
title={ __( 'Text Color' ) }
|
100 |
+
colorValue={ ctaTextColor }
|
101 |
+
initialOpen={ false }
|
102 |
+
>
|
103 |
+
<ColorPalette
|
104 |
+
label={ __( 'Text Color' ) }
|
105 |
+
value={ ctaTextColor }
|
106 |
+
onChange={ ( value ) => this.props.setAttributes( { ctaTextColor: value } ) }
|
107 |
+
/>
|
108 |
+
</PanelColor>
|
109 |
+
</PanelBody>
|
110 |
+
|
111 |
+
<PanelBody title={ __( 'Background Options' ) } initialOpen={ false }>
|
112 |
+
<p>{ __( 'Select a background image:' ) }</p>
|
113 |
+
<MediaUpload
|
114 |
+
onSelect={ onSelectImage }
|
115 |
+
type="image"
|
116 |
+
value={ imgID }
|
117 |
+
render={ ( { open } ) => (
|
118 |
+
<div>
|
119 |
+
<IconButton
|
120 |
+
className="ab-cta-inspector-media"
|
121 |
+
label={ __( 'Edit image' ) }
|
122 |
+
icon="format-image"
|
123 |
+
onClick={ open }
|
124 |
+
>
|
125 |
+
{ __( 'Select Image' ) }
|
126 |
+
</IconButton>
|
127 |
+
|
128 |
+
{ imgURL && !! imgURL.length && (
|
129 |
+
<IconButton
|
130 |
+
className="ab-cta-inspector-media"
|
131 |
+
label={ __( 'Remove Image' ) }
|
132 |
+
icon="dismiss"
|
133 |
+
onClick={ onRemoveImage }
|
134 |
+
>
|
135 |
+
{ __( 'Remove' ) }
|
136 |
+
</IconButton>
|
137 |
+
) }
|
138 |
+
</div>
|
139 |
+
) }
|
140 |
+
>
|
141 |
+
</MediaUpload>
|
142 |
+
|
143 |
+
{ imgURL && !! imgURL.length && (
|
144 |
+
<RangeControl
|
145 |
+
label={ __( 'Image Opacity' ) }
|
146 |
+
value={ dimRatio }
|
147 |
+
onChange={ ( value ) => this.props.setAttributes( { dimRatio: value } ) }
|
148 |
+
min={ 0 }
|
149 |
+
max={ 100 }
|
150 |
+
step={ 10 }
|
151 |
+
/>
|
152 |
+
) }
|
153 |
+
|
154 |
+
<PanelColor
|
155 |
+
title={ __( 'Background Color' ) }
|
156 |
+
colorValue={ ctaBackgroundColor }
|
157 |
+
initialOpen={ false }
|
158 |
+
>
|
159 |
+
<ColorPalette
|
160 |
+
label={ __( 'Background Color' ) }
|
161 |
+
value={ ctaBackgroundColor }
|
162 |
+
onChange={ ( value ) => this.props.setAttributes( { ctaBackgroundColor: value } ) }
|
163 |
+
/>
|
164 |
+
</PanelColor>
|
165 |
+
</PanelBody>
|
166 |
+
|
167 |
+
<PanelBody title={ __( 'Button Options' ) } initialOpen={ false }>
|
168 |
+
<ToggleControl
|
169 |
+
label={ __( 'Open link in new window' ) }
|
170 |
+
checked={ buttonTarget }
|
171 |
+
onChange={ () => this.props.setAttributes( { buttonTarget: ! buttonTarget } ) }
|
172 |
+
/>
|
173 |
+
|
174 |
+
<SelectControl
|
175 |
+
label={ __( 'Button Size' ) }
|
176 |
+
value={ buttonSize }
|
177 |
+
options={ buttonSizeOptions.map( ({ value, label }) => ( {
|
178 |
+
value: value,
|
179 |
+
label: label,
|
180 |
+
} ) ) }
|
181 |
+
onChange={ ( value ) => { this.props.setAttributes( { buttonSize: value } ) } }
|
182 |
+
/>
|
183 |
+
|
184 |
+
<SelectControl
|
185 |
+
label={ __( 'Button Shape' ) }
|
186 |
+
value={ buttonShape }
|
187 |
+
options={ buttonShapeOptions.map( ({ value, label }) => ( {
|
188 |
+
value: value,
|
189 |
+
label: label,
|
190 |
+
} ) ) }
|
191 |
+
onChange={ ( value ) => { this.props.setAttributes( { buttonShape: value } ) } }
|
192 |
+
/>
|
193 |
+
|
194 |
+
<PanelColor
|
195 |
+
title={ __( 'Button Color' ) }
|
196 |
+
colorValue={ buttonBackgroundColor }
|
197 |
+
initialOpen={ false }
|
198 |
+
>
|
199 |
+
<ColorPalette
|
200 |
+
label={ __( 'Button Color' ) }
|
201 |
+
value={ buttonBackgroundColor }
|
202 |
+
onChange={ ( value ) => { this.props.setAttributes( { buttonBackgroundColor: value } ) } }
|
203 |
+
colors={[
|
204 |
+
{ color: '#392F43', name: 'black' },
|
205 |
+
{ color: '#3373dc', name: 'royal blue' },
|
206 |
+
{ color: '#2DBAA3', name: 'teal' },
|
207 |
+
{ color: '#209cef', name: 'sky blue' },
|
208 |
+
{ color: '#2BAD59', name: 'green' },
|
209 |
+
{ color: '#ff3860', name: 'pink' },
|
210 |
+
{ color: '#7941b6', name: 'purple' },
|
211 |
+
{ color: '#F7812B', name: 'orange' },
|
212 |
+
]}
|
213 |
+
/>
|
214 |
+
</PanelColor>
|
215 |
+
|
216 |
+
<PanelColor
|
217 |
+
title={ __( 'Button Text Color' ) }
|
218 |
+
colorValue={ buttonTextColor }
|
219 |
+
initialOpen={ false }
|
220 |
+
>
|
221 |
+
<ColorPalette
|
222 |
+
label={ __( 'Button Text Color' ) }
|
223 |
+
value={ buttonTextColor }
|
224 |
+
onChange={ ( value ) => { this.props.setAttributes( { buttonTextColor: value } ) } }
|
225 |
+
colors={[
|
226 |
+
{ color: '#32373c', name: 'black' },
|
227 |
+
{ color: '#fff', name: 'white' },
|
228 |
+
]}
|
229 |
+
/>
|
230 |
+
</PanelColor>
|
231 |
+
</PanelBody>
|
232 |
+
</InspectorControls>
|
233 |
+
);
|
234 |
+
}
|
235 |
+
}
|
src/blocks/block-cta/index.js
ADDED
@@ -0,0 +1,406 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Call-To-Action
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import CallToAction from './components/cta';
|
9 |
+
|
10 |
+
// Import CSS
|
11 |
+
import './styles/style.scss';
|
12 |
+
import './styles/editor.scss';
|
13 |
+
|
14 |
+
// Components
|
15 |
+
const { __ } = wp.i18n;
|
16 |
+
|
17 |
+
// Extend component
|
18 |
+
const { Component } = wp.element;
|
19 |
+
|
20 |
+
// Register block
|
21 |
+
const { registerBlockType } = wp.blocks;
|
22 |
+
|
23 |
+
// Register editor components
|
24 |
+
const {
|
25 |
+
AlignmentToolbar,
|
26 |
+
URLInput,
|
27 |
+
BlockControls,
|
28 |
+
BlockAlignmentToolbar,
|
29 |
+
MediaUpload,
|
30 |
+
RichText,
|
31 |
+
} = wp.editor;
|
32 |
+
|
33 |
+
// Register components
|
34 |
+
const {
|
35 |
+
Button,
|
36 |
+
withFallbackStyles,
|
37 |
+
IconButton,
|
38 |
+
Dashicon,
|
39 |
+
Toolbar,
|
40 |
+
} = wp.components;
|
41 |
+
|
42 |
+
const blockAttributes = {
|
43 |
+
buttonText: {
|
44 |
+
type: 'string',
|
45 |
+
},
|
46 |
+
buttonUrl: {
|
47 |
+
type: 'string',
|
48 |
+
source: 'attribute',
|
49 |
+
selector: 'a',
|
50 |
+
attribute: 'href',
|
51 |
+
},
|
52 |
+
buttonAlignment: {
|
53 |
+
type: 'string',
|
54 |
+
default: 'center'
|
55 |
+
},
|
56 |
+
buttonBackgroundColor: {
|
57 |
+
type: 'string',
|
58 |
+
default: '#3373dc'
|
59 |
+
},
|
60 |
+
buttonTextColor: {
|
61 |
+
type: 'string',
|
62 |
+
default: '#ffffff'
|
63 |
+
},
|
64 |
+
buttonSize: {
|
65 |
+
type: 'string',
|
66 |
+
default: 'ab-button-size-medium'
|
67 |
+
},
|
68 |
+
buttonShape: {
|
69 |
+
type: 'string',
|
70 |
+
default: 'ab-button-shape-rounded'
|
71 |
+
},
|
72 |
+
buttonTarget: {
|
73 |
+
type: 'boolean',
|
74 |
+
default: false
|
75 |
+
},
|
76 |
+
ctaTitle: {
|
77 |
+
type: 'string',
|
78 |
+
},
|
79 |
+
ctaTitleFontSize: {
|
80 |
+
type: 'string',
|
81 |
+
default: '32'
|
82 |
+
},
|
83 |
+
ctaTextFontSize: {
|
84 |
+
type: 'string',
|
85 |
+
default: '20'
|
86 |
+
},
|
87 |
+
ctaText: {
|
88 |
+
type: 'array',
|
89 |
+
selector: '.ab-cta-text',
|
90 |
+
source: 'children',
|
91 |
+
},
|
92 |
+
ctaWidth: {
|
93 |
+
type: 'string',
|
94 |
+
default: 'center',
|
95 |
+
},
|
96 |
+
ctaBackgroundColor: {
|
97 |
+
type: 'string',
|
98 |
+
default: '#f2f2f2'
|
99 |
+
},
|
100 |
+
ctaTextColor: {
|
101 |
+
type: 'string',
|
102 |
+
default: '#32373c'
|
103 |
+
},
|
104 |
+
imgURL: {
|
105 |
+
type: 'string',
|
106 |
+
source: 'attribute',
|
107 |
+
attribute: 'src',
|
108 |
+
selector: 'img',
|
109 |
+
},
|
110 |
+
imgID: {
|
111 |
+
type: 'number',
|
112 |
+
},
|
113 |
+
imgAlt: {
|
114 |
+
type: 'string',
|
115 |
+
source: 'attribute',
|
116 |
+
attribute: 'alt',
|
117 |
+
selector: 'img',
|
118 |
+
},
|
119 |
+
dimRatio: {
|
120 |
+
type: 'number',
|
121 |
+
default: 50,
|
122 |
+
},
|
123 |
+
};
|
124 |
+
|
125 |
+
class ABCTABlock extends Component {
|
126 |
+
|
127 |
+
render() {
|
128 |
+
|
129 |
+
// Setup the attributes
|
130 |
+
const {
|
131 |
+
attributes: {
|
132 |
+
buttonText,
|
133 |
+
buttonUrl,
|
134 |
+
buttonAlignment,
|
135 |
+
buttonBackgroundColor,
|
136 |
+
buttonTextColor,
|
137 |
+
buttonSize,
|
138 |
+
buttonShape,
|
139 |
+
buttonTarget,
|
140 |
+
ctaTitle,
|
141 |
+
ctaText,
|
142 |
+
ctaTitleFontSize,
|
143 |
+
ctaTextFontSize,
|
144 |
+
ctaWidth,
|
145 |
+
ctaBackgroundColor,
|
146 |
+
ctaTextColor,
|
147 |
+
imgURL,
|
148 |
+
imgID,
|
149 |
+
imgAlt,
|
150 |
+
dimRatio,
|
151 |
+
},
|
152 |
+
attributes,
|
153 |
+
isSelected,
|
154 |
+
editable,
|
155 |
+
className,
|
156 |
+
setAttributes
|
157 |
+
} = this.props;
|
158 |
+
|
159 |
+
const onSelectImage = img => {
|
160 |
+
setAttributes( {
|
161 |
+
imgID: img.id,
|
162 |
+
imgURL: img.url,
|
163 |
+
imgAlt: img.alt,
|
164 |
+
} );
|
165 |
+
};
|
166 |
+
|
167 |
+
return [
|
168 |
+
// Show the alignment toolbar on focus
|
169 |
+
<BlockControls>
|
170 |
+
<BlockAlignmentToolbar
|
171 |
+
value={ ctaWidth }
|
172 |
+
onChange={ ctaWidth => setAttributes( { ctaWidth } ) }
|
173 |
+
controls={ [ 'center', 'wide', 'full' ] }
|
174 |
+
/>
|
175 |
+
<AlignmentToolbar
|
176 |
+
value={ buttonAlignment }
|
177 |
+
onChange={ ( value ) => {
|
178 |
+
setAttributes( { buttonAlignment: value } );
|
179 |
+
} }
|
180 |
+
/>
|
181 |
+
</BlockControls>,
|
182 |
+
// Show the block controls on focus
|
183 |
+
<Inspector
|
184 |
+
{ ...{ setAttributes, ...this.props } }
|
185 |
+
/>,
|
186 |
+
// Show the button markup in the editor
|
187 |
+
<CallToAction { ...this.props }>
|
188 |
+
{ imgURL && !! imgURL.length && (
|
189 |
+
<div class="ab-cta-image-wrap">
|
190 |
+
<img
|
191 |
+
className={ classnames(
|
192 |
+
'ab-cta-image',
|
193 |
+
dimRatioToClass( dimRatio ),
|
194 |
+
{
|
195 |
+
'has-background-dim': dimRatio !== 0,
|
196 |
+
}
|
197 |
+
) }
|
198 |
+
src={ imgURL }
|
199 |
+
alt={ imgAlt }
|
200 |
+
/>
|
201 |
+
</div>
|
202 |
+
) }
|
203 |
+
|
204 |
+
<div class="ab-cta-content">
|
205 |
+
<RichText
|
206 |
+
tagName="h2"
|
207 |
+
placeholder={ __( 'Call-To-Action Title' ) }
|
208 |
+
keepPlaceholderOnFocus
|
209 |
+
value={ ctaTitle }
|
210 |
+
className={ classnames(
|
211 |
+
'ab-cta-title',
|
212 |
+
'ab-font-size-' + ctaTitleFontSize,
|
213 |
+
) }
|
214 |
+
style={ {
|
215 |
+
color: ctaTextColor,
|
216 |
+
} }
|
217 |
+
onChange={ (value) => setAttributes( { ctaTitle: value } ) }
|
218 |
+
/>
|
219 |
+
<RichText
|
220 |
+
tagName="div"
|
221 |
+
multiline="p"
|
222 |
+
placeholder={ __( 'Call To Action Text' ) }
|
223 |
+
keepPlaceholderOnFocus
|
224 |
+
value={ ctaText }
|
225 |
+
className={ classnames(
|
226 |
+
'ab-cta-text',
|
227 |
+
'ab-font-size-' + ctaTextFontSize,
|
228 |
+
) }
|
229 |
+
style={ {
|
230 |
+
color: ctaTextColor,
|
231 |
+
} }
|
232 |
+
onChange={ ( value ) => setAttributes( { ctaText: value } ) }
|
233 |
+
inlineToolbar
|
234 |
+
/>
|
235 |
+
</div>
|
236 |
+
<div class="ab-cta-button">
|
237 |
+
<RichText
|
238 |
+
tagName="span"
|
239 |
+
placeholder={ __( 'Button text...' ) }
|
240 |
+
keepPlaceholderOnFocus
|
241 |
+
value={ buttonText }
|
242 |
+
formattingControls={ [] }
|
243 |
+
className={ classnames(
|
244 |
+
'ab-button',
|
245 |
+
buttonShape,
|
246 |
+
buttonSize,
|
247 |
+
) }
|
248 |
+
style={ {
|
249 |
+
color: buttonTextColor,
|
250 |
+
backgroundColor: buttonBackgroundColor,
|
251 |
+
} }
|
252 |
+
onChange={ (value) => setAttributes( { buttonText: value } ) }
|
253 |
+
/>
|
254 |
+
{ isSelected && (
|
255 |
+
<form
|
256 |
+
key="form-link"
|
257 |
+
className={ `blocks-button__inline-link ab-button-${buttonAlignment}`}
|
258 |
+
onSubmit={ event => event.preventDefault() }
|
259 |
+
style={ {
|
260 |
+
textAlign: buttonAlignment,
|
261 |
+
} }
|
262 |
+
>
|
263 |
+
<Dashicon icon={ 'admin-links' } />
|
264 |
+
<URLInput
|
265 |
+
className="button-url"
|
266 |
+
value={ buttonUrl }
|
267 |
+
onChange={ ( value ) => setAttributes( { buttonUrl: value } ) }
|
268 |
+
/>
|
269 |
+
<IconButton
|
270 |
+
icon="editor-break"
|
271 |
+
label={ __( 'Apply' ) }
|
272 |
+
type="submit"
|
273 |
+
/>
|
274 |
+
</form>
|
275 |
+
) }
|
276 |
+
</div>
|
277 |
+
</CallToAction>
|
278 |
+
];
|
279 |
+
}
|
280 |
+
}
|
281 |
+
|
282 |
+
// Register the block
|
283 |
+
registerBlockType( 'atomic-blocks/ab-cta', {
|
284 |
+
title: __( 'AB Call To Action' ),
|
285 |
+
description: __( 'Add a call to action section with a title, text, and a button.' ),
|
286 |
+
icon: 'megaphone',
|
287 |
+
category: 'atomic-blocks',
|
288 |
+
keywords: [
|
289 |
+
__( 'call to action' ),
|
290 |
+
__( 'cta' ),
|
291 |
+
__( 'atomic' ),
|
292 |
+
],
|
293 |
+
|
294 |
+
attributes: blockAttributes,
|
295 |
+
|
296 |
+
getEditWrapperProps( { ctaWidth } ) {
|
297 |
+
if ( 'left' === ctaWidth || 'right' === ctaWidth || 'full' === ctaWidth ) {
|
298 |
+
return { 'data-align': ctaWidth };
|
299 |
+
}
|
300 |
+
},
|
301 |
+
|
302 |
+
// Render the block components
|
303 |
+
edit: ABCTABlock,
|
304 |
+
|
305 |
+
// Save the attributes and markup
|
306 |
+
save: function( props ) {
|
307 |
+
|
308 |
+
// Setup the attributes
|
309 |
+
const {
|
310 |
+
buttonText,
|
311 |
+
buttonUrl,
|
312 |
+
buttonAlignment,
|
313 |
+
buttonBackgroundColor,
|
314 |
+
buttonTextColor,
|
315 |
+
buttonSize,
|
316 |
+
buttonShape,
|
317 |
+
buttonTarget,
|
318 |
+
ctaTitle,
|
319 |
+
ctaText,
|
320 |
+
ctaTitleFontSize,
|
321 |
+
ctaTextFontSize,
|
322 |
+
ctaWidth,
|
323 |
+
ctaBackgroundColor,
|
324 |
+
ctaTextColor,
|
325 |
+
imgURL,
|
326 |
+
imgID,
|
327 |
+
imgAlt,
|
328 |
+
dimRatio,
|
329 |
+
} = props.attributes;
|
330 |
+
|
331 |
+
// Save the block markup for the front end
|
332 |
+
return (
|
333 |
+
<CallToAction { ...props }>
|
334 |
+
{ imgURL && !! imgURL.length && (
|
335 |
+
<div class="ab-cta-image-wrap">
|
336 |
+
<img
|
337 |
+
className={ classnames(
|
338 |
+
'ab-cta-image',
|
339 |
+
dimRatioToClass( dimRatio ),
|
340 |
+
{
|
341 |
+
'has-background-dim': dimRatio !== 0,
|
342 |
+
}
|
343 |
+
) }
|
344 |
+
src={ imgURL }
|
345 |
+
alt={ imgAlt }
|
346 |
+
/>
|
347 |
+
</div>
|
348 |
+
) }
|
349 |
+
|
350 |
+
<div class="ab-cta-content">
|
351 |
+
{ ctaTitle && !! ctaTitle.length && (
|
352 |
+
<h2
|
353 |
+
className={ classnames(
|
354 |
+
'ab-cta-title',
|
355 |
+
'ab-font-size-' + ctaTitleFontSize,
|
356 |
+
) }
|
357 |
+
style={ {
|
358 |
+
color: ctaTextColor,
|
359 |
+
} }
|
360 |
+
>{ ctaTitle }</h2>
|
361 |
+
) }
|
362 |
+
{ ctaText && !! ctaText.length && (
|
363 |
+
<div
|
364 |
+
className={ classnames(
|
365 |
+
'ab-cta-text',
|
366 |
+
'ab-font-size-' + ctaTextFontSize,
|
367 |
+
) }
|
368 |
+
style={ {
|
369 |
+
color: ctaTextColor,
|
370 |
+
} }
|
371 |
+
>{ ctaText }</div>
|
372 |
+
) }
|
373 |
+
</div>
|
374 |
+
{ buttonText && !! buttonText.length && (
|
375 |
+
<div class="ab-cta-button">
|
376 |
+
<a
|
377 |
+
href={ buttonUrl }
|
378 |
+
target={ buttonTarget ? '_blank' : '_self' }
|
379 |
+
className={ classnames(
|
380 |
+
'ab-button',
|
381 |
+
buttonShape,
|
382 |
+
buttonSize,
|
383 |
+
) }
|
384 |
+
style={ {
|
385 |
+
color: buttonTextColor,
|
386 |
+
backgroundColor: buttonBackgroundColor,
|
387 |
+
} }
|
388 |
+
>{ buttonText }</a>
|
389 |
+
</div>
|
390 |
+
) }
|
391 |
+
</CallToAction>
|
392 |
+
);
|
393 |
+
},
|
394 |
+
} );
|
395 |
+
|
396 |
+
function dimRatioToClass( ratio ) {
|
397 |
+
return ( ratio === 0 || ratio === 50 ) ?
|
398 |
+
null :
|
399 |
+
'has-background-dim-' + ( 10 * Math.round( ratio / 10 ) );
|
400 |
+
}
|
401 |
+
|
402 |
+
function backgroundImageStyles( url ) {
|
403 |
+
return url ?
|
404 |
+
{ backgroundImage: `url(${ url })` } :
|
405 |
+
undefined;
|
406 |
+
}
|
src/blocks/block-cta/styles/editor.scss
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-cta {
|
6 |
+
margin-bottom: 0;
|
7 |
+
}
|
8 |
+
|
9 |
+
.editor-block-list__layout [data-type="atomic-blocks/ab-cta"] {
|
10 |
+
margin-bottom: 1.2em;
|
11 |
+
}
|
12 |
+
|
13 |
+
.ab-cta-button {
|
14 |
+
.blocks-button__inline-link .editor-url-input {
|
15 |
+
display: inline-block;
|
16 |
+
width: auto;
|
17 |
+
}
|
18 |
+
|
19 |
+
.blocks-button__inline-link .components-button {
|
20 |
+
display: inline-block;
|
21 |
+
}
|
22 |
+
|
23 |
+
.blocks-button__inline-link svg {
|
24 |
+
vertical-align: middle;
|
25 |
+
margin-right: 8px;
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
.ab-block-cta h2.editor-rich-text__tinymce.mce-content-body {
|
30 |
+
line-height: 1.2;
|
31 |
+
}
|
src/blocks/block-cta/styles/style.scss
ADDED
@@ -0,0 +1,310 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* CTA styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.ab-block-cta {
|
7 |
+
margin: 0 0 1.2em 0;
|
8 |
+
position: relative;
|
9 |
+
background: #f2f2f2;
|
10 |
+
color: #293038;
|
11 |
+
padding: 5% 3%;
|
12 |
+
border-radius: 5px;
|
13 |
+
|
14 |
+
.components-autocomplete {
|
15 |
+
display: inline-block;
|
16 |
+
width: auto;
|
17 |
+
margin: 0 auto;
|
18 |
+
position: relative;
|
19 |
+
}
|
20 |
+
|
21 |
+
* {
|
22 |
+
z-index: 10;
|
23 |
+
position: relative;
|
24 |
+
}
|
25 |
+
|
26 |
+
&.alignfull {
|
27 |
+
border-radius: 0;
|
28 |
+
padding: 8% 3%;
|
29 |
+
}
|
30 |
+
|
31 |
+
@media only screen and (max-width: 768px) {
|
32 |
+
padding: 8% 6%;
|
33 |
+
}
|
34 |
+
|
35 |
+
&.alignfull .ab-cta-content,
|
36 |
+
&.alignfull .ab-cta-button {
|
37 |
+
@media only screen and (min-width: 768px) {
|
38 |
+
max-width: 60%;
|
39 |
+
margin: 0 auto;
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
&.alignwide .ab-cta-content,
|
44 |
+
&.alignwide .ab-cta-button {
|
45 |
+
@media only screen and (min-width: 768px) {
|
46 |
+
max-width: 80%;
|
47 |
+
margin: 0 auto;
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
.ab-cta-image-wrap {
|
52 |
+
position: absolute;
|
53 |
+
top: 0;
|
54 |
+
right: 0;
|
55 |
+
left: 0;
|
56 |
+
height: 100%;
|
57 |
+
z-index: 1;
|
58 |
+
}
|
59 |
+
|
60 |
+
.ab-cta-image {
|
61 |
+
object-fit: cover;
|
62 |
+
height: 100%;
|
63 |
+
width: 100%;
|
64 |
+
transition: .3s ease;
|
65 |
+
}
|
66 |
+
|
67 |
+
.ab-cta-title {
|
68 |
+
display: inline-block;
|
69 |
+
width: 100%;
|
70 |
+
margin-bottom: .3em;
|
71 |
+
line-height: 1.2;
|
72 |
+
}
|
73 |
+
|
74 |
+
.ab-cta-text {
|
75 |
+
line-height: 1.4;
|
76 |
+
|
77 |
+
a {
|
78 |
+
color: inherit;
|
79 |
+
box-shadow: 0 -1px 0 inset;
|
80 |
+
text-decoration: none;
|
81 |
+
|
82 |
+
&:hover {
|
83 |
+
color: inherit;
|
84 |
+
box-shadow: 0 -2px 0 inset;
|
85 |
+
}
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
.ab-cta-button .blocks-rich-text {
|
90 |
+
display: inline-flex;
|
91 |
+
}
|
92 |
+
|
93 |
+
.ab-button {
|
94 |
+
text-align: center;
|
95 |
+
font-size: 18px;
|
96 |
+
line-height: 1 !important;
|
97 |
+
background-color: #32373c;
|
98 |
+
border: none;
|
99 |
+
border-radius: 50px;
|
100 |
+
box-shadow: none;
|
101 |
+
color: #fff;
|
102 |
+
cursor: pointer;
|
103 |
+
padding: .6em 1em;
|
104 |
+
text-decoration: none;
|
105 |
+
word-break: break-word;
|
106 |
+
transition: .3s ease;
|
107 |
+
display: inline-block;
|
108 |
+
|
109 |
+
&:hover {
|
110 |
+
box-shadow: inset 0 0 200px rgba(255, 255, 255, 0.15);
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
.ab-cta-title:empty,
|
115 |
+
.ab-cta-text:empty,
|
116 |
+
.ab-cta-button:empty,
|
117 |
+
.ab-button:empty {
|
118 |
+
display: none;
|
119 |
+
}
|
120 |
+
|
121 |
+
.ab-button-shape-square {
|
122 |
+
border-radius: 0;
|
123 |
+
}
|
124 |
+
|
125 |
+
.ab-button-shape-rounded {
|
126 |
+
border-radius: 5px;
|
127 |
+
}
|
128 |
+
|
129 |
+
.ab-button-shape-circular {
|
130 |
+
border-radius: 100px;
|
131 |
+
}
|
132 |
+
|
133 |
+
.ab-button-size-small {
|
134 |
+
font-size: 14px;
|
135 |
+
}
|
136 |
+
|
137 |
+
.ab-button-size-medium {
|
138 |
+
font-size: 20px;
|
139 |
+
}
|
140 |
+
|
141 |
+
.ab-button-size-large {
|
142 |
+
font-size: 26px;
|
143 |
+
padding: .8em 1.2em;
|
144 |
+
}
|
145 |
+
|
146 |
+
.ab-button-size-extralarge {
|
147 |
+
font-size: 32px;
|
148 |
+
padding: .8em 1.2em;
|
149 |
+
}
|
150 |
+
|
151 |
+
.ab-font-size-24.ab-cta-title {
|
152 |
+
font-size: 24px;
|
153 |
+
}
|
154 |
+
|
155 |
+
.ab-font-size-26.ab-cta-title {
|
156 |
+
font-size: 26px;
|
157 |
+
}
|
158 |
+
|
159 |
+
.ab-font-size-28.ab-cta-title {
|
160 |
+
font-size: 28px;
|
161 |
+
}
|
162 |
+
|
163 |
+
.ab-font-size-30.ab-cta-title {
|
164 |
+
font-size: 30px;
|
165 |
+
}
|
166 |
+
|
167 |
+
.ab-font-size-32.ab-cta-title {
|
168 |
+
font-size: 32px;
|
169 |
+
}
|
170 |
+
|
171 |
+
.ab-font-size-34.ab-cta-title {
|
172 |
+
font-size: 34px;
|
173 |
+
}
|
174 |
+
|
175 |
+
.ab-font-size-36.ab-cta-title {
|
176 |
+
font-size: 36px;
|
177 |
+
}
|
178 |
+
|
179 |
+
.ab-font-size-38.ab-cta-title {
|
180 |
+
font-size: 38px;
|
181 |
+
}
|
182 |
+
|
183 |
+
.ab-font-size-40.ab-cta-title {
|
184 |
+
font-size: 40px;
|
185 |
+
}
|
186 |
+
|
187 |
+
.ab-font-size-42.ab-cta-title {
|
188 |
+
font-size: 42px;
|
189 |
+
}
|
190 |
+
|
191 |
+
.ab-font-size-44.ab-cta-title {
|
192 |
+
font-size: 44px;
|
193 |
+
}
|
194 |
+
|
195 |
+
.ab-font-size-46.ab-cta-title {
|
196 |
+
font-size: 46px;
|
197 |
+
}
|
198 |
+
|
199 |
+
.ab-font-size-48.ab-cta-title {
|
200 |
+
font-size: 48px;
|
201 |
+
}
|
202 |
+
|
203 |
+
.ab-font-size-50.ab-cta-title {
|
204 |
+
font-size: 50px;
|
205 |
+
}
|
206 |
+
|
207 |
+
.ab-font-size-52.ab-cta-title {
|
208 |
+
font-size: 52px;
|
209 |
+
}
|
210 |
+
|
211 |
+
.ab-font-size-54.ab-cta-title {
|
212 |
+
font-size: 54px;
|
213 |
+
}
|
214 |
+
|
215 |
+
.ab-font-size-56.ab-cta-title {
|
216 |
+
font-size: 56px;
|
217 |
+
}
|
218 |
+
|
219 |
+
.ab-font-size-58.ab-cta-title {
|
220 |
+
font-size: 58px;
|
221 |
+
}
|
222 |
+
|
223 |
+
.ab-font-size-60.ab-cta-title {
|
224 |
+
font-size: 60px;
|
225 |
+
}
|
226 |
+
|
227 |
+
.blocks-button__inline-link {
|
228 |
+
margin-top: 15px;
|
229 |
+
}
|
230 |
+
|
231 |
+
.ab-cta-image:not(.has-background-dim) {
|
232 |
+
opacity: 0;
|
233 |
+
}
|
234 |
+
|
235 |
+
.has-background-dim {
|
236 |
+
opacity: .5;
|
237 |
+
}
|
238 |
+
|
239 |
+
.has-background-dim-10 {
|
240 |
+
opacity: .1;
|
241 |
+
}
|
242 |
+
|
243 |
+
.has-background-dim-20 {
|
244 |
+
opacity: .2;
|
245 |
+
}
|
246 |
+
|
247 |
+
.has-background-dim-30 {
|
248 |
+
opacity: .3;
|
249 |
+
}
|
250 |
+
|
251 |
+
.has-background-dim-40 {
|
252 |
+
opacity: .4;
|
253 |
+
}
|
254 |
+
|
255 |
+
.has-background-dim-50 {
|
256 |
+
opacity: .5;
|
257 |
+
}
|
258 |
+
|
259 |
+
.has-background-dim-60 {
|
260 |
+
opacity: .6;
|
261 |
+
}
|
262 |
+
|
263 |
+
.has-background-dim-70 {
|
264 |
+
opacity: .7;
|
265 |
+
}
|
266 |
+
|
267 |
+
.has-background-dim-80 {
|
268 |
+
opacity: .8;
|
269 |
+
}
|
270 |
+
|
271 |
+
.has-background-dim-90 {
|
272 |
+
opacity: .9;
|
273 |
+
}
|
274 |
+
|
275 |
+
.has-background-dim-100 {
|
276 |
+
opacity: 1;
|
277 |
+
}
|
278 |
+
}
|
279 |
+
|
280 |
+
.ab-button-right {
|
281 |
+
transform: translateX(-100%);
|
282 |
+
left: 100%;
|
283 |
+
position: relative;
|
284 |
+
}
|
285 |
+
|
286 |
+
.ab-button-center {
|
287 |
+
margin: 0 auto;
|
288 |
+
}
|
289 |
+
|
290 |
+
.ab-cta-inspector-media.components-button {
|
291 |
+
vertical-align: top;
|
292 |
+
border: 1px solid #e2e4e7;
|
293 |
+
background-color: #fff;
|
294 |
+
display: inline-flex;
|
295 |
+
border-radius: 3px;
|
296 |
+
margin-bottom: 15px;
|
297 |
+
|
298 |
+
&:hover {
|
299 |
+
box-shadow: none !important;
|
300 |
+
border: solid 1px #555d66;
|
301 |
+
}
|
302 |
+
|
303 |
+
&:first-child {
|
304 |
+
margin-right: 8px;
|
305 |
+
}
|
306 |
+
|
307 |
+
svg {
|
308 |
+
margin-right: 5px;
|
309 |
+
}
|
310 |
+
}
|
src/blocks/block-drop-cap/components/dropcap.js
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Testimonial Block Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Create a drop cap wrapper Component
|
13 |
+
*/
|
14 |
+
export default class DropCap extends Component {
|
15 |
+
|
16 |
+
constructor( props ) {
|
17 |
+
super( ...arguments );
|
18 |
+
}
|
19 |
+
|
20 |
+
render() {
|
21 |
+
|
22 |
+
// Setup the attributes
|
23 |
+
const { dropCapAlignment, dropCapTextColor, dropCapFontSize, dropCapStyle } = this.props.attributes;
|
24 |
+
|
25 |
+
return (
|
26 |
+
<div
|
27 |
+
style={ {
|
28 |
+
color: dropCapTextColor,
|
29 |
+
textAlign: dropCapAlignment,
|
30 |
+
} }
|
31 |
+
className={ classnames(
|
32 |
+
this.props.className,
|
33 |
+
dropCapStyle,
|
34 |
+
'ab-font-size-' + dropCapFontSize,
|
35 |
+
'ab-block-drop-cap',
|
36 |
+
) }
|
37 |
+
>
|
38 |
+
{ this.props.children }
|
39 |
+
</div>
|
40 |
+
);
|
41 |
+
}
|
42 |
+
}
|
src/blocks/block-drop-cap/components/icons.js
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const icons = {};
|
2 |
+
|
3 |
+
icons.upload = <svg width='20px' height='20px' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'>
|
4 |
+
<path d='m77.945 91.453h-72.371c-3.3711 0-5.5742-2.3633-5.5742-5.2422v-55.719c0-3.457 2.1172-6.0703 5.5742-6.0703h44.453v11.051l-38.98-0.003906v45.008h60.977v-17.133l11.988-0.007812v22.875c0 2.8789-2.7812 5.2422-6.0664 5.2422z'
|
5 |
+
/>
|
6 |
+
<path d='m16.543 75.48l23.25-22.324 10.441 9.7773 11.234-14.766 5.5039 10.539 0.039063 16.773z'
|
7 |
+
/>
|
8 |
+
<path d='m28.047 52.992c-3.168 0-5.7422-2.5742-5.7422-5.7461 0-3.1758 2.5742-5.75 5.7422-5.75 3.1797 0 5.7539 2.5742 5.7539 5.75 0 3.1719-2.5742 5.7461-5.7539 5.7461z'
|
9 |
+
/>
|
10 |
+
<path d='m84.043 30.492v22.02h-12.059l-0.015625-22.02h-15.852l21.941-21.945 21.941 21.945z'
|
11 |
+
/>
|
12 |
+
</svg>;
|
13 |
+
|
14 |
+
export default icons;
|
src/blocks/block-drop-cap/components/inspector.js
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
InspectorControls,
|
12 |
+
BlockDescription,
|
13 |
+
ColorPalette,
|
14 |
+
} = wp.editor;
|
15 |
+
|
16 |
+
// Import Inspector components
|
17 |
+
const {
|
18 |
+
Toolbar,
|
19 |
+
Button,
|
20 |
+
RangeControl,
|
21 |
+
SelectControl,
|
22 |
+
PanelBody,
|
23 |
+
} = wp.components;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Create an Inspector Controls wrapper Component
|
27 |
+
*/
|
28 |
+
export default class Inspector extends Component {
|
29 |
+
|
30 |
+
constructor( props ) {
|
31 |
+
super( ...arguments );
|
32 |
+
}
|
33 |
+
|
34 |
+
render() {
|
35 |
+
|
36 |
+
// Setup the attributes
|
37 |
+
const { dropCapFontSize, dropCapStyle } = this.props.attributes;
|
38 |
+
|
39 |
+
// Drop cap style options
|
40 |
+
const dropCapOptions = [
|
41 |
+
{ value: 'ab-drop-cap-letter', label: __( 'Letter' ) },
|
42 |
+
{ value: 'ab-drop-cap-square', label: __( 'Square' ) },
|
43 |
+
{ value: 'ab-drop-cap-border', label: __( 'Border' ) },
|
44 |
+
];
|
45 |
+
|
46 |
+
return (
|
47 |
+
<InspectorControls key="inspector">
|
48 |
+
<PanelBody>
|
49 |
+
<RangeControl
|
50 |
+
label={ __( 'Drop Cap Size' ) }
|
51 |
+
value={ dropCapFontSize }
|
52 |
+
onChange={ ( value ) => this.props.setAttributes( { dropCapFontSize: value } ) }
|
53 |
+
min={ 1 }
|
54 |
+
max={ 6 }
|
55 |
+
step={ 1 }
|
56 |
+
/>
|
57 |
+
|
58 |
+
<SelectControl
|
59 |
+
label={ __( 'Drop Cap Style' ) }
|
60 |
+
description={ __( 'Choose the style of the drop cap in your paragraph.' ) }
|
61 |
+
options={ dropCapOptions }
|
62 |
+
value={ dropCapStyle }
|
63 |
+
onChange={ ( value ) => this.props.setAttributes( { dropCapStyle: value } ) }
|
64 |
+
/>
|
65 |
+
</PanelBody>
|
66 |
+
</InspectorControls>
|
67 |
+
);
|
68 |
+
}
|
69 |
+
}
|
src/blocks/block-drop-cap/index.js
ADDED
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Drop Cap
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import DropCap from './components/dropcap';
|
9 |
+
import icons from './components/icons';
|
10 |
+
|
11 |
+
// Import CSS
|
12 |
+
import './styles/style.scss';
|
13 |
+
import './styles/editor.scss';
|
14 |
+
|
15 |
+
// Internationalization
|
16 |
+
const { __ } = wp.i18n;
|
17 |
+
|
18 |
+
// Extend component
|
19 |
+
const { Component } = wp.element;
|
20 |
+
|
21 |
+
// Register block
|
22 |
+
const { registerBlockType } = wp.blocks;
|
23 |
+
|
24 |
+
// Register editor components
|
25 |
+
const {
|
26 |
+
RichText,
|
27 |
+
AlignmentToolbar,
|
28 |
+
BlockControls,
|
29 |
+
BlockAlignmentToolbar,
|
30 |
+
MediaUpload,
|
31 |
+
} = wp.editor;
|
32 |
+
|
33 |
+
// Register components
|
34 |
+
const {
|
35 |
+
Button,
|
36 |
+
SelectControl,
|
37 |
+
} = wp.components;
|
38 |
+
|
39 |
+
class ABDropCapBlock extends Component {
|
40 |
+
|
41 |
+
render() {
|
42 |
+
|
43 |
+
// Setup the attributes
|
44 |
+
const { attributes: { dropCapContent, dropCapAlignment, dropCapBackgroundColor, dropCapTextColor, dropCapFontSize, dropCapStyle }, isSelected, className, setAttributes } = this.props;
|
45 |
+
|
46 |
+
return [
|
47 |
+
// Show the alignment toolbar on focus
|
48 |
+
<BlockControls key="controls">
|
49 |
+
<AlignmentToolbar
|
50 |
+
value={ dropCapAlignment }
|
51 |
+
onChange={ ( value ) => this.props.setAttributes( { dropCapAlignment: value } ) }
|
52 |
+
/>
|
53 |
+
</BlockControls>,
|
54 |
+
// Show the block controls on focus
|
55 |
+
<Inspector
|
56 |
+
{ ...this.props }
|
57 |
+
/>,
|
58 |
+
// Show the block markup in the editor
|
59 |
+
<DropCap { ...this.props }>
|
60 |
+
<RichText
|
61 |
+
tagName="div"
|
62 |
+
multiline="p"
|
63 |
+
placeholder={ __( 'Add paragraph text...' ) }
|
64 |
+
keepPlaceholderOnFocus
|
65 |
+
value={ dropCapContent }
|
66 |
+
formattingControls={ [ 'bold', 'italic', 'strikethrough', 'link' ] }
|
67 |
+
className={ classnames(
|
68 |
+
'ab-drop-cap-text',
|
69 |
+
'ab-font-size-' + dropCapFontSize,
|
70 |
+
) }
|
71 |
+
onChange={ ( value ) => this.props.setAttributes( { dropCapContent: value } ) }
|
72 |
+
/>
|
73 |
+
</DropCap>
|
74 |
+
];
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
// Register the block
|
79 |
+
registerBlockType( 'atomic-blocks/ab-drop-cap', {
|
80 |
+
title: __( 'AB Drop Cap' ),
|
81 |
+
description: __( 'Add a styled drop cap to the beginning of your paragraph.' ),
|
82 |
+
icon: 'format-quote',
|
83 |
+
category: 'atomic-blocks',
|
84 |
+
keywords: [
|
85 |
+
__( 'drop cap' ),
|
86 |
+
__( 'quote' ),
|
87 |
+
__( 'atomic' ),
|
88 |
+
],
|
89 |
+
attributes: {
|
90 |
+
dropCapContent: {
|
91 |
+
type: 'array',
|
92 |
+
selector: '.ab-drop-cap-text',
|
93 |
+
source: 'children',
|
94 |
+
},
|
95 |
+
dropCapAlignment: {
|
96 |
+
type: 'string',
|
97 |
+
},
|
98 |
+
dropCapBackgroundColor: {
|
99 |
+
type: 'string',
|
100 |
+
default: '#f2f2f2'
|
101 |
+
},
|
102 |
+
dropCapTextColor: {
|
103 |
+
type: 'string',
|
104 |
+
default: '#32373c'
|
105 |
+
},
|
106 |
+
dropCapFontSize: {
|
107 |
+
type: 'number',
|
108 |
+
default: 3,
|
109 |
+
},
|
110 |
+
dropCapStyle: {
|
111 |
+
type: 'string',
|
112 |
+
default: 'drop-cap-letter',
|
113 |
+
},
|
114 |
+
},
|
115 |
+
|
116 |
+
// Render the block components
|
117 |
+
edit: ABDropCapBlock,
|
118 |
+
|
119 |
+
// Save the attributes and markup
|
120 |
+
save: function( props ) {
|
121 |
+
|
122 |
+
const { dropCapContent, dropCapAlignment, dropCapBackgroundColor, dropCapTextColor, dropCapFontSize, dropCapStyle } = props.attributes;
|
123 |
+
|
124 |
+
// Save the block markup for the front end
|
125 |
+
return (
|
126 |
+
<DropCap { ...props }>
|
127 |
+
{ // Check if there is text and output
|
128 |
+
dropCapContent && (
|
129 |
+
<div
|
130 |
+
className={ classnames(
|
131 |
+
'ab-drop-cap-text'
|
132 |
+
) }
|
133 |
+
>
|
134 |
+
{ dropCapContent }
|
135 |
+
</div>
|
136 |
+
) }
|
137 |
+
</DropCap>
|
138 |
+
);
|
139 |
+
},
|
140 |
+
} );
|
src/blocks/block-drop-cap/styles/editor.scss
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-drop-cap {
|
6 |
+
.ab-drop-cap-text:not( :focus ):first-letter {
|
7 |
+
float: left;
|
8 |
+
font-size: 75px;
|
9 |
+
line-height: .7em;
|
10 |
+
margin-top: .15em;
|
11 |
+
margin-right: 25px;
|
12 |
+
margin-bottom: 25px;
|
13 |
+
font-weight: bold;
|
14 |
+
text-transform: uppercase;
|
15 |
+
}
|
16 |
+
|
17 |
+
&.ab-drop-cap-square .ab-drop-cap-text:not( :focus ):first-letter {
|
18 |
+
background: #32373c;
|
19 |
+
color: #fff;
|
20 |
+
padding: .2em;
|
21 |
+
}
|
22 |
+
|
23 |
+
&.ab-drop-cap-border .ab-drop-cap-text:not( :focus ):first-letter {
|
24 |
+
color: #32373c;
|
25 |
+
padding: .2em;
|
26 |
+
border: solid 4px;
|
27 |
+
}
|
28 |
+
|
29 |
+
/* Font size styles */
|
30 |
+
@media only screen and (min-width: 600px) {
|
31 |
+
.ab-font-size-1.ab-drop-cap-text:not( :focus ):first-letter {
|
32 |
+
font-size: 75px;
|
33 |
+
}
|
34 |
+
|
35 |
+
.ab-font-size-2.ab-drop-cap-text:not( :focus ):first-letter {
|
36 |
+
font-size: 85px;
|
37 |
+
}
|
38 |
+
|
39 |
+
.ab-font-size-3.ab-drop-cap-text:not( :focus ):first-letter {
|
40 |
+
font-size: 95px;
|
41 |
+
}
|
42 |
+
|
43 |
+
.ab-font-size-4.ab-drop-cap-text:not( :focus ):first-letter {
|
44 |
+
font-size: 105px;
|
45 |
+
}
|
46 |
+
|
47 |
+
.ab-font-size-5.ab-drop-cap-text:not( :focus ):first-letter {
|
48 |
+
font-size: 115px;
|
49 |
+
}
|
50 |
+
|
51 |
+
.ab-font-size-6.ab-drop-cap-text:not( :focus ):first-letter {
|
52 |
+
font-size: 125px;
|
53 |
+
}
|
54 |
+
}
|
55 |
+
}
|
src/blocks/block-drop-cap/styles/style.scss
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Drop cap styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.entry-content .ab-block-drop-cap {
|
7 |
+
.ab-drop-cap-text p:first-letter {
|
8 |
+
float: left;
|
9 |
+
font-size: 75px;
|
10 |
+
line-height: .7em;
|
11 |
+
margin-top: .15em;
|
12 |
+
margin-right: 25px;
|
13 |
+
margin-bottom: 25px;
|
14 |
+
font-weight: bold;
|
15 |
+
text-transform: uppercase;
|
16 |
+
}
|
17 |
+
|
18 |
+
&.ab-drop-cap-square .ab-drop-cap-text p:first-letter {
|
19 |
+
background: #32373c;
|
20 |
+
color: #fff;
|
21 |
+
padding: .2em;
|
22 |
+
}
|
23 |
+
|
24 |
+
&.ab-drop-cap-border .ab-drop-cap-text p:first-letter {
|
25 |
+
color: #32373c;
|
26 |
+
padding: .2em;
|
27 |
+
border: solid 4px;
|
28 |
+
}
|
29 |
+
|
30 |
+
/* Font size styles */
|
31 |
+
@media only screen and (min-width: 600px) {
|
32 |
+
&.ab-font-size-1 .ab-drop-cap-text:first-letter {
|
33 |
+
font-size: 75px;
|
34 |
+
}
|
35 |
+
|
36 |
+
&.ab-font-size-2 .ab-drop-cap-text:first-letter {
|
37 |
+
font-size: 85px;
|
38 |
+
}
|
39 |
+
|
40 |
+
&.ab-font-size-3 .ab-drop-cap-text:first-letter {
|
41 |
+
font-size: 95px;
|
42 |
+
}
|
43 |
+
|
44 |
+
&.ab-font-size-4 .ab-drop-cap-text:first-letter {
|
45 |
+
font-size: 105px;
|
46 |
+
}
|
47 |
+
|
48 |
+
&.ab-font-size-5 .ab-drop-cap-text:first-letter {
|
49 |
+
font-size: 115px;
|
50 |
+
}
|
51 |
+
|
52 |
+
&.ab-font-size-6 .ab-drop-cap-text p:first-letter {
|
53 |
+
font-size: 125px;
|
54 |
+
}
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
.ab-block-drop-cap {
|
59 |
+
&:before,
|
60 |
+
&:after {
|
61 |
+
content: '';
|
62 |
+
display: table;
|
63 |
+
}
|
64 |
+
|
65 |
+
&:after {
|
66 |
+
clear: both;
|
67 |
+
}
|
68 |
+
|
69 |
+
a {
|
70 |
+
color: inherit;
|
71 |
+
box-shadow: 0 -1px 0 inset;
|
72 |
+
text-decoration: none;
|
73 |
+
|
74 |
+
&:hover {
|
75 |
+
color: inherit;
|
76 |
+
box-shadow: 0 -2px 0 inset;
|
77 |
+
}
|
78 |
+
}
|
79 |
+
}
|
src/blocks/block-layout-split/components/icons.js
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const icons = {};
|
2 |
+
|
3 |
+
icons.upload = <svg width='32px' height='32px' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'>
|
4 |
+
<path d='m77.945 91.453h-72.371c-3.3711 0-5.5742-2.3633-5.5742-5.2422v-55.719c0-3.457 2.1172-6.0703 5.5742-6.0703h44.453v11.051l-38.98-0.003906v45.008h60.977v-17.133l11.988-0.007812v22.875c0 2.8789-2.7812 5.2422-6.0664 5.2422z'
|
5 |
+
/>
|
6 |
+
<path d='m16.543 75.48l23.25-22.324 10.441 9.7773 11.234-14.766 5.5039 10.539 0.039063 16.773z'
|
7 |
+
/>
|
8 |
+
<path d='m28.047 52.992c-3.168 0-5.7422-2.5742-5.7422-5.7461 0-3.1758 2.5742-5.75 5.7422-5.75 3.1797 0 5.7539 2.5742 5.7539 5.75 0 3.1719-2.5742 5.7461-5.7539 5.7461z'
|
9 |
+
/>
|
10 |
+
<path d='m84.043 30.492v22.02h-12.059l-0.015625-22.02h-15.852l21.941-21.945 21.941 21.945z'
|
11 |
+
/>
|
12 |
+
</svg>;
|
13 |
+
|
14 |
+
export default icons;
|
src/blocks/block-layout-split/components/inspector.js
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
InspectorControls,
|
12 |
+
BlockDescription,
|
13 |
+
ColorPalette,
|
14 |
+
} = wp.editor;
|
15 |
+
|
16 |
+
// Import Inspector components
|
17 |
+
const {
|
18 |
+
Panel,
|
19 |
+
PanelBody,
|
20 |
+
PanelRow,
|
21 |
+
PanelColor,
|
22 |
+
RangeControl,
|
23 |
+
SelectControl,
|
24 |
+
TextControl,
|
25 |
+
ToggleControl,
|
26 |
+
} = wp.components;
|
27 |
+
|
28 |
+
// Create an Inspector Controls wrapper Component
|
29 |
+
export default class Inspector extends Component {
|
30 |
+
|
31 |
+
constructor( props ) {
|
32 |
+
super( ...arguments );
|
33 |
+
}
|
34 |
+
|
35 |
+
render() {
|
36 |
+
|
37 |
+
// Setup the attributes
|
38 |
+
const { profileName, profileTitle, profileContent, profileAlignment, profileImgURL, profileImgID, profileFontSize, profileBackgroundColor, profileTextColor, profileLinkColor, twitter, facebook, instagram, pinterest, google, youtube, github, email, website, profileAvatarShape, layoutToggle } = this.props.attributes;
|
39 |
+
|
40 |
+
// Avatar shape options
|
41 |
+
const profileAvatarShapeOptions = [
|
42 |
+
{ value: 'top', label: __( 'Top' ) },
|
43 |
+
{ value: 'center', label: __( 'Center' ) },
|
44 |
+
{ value: 'flex', label: __( 'Flex' ) },
|
45 |
+
];
|
46 |
+
|
47 |
+
return (
|
48 |
+
<InspectorControls key="inspector">
|
49 |
+
<PanelBody>
|
50 |
+
<ToggleControl
|
51 |
+
label={ __( 'Reverse Layout' ) }
|
52 |
+
checked={ !! layoutToggle }
|
53 |
+
onChange={ () => this.props.setAttributes( { layoutToggle: ! layoutToggle } ) }
|
54 |
+
/>
|
55 |
+
|
56 |
+
<RangeControl
|
57 |
+
label={ __( 'Font Size' ) }
|
58 |
+
value={ profileFontSize }
|
59 |
+
onChange={ ( value ) => this.props.setAttributes( { profileFontSize: value } ) }
|
60 |
+
min={ 14 }
|
61 |
+
max={ 24 }
|
62 |
+
step={ 1 }
|
63 |
+
/>
|
64 |
+
|
65 |
+
<SelectControl
|
66 |
+
label={ __( 'Avatar Shape' ) }
|
67 |
+
description={ __( 'Choose between a round or square avatar shape.' ) }
|
68 |
+
options={ profileAvatarShapeOptions }
|
69 |
+
value={ profileAvatarShape }
|
70 |
+
onChange={ ( value ) => this.props.setAttributes( { profileAvatarShape: value } ) }
|
71 |
+
/>
|
72 |
+
|
73 |
+
<PanelColor
|
74 |
+
title={ __( 'Background Color' ) }
|
75 |
+
colorValue={ profileBackgroundColor }
|
76 |
+
initialOpen={ false }
|
77 |
+
>
|
78 |
+
<ColorPalette
|
79 |
+
label={ __( 'Background Color' ) }
|
80 |
+
value={ profileBackgroundColor }
|
81 |
+
onChange={ ( value ) => this.props.setAttributes( { profileBackgroundColor: value } ) }
|
82 |
+
/>
|
83 |
+
</PanelColor>
|
84 |
+
</PanelBody>
|
85 |
+
</InspectorControls>
|
86 |
+
);
|
87 |
+
}
|
88 |
+
}
|
src/blocks/block-layout-split/components/profile.js
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Profile Box Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
|
11 |
+
// Create a profile box wrapper Component
|
12 |
+
export default class ProfileBox extends Component {
|
13 |
+
|
14 |
+
constructor( props ) {
|
15 |
+
super( ...arguments );
|
16 |
+
}
|
17 |
+
|
18 |
+
render() {
|
19 |
+
|
20 |
+
// Setup the attributes
|
21 |
+
const { profileAlignment, profileImgURL, profileFontSize, profileBackgroundColor, profileTextColor, profileAvatarShape, layoutToggle } = this.props.attributes;
|
22 |
+
|
23 |
+
return (
|
24 |
+
<div
|
25 |
+
style={ {
|
26 |
+
backgroundColor: profileBackgroundColor,
|
27 |
+
color: profileTextColor,
|
28 |
+
} }
|
29 |
+
className={ classnames(
|
30 |
+
this.props.className,
|
31 |
+
profileAlignment,
|
32 |
+
layoutToggle && 'ab-layout-split-flip',
|
33 |
+
'ab-layout-split-image-' + profileAvatarShape,
|
34 |
+
{ 'ab-has-avatar': profileImgURL },
|
35 |
+
'ab-font-size-' + profileFontSize,
|
36 |
+
'ab-layout-split',
|
37 |
+
'ab-profile-columns',
|
38 |
+
) }>
|
39 |
+
{ this.props.children }
|
40 |
+
</div>
|
41 |
+
);
|
42 |
+
}
|
43 |
+
}
|
src/blocks/block-layout-split/components/social.js
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Social Media Icons
|
3 |
+
*/
|
4 |
+
const { __ } = wp.i18n;
|
5 |
+
const { Component } = wp.element;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Create an SocialIcons wrapper Component
|
9 |
+
*/
|
10 |
+
export default class SocialIcons extends Component {
|
11 |
+
|
12 |
+
constructor( props ) {
|
13 |
+
super( ...arguments );
|
14 |
+
}
|
15 |
+
|
16 |
+
render() {
|
17 |
+
return (
|
18 |
+
<ul class="ab-social-links">
|
19 |
+
{ this.props.attributes.website && !! this.props.attributes.website.length && (
|
20 |
+
<li>
|
21 |
+
<a href={ this.props.attributes.website } target="_blank">{ __( 'Website' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fas fa-link"></i></a>
|
22 |
+
</li>
|
23 |
+
) }
|
24 |
+
|
25 |
+
{ this.props.attributes.twitter && !! this.props.attributes.twitter.length && (
|
26 |
+
<li>
|
27 |
+
<a href={ this.props.attributes.twitter } target="_blank">{ __( 'Twitter' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-twitter"></i></a>
|
28 |
+
</li>
|
29 |
+
) }
|
30 |
+
|
31 |
+
{ this.props.attributes.facebook && !! this.props.attributes.facebook.length && (
|
32 |
+
<li>
|
33 |
+
<a href={ this.props.attributes.facebook } target="_blank">{ __( 'Facebook' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-facebook-f"></i></a>
|
34 |
+
</li>
|
35 |
+
) }
|
36 |
+
|
37 |
+
{ this.props.attributes.instagram && !! this.props.attributes.instagram.length && (
|
38 |
+
<li>
|
39 |
+
<a href={ this.props.attributes.instagram } target="_blank">{ __( 'Instagram' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-instagram"></i></a>
|
40 |
+
</li>
|
41 |
+
) }
|
42 |
+
|
43 |
+
{ this.props.attributes.pinterest && !! this.props.attributes.pinterest.length && (
|
44 |
+
<li>
|
45 |
+
<a href={ this.props.attributes.pinterest } target="_blank">{ __( 'Pinterest' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-pinterest"></i></a>
|
46 |
+
</li>
|
47 |
+
) }
|
48 |
+
|
49 |
+
{ this.props.attributes.google && !! this.props.attributes.google.length && (
|
50 |
+
<li>
|
51 |
+
<a href={ this.props.attributes.google } target="_blank">{ __( 'Google' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-google"></i></a>
|
52 |
+
</li>
|
53 |
+
) }
|
54 |
+
|
55 |
+
{ this.props.attributes.youtube && !! this.props.attributes.youtube.length && (
|
56 |
+
<li>
|
57 |
+
<a href={ this.props.attributes.youtube } target="_blank">{ __( 'YouTube' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-youtube"></i></a>
|
58 |
+
</li>
|
59 |
+
) }
|
60 |
+
|
61 |
+
{ this.props.attributes.github && !! this.props.attributes.github.length && (
|
62 |
+
<li>
|
63 |
+
<a href={ this.props.attributes.github } target="_blank">{ __( 'Github' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="fab fa-github"></i></a>
|
64 |
+
</li>
|
65 |
+
) }
|
66 |
+
|
67 |
+
{ this.props.attributes.email && !! this.props.attributes.email.length && (
|
68 |
+
<li>
|
69 |
+
<a href={ this.props.attributes.email } target="_blank">{ __( 'Email' ) } <i style={ { backgroundColor:this.props.attributes.profileLinkColor } } class="far fa-envelope"></i></a>
|
70 |
+
</li>
|
71 |
+
) }
|
72 |
+
</ul>
|
73 |
+
);
|
74 |
+
}
|
75 |
+
}
|
src/blocks/block-layout-split/index.js
ADDED
@@ -0,0 +1,286 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Profile Box
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import ProfileBox from './components/profile';
|
9 |
+
import SocialIcons from './components/social';
|
10 |
+
import icons from './components/icons';
|
11 |
+
|
12 |
+
// Import styles
|
13 |
+
import './styles/style.scss';
|
14 |
+
import './styles/editor.scss';
|
15 |
+
|
16 |
+
// Internationalization
|
17 |
+
const { __ } = wp.i18n;
|
18 |
+
|
19 |
+
// Extend component
|
20 |
+
const { Component } = wp.element;
|
21 |
+
|
22 |
+
// Register block
|
23 |
+
const { registerBlockType } = wp.blocks;
|
24 |
+
|
25 |
+
// Register components
|
26 |
+
const {
|
27 |
+
RichText,
|
28 |
+
AlignmentToolbar,
|
29 |
+
BlockControls,
|
30 |
+
InspectorControls,
|
31 |
+
MediaUpload,
|
32 |
+
MediaPlaceholder,
|
33 |
+
InnerBlocks,
|
34 |
+
} = wp.editor;
|
35 |
+
|
36 |
+
// Register Inspector components
|
37 |
+
const {
|
38 |
+
Button,
|
39 |
+
Toolbar,
|
40 |
+
IconButton,
|
41 |
+
} = wp.components;
|
42 |
+
|
43 |
+
const blockAttributes = {
|
44 |
+
profileName: {
|
45 |
+
type: 'string',
|
46 |
+
selector: '.ab-profile-name',
|
47 |
+
},
|
48 |
+
profileTitle: {
|
49 |
+
type: 'string',
|
50 |
+
selector: '.ab-profile-title',
|
51 |
+
},
|
52 |
+
profileContent: {
|
53 |
+
type: 'array',
|
54 |
+
selector: '.ab-profile-text',
|
55 |
+
source: 'children',
|
56 |
+
},
|
57 |
+
profileAlignment: {
|
58 |
+
type: 'string',
|
59 |
+
},
|
60 |
+
profileImgURL: {
|
61 |
+
type: 'string',
|
62 |
+
source: 'attribute',
|
63 |
+
attribute: 'src',
|
64 |
+
selector: 'img',
|
65 |
+
},
|
66 |
+
profileImgID: {
|
67 |
+
type: 'number',
|
68 |
+
},
|
69 |
+
profileBackgroundColor: {
|
70 |
+
type: 'string',
|
71 |
+
default: '#f2f2f2'
|
72 |
+
},
|
73 |
+
profileTextColor: {
|
74 |
+
type: 'string',
|
75 |
+
default: '#32373c'
|
76 |
+
},
|
77 |
+
profileLinkColor: {
|
78 |
+
type: 'string',
|
79 |
+
default: '#392f43'
|
80 |
+
},
|
81 |
+
profileFontSize: {
|
82 |
+
type: 'number',
|
83 |
+
default: 18
|
84 |
+
},
|
85 |
+
profileAvatarShape: {
|
86 |
+
type: 'string',
|
87 |
+
default: 'top',
|
88 |
+
},
|
89 |
+
layoutToggle: {
|
90 |
+
type: 'boolean',
|
91 |
+
defaut: true,
|
92 |
+
},
|
93 |
+
facebook: {
|
94 |
+
type: 'url',
|
95 |
+
},
|
96 |
+
instagram: {
|
97 |
+
type: 'url',
|
98 |
+
},
|
99 |
+
pinterest: {
|
100 |
+
type: 'url',
|
101 |
+
},
|
102 |
+
google: {
|
103 |
+
type: 'url',
|
104 |
+
},
|
105 |
+
youtube: {
|
106 |
+
type: 'url',
|
107 |
+
},
|
108 |
+
github: {
|
109 |
+
type: 'url',
|
110 |
+
},
|
111 |
+
email: {
|
112 |
+
type: 'url',
|
113 |
+
},
|
114 |
+
website: {
|
115 |
+
type: 'url',
|
116 |
+
},
|
117 |
+
};
|
118 |
+
|
119 |
+
class ABLayoutSplit extends Component {
|
120 |
+
|
121 |
+
render() {
|
122 |
+
|
123 |
+
// Setup the attributes
|
124 |
+
const {
|
125 |
+
attributes: {
|
126 |
+
profileName,
|
127 |
+
profileTitle,
|
128 |
+
profileContent,
|
129 |
+
profileAlignment,
|
130 |
+
profileImgURL,
|
131 |
+
profileImgID,
|
132 |
+
profileFontSize,
|
133 |
+
profileBackgroundColor,
|
134 |
+
profileTextColor,
|
135 |
+
profileLinkColor,
|
136 |
+
twitter,
|
137 |
+
facebook,
|
138 |
+
instagram,
|
139 |
+
pinterest,
|
140 |
+
google,
|
141 |
+
youtube,
|
142 |
+
github,
|
143 |
+
email,
|
144 |
+
website,
|
145 |
+
profileAvatarShape,
|
146 |
+
layoutToggle
|
147 |
+
},
|
148 |
+
attributes,
|
149 |
+
isSelected,
|
150 |
+
editable,
|
151 |
+
className,
|
152 |
+
setAttributes
|
153 |
+
} = this.props;
|
154 |
+
|
155 |
+
const onSelectImage = img => {
|
156 |
+
setAttributes( {
|
157 |
+
profileImgID: img.id,
|
158 |
+
profileImgURL: img.url,
|
159 |
+
} );
|
160 |
+
};
|
161 |
+
|
162 |
+
const onRemoveImage = () => {
|
163 |
+
setAttributes({
|
164 |
+
profileImgID: null,
|
165 |
+
profileImgURL: null,
|
166 |
+
});
|
167 |
+
}
|
168 |
+
|
169 |
+
return [
|
170 |
+
// Show the block alignment controls on focus
|
171 |
+
<BlockControls key="controls">
|
172 |
+
<Toolbar>
|
173 |
+
<MediaUpload
|
174 |
+
onSelect={ onSelectImage }
|
175 |
+
type="image"
|
176 |
+
value={ profileImgID }
|
177 |
+
render={ ( { open } ) => (
|
178 |
+
<IconButton
|
179 |
+
className="components-toolbar__control"
|
180 |
+
label={ __( 'Edit image' ) }
|
181 |
+
icon="format-image"
|
182 |
+
onClick={ open }
|
183 |
+
/>
|
184 |
+
) }
|
185 |
+
/>
|
186 |
+
</Toolbar>
|
187 |
+
|
188 |
+
{ profileImgURL && (
|
189 |
+
<Toolbar>
|
190 |
+
<IconButton
|
191 |
+
className="components-toolbar__control"
|
192 |
+
label={ __( 'Remove image' ) }
|
193 |
+
icon="no"
|
194 |
+
onClick={ onRemoveImage }
|
195 |
+
/>
|
196 |
+
</Toolbar>
|
197 |
+
) }
|
198 |
+
</BlockControls>,
|
199 |
+
// Show the block controls on focus
|
200 |
+
<Inspector
|
201 |
+
{ ...{ setAttributes, ...this.props } }
|
202 |
+
/>,
|
203 |
+
// Show the block markup in the editor
|
204 |
+
<ProfileBox { ...this.props }>
|
205 |
+
<div class="ab-layout-split-column ab-layout-split-image">
|
206 |
+
{ profileImgID && <img
|
207 |
+
class="profile-avatar"
|
208 |
+
src={ profileImgURL }
|
209 |
+
alt="avatar"
|
210 |
+
/> }
|
211 |
+
{ ! profileImgURL && (
|
212 |
+
<MediaPlaceholder
|
213 |
+
className={ classnames(
|
214 |
+
'ab-layout-split-media'
|
215 |
+
) }
|
216 |
+
labels={ {
|
217 |
+
title: __( 'test' ),
|
218 |
+
name: __( 'an image' ),
|
219 |
+
} }
|
220 |
+
onSelect={ onSelectImage }
|
221 |
+
accept="image/*"
|
222 |
+
type="image"
|
223 |
+
/>
|
224 |
+
) }
|
225 |
+
</div>
|
226 |
+
|
227 |
+
<div
|
228 |
+
className={ classnames(
|
229 |
+
'ab-layout-split-column ab-layout-split-content'
|
230 |
+
) }
|
231 |
+
>
|
232 |
+
<InnerBlocks />
|
233 |
+
</div>
|
234 |
+
</ProfileBox>
|
235 |
+
];
|
236 |
+
}
|
237 |
+
}
|
238 |
+
|
239 |
+
// Register the block
|
240 |
+
registerBlockType( 'atomic-blocks/ab-layout-split', {
|
241 |
+
title: __( 'AB Layout - Split' ),
|
242 |
+
description: __( 'Add a profile box with bio info and social media links.' ),
|
243 |
+
icon: 'admin-users',
|
244 |
+
category: 'atomic-blocks',
|
245 |
+
keywords: [
|
246 |
+
__( 'author' ),
|
247 |
+
__( 'profile' ),
|
248 |
+
__( 'atomic' ),
|
249 |
+
],
|
250 |
+
// Setup the block attributes
|
251 |
+
attributes: blockAttributes,
|
252 |
+
|
253 |
+
// Render the block components
|
254 |
+
edit: ABLayoutSplit,
|
255 |
+
|
256 |
+
// Save the block markup
|
257 |
+
save: function( props ) {
|
258 |
+
|
259 |
+
// Setup the attributes
|
260 |
+
const { profileName, profileTitle, profileContent, profileAlignment, profileImgURL, profileImgID, profileFontSize, profileBackgroundColor, profileTextColor, profileLinkColor, twitter, facebook, instagram, pinterest, google, youtube, github, email, website, profileAvatarShape, layoutToggle } = props.attributes;
|
261 |
+
|
262 |
+
return (
|
263 |
+
// Save the block markup for the front end
|
264 |
+
<ProfileBox { ...props }>
|
265 |
+
|
266 |
+
{ profileImgURL && !! profileImgURL.length && (
|
267 |
+
<div class="ab-layout-split-column ab-layout-split-image">
|
268 |
+
<img
|
269 |
+
class="ab-profile-avatar"
|
270 |
+
src={ profileImgURL }
|
271 |
+
alt="avatar"
|
272 |
+
/>
|
273 |
+
</div>
|
274 |
+
) }
|
275 |
+
|
276 |
+
<div
|
277 |
+
className={ classnames(
|
278 |
+
'ab-layout-split-column ab-layout-split-content'
|
279 |
+
) }
|
280 |
+
>
|
281 |
+
<InnerBlocks.Content />
|
282 |
+
</div>
|
283 |
+
</ProfileBox>
|
284 |
+
);
|
285 |
+
},
|
286 |
+
} );
|
src/blocks/block-layout-split/styles/editor.scss
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-profile {
|
6 |
+
margin-bottom: 0;
|
7 |
+
}
|
8 |
+
|
9 |
+
.editor-block-list__layout [data-type="atomic-blocks/ab-profile-box"] {
|
10 |
+
margin-bottom: 1.2em;
|
11 |
+
}
|
12 |
+
|
13 |
+
.ab-profile-image-wrap {
|
14 |
+
svg {
|
15 |
+
pointer-events: none;
|
16 |
+
margin: 0 auto;
|
17 |
+
}
|
18 |
+
|
19 |
+
.components-button:not(:disabled):not([aria-disabled=true]):focus {
|
20 |
+
background: none;
|
21 |
+
box-shadow: none;
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
.ab-profile-content-wrap {
|
26 |
+
h2.editor-rich-text__tinymce {
|
27 |
+
line-height: 1.2;
|
28 |
+
}
|
29 |
+
|
30 |
+
p.editor-rich-text__tinymce {
|
31 |
+
line-height: 1.6;
|
32 |
+
}
|
33 |
+
}
|
src/blocks/block-layout-split/styles/style.scss
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Loads on front end and back end
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-layout-split {
|
6 |
+
background: #f2f2f2;
|
7 |
+
color: #293038;
|
8 |
+
margin: 0 auto;
|
9 |
+
padding: 0;
|
10 |
+
margin-bottom: 1.2em;
|
11 |
+
display: flex;
|
12 |
+
flex-flow: row wrap;
|
13 |
+
justify-content: space-around;
|
14 |
+
align-items: center;
|
15 |
+
width: 100%;
|
16 |
+
|
17 |
+
.ab-layout-split-column {
|
18 |
+
flex: 2 0 0;
|
19 |
+
}
|
20 |
+
|
21 |
+
.ab-layout-split-content {
|
22 |
+
padding: 5%;
|
23 |
+
}
|
24 |
+
|
25 |
+
.ab-layout-split-image-wrap {
|
26 |
+
position: relative;
|
27 |
+
}
|
28 |
+
|
29 |
+
img + .ab-layout-split-media {
|
30 |
+
display: none;
|
31 |
+
}
|
32 |
+
|
33 |
+
.ab-layout-split-media {
|
34 |
+
height: 100%;
|
35 |
+
}
|
36 |
+
}
|
37 |
+
|
38 |
+
.ab-layout-split-image-flex {
|
39 |
+
align-items: stretch;
|
40 |
+
|
41 |
+
img,
|
42 |
+
.gutenberg__editor & img {
|
43 |
+
object-fit: cover;
|
44 |
+
height: 100%;
|
45 |
+
width: 100%;
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
.ab-layout-split-image-top {
|
50 |
+
align-items: flex-start;
|
51 |
+
}
|
52 |
+
|
53 |
+
.ab-layout-split-image-center {
|
54 |
+
align-items: center;
|
55 |
+
}
|
56 |
+
|
57 |
+
.ab-layout-split-flip {
|
58 |
+
flex-direction: row-reverse;
|
59 |
+
}
|
src/blocks/block-notice/components/button.js
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Notice Box Dismiss Button
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Register components
|
9 |
+
const {
|
10 |
+
Button
|
11 |
+
} = wp.components;
|
12 |
+
|
13 |
+
// Import block dependencies and components
|
14 |
+
import classnames from 'classnames';
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Create a button wrapper Component
|
18 |
+
*/
|
19 |
+
export default class DismissButton extends Component {
|
20 |
+
|
21 |
+
constructor( props ) {
|
22 |
+
super( ...arguments );
|
23 |
+
}
|
24 |
+
|
25 |
+
render() {
|
26 |
+
|
27 |
+
// Setup the attributes
|
28 |
+
const { attributes: { noticeTitleColor } } = this.props;
|
29 |
+
|
30 |
+
return (
|
31 |
+
<Button
|
32 |
+
className="ab-notice-dismiss"
|
33 |
+
style={ {
|
34 |
+
fill: noticeTitleColor,
|
35 |
+
color: noticeTitleColor,
|
36 |
+
} }>
|
37 |
+
{ this.props.children }
|
38 |
+
</Button>
|
39 |
+
);
|
40 |
+
}
|
41 |
+
}
|
src/blocks/block-notice/components/icons.js
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const icons = {};
|
2 |
+
|
3 |
+
icons.upload = <svg width='20px' height='20px' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'>
|
4 |
+
<path d='m77.945 91.453h-72.371c-3.3711 0-5.5742-2.3633-5.5742-5.2422v-55.719c0-3.457 2.1172-6.0703 5.5742-6.0703h44.453v11.051l-38.98-0.003906v45.008h60.977v-17.133l11.988-0.007812v22.875c0 2.8789-2.7812 5.2422-6.0664 5.2422z'
|
5 |
+
/>
|
6 |
+
<path d='m16.543 75.48l23.25-22.324 10.441 9.7773 11.234-14.766 5.5039 10.539 0.039063 16.773z'
|
7 |
+
/>
|
8 |
+
<path d='m28.047 52.992c-3.168 0-5.7422-2.5742-5.7422-5.7461 0-3.1758 2.5742-5.75 5.7422-5.75 3.1797 0 5.7539 2.5742 5.7539 5.75 0 3.1719-2.5742 5.7461-5.7539 5.7461z'
|
9 |
+
/>
|
10 |
+
<path d='m84.043 30.492v22.02h-12.059l-0.015625-22.02h-15.852l21.941-21.945 21.941 21.945z'
|
11 |
+
/>
|
12 |
+
</svg>;
|
13 |
+
|
14 |
+
icons.dismiss = <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns='http://www.w3.org/2000/svg' width="20" height="20" viewBox="0 0 20 20">
|
15 |
+
<path d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zM15 13l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z"></path>
|
16 |
+
</svg>;
|
17 |
+
|
18 |
+
export default icons;
|
src/blocks/block-notice/components/inspector.js
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
BlockDescription,
|
12 |
+
ColorPalette,
|
13 |
+
InspectorControls,
|
14 |
+
} = wp.editor;
|
15 |
+
|
16 |
+
// Import Inspector components
|
17 |
+
const {
|
18 |
+
Toolbar,
|
19 |
+
Button,
|
20 |
+
PanelBody,
|
21 |
+
PanelRow,
|
22 |
+
PanelColor,
|
23 |
+
FormToggle,
|
24 |
+
RangeControl,
|
25 |
+
SelectControl,
|
26 |
+
} = wp.components;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Create an Inspector Controls wrapper Component
|
30 |
+
*/
|
31 |
+
export default class Inspector extends Component {
|
32 |
+
|
33 |
+
constructor( props ) {
|
34 |
+
super( ...arguments );
|
35 |
+
}
|
36 |
+
|
37 |
+
render() {
|
38 |
+
|
39 |
+
// Notice dismiss options
|
40 |
+
const noticeDismissOptions = [
|
41 |
+
{ value: null, label: __( 'Always Show' ) },
|
42 |
+
{ value: 'ab-dismissable', label: __( 'Dismissable' ) },
|
43 |
+
];
|
44 |
+
|
45 |
+
// Setup the attributes
|
46 |
+
const { attributes: { noticeTitle, noticeContent, noticeAlignment, noticeBackgroundColor, noticeTextColor, noticeTitleColor, noticeFontSize, noticeDismiss } } = this.props;
|
47 |
+
|
48 |
+
return (
|
49 |
+
<InspectorControls key="inspector">
|
50 |
+
<PanelBody>
|
51 |
+
<RangeControl
|
52 |
+
label={ __( 'Font Size' ) }
|
53 |
+
value={ noticeFontSize }
|
54 |
+
onChange={ ( value ) => this.props.setAttributes( { noticeFontSize: value } ) }
|
55 |
+
min={ 14 }
|
56 |
+
max={ 24 }
|
57 |
+
step={ 1 }
|
58 |
+
/>
|
59 |
+
|
60 |
+
<SelectControl
|
61 |
+
label={ __( 'Notice Display' ) }
|
62 |
+
description={ __( 'Do you want the message to always show or dismissable?' ) }
|
63 |
+
options={ noticeDismissOptions }
|
64 |
+
value={ noticeDismiss }
|
65 |
+
onChange={ ( value ) => this.props.setAttributes( { noticeDismiss: value } ) }
|
66 |
+
/>
|
67 |
+
|
68 |
+
<PanelColor
|
69 |
+
title={ __( 'Notice Color' ) }
|
70 |
+
colorValue={ noticeBackgroundColor }
|
71 |
+
initialOpen={ false }
|
72 |
+
>
|
73 |
+
<ColorPalette
|
74 |
+
label={ __( 'Notice Color' ) }
|
75 |
+
value={ noticeBackgroundColor }
|
76 |
+
onChange={ ( value ) => this.props.setAttributes( { noticeBackgroundColor: value } ) }
|
77 |
+
colors={[
|
78 |
+
{ color: '#00d1b2', name: 'teal' },
|
79 |
+
{ color: '#3373dc', name: 'royal blue' },
|
80 |
+
{ color: '#209cef', name: 'sky blue' },
|
81 |
+
{ color: '#22d25f', name: 'green' },
|
82 |
+
{ color: '#ffdd57', name: 'yellow' },
|
83 |
+
{ color: '#ff3860', name: 'pink' },
|
84 |
+
{ color: '#7941b6', name: 'purple' },
|
85 |
+
{ color: '#392F43', name: 'black' },
|
86 |
+
]}
|
87 |
+
/>
|
88 |
+
</PanelColor>
|
89 |
+
|
90 |
+
<PanelColor
|
91 |
+
title={ __( 'Title Color' ) }
|
92 |
+
colorValue={ noticeTitleColor }
|
93 |
+
initialOpen={ false }
|
94 |
+
>
|
95 |
+
<ColorPalette
|
96 |
+
label={ __( 'Title Color' ) }
|
97 |
+
value={ noticeTitleColor }
|
98 |
+
onChange={ ( value ) => this.props.setAttributes( { noticeTitleColor: value } ) }
|
99 |
+
colors={[
|
100 |
+
{ color: '#fff', name: 'white' },
|
101 |
+
{ color: '#32373c', name: 'black' },
|
102 |
+
]}
|
103 |
+
/>
|
104 |
+
</PanelColor>
|
105 |
+
|
106 |
+
<PanelColor
|
107 |
+
title={ __( 'Text Color' ) }
|
108 |
+
colorValue={ noticeTextColor }
|
109 |
+
initialOpen={ false }
|
110 |
+
>
|
111 |
+
<ColorPalette
|
112 |
+
label={ __( 'Background Color' ) }
|
113 |
+
value={ noticeTextColor }
|
114 |
+
onChange={ ( value ) => this.props.setAttributes( { noticeTextColor: value } ) }
|
115 |
+
colors={[
|
116 |
+
{ color: '#fff', name: 'white' },
|
117 |
+
{ color: '#32373c', name: 'black' },
|
118 |
+
]}
|
119 |
+
/>
|
120 |
+
</PanelColor>
|
121 |
+
</PanelBody>
|
122 |
+
</InspectorControls>
|
123 |
+
);
|
124 |
+
}
|
125 |
+
}
|
src/blocks/block-notice/components/notice.js
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Notice Box Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
import * as uniqueID from './../../../utils/helper';
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Create a Notice wrapper Component
|
14 |
+
*/
|
15 |
+
export default class NoticeBox extends Component {
|
16 |
+
|
17 |
+
constructor( props ) {
|
18 |
+
super( ...arguments );
|
19 |
+
}
|
20 |
+
|
21 |
+
render() {
|
22 |
+
|
23 |
+
// Setup the attributes
|
24 |
+
const { attributes: { noticeTitle, noticeAlignment, noticeBackgroundColor, noticeTextColor, noticeFontSize, noticeDismiss } } = this.props;
|
25 |
+
|
26 |
+
// Generate a unique ID for the dismissable notice
|
27 |
+
const blockID = uniqueID.generateUniqueID( noticeDismiss + noticeTitle )
|
28 |
+
|
29 |
+
return (
|
30 |
+
<div
|
31 |
+
style={ {
|
32 |
+
color: noticeTextColor,
|
33 |
+
textAlign: noticeAlignment,
|
34 |
+
backgroundColor: noticeBackgroundColor,
|
35 |
+
} }
|
36 |
+
className={ classnames(
|
37 |
+
this.props.className,
|
38 |
+
noticeDismiss,
|
39 |
+
'ab-font-size-' + noticeFontSize,
|
40 |
+
'ab-block-notice'
|
41 |
+
)
|
42 |
+
}
|
43 |
+
data-id={ blockID }
|
44 |
+
>
|
45 |
+
{ this.props.children }
|
46 |
+
</div>
|
47 |
+
);
|
48 |
+
}
|
49 |
+
}
|
src/blocks/block-notice/index.js
ADDED
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Notice
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import NoticeBox from './components/notice';
|
9 |
+
import DismissButton from './components/button';
|
10 |
+
import icons from './components/icons';
|
11 |
+
import * as uniqueID from './../../utils/helper';
|
12 |
+
import md5 from 'md5';
|
13 |
+
|
14 |
+
// Import CSS
|
15 |
+
import './styles/style.scss';
|
16 |
+
import './styles/editor.scss';
|
17 |
+
|
18 |
+
// Internationalization
|
19 |
+
const { __ } = wp.i18n;
|
20 |
+
|
21 |
+
// Extend component
|
22 |
+
const { Component } = wp.element;
|
23 |
+
|
24 |
+
// Register block
|
25 |
+
const { registerBlockType } = wp.blocks;
|
26 |
+
|
27 |
+
// Register editor components
|
28 |
+
const {
|
29 |
+
RichText,
|
30 |
+
AlignmentToolbar,
|
31 |
+
BlockControls,
|
32 |
+
BlockAlignmentToolbar,
|
33 |
+
MediaUpload,
|
34 |
+
} = wp.editor;
|
35 |
+
|
36 |
+
// Register components
|
37 |
+
const {
|
38 |
+
Button,
|
39 |
+
SelectControl,
|
40 |
+
withFallbackStyles,
|
41 |
+
withState,
|
42 |
+
} = wp.components;
|
43 |
+
|
44 |
+
class ABNoticeBlock extends Component {
|
45 |
+
|
46 |
+
render() {
|
47 |
+
|
48 |
+
// Setup the attributes
|
49 |
+
const {
|
50 |
+
attributes: {
|
51 |
+
noticeTitle,
|
52 |
+
noticeContent,
|
53 |
+
noticeAlignment,
|
54 |
+
noticeBackgroundColor,
|
55 |
+
noticeTextColor,
|
56 |
+
noticeTitleColor,
|
57 |
+
noticeFontSize,
|
58 |
+
noticeDismiss
|
59 |
+
},
|
60 |
+
attributes,
|
61 |
+
isSelected,
|
62 |
+
editable,
|
63 |
+
className,
|
64 |
+
setAttributes
|
65 |
+
} = this.props;
|
66 |
+
|
67 |
+
const onSelectImage = img => {
|
68 |
+
setAttributes( {
|
69 |
+
imgID: img.id,
|
70 |
+
imgURL: img.url,
|
71 |
+
imgAlt: img.alt,
|
72 |
+
} );
|
73 |
+
};
|
74 |
+
|
75 |
+
return [
|
76 |
+
// Show the alignment toolbar on focus
|
77 |
+
<BlockControls key="controls">
|
78 |
+
<AlignmentToolbar
|
79 |
+
value={ noticeAlignment }
|
80 |
+
onChange={ ( value ) => setAttributes( { noticeAlignment: value } ) }
|
81 |
+
/>
|
82 |
+
</BlockControls>,
|
83 |
+
// Show the block controls on focus
|
84 |
+
<Inspector
|
85 |
+
{ ...{ setAttributes, ...this.props } }
|
86 |
+
/>,
|
87 |
+
// Show the block markup in the editor
|
88 |
+
<NoticeBox { ...this.props }>
|
89 |
+
{ // Check if the notice is dismissable and output the button
|
90 |
+
noticeDismiss && (
|
91 |
+
<DismissButton { ...this.props }>
|
92 |
+
{ icons.dismiss }
|
93 |
+
</DismissButton>
|
94 |
+
) }
|
95 |
+
|
96 |
+
<RichText
|
97 |
+
tagName="p"
|
98 |
+
placeholder={ __( 'Notice Title' ) }
|
99 |
+
keepPlaceholderOnFocus
|
100 |
+
value={ noticeTitle }
|
101 |
+
className={ classnames(
|
102 |
+
'ab-notice-title'
|
103 |
+
) }
|
104 |
+
style={ {
|
105 |
+
color: noticeTitleColor,
|
106 |
+
} }
|
107 |
+
onChange={ ( value ) => setAttributes( { noticeTitle: value } ) }
|
108 |
+
/>
|
109 |
+
|
110 |
+
<RichText
|
111 |
+
tagName="div"
|
112 |
+
multiline="p"
|
113 |
+
placeholder={ __( 'Add notice text...' ) }
|
114 |
+
keepPlaceholderOnFocus
|
115 |
+
value={ noticeContent }
|
116 |
+
formattingControls={ [ 'bold', 'italic', 'strikethrough', 'link' ] }
|
117 |
+
className={ classnames(
|
118 |
+
'ab-notice-text'
|
119 |
+
) }
|
120 |
+
style={ {
|
121 |
+
borderColor: noticeBackgroundColor,
|
122 |
+
} }
|
123 |
+
onChange={ ( value ) => setAttributes( { noticeContent: value } ) }
|
124 |
+
inlineToolbar
|
125 |
+
/>
|
126 |
+
</NoticeBox>
|
127 |
+
];
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
// Register the block
|
132 |
+
registerBlockType( 'atomic-blocks/ab-notice', {
|
133 |
+
title: __( 'AB Notice' ),
|
134 |
+
description: __( 'Add a stylized text notice.' ),
|
135 |
+
icon: 'format-aside',
|
136 |
+
category: 'atomic-blocks',
|
137 |
+
keywords: [
|
138 |
+
__( 'notice' ),
|
139 |
+
__( 'message' ),
|
140 |
+
__( 'atomic' ),
|
141 |
+
],
|
142 |
+
attributes: {
|
143 |
+
noticeTitle: {
|
144 |
+
type: 'string',
|
145 |
+
selector: '.ab-notice-title',
|
146 |
+
},
|
147 |
+
noticeContent: {
|
148 |
+
type: 'array',
|
149 |
+
selector: '.ab-notice-text',
|
150 |
+
source: 'children',
|
151 |
+
},
|
152 |
+
noticeAlignment: {
|
153 |
+
type: 'string',
|
154 |
+
},
|
155 |
+
noticeBackgroundColor: {
|
156 |
+
type: 'string',
|
157 |
+
default: '#00d1b2'
|
158 |
+
},
|
159 |
+
noticeTextColor: {
|
160 |
+
type: 'string',
|
161 |
+
default: '#32373c'
|
162 |
+
},
|
163 |
+
noticeTitleColor: {
|
164 |
+
type: 'string',
|
165 |
+
default: '#fff'
|
166 |
+
},
|
167 |
+
noticeFontSize: {
|
168 |
+
type: 'number',
|
169 |
+
default: 18
|
170 |
+
},
|
171 |
+
noticeDismiss: {
|
172 |
+
type: 'string',
|
173 |
+
default: '',
|
174 |
+
},
|
175 |
+
},
|
176 |
+
|
177 |
+
// Render the block components
|
178 |
+
edit: ABNoticeBlock,
|
179 |
+
|
180 |
+
// Save the attributes and markup
|
181 |
+
save: function( props ) {
|
182 |
+
|
183 |
+
// Setup the attributes
|
184 |
+
const {
|
185 |
+
noticeTitle,
|
186 |
+
noticeContent,
|
187 |
+
noticeAlignment,
|
188 |
+
noticeBackgroundColor,
|
189 |
+
noticeTextColor,
|
190 |
+
noticeTitleColor,
|
191 |
+
noticeFontSize,
|
192 |
+
noticeDismiss
|
193 |
+
} = props.attributes;
|
194 |
+
|
195 |
+
// Save the block markup for the front end
|
196 |
+
return (
|
197 |
+
<NoticeBox { ...props }>
|
198 |
+
{ noticeDismiss && !! noticeDismiss.length && (
|
199 |
+
<DismissButton { ...props }>
|
200 |
+
{ icons.dismiss }
|
201 |
+
</DismissButton>
|
202 |
+
) }
|
203 |
+
|
204 |
+
{ noticeTitle && !! noticeTitle.length && (
|
205 |
+
<div
|
206 |
+
class="ab-notice-title"
|
207 |
+
style={ {
|
208 |
+
color: noticeTitleColor
|
209 |
+
} }
|
210 |
+
>
|
211 |
+
<p>{ noticeTitle }</p>
|
212 |
+
</div>
|
213 |
+
) }
|
214 |
+
|
215 |
+
{ noticeContent && !! noticeContent.length && (
|
216 |
+
<div
|
217 |
+
class="ab-notice-text"
|
218 |
+
style={ {
|
219 |
+
borderColor: noticeBackgroundColor
|
220 |
+
} }
|
221 |
+
>
|
222 |
+
{ noticeContent }
|
223 |
+
</div>
|
224 |
+
) }
|
225 |
+
</NoticeBox>
|
226 |
+
);
|
227 |
+
},
|
228 |
+
} );
|
src/blocks/block-notice/styles/editor.scss
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-notice {
|
6 |
+
margin-bottom: 0;
|
7 |
+
}
|
8 |
+
|
9 |
+
.editor-block-list__layout [data-type="atomic-blocks/ab-notice"] {
|
10 |
+
margin-bottom: 1.2em;
|
11 |
+
}
|
src/blocks/block-notice/styles/style.scss
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Notice styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.ab-block-notice {
|
7 |
+
border-radius: 5px;
|
8 |
+
position: relative;
|
9 |
+
margin-bottom: 1.2em;
|
10 |
+
|
11 |
+
.ab-notice-dismiss {
|
12 |
+
position: absolute;
|
13 |
+
top: 13px;
|
14 |
+
right: 13px;
|
15 |
+
opacity: .8;
|
16 |
+
padding: 0;
|
17 |
+
background: none;
|
18 |
+
transition: .3s ease;
|
19 |
+
|
20 |
+
&:hover {
|
21 |
+
opacity: 1;
|
22 |
+
cursor: pointer;
|
23 |
+
box-shadow: none;
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
.ab-notice-title {
|
28 |
+
font-weight: bold;
|
29 |
+
padding: .5em 1em;
|
30 |
+
color: #fff;
|
31 |
+
border-top-right-radius: 5px;
|
32 |
+
border-top-left-radius: 5px;
|
33 |
+
width: 100%;
|
34 |
+
display: inline-block;
|
35 |
+
|
36 |
+
p {
|
37 |
+
margin-bottom: 0;
|
38 |
+
}
|
39 |
+
|
40 |
+
&:empty {
|
41 |
+
display: none;
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
.ab-notice-text {
|
46 |
+
padding: 1em;
|
47 |
+
border: solid 2px #333;
|
48 |
+
border-radius: 5px;
|
49 |
+
background: #fff;
|
50 |
+
|
51 |
+
a {
|
52 |
+
color: inherit;
|
53 |
+
box-shadow: 0 -1px 0 inset;
|
54 |
+
text-decoration: none;
|
55 |
+
|
56 |
+
&:hover {
|
57 |
+
color: inherit;
|
58 |
+
box-shadow: 0 -2px 0 inset;
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
p:last-child {
|
63 |
+
margin-bottom: 0;
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
.ab-notice-title:not(:empty) + .notice-text,
|
68 |
+
.blocks-rich-text + .blocks-rich-text .ab-notice-text {
|
69 |
+
border-top-right-radius: 0;
|
70 |
+
border-top-left-radius: 0;
|
71 |
+
border-bottom-right-radius: 5px;
|
72 |
+
border-bottom-left-radius: 5px;
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
body:not(.wp-admin) .ab-block-notice.ab-dismissable {
|
77 |
+
display: none;
|
78 |
+
}
|
src/blocks/block-post-grid/edit.js
ADDED
@@ -0,0 +1,298 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* External dependencies
|
3 |
+
*/
|
4 |
+
|
5 |
+
import get from 'lodash/get';
|
6 |
+
import isUndefined from 'lodash/isUndefined';
|
7 |
+
import pickBy from 'lodash/pickBy';
|
8 |
+
import moment from 'moment';
|
9 |
+
import classnames from 'classnames';
|
10 |
+
import { stringify } from 'querystringify';
|
11 |
+
|
12 |
+
const { Component, Fragment } = wp.element;
|
13 |
+
|
14 |
+
const { __ } = wp.i18n;
|
15 |
+
|
16 |
+
const { decodeEntities } = wp.htmlEntities;
|
17 |
+
|
18 |
+
const {
|
19 |
+
PanelBody,
|
20 |
+
Placeholder,
|
21 |
+
QueryControls,
|
22 |
+
RangeControl,
|
23 |
+
SelectControl,
|
24 |
+
Spinner,
|
25 |
+
ToggleControl,
|
26 |
+
Toolbar,
|
27 |
+
withAPIData,
|
28 |
+
} = wp.components;
|
29 |
+
|
30 |
+
const {
|
31 |
+
InspectorControls,
|
32 |
+
BlockAlignmentToolbar,
|
33 |
+
BlockControls,
|
34 |
+
} = wp.editor;
|
35 |
+
|
36 |
+
const MAX_POSTS_COLUMNS = 4;
|
37 |
+
|
38 |
+
class LatestPostsBlock extends Component {
|
39 |
+
constructor() {
|
40 |
+
super( ...arguments );
|
41 |
+
|
42 |
+
this.toggleDisplayPostDate = this.toggleDisplayPostDate.bind( this );
|
43 |
+
this.toggleDisplayPostExcerpt = this.toggleDisplayPostExcerpt.bind( this );
|
44 |
+
this.toggleDisplayPostAuthor = this.toggleDisplayPostAuthor.bind( this );
|
45 |
+
this.toggleDisplayPostImage = this.toggleDisplayPostImage.bind( this );
|
46 |
+
this.toggleDisplayPostLink = this.toggleDisplayPostLink.bind( this );
|
47 |
+
}
|
48 |
+
|
49 |
+
toggleDisplayPostDate() {
|
50 |
+
const { displayPostDate } = this.props.attributes;
|
51 |
+
const { setAttributes } = this.props;
|
52 |
+
|
53 |
+
setAttributes( { displayPostDate: ! displayPostDate } );
|
54 |
+
}
|
55 |
+
|
56 |
+
toggleDisplayPostExcerpt() {
|
57 |
+
const { displayPostExcerpt } = this.props.attributes;
|
58 |
+
const { setAttributes } = this.props;
|
59 |
+
|
60 |
+
setAttributes( { displayPostExcerpt: ! displayPostExcerpt } );
|
61 |
+
}
|
62 |
+
|
63 |
+
toggleDisplayPostAuthor() {
|
64 |
+
const { displayPostAuthor } = this.props.attributes;
|
65 |
+
const { setAttributes } = this.props;
|
66 |
+
|
67 |
+
setAttributes( { displayPostAuthor: ! displayPostAuthor } );
|
68 |
+
}
|
69 |
+
|
70 |
+
toggleDisplayPostImage() {
|
71 |
+
const { displayPostImage } = this.props.attributes;
|
72 |
+
const { setAttributes } = this.props;
|
73 |
+
|
74 |
+
setAttributes( { displayPostImage: ! displayPostImage } );
|
75 |
+
}
|
76 |
+
|
77 |
+
toggleDisplayPostLink() {
|
78 |
+
const { displayPostLink } = this.props.attributes;
|
79 |
+
const { setAttributes } = this.props;
|
80 |
+
|
81 |
+
setAttributes( { displayPostLink: ! displayPostLink } );
|
82 |
+
}
|
83 |
+
|
84 |
+
render() {
|
85 |
+
const latestPosts = this.props.latestPosts.data;
|
86 |
+
const { attributes, categoriesList, setAttributes } = this.props;
|
87 |
+
const { displayPostDate, displayPostExcerpt, displayPostAuthor, displayPostImage,displayPostLink, align, postLayout, columns, order, orderBy, categories, postsToShow, width, imageCrop } = attributes;
|
88 |
+
|
89 |
+
// Thumbnail options
|
90 |
+
const imageCropOptions = [
|
91 |
+
{ value: 'landscape', label: __( 'Landscape' ) },
|
92 |
+
{ value: 'square', label: __( 'Square' ) },
|
93 |
+
];
|
94 |
+
|
95 |
+
const isLandscape = imageCrop === 'landscape';
|
96 |
+
|
97 |
+
const inspectorControls = (
|
98 |
+
<InspectorControls>
|
99 |
+
<PanelBody title={ __( 'Post Grid Settings' ) }>
|
100 |
+
<QueryControls
|
101 |
+
{ ...{ order, orderBy } }
|
102 |
+
numberOfItems={ postsToShow }
|
103 |
+
categoriesList={ get( categoriesList, [ 'data' ], {} ) }
|
104 |
+
selectedCategoryId={ categories }
|
105 |
+
onOrderChange={ ( value ) => setAttributes( { order: value } ) }
|
106 |
+
onOrderByChange={ ( value ) => setAttributes( { orderBy: value } ) }
|
107 |
+
onCategoryChange={ ( value ) => setAttributes( { categories: '' !== value ? value : undefined } ) }
|
108 |
+
onNumberOfItemsChange={ ( value ) => setAttributes( { postsToShow: value } ) }
|
109 |
+
/>
|
110 |
+
{ postLayout === 'grid' &&
|
111 |
+
<RangeControl
|
112 |
+
label={ __( 'Columns' ) }
|
113 |
+
value={ columns }
|
114 |
+
onChange={ ( value ) => setAttributes( { columns: value } ) }
|
115 |
+
min={ 2 }
|
116 |
+
max={ ! hasPosts ? MAX_POSTS_COLUMNS : Math.min( MAX_POSTS_COLUMNS, latestPosts.length ) }
|
117 |
+
/>
|
118 |
+
}
|
119 |
+
<ToggleControl
|
120 |
+
label={ __( 'Display Featured Image' ) }
|
121 |
+
checked={ displayPostImage }
|
122 |
+
onChange={ this.toggleDisplayPostImage }
|
123 |
+
/>
|
124 |
+
{ displayPostImage &&
|
125 |
+
<SelectControl
|
126 |
+
label={ __( 'Featured Image Style' ) }
|
127 |
+
options={ imageCropOptions }
|
128 |
+
value={ imageCrop }
|
129 |
+
onChange={ ( value ) => this.props.setAttributes( { imageCrop: value } ) }
|
130 |
+
/>
|
131 |
+
}
|
132 |
+
<ToggleControl
|
133 |
+
label={ __( 'Display Post Author' ) }
|
134 |
+
checked={ displayPostAuthor }
|
135 |
+
onChange={ this.toggleDisplayPostAuthor }
|
136 |
+
/>
|
137 |
+
<ToggleControl
|
138 |
+
label={ __( 'Display Post Date' ) }
|
139 |
+
checked={ displayPostDate }
|
140 |
+
onChange={ this.toggleDisplayPostDate }
|
141 |
+
/>
|
142 |
+
<ToggleControl
|
143 |
+
label={ __( 'Display Post Excerpt' ) }
|
144 |
+
checked={ displayPostExcerpt }
|
145 |
+
onChange={ this.toggleDisplayPostExcerpt }
|
146 |
+
/>
|
147 |
+
<ToggleControl
|
148 |
+
label={ __( 'Display Continue Reading Link' ) }
|
149 |
+
checked={ displayPostLink }
|
150 |
+
onChange={ this.toggleDisplayPostLink }
|
151 |
+
/>
|
152 |
+
|
153 |
+
</PanelBody>
|
154 |
+
</InspectorControls>
|
155 |
+
);
|
156 |
+
|
157 |
+
const hasPosts = Array.isArray( latestPosts ) && latestPosts.length;
|
158 |
+
if ( ! hasPosts ) {
|
159 |
+
return (
|
160 |
+
<Fragment>
|
161 |
+
{ inspectorControls }
|
162 |
+
<Placeholder
|
163 |
+
icon="admin-post"
|
164 |
+
label={ __( 'Atomic Blocks Post Grid' ) }
|
165 |
+
>
|
166 |
+
{ ! Array.isArray( latestPosts ) ?
|
167 |
+
<Spinner /> :
|
168 |
+
__( 'No posts found.' )
|
169 |
+
}
|
170 |
+
</Placeholder>
|
171 |
+
</Fragment>
|
172 |
+
);
|
173 |
+
}
|
174 |
+
|
175 |
+
// Removing posts from display should be instant.
|
176 |
+
const displayPosts = latestPosts.length > postsToShow ?
|
177 |
+
latestPosts.slice( 0, postsToShow ) :
|
178 |
+
latestPosts;
|
179 |
+
|
180 |
+
const layoutControls = [
|
181 |
+
{
|
182 |
+
icon: 'grid-view',
|
183 |
+
title: __( 'Grid View' ),
|
184 |
+
onClick: () => setAttributes( { postLayout: 'grid' } ),
|
185 |
+
isActive: postLayout === 'grid',
|
186 |
+
},
|
187 |
+
{
|
188 |
+
icon: 'list-view',
|
189 |
+
title: __( 'List View' ),
|
190 |
+
onClick: () => setAttributes( { postLayout: 'list' } ),
|
191 |
+
isActive: postLayout === 'list',
|
192 |
+
},
|
193 |
+
];
|
194 |
+
|
195 |
+
return (
|
196 |
+
<Fragment>
|
197 |
+
{ inspectorControls }
|
198 |
+
<BlockControls>
|
199 |
+
<BlockAlignmentToolbar
|
200 |
+
value={ align }
|
201 |
+
onChange={ ( value ) => {
|
202 |
+
setAttributes( { align: value } );
|
203 |
+
} }
|
204 |
+
controls={ [ 'center', 'wide' ] }
|
205 |
+
/>
|
206 |
+
<Toolbar controls={ layoutControls } />
|
207 |
+
</BlockControls>
|
208 |
+
<div
|
209 |
+
className={ classnames(
|
210 |
+
this.props.className,
|
211 |
+
'ab-block-post-grid',
|
212 |
+
) }
|
213 |
+
>
|
214 |
+
<div
|
215 |
+
className={ classnames( {
|
216 |
+
'is-grid': postLayout === 'grid',
|
217 |
+
'is-list': postLayout === 'list',
|
218 |
+
[ `columns-${ columns }` ]: postLayout === 'grid',
|
219 |
+
'ab-post-grid-items' : 'ab-post-grid-items'
|
220 |
+
} ) }
|
221 |
+
>
|
222 |
+
{ displayPosts.map( ( post, i ) =>
|
223 |
+
<article
|
224 |
+
key={ i }
|
225 |
+
className={ classnames(
|
226 |
+
post.featured_image_src && displayPostImage ? 'has-thumb' : 'no-thumb'
|
227 |
+
) }
|
228 |
+
>
|
229 |
+
{
|
230 |
+
displayPostImage && post.featured_image_src !== undefined && post.featured_image_src ? (
|
231 |
+
<div class="ab-block-post-grid-image">
|
232 |
+
<a href={ post.link } target="_blank" rel="bookmark">
|
233 |
+
<img
|
234 |
+
src={ isLandscape ? post.featured_image_src : post.featured_image_src_square }
|
235 |
+
alt={ decodeEntities( post.title.rendered.trim() ) || __( '(Untitled)' ) }
|
236 |
+
/>
|
237 |
+
</a>
|
238 |
+
</div>
|
239 |
+
) : (
|
240 |
+
null
|
241 |
+
)
|
242 |
+
}
|
243 |
+
|
244 |
+
{ console.log(post) }
|
245 |
+
|
246 |
+
<div class="ab-block-post-grid-text">
|
247 |
+
<h2 class="entry-title"><a href={ post.link } target="_blank" rel="bookmark">{ decodeEntities( post.title.rendered.trim() ) || __( '(Untitled)' ) }</a></h2>
|
248 |
+
|
249 |
+
<div class="ab-block-post-grid-byline">
|
250 |
+
{ displayPostAuthor && post.author_info.display_name &&
|
251 |
+
<div class="ab-block-post-grid-author"><a class="ab-text-link" target="_blank" href={ post.author_info.author_link }>{ post.author_info.display_name }</a></div>
|
252 |
+
}
|
253 |
+
|
254 |
+
{ displayPostDate && post.date_gmt &&
|
255 |
+
<time dateTime={ moment( post.date_gmt ).utc().format() } className={ 'ab-block-post-grid-date' }>
|
256 |
+
{ moment( post.date_gmt ).local().format( 'MMMM DD, Y' ) }
|
257 |
+
</time>
|
258 |
+
}
|
259 |
+
</div>
|
260 |
+
|
261 |
+
<div class="ab-block-post-grid-excerpt">
|
262 |
+
{ displayPostExcerpt && post.excerpt &&
|
263 |
+
<div dangerouslySetInnerHTML={ { __html: post.excerpt.rendered } } />
|
264 |
+
}
|
265 |
+
|
266 |
+
{ displayPostLink &&
|
267 |
+
<p><a class="ab-block-post-grid-link ab-text-link" href={ post.link } target="_blank" rel="bookmark">{ __( 'Continue Reading', 'atomic-blocks' ) }</a></p>
|
268 |
+
}
|
269 |
+
</div>
|
270 |
+
</div>
|
271 |
+
</article>
|
272 |
+
) }
|
273 |
+
</div>
|
274 |
+
</div>
|
275 |
+
</Fragment>
|
276 |
+
);
|
277 |
+
}
|
278 |
+
}
|
279 |
+
|
280 |
+
export default withAPIData( ( props ) => {
|
281 |
+
const { postsToShow, order, orderBy, categories } = props.attributes;
|
282 |
+
const latestPostsQuery = stringify( pickBy( {
|
283 |
+
categories,
|
284 |
+
order,
|
285 |
+
orderby: orderBy,
|
286 |
+
per_page: postsToShow,
|
287 |
+
_fields: [ 'date_gmt', 'link', 'title', 'featured_media', 'featured_image_src', 'featured_image_src_square', 'excerpt', 'author_info' ],
|
288 |
+
_embed: 'embed',
|
289 |
+
}, ( value ) => ! isUndefined( value ) ) );
|
290 |
+
const categoriesListQuery = stringify( {
|
291 |
+
per_page: 100,
|
292 |
+
_fields: [ 'id', 'name', 'parent' ],
|
293 |
+
} );
|
294 |
+
return {
|
295 |
+
latestPosts: `/wp/v2/posts?${ latestPostsQuery }`,
|
296 |
+
categoriesList: `/wp/v2/categories?${ categoriesListQuery }`,
|
297 |
+
};
|
298 |
+
} )( LatestPostsBlock );
|
src/blocks/block-post-grid/index.js
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Page Grid
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import edit from './edit';
|
8 |
+
|
9 |
+
// Import CSS
|
10 |
+
import './styles/style.scss';
|
11 |
+
import './styles/editor.scss';
|
12 |
+
|
13 |
+
// Components
|
14 |
+
const { __ } = wp.i18n;
|
15 |
+
|
16 |
+
// Extend component
|
17 |
+
const { Component } = wp.element;
|
18 |
+
|
19 |
+
// Register block controls
|
20 |
+
const {
|
21 |
+
registerBlockType,
|
22 |
+
} = wp.blocks;
|
23 |
+
|
24 |
+
// Register alignments
|
25 |
+
const validAlignments = [ 'center', 'wide' ];
|
26 |
+
|
27 |
+
export const name = 'core/latest-posts';
|
28 |
+
|
29 |
+
// Register the block
|
30 |
+
registerBlockType( 'atomic-blocks/ab-post-grid', {
|
31 |
+
title: __( 'AB Post Grid' ),
|
32 |
+
description: __( 'Add a grid or list of customizable posts to your page.' ),
|
33 |
+
icon: 'grid-view',
|
34 |
+
category: 'atomic-blocks',
|
35 |
+
keywords: [
|
36 |
+
__( 'post' ),
|
37 |
+
__( 'grid' ),
|
38 |
+
__( 'atomic' ),
|
39 |
+
],
|
40 |
+
|
41 |
+
getEditWrapperProps( attributes ) {
|
42 |
+
const { align } = attributes;
|
43 |
+
if ( -1 !== validAlignments.indexOf( align ) ) {
|
44 |
+
return { 'data-align': align };
|
45 |
+
}
|
46 |
+
},
|
47 |
+
|
48 |
+
edit,
|
49 |
+
|
50 |
+
// Render via PHP
|
51 |
+
save() {
|
52 |
+
return null;
|
53 |
+
},
|
54 |
+
} );
|
src/blocks/block-post-grid/styles/editor.scss
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-post-grid {
|
6 |
+
h2 a {
|
7 |
+
text-decoration: none;
|
8 |
+
}
|
9 |
+
}
|
10 |
+
|
11 |
+
div[data-type="atomic-blocks/ab-post-grid"] .editor-block-list__block-edit:before {
|
12 |
+
|
13 |
+
}
|
14 |
+
|
src/blocks/block-post-grid/styles/style.scss
ADDED
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Post grid styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.ab-block-post-grid {
|
7 |
+
margin: 0 0 1.2em 0;
|
8 |
+
position: relative;
|
9 |
+
|
10 |
+
.is-grid {
|
11 |
+
display: grid;
|
12 |
+
grid-template-columns: 1fr 1fr;
|
13 |
+
grid-template-rows: 1fr;
|
14 |
+
grid-gap: 0 2em;
|
15 |
+
|
16 |
+
article {
|
17 |
+
margin-bottom: 2.5em;
|
18 |
+
}
|
19 |
+
}
|
20 |
+
|
21 |
+
.is-grid.columns-2 {
|
22 |
+
grid-template-columns: 1fr 1fr;
|
23 |
+
}
|
24 |
+
|
25 |
+
.is-grid.columns-3 {
|
26 |
+
grid-template-columns: 1fr 1fr 1fr;
|
27 |
+
}
|
28 |
+
|
29 |
+
.is-grid.columns-4 {
|
30 |
+
grid-template-columns: 1fr 1fr 1fr 1fr;
|
31 |
+
}
|
32 |
+
|
33 |
+
div[class*="columns"].is-grid {
|
34 |
+
@media only screen and (max-width: 600px) {
|
35 |
+
grid-template-columns: 1fr;
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
.ab-block-post-grid-image {
|
40 |
+
margin-bottom: 1.2em;
|
41 |
+
|
42 |
+
img {
|
43 |
+
display: block;
|
44 |
+
width: 100%;
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
.ab-block-post-grid-text {
|
49 |
+
text-align: left;
|
50 |
+
}
|
51 |
+
|
52 |
+
h2 {
|
53 |
+
margin-top: 0;
|
54 |
+
margin-bottom: 15px;
|
55 |
+
font-size: 28px;
|
56 |
+
line-height: 1.2;
|
57 |
+
|
58 |
+
a {
|
59 |
+
color: $black;
|
60 |
+
box-shadow: none;
|
61 |
+
transition: .3s ease;
|
62 |
+
|
63 |
+
&:hover {
|
64 |
+
box-shadow: inset 0 -2px 0 $accent;
|
65 |
+
color: $accent;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
.ab-block-post-grid-byline {
|
71 |
+
text-transform: uppercase;
|
72 |
+
font-size: 13px;
|
73 |
+
letter-spacing: 1px;
|
74 |
+
color: $lightgray;
|
75 |
+
margin-bottom: 15px;
|
76 |
+
}
|
77 |
+
|
78 |
+
.ab-block-post-grid-author,
|
79 |
+
.ab-block-post-grid-date {
|
80 |
+
display: inline-block;
|
81 |
+
|
82 |
+
&:not(:last-child):after {
|
83 |
+
content: "\B7";
|
84 |
+
vertical-align: middle;
|
85 |
+
margin: 0 5px;
|
86 |
+
line-height: 1;
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
.ab-block-post-grid-author a {
|
91 |
+
box-shadow: none;
|
92 |
+
|
93 |
+
&:hover {
|
94 |
+
color: inherit;
|
95 |
+
box-shadow: 0 -1px 0 inset;
|
96 |
+
color: $accent;
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
.ab-block-post-grid-text p {
|
101 |
+
margin: 0 0 15px 0;
|
102 |
+
line-height: 1.5;
|
103 |
+
font-size: 18px;
|
104 |
+
|
105 |
+
@media only screen and (max-width: 600px) {
|
106 |
+
font-size: 16px;
|
107 |
+
}
|
108 |
+
|
109 |
+
&:last-of-type {
|
110 |
+
margin-bottom: 0;
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
.ab-block-post-grid-link {
|
115 |
+
display: inline-block;
|
116 |
+
box-shadow: none;
|
117 |
+
transition: .3s ease;
|
118 |
+
font-weight: bold;
|
119 |
+
color: $black;
|
120 |
+
|
121 |
+
&:hover {
|
122 |
+
box-shadow: 0 -2px 0 inset;
|
123 |
+
}
|
124 |
+
}
|
125 |
+
|
126 |
+
.ab-block-post-grid-excerpt div + p {
|
127 |
+
margin-top: 15px;
|
128 |
+
}
|
129 |
+
|
130 |
+
.is-list {
|
131 |
+
article {
|
132 |
+
display: grid;
|
133 |
+
grid-template-columns: 30% 1fr;
|
134 |
+
grid-template-rows: 1fr;
|
135 |
+
grid-gap: 0 2em;
|
136 |
+
|
137 |
+
&:not(:last-child) {
|
138 |
+
margin-bottom: 5%;
|
139 |
+
padding-bottom: 5%;
|
140 |
+
}
|
141 |
+
|
142 |
+
@media only screen and (min-width: 600px) {
|
143 |
+
&:not(:last-child) {
|
144 |
+
border-bottom: solid 1px #eee;
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
@media only screen and (max-width: 600px) {
|
149 |
+
grid-template-columns: 1fr;
|
150 |
+
}
|
151 |
+
}
|
152 |
+
|
153 |
+
.ab-block-post-grid-image {
|
154 |
+
margin-bottom: 0;
|
155 |
+
|
156 |
+
@media only screen and (max-width: 600px) {
|
157 |
+
margin-bottom: 5%;
|
158 |
+
}
|
159 |
+
}
|
160 |
+
|
161 |
+
.ab-block-post-grid-title {
|
162 |
+
@media only screen and (min-width: 600px) {
|
163 |
+
font-size: 34px;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
.no-thumb .ab-block-post-grid-text {
|
168 |
+
grid-column: span 2;
|
169 |
+
}
|
170 |
+
}
|
171 |
+
}
|
src/blocks/block-sharing/components/inspector.js
ADDED
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
InspectorControls,
|
12 |
+
BlockDescription,
|
13 |
+
ColorPalette,
|
14 |
+
} = wp.editor;
|
15 |
+
|
16 |
+
// Import Inspector components
|
17 |
+
const {
|
18 |
+
Toolbar,
|
19 |
+
Button,
|
20 |
+
PanelBody,
|
21 |
+
PanelRow,
|
22 |
+
PanelColor,
|
23 |
+
FormToggle,
|
24 |
+
RangeControl,
|
25 |
+
SelectControl,
|
26 |
+
ToggleControl,
|
27 |
+
} = wp.components;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Create an Inspector Controls wrapper Component
|
31 |
+
*/
|
32 |
+
export default class Inspector extends Component {
|
33 |
+
|
34 |
+
constructor( props ) {
|
35 |
+
super( ...arguments );
|
36 |
+
}
|
37 |
+
|
38 |
+
render() {
|
39 |
+
|
40 |
+
// Setup the attributes
|
41 |
+
const {
|
42 |
+
twitter,
|
43 |
+
facebook,
|
44 |
+
google,
|
45 |
+
linkedin,
|
46 |
+
pinterest,
|
47 |
+
email,
|
48 |
+
reddit,
|
49 |
+
shareAlignment,
|
50 |
+
shareButtonStyle,
|
51 |
+
shareButtonShape,
|
52 |
+
shareButtonSize,
|
53 |
+
shareButtonColor,
|
54 |
+
} = this.props.attributes;
|
55 |
+
|
56 |
+
// Button style values
|
57 |
+
const buttonStyleOptions = [
|
58 |
+
{ value: 'ab-share-icon-text', label: __( 'Icon and Text' ) },
|
59 |
+
{ value: 'ab-share-icon-only', label: __( 'Icon Only' ) },
|
60 |
+
{ value: 'ab-share-text-only', label: __( 'Text Only' ) },
|
61 |
+
];
|
62 |
+
|
63 |
+
// Button shape values
|
64 |
+
const buttonShapeOptions = [
|
65 |
+
{ value: 'ab-share-shape-square', label: __( 'Square' ) },
|
66 |
+
{ value: 'ab-share-shape-rounded', label: __( 'Rounded Square' ) },
|
67 |
+
{ value: 'ab-share-shape-circular', label: __( 'Circular' ) },
|
68 |
+
];
|
69 |
+
|
70 |
+
// Button size values
|
71 |
+
const shareButtonSizeOptions = [
|
72 |
+
{ value: 'ab-share-size-small', label: __( 'Small' ) },
|
73 |
+
{ value: 'ab-share-size-medium', label: __( 'Medium' ) },
|
74 |
+
{ value: 'ab-share-size-large', label: __( 'Large' ) },
|
75 |
+
];
|
76 |
+
|
77 |
+
// Button color values
|
78 |
+
const shareButtonColorOptions = [
|
79 |
+
{ value: 'ab-share-color-standard', label: __( 'Standard' ) },
|
80 |
+
{ value: 'ab-share-color-social', label: __( 'Social Colors' ) },
|
81 |
+
];
|
82 |
+
|
83 |
+
return (
|
84 |
+
<InspectorControls key="inspector">
|
85 |
+
<PanelBody>
|
86 |
+
<p>{ __( 'Enable or disable the sharing links you want to output.' ) }</p>
|
87 |
+
|
88 |
+
<ToggleControl
|
89 |
+
label={ __( 'Twitter' ) }
|
90 |
+
checked={ !! twitter }
|
91 |
+
onChange={ () => this.props.setAttributes( { twitter: ! twitter } ) }
|
92 |
+
/>
|
93 |
+
<ToggleControl
|
94 |
+
label={ __( 'Facebook' ) }
|
95 |
+
checked={ !! facebook }
|
96 |
+
onChange={ () => this.props.setAttributes( { facebook: ! facebook } ) }
|
97 |
+
/>
|
98 |
+
<ToggleControl
|
99 |
+
label={ __( 'Google' ) }
|
100 |
+
checked={ !! google }
|
101 |
+
onChange={ () => this.props.setAttributes( { google: ! google } ) }
|
102 |
+
/>
|
103 |
+
<ToggleControl
|
104 |
+
label={ __( 'Pinterest' ) }
|
105 |
+
checked={ !! pinterest }
|
106 |
+
onChange={ () => this.props.setAttributes( { pinterest: ! pinterest } ) }
|
107 |
+
/>
|
108 |
+
<ToggleControl
|
109 |
+
label={ __( 'LinkedIn' ) }
|
110 |
+
checked={ !! linkedin }
|
111 |
+
onChange={ () => this.props.setAttributes( { linkedin: ! linkedin } ) }
|
112 |
+
/>
|
113 |
+
<ToggleControl
|
114 |
+
label={ __( 'Reddit' ) }
|
115 |
+
checked={ !! reddit }
|
116 |
+
onChange={ () => this.props.setAttributes( { reddit: ! reddit } ) }
|
117 |
+
/>
|
118 |
+
<ToggleControl
|
119 |
+
label={ __( 'Email' ) }
|
120 |
+
checked={ !! email }
|
121 |
+
onChange={ () => this.props.setAttributes( { email: ! email } ) }
|
122 |
+
/>
|
123 |
+
</PanelBody>
|
124 |
+
|
125 |
+
<PanelBody title={ __( 'Sharing Button Options' ) } initialOpen={ false }>
|
126 |
+
<SelectControl
|
127 |
+
label={ __( 'Button Style' ) }
|
128 |
+
value={ shareButtonStyle }
|
129 |
+
options={ buttonStyleOptions.map( ({ value, label }) => ( {
|
130 |
+
value: value,
|
131 |
+
label: label,
|
132 |
+
} ) ) }
|
133 |
+
onChange={ ( value ) => { this.props.setAttributes( { shareButtonStyle: value } ) } }
|
134 |
+
/>
|
135 |
+
|
136 |
+
<SelectControl
|
137 |
+
label={ __( 'Button Shape' ) }
|
138 |
+
value={ shareButtonShape }
|
139 |
+
options={ buttonShapeOptions.map( ({ value, label }) => ( {
|
140 |
+
value: value,
|
141 |
+
label: label,
|
142 |
+
} ) ) }
|
143 |
+
onChange={ ( value ) => { this.props.setAttributes( { shareButtonShape: value } ) } }
|
144 |
+
/>
|
145 |
+
|
146 |
+
<SelectControl
|
147 |
+
label={ __( 'Button Size' ) }
|
148 |
+
value={ shareButtonSize }
|
149 |
+
options={ shareButtonSizeOptions.map( ({ value, label }) => ( {
|
150 |
+
value: value,
|
151 |
+
label: label,
|
152 |
+
} ) ) }
|
153 |
+
onChange={ ( value ) => { this.props.setAttributes( { shareButtonSize: value } ) } }
|
154 |
+
/>
|
155 |
+
|
156 |
+
<SelectControl
|
157 |
+
label={ __( 'Button Color' ) }
|
158 |
+
value={ shareButtonColor }
|
159 |
+
options={ shareButtonColorOptions.map( ({ value, label }) => ( {
|
160 |
+
value: value,
|
161 |
+
label: label,
|
162 |
+
} ) ) }
|
163 |
+
onChange={ ( value ) => { this.props.setAttributes( { shareButtonColor: value } ) } }
|
164 |
+
/>
|
165 |
+
</PanelBody>
|
166 |
+
</InspectorControls>
|
167 |
+
);
|
168 |
+
}
|
169 |
+
}
|
src/blocks/block-sharing/components/sharing.js
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Sharing Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Create a ShareLinks wrapper Component
|
13 |
+
*/
|
14 |
+
export default class ShareLinks extends Component {
|
15 |
+
|
16 |
+
constructor( props ) {
|
17 |
+
super( ...arguments );
|
18 |
+
}
|
19 |
+
|
20 |
+
render() {
|
21 |
+
|
22 |
+
return (
|
23 |
+
<div
|
24 |
+
className={ classnames(
|
25 |
+
this.props.className,
|
26 |
+
this.props.attributes.shareButtonStyle,
|
27 |
+
this.props.attributes.shareButtonShape,
|
28 |
+
this.props.attributes.shareButtonSize,
|
29 |
+
this.props.attributes.shareButtonColor,
|
30 |
+
this.props.attributes.shareAlignment,
|
31 |
+
'ab-block-sharing'
|
32 |
+
) }
|
33 |
+
>
|
34 |
+
{ this.props.children }
|
35 |
+
</div>
|
36 |
+
);
|
37 |
+
}
|
38 |
+
}
|
src/blocks/block-sharing/index.js
ADDED
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Sharing
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import ShareLinks from './components/sharing';
|
9 |
+
|
10 |
+
// Import CSS
|
11 |
+
import './styles/style.scss';
|
12 |
+
import './styles/editor.scss';
|
13 |
+
|
14 |
+
// Components
|
15 |
+
const { __ } = wp.i18n;
|
16 |
+
|
17 |
+
// Extend component
|
18 |
+
const { Component } = wp.element;
|
19 |
+
|
20 |
+
// Register block
|
21 |
+
const { registerBlockType } = wp.blocks;
|
22 |
+
|
23 |
+
// Register editor components
|
24 |
+
const {
|
25 |
+
RichText,
|
26 |
+
AlignmentToolbar,
|
27 |
+
BlockControls,
|
28 |
+
BlockAlignmentToolbar,
|
29 |
+
} = wp.editor;
|
30 |
+
|
31 |
+
// Register components
|
32 |
+
const {
|
33 |
+
Button,
|
34 |
+
withFallbackStyles,
|
35 |
+
IconButton,
|
36 |
+
Dashicon,
|
37 |
+
} = wp.components;
|
38 |
+
|
39 |
+
// Register the block
|
40 |
+
registerBlockType( 'atomic-blocks/ab-sharing', {
|
41 |
+
title: __( 'AB Sharing' ),
|
42 |
+
description: __( 'Add sharing buttons to your posts and pages.' ),
|
43 |
+
icon: 'admin-links',
|
44 |
+
category: 'atomic-blocks',
|
45 |
+
keywords: [
|
46 |
+
__( 'sharing' ),
|
47 |
+
__( 'social' ),
|
48 |
+
__( 'atomic' ),
|
49 |
+
],
|
50 |
+
|
51 |
+
// Render the block components
|
52 |
+
edit: props => {
|
53 |
+
|
54 |
+
// Setup the props
|
55 |
+
const {
|
56 |
+
attributes,
|
57 |
+
isSelected,
|
58 |
+
editable,
|
59 |
+
className,
|
60 |
+
setAttributes
|
61 |
+
} = props;
|
62 |
+
|
63 |
+
const {
|
64 |
+
twitter,
|
65 |
+
facebook,
|
66 |
+
google,
|
67 |
+
linkedin,
|
68 |
+
pinterest,
|
69 |
+
email,
|
70 |
+
reddit,
|
71 |
+
shareAlignment,
|
72 |
+
shareButtonStyle,
|
73 |
+
shareButtonShape,
|
74 |
+
shareButtonColor,
|
75 |
+
} = props.attributes;
|
76 |
+
|
77 |
+
return [
|
78 |
+
// Show the alignment toolbar on focus
|
79 |
+
<BlockControls key="controls">
|
80 |
+
<AlignmentToolbar
|
81 |
+
value={ shareAlignment }
|
82 |
+
onChange={ ( value ) => {
|
83 |
+
setAttributes( { shareAlignment: value } );
|
84 |
+
} }
|
85 |
+
/>
|
86 |
+
</BlockControls>,
|
87 |
+
// Show the block controls on focus
|
88 |
+
<Inspector
|
89 |
+
{ ...props }
|
90 |
+
/>,
|
91 |
+
// Show the button markup in the editor
|
92 |
+
<ShareLinks { ...props }>
|
93 |
+
<ul class="ab-share-list">
|
94 |
+
{ twitter &&
|
95 |
+
<li>
|
96 |
+
<a className='ab-share-twitter'>
|
97 |
+
<i class="fab fa-twitter"></i>
|
98 |
+
<span className={ 'ab-social-text' }>
|
99 |
+
{ __( 'Share on Twitter' ) }
|
100 |
+
</span>
|
101 |
+
</a>
|
102 |
+
</li>
|
103 |
+
}
|
104 |
+
|
105 |
+
{ facebook &&
|
106 |
+
<li>
|
107 |
+
<a className='ab-share-facebook'>
|
108 |
+
<i class="fab fa-facebook-f"></i>
|
109 |
+
<span className={ 'ab-social-text' }>
|
110 |
+
{ __( 'Share on Facebook' ) }
|
111 |
+
</span>
|
112 |
+
</a>
|
113 |
+
</li>
|
114 |
+
}
|
115 |
+
|
116 |
+
{ google &&
|
117 |
+
<li>
|
118 |
+
<a className='ab-share-google'>
|
119 |
+
<i class="fab fa-google"></i>
|
120 |
+
<span className={ 'ab-social-text' }>
|
121 |
+
{ __( 'Share on Google' ) }
|
122 |
+
</span>
|
123 |
+
</a>
|
124 |
+
</li>
|
125 |
+
}
|
126 |
+
|
127 |
+
{ pinterest &&
|
128 |
+
<li>
|
129 |
+
<a className='ab-share-pinterest'>
|
130 |
+
<i class="fab fa-pinterest-p"></i>
|
131 |
+
<span className={ 'ab-social-text' }>
|
132 |
+
{ __( 'Share on Pinterest' ) }
|
133 |
+
</span>
|
134 |
+
</a>
|
135 |
+
</li>
|
136 |
+
}
|
137 |
+
|
138 |
+
{ linkedin &&
|
139 |
+
<li>
|
140 |
+
<a className='ab-share-linkedin'>
|
141 |
+
<i class="fab fa-linkedin"></i>
|
142 |
+
<span className={ 'ab-social-text' }>
|
143 |
+
{ __( 'Share on LinkedIn' ) }
|
144 |
+
</span>
|
145 |
+
</a>
|
146 |
+
</li>
|
147 |
+
}
|
148 |
+
|
149 |
+
{ reddit &&
|
150 |
+
<li>
|
151 |
+
<a className='ab-share-reddit'>
|
152 |
+
<i class="fab fa-reddit-alien"></i>
|
153 |
+
<span className={ 'ab-social-text' }>
|
154 |
+
{ __( 'Share on reddit' ) }
|
155 |
+
</span>
|
156 |
+
</a>
|
157 |
+
</li>
|
158 |
+
}
|
159 |
+
|
160 |
+
{ email &&
|
161 |
+
<li>
|
162 |
+
<a className='ab-share-email'>
|
163 |
+
<i class="fas fa-envelope"></i>
|
164 |
+
<span className={ 'ab-social-text' }>
|
165 |
+
{ __( 'Share via Email' ) }
|
166 |
+
</span>
|
167 |
+
</a>
|
168 |
+
</li>
|
169 |
+
}
|
170 |
+
</ul>
|
171 |
+
</ShareLinks>
|
172 |
+
];
|
173 |
+
},
|
174 |
+
|
175 |
+
// Render via PHP
|
176 |
+
save() {
|
177 |
+
return null;
|
178 |
+
},
|
179 |
+
} );
|
src/blocks/block-sharing/styles/editor.scss
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-sharing {
|
6 |
+
margin-bottom: 0;
|
7 |
+
}
|
src/blocks/block-sharing/styles/style.scss
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Sharing styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.ab-block-sharing {
|
7 |
+
margin: 0 0 1.2em 0;
|
8 |
+
position: relative;
|
9 |
+
|
10 |
+
.blocks-rich-text {
|
11 |
+
display: inline-flex;
|
12 |
+
}
|
13 |
+
|
14 |
+
.ab-share-list {
|
15 |
+
margin: 0;
|
16 |
+
padding: 0;
|
17 |
+
|
18 |
+
li {
|
19 |
+
list-style: none;
|
20 |
+
display: inline-block;
|
21 |
+
margin: 0 5px 5px 0;
|
22 |
+
}
|
23 |
+
|
24 |
+
a {
|
25 |
+
background: #272c30;
|
26 |
+
color: #fff;
|
27 |
+
padding: 10px 15px;
|
28 |
+
text-align: center;
|
29 |
+
display: block;
|
30 |
+
line-height: 1;
|
31 |
+
font-size: 16px;
|
32 |
+
transition: .3s ease;
|
33 |
+
|
34 |
+
&:hover {
|
35 |
+
box-shadow: inset 0 0 200px rgba(255, 255, 255, 0.15);
|
36 |
+
}
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
&.ab-share-icon-text {
|
41 |
+
i {
|
42 |
+
margin-right: 5px;
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
&.ab-share-icon-only {
|
47 |
+
a {
|
48 |
+
padding: 10px 11px;
|
49 |
+
min-width: 37px;
|
50 |
+
}
|
51 |
+
|
52 |
+
.ab-social-text {
|
53 |
+
border: 0;
|
54 |
+
clip: rect(1px, 1px, 1px, 1px);
|
55 |
+
clip-path: inset(50%);
|
56 |
+
height: 1px;
|
57 |
+
margin: -1px;
|
58 |
+
overflow: hidden;
|
59 |
+
padding: 0;
|
60 |
+
position: absolute !important;
|
61 |
+
width: 1px;
|
62 |
+
word-wrap: normal !important;
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
&.ab-share-text-only {
|
67 |
+
i {
|
68 |
+
display: none;
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
&.ab-share-shape-square {
|
73 |
+
a {
|
74 |
+
border-radius: 0;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
&.ab-share-shape-rounded {
|
79 |
+
a {
|
80 |
+
border-radius: 5px;
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
&.ab-share-shape-circular {
|
85 |
+
a {
|
86 |
+
border-radius: 100px;
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
&.ab-share-size-small {
|
91 |
+
a {
|
92 |
+
font-size: 13px;
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
&.ab-share-size-small.ab-share-icon-only {
|
97 |
+
a {
|
98 |
+
padding: 7px 6px;
|
99 |
+
min-width: 28px;
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
&.ab-share-size-medium {
|
104 |
+
a {
|
105 |
+
font-size: 16px;
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
&.ab-share-size-large {
|
110 |
+
a {
|
111 |
+
font-size: 20px;
|
112 |
+
}
|
113 |
+
}
|
114 |
+
|
115 |
+
&.ab-share-size-large.ab-share-icon-only {
|
116 |
+
a {
|
117 |
+
font-size: 26px;
|
118 |
+
min-width: 48px;
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
&.ab-share-size-large.ab-share-icon-text {
|
123 |
+
i {
|
124 |
+
margin-right: 10px;
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
&.ab-share-color-social {
|
129 |
+
a {
|
130 |
+
color: #fff;
|
131 |
+
}
|
132 |
+
|
133 |
+
.ab-share-twitter {
|
134 |
+
background: #1ca1f3;
|
135 |
+
}
|
136 |
+
|
137 |
+
.ab-share-facebook {
|
138 |
+
background: #3b5999;
|
139 |
+
}
|
140 |
+
|
141 |
+
.ab-share-google {
|
142 |
+
background: #dc4b45;
|
143 |
+
}
|
144 |
+
|
145 |
+
.ab-share-pinterest {
|
146 |
+
background: #bd091c;
|
147 |
+
}
|
148 |
+
|
149 |
+
.ab-share-linkedin {
|
150 |
+
background: #0077b5;
|
151 |
+
}
|
152 |
+
|
153 |
+
.ab-share-reddit {
|
154 |
+
background: #ff4500;
|
155 |
+
}
|
156 |
+
}
|
157 |
+
}
|
158 |
+
|
159 |
+
.ab-button-right {
|
160 |
+
transform: translateX(-100%);
|
161 |
+
left: 100%;
|
162 |
+
position: relative;
|
163 |
+
}
|
164 |
+
|
165 |
+
.ab-button-center {
|
166 |
+
margin: 0 auto;
|
167 |
+
}
|
src/blocks/block-spacer/components/icons.js
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const icons = {};
|
2 |
+
|
3 |
+
icons.upload = <svg width='20px' height='20px' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'>
|
4 |
+
<path d='m77.945 91.453h-72.371c-3.3711 0-5.5742-2.3633-5.5742-5.2422v-55.719c0-3.457 2.1172-6.0703 5.5742-6.0703h44.453v11.051l-38.98-0.003906v45.008h60.977v-17.133l11.988-0.007812v22.875c0 2.8789-2.7812 5.2422-6.0664 5.2422z'
|
5 |
+
/>
|
6 |
+
<path d='m16.543 75.48l23.25-22.324 10.441 9.7773 11.234-14.766 5.5039 10.539 0.039063 16.773z'
|
7 |
+
/>
|
8 |
+
<path d='m28.047 52.992c-3.168 0-5.7422-2.5742-5.7422-5.7461 0-3.1758 2.5742-5.75 5.7422-5.75 3.1797 0 5.7539 2.5742 5.7539 5.75 0 3.1719-2.5742 5.7461-5.7539 5.7461z'
|
9 |
+
/>
|
10 |
+
<path d='m84.043 30.492v22.02h-12.059l-0.015625-22.02h-15.852l21.941-21.945 21.941 21.945z'
|
11 |
+
/>
|
12 |
+
</svg>;
|
13 |
+
|
14 |
+
icons.dismiss = <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns='http://www.w3.org/2000/svg' width="20" height="20" viewBox="0 0 20 20">
|
15 |
+
<path d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zM15 13l-3-3 3-3-2-2-3 3-3-3-2 2 3 3-3 3 2 2 3-3 3 3z"></path>
|
16 |
+
</svg>;
|
17 |
+
|
18 |
+
export default icons;
|
src/blocks/block-spacer/components/inspector.js
ADDED
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
InspectorControls,
|
12 |
+
BlockDescription,
|
13 |
+
ColorPalette,
|
14 |
+
} = wp.editor;
|
15 |
+
|
16 |
+
// Import Inspector components
|
17 |
+
const {
|
18 |
+
Toolbar,
|
19 |
+
Button,
|
20 |
+
PanelBody,
|
21 |
+
PanelRow,
|
22 |
+
PanelColor,
|
23 |
+
RangeControl,
|
24 |
+
ToggleControl,
|
25 |
+
SelectControl,
|
26 |
+
} = wp.components;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Create an Inspector Controls wrapper Component
|
30 |
+
*/
|
31 |
+
export default class Inspector extends Component {
|
32 |
+
|
33 |
+
constructor( props ) {
|
34 |
+
super( ...arguments );
|
35 |
+
}
|
36 |
+
|
37 |
+
render() {
|
38 |
+
|
39 |
+
// Setup the attributes
|
40 |
+
const { spacerHeight, spacerDivider, spacerDividerStyle, spacerDividerColor, spacerDividerHeight } = this.props.attributes;
|
41 |
+
|
42 |
+
// Button size values
|
43 |
+
const spacerStyleOptions = [
|
44 |
+
{ value: 'ab-divider-solid', label: __( 'Solid' ) },
|
45 |
+
{ value: 'ab-divider-dashed', label: __( 'Dashed' ) },
|
46 |
+
{ value: 'ab-divider-dotted', label: __( 'Dotted' ) },
|
47 |
+
];
|
48 |
+
|
49 |
+
return (
|
50 |
+
<InspectorControls key="inspector">
|
51 |
+
<PanelBody>
|
52 |
+
<RangeControl
|
53 |
+
label={ __( 'Spacer Height' ) }
|
54 |
+
value={ spacerHeight || '' }
|
55 |
+
onChange={ ( value ) => this.props.setAttributes( { spacerHeight: value } ) }
|
56 |
+
min={ 50 }
|
57 |
+
max={ 600 }
|
58 |
+
/>
|
59 |
+
|
60 |
+
<ToggleControl
|
61 |
+
label={ __( 'Add Divider' ) }
|
62 |
+
checked={ spacerDivider }
|
63 |
+
onChange={ () => this.props.setAttributes( { spacerDivider: ! spacerDivider } ) }
|
64 |
+
/>
|
65 |
+
|
66 |
+
{ spacerDivider ?
|
67 |
+
<PanelBody>
|
68 |
+
<SelectControl
|
69 |
+
label={ __( 'Divider Style' ) }
|
70 |
+
value={ spacerDividerStyle }
|
71 |
+
options={ spacerStyleOptions.map( ({ value, label }) => ( {
|
72 |
+
value: value,
|
73 |
+
label: label,
|
74 |
+
} ) ) }
|
75 |
+
onChange={ ( value ) => { this.props.setAttributes( { spacerDividerStyle: value } ) } }
|
76 |
+
/>
|
77 |
+
|
78 |
+
<RangeControl
|
79 |
+
label={ __( 'Divider Height' ) }
|
80 |
+
value={ spacerDividerHeight || '' }
|
81 |
+
onChange={ ( value ) => this.props.setAttributes( { spacerDividerHeight: value } ) }
|
82 |
+
min={ 1 }
|
83 |
+
max={ 5 }
|
84 |
+
/>
|
85 |
+
|
86 |
+
<PanelColor
|
87 |
+
title={ __( 'Divider Color' ) }
|
88 |
+
colorValue={ spacerDividerColor }
|
89 |
+
initialOpen={ false }
|
90 |
+
>
|
91 |
+
<ColorPalette
|
92 |
+
label={ __( 'Divider Color' ) }
|
93 |
+
value={ spacerDividerColor }
|
94 |
+
onChange={ ( value ) => { this.props.setAttributes( { spacerDividerColor: value } ) } }
|
95 |
+
colors={[
|
96 |
+
{ color: '#ddd', name: 'white' },
|
97 |
+
{ color: '#333', name: 'black' },
|
98 |
+
{ color: '#3373dc', name: 'royal blue' },
|
99 |
+
{ color: '#22d25f', name: 'green' },
|
100 |
+
{ color: '#ffdd57', name: 'yellow' },
|
101 |
+
{ color: '#ff3860', name: 'pink' },
|
102 |
+
{ color: '#7941b6', name: 'purple' },
|
103 |
+
]}
|
104 |
+
/>
|
105 |
+
</PanelColor>
|
106 |
+
</PanelBody>
|
107 |
+
: null }
|
108 |
+
</PanelBody>
|
109 |
+
</InspectorControls>
|
110 |
+
);
|
111 |
+
}
|
112 |
+
}
|
src/blocks/block-spacer/components/spacer.js
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Button Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Create a Button wrapper Component
|
13 |
+
*/
|
14 |
+
export default class Spacer extends Component {
|
15 |
+
|
16 |
+
constructor( props ) {
|
17 |
+
super( ...arguments );
|
18 |
+
}
|
19 |
+
|
20 |
+
render() {
|
21 |
+
|
22 |
+
// Setup the attributes
|
23 |
+
const { spacerHeight, spacerDivider, spacerDividerStyle, spacerDividerColor, spacerDividerHeight } = this.props.attributes;
|
24 |
+
|
25 |
+
return (
|
26 |
+
<div
|
27 |
+
style={ {
|
28 |
+
color: spacerDividerColor
|
29 |
+
} }
|
30 |
+
className={ classnames(
|
31 |
+
this.props.className,
|
32 |
+
'ab-block-spacer',
|
33 |
+
spacerDividerStyle,
|
34 |
+
{ 'ab-spacer-divider': spacerDivider },
|
35 |
+
'ab-divider-size-' + spacerDividerHeight,
|
36 |
+
) }
|
37 |
+
>
|
38 |
+
{ this.props.children }
|
39 |
+
</div>
|
40 |
+
);
|
41 |
+
}
|
42 |
+
}
|
src/blocks/block-spacer/index.js
ADDED
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Button
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import Spacer from './components/spacer';
|
9 |
+
import icons from './components/icons';
|
10 |
+
import Resizable from 're-resizable';
|
11 |
+
|
12 |
+
// Import CSS
|
13 |
+
import './styles/style.scss';
|
14 |
+
import './styles/editor.scss';
|
15 |
+
|
16 |
+
// Components
|
17 |
+
const { __ } = wp.i18n;
|
18 |
+
|
19 |
+
// Extend component
|
20 |
+
const { Component } = wp.element;
|
21 |
+
|
22 |
+
// Register block
|
23 |
+
const { registerBlockType } = wp.blocks;
|
24 |
+
|
25 |
+
// Register editor components
|
26 |
+
const {
|
27 |
+
RichText,
|
28 |
+
AlignmentToolbar,
|
29 |
+
BlockControls,
|
30 |
+
BlockAlignmentToolbar,
|
31 |
+
UrlInput,
|
32 |
+
} = wp.editor;
|
33 |
+
|
34 |
+
// Register components
|
35 |
+
const {
|
36 |
+
Button,
|
37 |
+
withFallbackStyles,
|
38 |
+
IconButton,
|
39 |
+
Dashicon,
|
40 |
+
} = wp.components;
|
41 |
+
|
42 |
+
class ABSpacerBlock extends Component {
|
43 |
+
|
44 |
+
render() {
|
45 |
+
|
46 |
+
// Setup the attributes
|
47 |
+
const { attributes: { spacerHeight, spacerDivider, spacerDividerStyle, spacerDividerColor }, isSelected, className, setAttributes, toggleSelection, spacerDividerHeight } = this.props;
|
48 |
+
|
49 |
+
return [
|
50 |
+
// Show the block controls on focus
|
51 |
+
<Inspector
|
52 |
+
{ ...this.props }
|
53 |
+
/>,
|
54 |
+
// Show the button markup in the editor
|
55 |
+
<Spacer { ...this.props }>
|
56 |
+
<Resizable
|
57 |
+
className={ classnames( className, 'ab-spacer-handle' ) }
|
58 |
+
style={ {
|
59 |
+
color: spacerDividerColor
|
60 |
+
} }
|
61 |
+
size={ {
|
62 |
+
width: '100%',
|
63 |
+
height: spacerHeight,
|
64 |
+
} }
|
65 |
+
minWidth= { '100%' }
|
66 |
+
maxWidth= { '100%' }
|
67 |
+
minHeight= { '100%' }
|
68 |
+
handleClasses={ {
|
69 |
+
bottomLeft: 'ab-spacer-control__resize-handle',
|
70 |
+
} }
|
71 |
+
enable={ { top: false, right: false, bottom: true, left: false, topRight: false, bottomRight: false, bottomLeft: true, topLeft: false } }
|
72 |
+
onResizeStart={ () => {
|
73 |
+
toggleSelection( false );
|
74 |
+
} }
|
75 |
+
onResizeStop={ ( event, direction, elt, delta ) => {
|
76 |
+
setAttributes( {
|
77 |
+
spacerHeight: parseInt( spacerHeight + delta.height, 10 ),
|
78 |
+
} );
|
79 |
+
toggleSelection( true );
|
80 |
+
} }
|
81 |
+
>
|
82 |
+
</Resizable>
|
83 |
+
</Spacer>
|
84 |
+
];
|
85 |
+
}
|
86 |
+
}
|
87 |
+
|
88 |
+
// Register the block
|
89 |
+
registerBlockType( 'atomic-blocks/ab-spacer', {
|
90 |
+
title: __( 'AB Spacer' ),
|
91 |
+
description: __( 'Add a spacer and divider between your blocks.' ),
|
92 |
+
icon: 'image-flip-vertical',
|
93 |
+
category: 'atomic-blocks',
|
94 |
+
keywords: [
|
95 |
+
__( 'spacer' ),
|
96 |
+
__( 'divider' ),
|
97 |
+
__( 'atomic' ),
|
98 |
+
],
|
99 |
+
attributes: {
|
100 |
+
spacerHeight: {
|
101 |
+
type: 'number',
|
102 |
+
default: 30,
|
103 |
+
},
|
104 |
+
spacerDivider: {
|
105 |
+
type: 'boolean',
|
106 |
+
default: false
|
107 |
+
},
|
108 |
+
spacerDividerStyle: {
|
109 |
+
type: 'string',
|
110 |
+
default: 'ab-divider-solid'
|
111 |
+
},
|
112 |
+
spacerDividerColor: {
|
113 |
+
type: 'string',
|
114 |
+
default: '#ddd'
|
115 |
+
},
|
116 |
+
spacerDividerHeight: {
|
117 |
+
type: 'number',
|
118 |
+
default: 1,
|
119 |
+
},
|
120 |
+
},
|
121 |
+
|
122 |
+
// Render the block components
|
123 |
+
edit: ABSpacerBlock,
|
124 |
+
|
125 |
+
// Save the attributes and markup
|
126 |
+
save: function( props ) {
|
127 |
+
|
128 |
+
// Setup the attributes
|
129 |
+
const { spacerHeight, spacerDivider, spacerDividerStyle, spacerDividerColor, spacerDividerHeight } = props.attributes;
|
130 |
+
|
131 |
+
// Save the block markup for the front end
|
132 |
+
return (
|
133 |
+
<Spacer { ...props }>
|
134 |
+
<hr style={ { height: spacerHeight ? spacerHeight + 'px' : undefined } }></hr>
|
135 |
+
</Spacer>
|
136 |
+
);
|
137 |
+
},
|
138 |
+
} );
|
src/blocks/block-spacer/styles/editor.scss
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.editor-block-list__layout [data-type="atomic-blocks/ab-spacer"] {
|
6 |
+
margin-bottom: 1.2em;
|
7 |
+
}
|
8 |
+
|
9 |
+
.ab-block-spacer {
|
10 |
+
border: dashed 1px #ddd;
|
11 |
+
margin-bottom: 0;
|
12 |
+
|
13 |
+
.ab-spacer-handle {
|
14 |
+
margin-bottom: 0;
|
15 |
+
}
|
16 |
+
|
17 |
+
&.is-selected::before {
|
18 |
+
outline: none;
|
19 |
+
}
|
20 |
+
|
21 |
+
.editor-block-list__block-edit {
|
22 |
+
outline: 1px dashed #ddd;
|
23 |
+
}
|
24 |
+
|
25 |
+
&.is-selected .editor-block-list__block-edit,
|
26 |
+
&.is-hovered .editor-block-list__block-edit {
|
27 |
+
outline: 1px dotted #ddd;
|
28 |
+
}
|
29 |
+
|
30 |
+
&.is-selected .editor-block-list__block-edit {
|
31 |
+
outline: 1px solid #ddd;
|
32 |
+
}
|
33 |
+
}
|
34 |
+
|
35 |
+
.ab-spacer-control__resize-handle {
|
36 |
+
background: none;
|
37 |
+
background: none;
|
38 |
+
border-radius: 0;
|
39 |
+
bottom: -15px !important;
|
40 |
+
cursor: row-resize !important;
|
41 |
+
display: none;
|
42 |
+
height: 32px !important;
|
43 |
+
left: 0 !important;
|
44 |
+
width: 100% !important;
|
45 |
+
z-index: 999;
|
46 |
+
|
47 |
+
.editor-block-list__block[data-type="atomic-blocks/ab-spacer"].is-selected &,
|
48 |
+
.editor-block-list__block[data-type="atomic-blocks/ab-spacer"].is-hovered & {
|
49 |
+
display: block;
|
50 |
+
}
|
51 |
+
|
52 |
+
&:after {
|
53 |
+
background-color: #32373c;
|
54 |
+
border-radius: 50px;
|
55 |
+
border: 2px solid #fff;
|
56 |
+
content: '';
|
57 |
+
display: block;
|
58 |
+
height: 12px;
|
59 |
+
left: 50%;
|
60 |
+
margin-left: -8px;
|
61 |
+
margin-top: -6px;
|
62 |
+
position: absolute;
|
63 |
+
top: 50%;
|
64 |
+
width: 12px;
|
65 |
+
}
|
66 |
+
}
|
src/blocks/block-spacer/styles/style.scss
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Spacer styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.ab-block-spacer {
|
7 |
+
margin: 0 0 1.2em 0;
|
8 |
+
position: relative;
|
9 |
+
|
10 |
+
hr {
|
11 |
+
border: none;
|
12 |
+
margin: 0;
|
13 |
+
}
|
14 |
+
|
15 |
+
&.ab-spacer-divider:after {
|
16 |
+
content: " ";
|
17 |
+
width: 100%;
|
18 |
+
height: 1px;
|
19 |
+
border-top: solid 1px;
|
20 |
+
position: absolute;
|
21 |
+
top: 50%;
|
22 |
+
}
|
23 |
+
|
24 |
+
&.ab-divider-solid.ab-spacer-divider:after {
|
25 |
+
border-top-style: solid;
|
26 |
+
}
|
27 |
+
|
28 |
+
&.ab-divider-dotted.ab-spacer-divider:after {
|
29 |
+
border-top-style: dotted;
|
30 |
+
}
|
31 |
+
|
32 |
+
&.ab-divider-dashed.ab-spacer-divider:after {
|
33 |
+
border-top-style: dashed;
|
34 |
+
}
|
35 |
+
|
36 |
+
&.ab-divider-size-1.ab-spacer-divider:after {
|
37 |
+
border-top-width: 1px;
|
38 |
+
}
|
39 |
+
|
40 |
+
&.ab-divider-size-2.ab-spacer-divider:after {
|
41 |
+
border-top-width: 2px;
|
42 |
+
}
|
43 |
+
|
44 |
+
&.ab-divider-size-3.ab-spacer-divider:after {
|
45 |
+
border-top-width: 3px;
|
46 |
+
}
|
47 |
+
|
48 |
+
&.ab-divider-size-4.ab-spacer-divider:after {
|
49 |
+
border-top-width: 4px;
|
50 |
+
}
|
51 |
+
|
52 |
+
&.ab-divider-size-5.ab-spacer-divider:after {
|
53 |
+
border-top-width: 5px;
|
54 |
+
}
|
55 |
+
}
|
src/blocks/block-testimonial/components/icons.js
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const icons = {};
|
2 |
+
|
3 |
+
icons.upload = <svg width='20px' height='20px' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'>
|
4 |
+
<path d='m77.945 91.453h-72.371c-3.3711 0-5.5742-2.3633-5.5742-5.2422v-55.719c0-3.457 2.1172-6.0703 5.5742-6.0703h44.453v11.051l-38.98-0.003906v45.008h60.977v-17.133l11.988-0.007812v22.875c0 2.8789-2.7812 5.2422-6.0664 5.2422z'
|
5 |
+
/>
|
6 |
+
<path d='m16.543 75.48l23.25-22.324 10.441 9.7773 11.234-14.766 5.5039 10.539 0.039063 16.773z'
|
7 |
+
/>
|
8 |
+
<path d='m28.047 52.992c-3.168 0-5.7422-2.5742-5.7422-5.7461 0-3.1758 2.5742-5.75 5.7422-5.75 3.1797 0 5.7539 2.5742 5.7539 5.75 0 3.1719-2.5742 5.7461-5.7539 5.7461z'
|
9 |
+
/>
|
10 |
+
<path d='m84.043 30.492v22.02h-12.059l-0.015625-22.02h-15.852l21.941-21.945 21.941 21.945z'
|
11 |
+
/>
|
12 |
+
</svg>;
|
13 |
+
|
14 |
+
export default icons;
|
src/blocks/block-testimonial/components/inspector.js
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Inspector Controls
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { __ } = wp.i18n;
|
7 |
+
const { Component } = wp.element;
|
8 |
+
|
9 |
+
// Import block components
|
10 |
+
const {
|
11 |
+
InspectorControls,
|
12 |
+
BlockDescription,
|
13 |
+
ColorPalette,
|
14 |
+
} = wp.editor;
|
15 |
+
|
16 |
+
// Import Inspector components
|
17 |
+
const {
|
18 |
+
Toolbar,
|
19 |
+
Button,
|
20 |
+
PanelBody,
|
21 |
+
PanelRow,
|
22 |
+
PanelColor,
|
23 |
+
FormToggle,
|
24 |
+
RangeControl,
|
25 |
+
SelectControl,
|
26 |
+
} = wp.components;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Create an Inspector Controls wrapper Component
|
30 |
+
*/
|
31 |
+
export default class Inspector extends Component {
|
32 |
+
|
33 |
+
constructor( props ) {
|
34 |
+
super( ...arguments );
|
35 |
+
}
|
36 |
+
|
37 |
+
render() {
|
38 |
+
|
39 |
+
// Cite Alignment Options
|
40 |
+
const citeAlignOptions = [
|
41 |
+
{ value: 'left-aligned', label: __( 'Left Aligned' ) },
|
42 |
+
{ value: 'right-aligned', label: __( 'Right Aligned' ) },
|
43 |
+
];
|
44 |
+
|
45 |
+
// Setup the attributes
|
46 |
+
const { attributes: { testimonialName, testimonialTitle, testimonialContent, testimonialAlignment, testimonialImgURL, testimonialImgID, testimonialBackgroundColor, testimonialTextColor, testimonialFontSize, testimonialCiteAlign }, isSelected, className, setAttributes } = this.props;
|
47 |
+
|
48 |
+
return (
|
49 |
+
<InspectorControls key="inspector">
|
50 |
+
<PanelBody>
|
51 |
+
<RangeControl
|
52 |
+
label={ __( 'Font Size' ) }
|
53 |
+
value={ testimonialFontSize }
|
54 |
+
onChange={ ( value ) => this.props.setAttributes( { testimonialFontSize: value } ) }
|
55 |
+
min={ 14 }
|
56 |
+
max={ 24 }
|
57 |
+
step={ 1 }
|
58 |
+
/>
|
59 |
+
|
60 |
+
<SelectControl
|
61 |
+
label={ __( 'Cite Alignment' ) }
|
62 |
+
description={ __( 'Left or right align the cite name and title.' ) }
|
63 |
+
options={ citeAlignOptions }
|
64 |
+
value={ testimonialCiteAlign }
|
65 |
+
onChange={ ( value ) => this.props.setAttributes( { testimonialCiteAlign: value } ) }
|
66 |
+
/>
|
67 |
+
|
68 |
+
<PanelColor
|
69 |
+
title={ __( 'Background Color' ) }
|
70 |
+
colorValue={ testimonialBackgroundColor }
|
71 |
+
initialOpen={ false }
|
72 |
+
>
|
73 |
+
<ColorPalette
|
74 |
+
label={ __( 'Background Color' ) }
|
75 |
+
value={ testimonialBackgroundColor }
|
76 |
+
onChange={ ( value ) => this.props.setAttributes( { testimonialBackgroundColor: value } ) }
|
77 |
+
colors={[
|
78 |
+
{ color: '#00d1b2', name: 'teal' },
|
79 |
+
{ color: '#3373dc', name: 'royal blue' },
|
80 |
+
{ color: '#209cef', name: 'sky blue' },
|
81 |
+
{ color: '#22d25f', name: 'green' },
|
82 |
+
{ color: '#ffdd57', name: 'yellow' },
|
83 |
+
{ color: '#ff3860', name: 'pink' },
|
84 |
+
{ color: '#7941b6', name: 'purple' },
|
85 |
+
{ color: '#392F43', name: 'black' },
|
86 |
+
]}
|
87 |
+
/>
|
88 |
+
</PanelColor>
|
89 |
+
|
90 |
+
<PanelColor
|
91 |
+
title={ __( 'Text Color' ) }
|
92 |
+
colorValue={ testimonialTextColor }
|
93 |
+
initialOpen={ false }
|
94 |
+
>
|
95 |
+
<ColorPalette
|
96 |
+
label={ __( 'Text Color' ) }
|
97 |
+
value={ testimonialTextColor }
|
98 |
+
onChange={ ( value ) => this.props.setAttributes( { testimonialTextColor: value } ) }
|
99 |
+
colors={[
|
100 |
+
{ color: '#fff', name: 'white' },
|
101 |
+
{ color: '#32373c', name: 'black' },
|
102 |
+
]}
|
103 |
+
/>
|
104 |
+
</PanelColor>
|
105 |
+
</PanelBody>
|
106 |
+
</InspectorControls>
|
107 |
+
);
|
108 |
+
}
|
109 |
+
}
|
src/blocks/block-testimonial/components/testimonial.js
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Testimonial Block Wrapper
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Setup the block
|
6 |
+
const { Component } = wp.element;
|
7 |
+
|
8 |
+
// Import block dependencies and components
|
9 |
+
import classnames from 'classnames';
|
10 |
+
import * as fontSize from './../../../utils/helper';
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Create a Testimonial wrapper Component
|
14 |
+
*/
|
15 |
+
export default class Testimonial extends Component {
|
16 |
+
|
17 |
+
constructor( props ) {
|
18 |
+
super( ...arguments );
|
19 |
+
}
|
20 |
+
|
21 |
+
render() {
|
22 |
+
|
23 |
+
// Setup the attributes
|
24 |
+
const { attributes: { testimonialAlignment, testimonialImgURL, testimonialBackgroundColor, testimonialTextColor, testimonialFontSize, testimonialCiteAlign } } = this.props;
|
25 |
+
|
26 |
+
return (
|
27 |
+
<div
|
28 |
+
style={ {
|
29 |
+
backgroundColor: testimonialBackgroundColor,
|
30 |
+
color: testimonialTextColor,
|
31 |
+
} }
|
32 |
+
className={ classnames(
|
33 |
+
this.props.className,
|
34 |
+
testimonialCiteAlign,
|
35 |
+
{ 'ab-has-avatar': testimonialImgURL },
|
36 |
+
'ab-font-size-' + testimonialFontSize,
|
37 |
+
'ab-block-testimonial'
|
38 |
+
) }
|
39 |
+
>
|
40 |
+
{ this.props.children }
|
41 |
+
</div>
|
42 |
+
);
|
43 |
+
}
|
44 |
+
}
|
src/blocks/block-testimonial/index.js
ADDED
@@ -0,0 +1,282 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: Atomic Blocks Testimonial
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import block dependencies and components
|
6 |
+
import classnames from 'classnames';
|
7 |
+
import Inspector from './components/inspector';
|
8 |
+
import Testimonial from './components/testimonial';
|
9 |
+
import icons from './components/icons';
|
10 |
+
|
11 |
+
// Import CSS
|
12 |
+
import './styles/style.scss';
|
13 |
+
import './styles/editor.scss';
|
14 |
+
|
15 |
+
// Internationalization
|
16 |
+
const { __ } = wp.i18n;
|
17 |
+
|
18 |
+
// Extend component
|
19 |
+
const { Component } = wp.element;
|
20 |
+
|
21 |
+
// Register block
|
22 |
+
const { registerBlockType } = wp.blocks;
|
23 |
+
|
24 |
+
// Register editor components
|
25 |
+
const {
|
26 |
+
RichText,
|
27 |
+
AlignmentToolbar,
|
28 |
+
BlockControls,
|
29 |
+
BlockAlignmentToolbar,
|
30 |
+
MediaUpload,
|
31 |
+
} = wp.editor;
|
32 |
+
|
33 |
+
// Register components
|
34 |
+
const {
|
35 |
+
Button,
|
36 |
+
SelectControl,
|
37 |
+
} = wp.components;
|
38 |
+
|
39 |
+
class ABTestimonialBlock extends Component {
|
40 |
+
|
41 |
+
render() {
|
42 |
+
|
43 |
+
// Setup the attributes
|
44 |
+
const {
|
45 |
+
attributes: {
|
46 |
+
testimonialName,
|
47 |
+
testimonialTitle,
|
48 |
+
testimonialContent,
|
49 |
+
testimonialAlignment,
|
50 |
+
testimonialImgURL,
|
51 |
+
testimonialImgID,
|
52 |
+
testimonialBackgroundColor,
|
53 |
+
testimonialTextColor,
|
54 |
+
testimonialFontSize,
|
55 |
+
testimonialCiteAlign
|
56 |
+
},
|
57 |
+
attributes,
|
58 |
+
isSelected,
|
59 |
+
editable,
|
60 |
+
className,
|
61 |
+
setAttributes
|
62 |
+
} = this.props;
|
63 |
+
|
64 |
+
const onSelectImage = img => {
|
65 |
+
setAttributes( {
|
66 |
+
testimonialImgID: img.id,
|
67 |
+
testimonialImgURL: img.url,
|
68 |
+
} );
|
69 |
+
};
|
70 |
+
|
71 |
+
return [
|
72 |
+
// Show the alignment toolbar on focus
|
73 |
+
<BlockControls key="controls">
|
74 |
+
<AlignmentToolbar
|
75 |
+
value={ testimonialAlignment }
|
76 |
+
onChange={ ( value ) => setAttributes( { testimonialAlignment: value } ) }
|
77 |
+
/>
|
78 |
+
</BlockControls>,
|
79 |
+
// Show the block controls on focus
|
80 |
+
<Inspector
|
81 |
+
{ ...{ setAttributes, ...this.props } }
|
82 |
+
/>,
|
83 |
+
// Show the block markup in the editor
|
84 |
+
<Testimonial { ...this.props }>
|
85 |
+
<RichText
|
86 |
+
tagName="div"
|
87 |
+
multiline="p"
|
88 |
+
placeholder={ __( 'Add testimonial text...' ) }
|
89 |
+
keepPlaceholderOnFocus
|
90 |
+
value={ testimonialContent }
|
91 |
+
formattingControls={ [ 'bold', 'italic', 'strikethrough', 'link' ] }
|
92 |
+
className={ classnames(
|
93 |
+
'ab-testimonial-text'
|
94 |
+
) }
|
95 |
+
style={ {
|
96 |
+
textAlign: testimonialAlignment,
|
97 |
+
} }
|
98 |
+
onChange={ ( value ) => setAttributes( { testimonialContent: value } ) }
|
99 |
+
inlineToolbar
|
100 |
+
/>
|
101 |
+
|
102 |
+
<div class="ab-testimonial-info">
|
103 |
+
<div class="ab-testimonial-avatar-wrap">
|
104 |
+
<div class="ab-testimonial-image-wrap">
|
105 |
+
<MediaUpload
|
106 |
+
buttonProps={ {
|
107 |
+
className: 'change-image'
|
108 |
+
} }
|
109 |
+
onSelect={ ( img ) => setAttributes(
|
110 |
+
{
|
111 |
+
testimonialImgID: img.id,
|
112 |
+
testimonialImgURL: img.url,
|
113 |
+
}
|
114 |
+
) }
|
115 |
+
type="image"
|
116 |
+
value={ testimonialImgID }
|
117 |
+
render={ ( { open } ) => (
|
118 |
+
<Button onClick={ open }>
|
119 |
+
{ ! testimonialImgID ? icons.upload : <img
|
120 |
+
class="ab-testimonial-avatar"
|
121 |
+
src={ testimonialImgURL }
|
122 |
+
alt="avatar"
|
123 |
+
/> }
|
124 |
+
</Button>
|
125 |
+
) }
|
126 |
+
>
|
127 |
+
</MediaUpload>
|
128 |
+
</div>
|
129 |
+
</div>
|
130 |
+
|
131 |
+
<RichText
|
132 |
+
tagName="h2"
|
133 |
+
placeholder={ __( 'Add name' ) }
|
134 |
+
keepPlaceholderOnFocus
|
135 |
+
value={ testimonialName }
|
136 |
+
className='ab-testimonial-name'
|
137 |
+
style={ {
|
138 |
+
color: testimonialTextColor
|
139 |
+
} }
|
140 |
+
onChange={ ( value ) => this.props.setAttributes( { testimonialName: value } ) }
|
141 |
+
/>
|
142 |
+
|
143 |
+
<RichText
|
144 |
+
tagName="small"
|
145 |
+
placeholder={ __( 'Add title' ) }
|
146 |
+
keepPlaceholderOnFocus
|
147 |
+
value={ testimonialTitle }
|
148 |
+
className='ab-testimonial-title'
|
149 |
+
style={ {
|
150 |
+
color: testimonialTextColor
|
151 |
+
} }
|
152 |
+
onChange={ ( value ) => this.props.setAttributes( { testimonialTitle: value } ) }
|
153 |
+
/>
|
154 |
+
</div>
|
155 |
+
</Testimonial>
|
156 |
+
];
|
157 |
+
}
|
158 |
+
}
|
159 |
+
|
160 |
+
// Register the block
|
161 |
+
registerBlockType( 'atomic-blocks/ab-testimonial', {
|
162 |
+
title: __( 'AB Testimonial' ),
|
163 |
+
description: __( 'Add a user testimonial with a name and title.' ),
|
164 |
+
icon: 'format-quote',
|
165 |
+
category: 'atomic-blocks',
|
166 |
+
keywords: [
|
167 |
+
__( 'testimonial' ),
|
168 |
+
__( 'quote' ),
|
169 |
+
__( 'atomic' ),
|
170 |
+
],
|
171 |
+
attributes: {
|
172 |
+
testimonialName: {
|
173 |
+
type: 'string',
|
174 |
+
selector: '.ab-testimonial-name',
|
175 |
+
},
|
176 |
+
testimonialTitle: {
|
177 |
+
type: 'array',
|
178 |
+
selector: '.ab-testimonial-title',
|
179 |
+
source: 'children',
|
180 |
+
},
|
181 |
+
testimonialContent: {
|
182 |
+
type: 'array',
|
183 |
+
selector: '.ab-testimonial-text',
|
184 |
+
source: 'children',
|
185 |
+
},
|
186 |
+
testimonialAlignment: {
|
187 |
+
type: 'string',
|
188 |
+
},
|
189 |
+
testimonialImgURL: {
|
190 |
+
type: 'string',
|
191 |
+
source: 'attribute',
|
192 |
+
attribute: 'src',
|
193 |
+
selector: 'img',
|
194 |
+
},
|
195 |
+
testimonialImgID: {
|
196 |
+
type: 'number',
|
197 |
+
},
|
198 |
+
testimonialBackgroundColor: {
|
199 |
+
type: 'string',
|
200 |
+
default: '#f2f2f2'
|
201 |
+
},
|
202 |
+
testimonialTextColor: {
|
203 |
+
type: 'string',
|
204 |
+
default: '#32373c'
|
205 |
+
},
|
206 |
+
testimonialFontSize: {
|
207 |
+
type: 'number',
|
208 |
+
default: 18,
|
209 |
+
},
|
210 |
+
testimonialCiteAlign: {
|
211 |
+
type: 'string',
|
212 |
+
default: 'left-aligned',
|
213 |
+
},
|
214 |
+
},
|
215 |
+
|
216 |
+
// Render the block components
|
217 |
+
edit: ABTestimonialBlock,
|
218 |
+
|
219 |
+
// Save the attributes and markup
|
220 |
+
save: function( props ) {
|
221 |
+
|
222 |
+
// Setup the attributes
|
223 |
+
const {
|
224 |
+
testimonialName,
|
225 |
+
testimonialTitle,
|
226 |
+
testimonialContent,
|
227 |
+
testimonialAlignment,
|
228 |
+
testimonialImgURL,
|
229 |
+
testimonialImgID,
|
230 |
+
testimonialBackgroundColor,
|
231 |
+
testimonialTextColor,
|
232 |
+
testimonialFontSize,
|
233 |
+
testimonialCiteAlign
|
234 |
+
} = props.attributes;
|
235 |
+
|
236 |
+
// Save the block markup for the front end
|
237 |
+
return (
|
238 |
+
<Testimonial { ...props }>
|
239 |
+
<div
|
240 |
+
className={ classnames(
|
241 |
+
'ab-testimonial-text',
|
242 |
+
) }
|
243 |
+
style={ {
|
244 |
+
textAlign: testimonialAlignment,
|
245 |
+
} }
|
246 |
+
>
|
247 |
+
{ testimonialContent }
|
248 |
+
</div>
|
249 |
+
|
250 |
+
<div class="ab-testimonial-info">
|
251 |
+
{ testimonialImgURL && !! testimonialImgURL.length && (
|
252 |
+
<div class="ab-testimonial-avatar-wrap">
|
253 |
+
<div class="ab-testimonial-image-wrap">
|
254 |
+
<img
|
255 |
+
class="ab-testimonial-avatar"
|
256 |
+
src={ testimonialImgURL }
|
257 |
+
alt="avatar"
|
258 |
+
/>
|
259 |
+
</div>
|
260 |
+
</div>
|
261 |
+
) }
|
262 |
+
|
263 |
+
{ testimonialName && !! testimonialName.length && (
|
264 |
+
<h2 class="ab-testimonial-name"
|
265 |
+
style={ {
|
266 |
+
color: testimonialTextColor
|
267 |
+
} }
|
268 |
+
>{ testimonialName }</h2>
|
269 |
+
) }
|
270 |
+
|
271 |
+
{ testimonialTitle && !! testimonialTitle.length && (
|
272 |
+
<small class="ab-testimonial-title"
|
273 |
+
style={ {
|
274 |
+
color: testimonialTextColor
|
275 |
+
} }
|
276 |
+
>{ testimonialTitle }</small>
|
277 |
+
) }
|
278 |
+
</div>
|
279 |
+
</Testimonial>
|
280 |
+
);
|
281 |
+
},
|
282 |
+
} );
|
src/blocks/block-testimonial/styles/editor.scss
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Editor styles for the admin
|
3 |
+
*/
|
4 |
+
|
5 |
+
.ab-block-testimonial {
|
6 |
+
margin-bottom: 0;
|
7 |
+
|
8 |
+
.components-button:not(:disabled):not([aria-disabled=true]):focus {
|
9 |
+
background: none;
|
10 |
+
box-shadow: none;
|
11 |
+
}
|
12 |
+
}
|
13 |
+
|
14 |
+
.editor-block-list__layout [data-type="atomic-blocks/ab-testimonial"] {
|
15 |
+
margin-bottom: 1.2em;
|
16 |
+
}
|
17 |
+
|
18 |
+
.ab-testimonial-info {
|
19 |
+
h2.editor-rich-text__tinymce {
|
20 |
+
line-height: 1.2;
|
21 |
+
}
|
22 |
+
|
23 |
+
p.editor-rich-text__tinymce {
|
24 |
+
line-height: 1.6;
|
25 |
+
}
|
26 |
+
|
27 |
+
.ab-testimonial-title + .ab-testimonial-title {
|
28 |
+
line-height: 1.8;
|
29 |
+
}
|
30 |
+
}
|
src/blocks/block-testimonial/styles/style.scss
ADDED
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Testimonial styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
.ab-block-testimonial {
|
7 |
+
background: #f2f2f2;
|
8 |
+
color: #293038;
|
9 |
+
margin: 0 auto;
|
10 |
+
padding: 5%;
|
11 |
+
border-radius: 5px;
|
12 |
+
margin-bottom: 1.2em;
|
13 |
+
|
14 |
+
.ab-testimonial-info {
|
15 |
+
position: relative;
|
16 |
+
display: inline-block;
|
17 |
+
width: 100%;
|
18 |
+
margin-top: 15px;
|
19 |
+
min-height: 55px;
|
20 |
+
padding-top: 5px;
|
21 |
+
line-height: 1.4;
|
22 |
+
}
|
23 |
+
|
24 |
+
.ab-testimonial-info {
|
25 |
+
.blocks-editable {
|
26 |
+
padding-left: 0;
|
27 |
+
}
|
28 |
+
|
29 |
+
.ab-testimonial-avatar-wrap {
|
30 |
+
position: absolute;
|
31 |
+
left: 0;
|
32 |
+
top: 0;
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
.ab-testimonial-avatar-wrap + .ab-testimonial-name,
|
37 |
+
.ab-testimonial-avatar-wrap + .ab-testimonial-name + .ab-testimonial-title,
|
38 |
+
.ab-testimonial-avatar-wrap + .ab-testimonial-title,
|
39 |
+
.ab-testimonial-avatar-wrap + .editor-rich-text,
|
40 |
+
.ab-testimonial-avatar-wrap + .editor-rich-text + .editor-rich-text {
|
41 |
+
margin-left: 70px;
|
42 |
+
padding-left: 0;
|
43 |
+
}
|
44 |
+
|
45 |
+
.ab-testimonial-text {
|
46 |
+
p {
|
47 |
+
line-height: 1.6;
|
48 |
+
}
|
49 |
+
|
50 |
+
a {
|
51 |
+
color: inherit;
|
52 |
+
box-shadow: 0 -1px 0 inset;
|
53 |
+
text-decoration: none;
|
54 |
+
|
55 |
+
&:hover {
|
56 |
+
color: inherit;
|
57 |
+
box-shadow: 0 -2px 0 inset;
|
58 |
+
}
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
.ab-testimonial-name {
|
63 |
+
font-size: 1em;
|
64 |
+
font-weight: bold;
|
65 |
+
line-height: 1.2;
|
66 |
+
margin: 0;
|
67 |
+
padding: 0;
|
68 |
+
}
|
69 |
+
|
70 |
+
.ab-testimonial-title {
|
71 |
+
opacity: .8;
|
72 |
+
}
|
73 |
+
|
74 |
+
.ab-testimonial-avatar {
|
75 |
+
border-radius: 200px;
|
76 |
+
max-width: 100px;
|
77 |
+
}
|
78 |
+
|
79 |
+
.ab-testimonial-image-wrap {
|
80 |
+
height: 55px;
|
81 |
+
width: 55px;
|
82 |
+
background: #ddd;
|
83 |
+
border-radius: 200px;
|
84 |
+
position: relative;
|
85 |
+
|
86 |
+
button {
|
87 |
+
position: absolute;
|
88 |
+
left: 19px;
|
89 |
+
top: 16px;
|
90 |
+
z-index: 50;
|
91 |
+
padding: 0;
|
92 |
+
}
|
93 |
+
|
94 |
+
button:focus {
|
95 |
+
background: none;
|
96 |
+
border: none;
|
97 |
+
outline: none;
|
98 |
+
box-shadow: none;
|
99 |
+
}
|
100 |
+
|
101 |
+
img {
|
102 |
+
object-fit: cover;
|
103 |
+
height: 100%;
|
104 |
+
width: 100%;
|
105 |
+
position: relative;
|
106 |
+
z-index: 10;
|
107 |
+
border-radius: 40px;
|
108 |
+
z-index: 5;
|
109 |
+
}
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
#editor .ab-has-avatar {
|
114 |
+
.ab-testimonial-image-wrap {
|
115 |
+
button {
|
116 |
+
top: 0;
|
117 |
+
left: 0;
|
118 |
+
opacity: 1 !important;
|
119 |
+
height: 100%;
|
120 |
+
}
|
121 |
+
|
122 |
+
&:hover {
|
123 |
+
cursor: pointer;
|
124 |
+
|
125 |
+
img {
|
126 |
+
opacity: .7;
|
127 |
+
}
|
128 |
+
|
129 |
+
button {
|
130 |
+
opacity: 1;
|
131 |
+
}
|
132 |
+
}
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
.right-aligned {
|
137 |
+
.ab-testimonial-info {
|
138 |
+
text-align: right;
|
139 |
+
|
140 |
+
h2 {
|
141 |
+
left: 0;
|
142 |
+
}
|
143 |
+
|
144 |
+
.ab-testimonial-name,
|
145 |
+
.ab-testimonial-title {
|
146 |
+
margin-right: 70px;
|
147 |
+
margin-left: 0;
|
148 |
+
}
|
149 |
+
|
150 |
+
.ab-testimonial-avatar-wrap {
|
151 |
+
left: auto;
|
152 |
+
right: 0;
|
153 |
+
}
|
154 |
+
}
|
155 |
+
}
|
src/common.scss
ADDED
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Common styles
|
3 |
+
* Loads on front end and back end
|
4 |
+
*/
|
5 |
+
|
6 |
+
// Variables
|
7 |
+
$black: #293038;
|
8 |
+
$accent: #5a3fd6;
|
9 |
+
$lightgray: #626e81;
|
10 |
+
|
11 |
+
/* Font size styles */
|
12 |
+
@media only screen and (min-width: 600px) {
|
13 |
+
div[class*="wp-block-atomic"].ab-font-size-14 {
|
14 |
+
&.ab-block-testimonial p,
|
15 |
+
&.ab-block-notice p,
|
16 |
+
&.ab-block-profile p,
|
17 |
+
&.ab-block-accordion p,
|
18 |
+
&.ab-block-cta p {
|
19 |
+
font-size: 14px;
|
20 |
+
}
|
21 |
+
}
|
22 |
+
|
23 |
+
div[class*="wp-block-atomic"].ab-font-size-15 {
|
24 |
+
&.ab-block-testimonial p,
|
25 |
+
&.ab-block-notice p,
|
26 |
+
&.ab-block-profile p,
|
27 |
+
&.ab-block-accordion p,
|
28 |
+
&.ab-block-cta p {
|
29 |
+
font-size: 15px;
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
div[class*="wp-block-atomic"].ab-font-size-16 {
|
34 |
+
&.ab-block-testimonial p,
|
35 |
+
&.ab-block-notice p,
|
36 |
+
&.ab-block-profile p,
|
37 |
+
&.ab-block-accordion p,
|
38 |
+
&.ab-block-cta p {
|
39 |
+
font-size: 16px;
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
div[class*="wp-block-atomic"].ab-font-size-17 {
|
44 |
+
&.ab-block-testimonial p,
|
45 |
+
&.ab-block-notice p,
|
46 |
+
&.ab-block-profile p,
|
47 |
+
&.ab-block-accordion p,
|
48 |
+
&.ab-block-cta p {
|
49 |
+
font-size: 17px;
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
div[class*="wp-block-atomic"].ab-font-size-18 {
|
54 |
+
&.ab-block-testimonial p,
|
55 |
+
&.ab-block-notice p,
|
56 |
+
&.ab-block-profile p,
|
57 |
+
&.ab-block-accordion p,
|
58 |
+
&.ab-block-cta p {
|
59 |
+
font-size: 18px;
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
div[class*="wp-block-atomic"].ab-font-size-19 {
|
64 |
+
&.ab-block-testimonial p,
|
65 |
+
&.ab-block-notice p,
|
66 |
+
&.ab-block-profile p,
|
67 |
+
&.ab-block-accordion p,
|
68 |
+
&.ab-block-cta p {
|
69 |
+
font-size: 19px;
|
70 |
+
}
|
71 |
+
}
|
72 |
+
|
73 |
+
div[class*="wp-block-atomic"].ab-font-size-20 {
|
74 |
+
&.ab-block-testimonial p,
|
75 |
+
&.ab-block-notice p,
|
76 |
+
&.ab-block-profile p,
|
77 |
+
&.ab-block-accordion p,
|
78 |
+
&.ab-block-cta p {
|
79 |
+
font-size: 20px;
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
div[class*="wp-block-atomic"].ab-font-size-21 {
|
84 |
+
&.ab-block-testimonial p,
|
85 |
+
&.ab-block-notice p,
|
86 |
+
&.ab-block-profile p,
|
87 |
+
&.ab-block-accordion p,
|
88 |
+
&.ab-block-cta p {
|
89 |
+
font-size: 21px;
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
div[class*="wp-block-atomic"].ab-font-size-22 {
|
94 |
+
&.ab-block-testimonial p,
|
95 |
+
&.ab-block-notice p,
|
96 |
+
&.ab-block-profile p,
|
97 |
+
&.ab-block-accordion p,
|
98 |
+
&.ab-block-cta p {
|
99 |
+
font-size: 22px;
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
div[class*="wp-block-atomic"].ab-font-size-23 {
|
104 |
+
&.ab-block-testimonial p,
|
105 |
+
&.ab-block-notice p,
|
106 |
+
&.ab-block-profile p,
|
107 |
+
&.ab-block-accordion p,
|
108 |
+
&.ab-block-cta p {
|
109 |
+
font-size: 23px;
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
div[class*="wp-block-atomic"].ab-font-size-24 {
|
114 |
+
&.ab-block-testimonial p,
|
115 |
+
&.ab-block-notice p,
|
116 |
+
&.ab-block-profile p,
|
117 |
+
&.ab-block-accordion p,
|
118 |
+
&.ab-block-cta p {
|
119 |
+
font-size: 24px;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
.center {
|
125 |
+
text-align: center;
|
126 |
+
}
|
127 |
+
|
128 |
+
.left {
|
129 |
+
text-align: left;
|
130 |
+
}
|
131 |
+
|
132 |
+
.right {
|
133 |
+
text-align: right;
|
134 |
+
}
|
135 |
+
|
136 |
+
@media only screen and (min-width: 600px) {
|
137 |
+
.wp-block-columns .layout-column-1,
|
138 |
+
.wp-block-columns .layout-column-2 {
|
139 |
+
margin-right: 5%;
|
140 |
+
}
|
141 |
+
}
|
142 |
+
|
143 |
+
.wp-block-image {
|
144 |
+
margin-bottom: 1.2em;
|
145 |
+
}
|
146 |
+
|
147 |
+
.ab-text-link {
|
148 |
+
color: inherit;
|
149 |
+
box-shadow: 0 -1px 0 inset;
|
150 |
+
text-decoration: none;
|
151 |
+
transition: .3s ease;
|
152 |
+
|
153 |
+
&:hover {
|
154 |
+
color: inherit;
|
155 |
+
box-shadow: 0 -2px 0 inset;
|
156 |
+
color: $accent;
|
157 |
+
}
|
158 |
+
}
|
src/utils/helper.js
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Helper Functions
|
3 |
+
*/
|
4 |
+
|
5 |
+
// Import helper dependencies
|
6 |
+
import md5 from 'md5';
|
7 |
+
|
8 |
+
// Calculate the font size
|
9 |
+
export function fontRatioToClass( ratio ) {
|
10 |
+
return ( ratio === 0 || ratio === 50 ) ?
|
11 |
+
null :
|
12 |
+
'font-size-' + ( 1 * Math.round( ratio / 1 ) );
|
13 |
+
}
|
14 |
+
|
15 |
+
// Generate a unique ID for the notice block
|
16 |
+
export function generateUniqueID( input ) {
|
17 |
+
return md5( input ).substr( 0, 6 );
|
18 |
+
}
|