diff --git a/tinymce-per-block/src/assets/stylesheets/theme.scss b/tinymce-per-block/src/assets/stylesheets/theme.scss index 53d2e759d8c34..ef6b8c1f198fe 100644 --- a/tinymce-per-block/src/assets/stylesheets/theme.scss +++ b/tinymce-per-block/src/assets/stylesheets/theme.scss @@ -28,6 +28,7 @@ font-weight: 300; font-size: 14px; color: $gray-dark-300; + text-align: center; } } diff --git a/tinymce-per-block/src/blocks/embed-block/_style.scss b/tinymce-per-block/src/blocks/embed-block/_style.scss index 9953abc6769e5..7cba85104d005 100644 --- a/tinymce-per-block/src/blocks/embed-block/_style.scss +++ b/tinymce-per-block/src/blocks/embed-block/_style.scss @@ -1,4 +1,41 @@ -.embed-block__form textarea, .embed-block__form .textarea-mirror { +.embed-block__form { + margin: 50px auto; + width: 50%; + textarea, .textarea-mirror { + width: 100%; + border: 1px solid $gray-light; + border-radius: 4px; + padding: 6px 12px; + font: inherit; + font-weight: 300; + font-size: 14px; + color: $gray-dark-300; + resize: none; + + &:focus { + outline: 0; + } + } + + .embed-block__title { + color: #87919d; + text-align: center; + vertical-align: middle; + font-weight: bold; + margin-bottom: 10px; + + .dashicon { + width: 24px; + height: 24px; + vertical-align: middle; + margin-right: 5px; + fill: #87919d; + } + } +} + +.embed-block__caption textarea, +.embed-block__caption .textarea-mirror { margin-top: 10px; width: 100%; border: none; @@ -8,12 +45,38 @@ font-size: 14px; color: $gray-dark-300; resize: none; + text-align: center; &:focus { outline: 0; } } -.embed-block__content iframe { - width: 100%; +.embed-block { + &.align-full-width { + margin-left: calc(50% - 50vw); + width: 100vw; + max-width: none; + padding-left: 0; + padding-right: 0; + + .embed-block__content { + width: 100%; + } + } + + &.align-left { + float: left; + z-index: 1; + } + + &.align-right { + float: right; + z-index: 1; + } + + &.align-center { + text-align: center; + max-width: 100%; + } } diff --git a/tinymce-per-block/src/blocks/embed-block/form.js b/tinymce-per-block/src/blocks/embed-block/form.js index 5668af24f45ee..39ccf42e226de 100644 --- a/tinymce-per-block/src/blocks/embed-block/form.js +++ b/tinymce-per-block/src/blocks/embed-block/form.js @@ -2,50 +2,93 @@ * External dependencies */ import { createElement, Component } from 'wp-elements'; +import { CloudOutline } from 'dashicons'; +import classNames from 'classnames'; +/** + * Internal Dependencies + */ import { EnhancedInputComponent } from 'wp-blocks'; import BlockArrangement from 'controls/block-arrangement'; import { getEmbedHtmlFromUrl } from '../../utils/embed'; +import FigureAlignmentToolbar from 'controls/figure-alignment-toolbar'; export default class EmbedBlockForm extends Component { merge = () => { this.props.remove(); }; - bindInput = ( ref ) => { - this.input = ref; + setAlignment = ( id ) => { + this.props.change( { align: id } ); }; render() { const { block, isSelected, change, moveCursorUp, moveCursorDown, - remove, focusConfig, focus, moveBlockUp, moveBlockDown } = this.props; + remove, focusConfig, focus, moveBlockUp, moveBlockDown, appendBlock } = this.props; const removePrevious = () => { if ( ! block.url ) { remove(); } }; + const splitValue = ( left, right ) => { + change( { caption: left } ); + appendBlock( { + blockType: 'text', + content: right + } ); + }; const html = getEmbedHtmlFromUrl( block.url ); return ( -
+
{ isSelected && } -
-
- change( { url: value } ) } - focusConfig={ focusConfig } - onFocusChange={ ( config ) => focus( config ) } - placeholder="Enter an embed URL" - /> -
+ { isSelected && +
+
+ +
+
+ } + { ! block.url && +
+
+ Embed URL +
+ change( { url: value } ) } + focusConfig={ focusConfig } + onFocusChange={ ( config ) => focus( config ) } + placeholder="Paste URL to embed here..." + /> +
+ } + { block.url && +
+
+
+ change( { caption: value } ) } + placeholder="Write caption" + focusConfig={ focusConfig } + onFocusChange={ focus } + /> +
+
+ }
); } diff --git a/tinymce-per-block/src/blocks/embed-block/index.js b/tinymce-per-block/src/blocks/embed-block/index.js index 53b4c57af58fd..80895d9fa3ba2 100644 --- a/tinymce-per-block/src/blocks/embed-block/index.js +++ b/tinymce-per-block/src/blocks/embed-block/index.js @@ -8,29 +8,49 @@ import { VideoAlt3Icon } from 'dashicons'; * Internal dependencies */ import form from './form'; -import { getEmbedHtmlFromUrl } from '../../utils/embed'; +import { getEmbedHtmlFromUrl } from 'utils/embed'; +import { getFigureAlignmentStyles } from 'utils/figure-alignment'; registerBlock( 'embed', { title: 'Embed', form: form, icon: VideoAlt3Icon, parse: ( rawBlock ) => { + const div = document.createElement( 'div' ); + div.innerHTML = rawBlock.rawContent; + const captionNode = div.firstChild.nodeName === 'FIGURE' + ? div.firstChild.querySelector( 'figure > figcaption' ) + : null; + const caption = captionNode ? captionNode.innerHTML : ''; + return { blockType: 'embed', url: rawBlock.attrs.url, + align: rawBlock.attrs.align, + caption }; }, serialize: ( block ) => { + const styles = getFigureAlignmentStyles( block.align ); + const rawContent = [ + ``, + `${ getEmbedHtmlFromUrl( block.url ) }
`, + `
${ block.caption }
`, + '' + ].join( '' ); + return { blockType: 'embed', - attrs: { url: block.url }, - rawContent: getEmbedHtmlFromUrl( block.url ) + attrs: { url: block.url, align: block.align }, + rawContent }; }, create: () => { return { blockType: 'embed', - url: '' + url: '', + align: 'no-align', + caption: '' }; } } ); diff --git a/tinymce-per-block/src/blocks/html-block/index.js b/tinymce-per-block/src/blocks/html-block/index.js index fc54132d22e37..792c1361cf25b 100644 --- a/tinymce-per-block/src/blocks/html-block/index.js +++ b/tinymce-per-block/src/blocks/html-block/index.js @@ -18,20 +18,23 @@ registerBlock( 'html', { blockType: 'html', align: rawBlock.attrs.align || 'no-align', content: rawBlock.rawContent, + caption: rawBlock.caption }; }, serialize: ( block ) => { return { blockType: 'html', attrs: { align: block.align }, - rawContent: block.content + rawContent: block.content, + caption: block.caption }; }, create: () => { return { blockType: 'html', content: '', - align: 'no-align' + align: 'no-align', + caption: '' }; } } ); diff --git a/tinymce-per-block/src/blocks/image-block/_style.scss b/tinymce-per-block/src/blocks/image-block/_style.scss index 75fde17e00ade..6b6e9add66a3c 100644 --- a/tinymce-per-block/src/blocks/image-block/_style.scss +++ b/tinymce-per-block/src/blocks/image-block/_style.scss @@ -25,9 +25,13 @@ z-index: 1; } + &.align-center { + text-align: center; + max-width: 100%; + } .image-block__display { - display: block; + display: inline-block; max-width: 100%; } @@ -42,6 +46,7 @@ font-size: 14px; color: $gray-dark-300; resize: none; + text-align: center; &:focus { outline: 0; diff --git a/tinymce-per-block/src/blocks/image-block/form.js b/tinymce-per-block/src/blocks/image-block/form.js index dccd5903ceb99..ae6d1389bac47 100644 --- a/tinymce-per-block/src/blocks/image-block/form.js +++ b/tinymce-per-block/src/blocks/image-block/form.js @@ -2,16 +2,11 @@ * External dependencies */ import { createElement, Component } from 'wp-elements'; -import { - ImageNoAlignIcon, - ImageAlignRightIcon, - ImageAlignLeftIcon, - ImageFullWidthIcon -} from 'dashicons'; import classNames from 'classnames'; import { EnhancedInputComponent } from 'wp-blocks'; import BlockArrangement from 'controls/block-arrangement'; +import FigureAlignmentToolbar from 'controls/figure-alignment-toolbar'; export default class ImageBlockForm extends Component { @@ -19,11 +14,7 @@ export default class ImageBlockForm extends Component { this.props.remove(); } - bindCaption = ( ref ) => { - this.caption = ref; - } - - setImageAlignment = ( id ) => () => { + setAlignment = ( id ) => { this.props.change( { align: id } ); }; @@ -42,32 +33,15 @@ export default class ImageBlockForm extends Component { content: right } ); }; - const imageAlignments = [ - { id: 'no-align', icon: ImageNoAlignIcon }, - { id: 'align-left', icon: ImageAlignLeftIcon }, - { id: 'align-right', icon: ImageAlignRightIcon }, - { id: 'align-full-width', icon: ImageFullWidthIcon }, - ]; - const alignValue = block.align || 'no-align'; return ( -
+
{ isSelected && } { isSelected &&
- { imageAlignments.map( ( { id, icon: Icon } ) => - - ) } +
} @@ -80,14 +54,13 @@ export default class ImageBlockForm extends Component { />
change( { caption: value } ) } - placeholder="Enter a caption" + placeholder="Write caption" focusConfig={ focusConfig } onFocusChange={ focus } /> diff --git a/tinymce-per-block/src/blocks/image-block/index.js b/tinymce-per-block/src/blocks/image-block/index.js index a7c0afde01ed0..0ebae2139eca3 100644 --- a/tinymce-per-block/src/blocks/image-block/index.js +++ b/tinymce-per-block/src/blocks/image-block/index.js @@ -8,6 +8,7 @@ import { FormatImageIcon } from 'dashicons'; * Internal dependencies */ import form from './form'; +import { getFigureAlignmentStyles } from 'utils/figure-alignment'; registerBlock( 'image', { title: 'Image', @@ -40,36 +41,24 @@ registerBlock( 'image', { return { blockType: 'image', - align: rawBlock.attrs.align || 'no-align', + align: rawBlock.attrs.align, src, caption }; }, serialize: ( block ) => { - const styles = { - 'align-left': { - figure: 'float: left;' - }, - 'align-right': { - figure: 'float: right;' - }, - 'align-full-width': { - figure: 'margin-left: calc(50% - 50vw);width: 100vw;max-width: none;padding-left: 0;padding-right: 0;', - img: 'width: 100%' - } - }; - const figureStyle = styles[ block.align ] && styles[ block.align ].figure - ? ` style="${ styles[ block.align ].figure }"` - : ''; - const imgStyle = styles[ block.align ] && styles[ block.align ].img - ? ` style="${ styles[ block.align ].img }"` - : ''; + const styles = getFigureAlignmentStyles( block.align ); const captionHtml = block.caption ? `
${ block.caption }
` : ''; - const rawContent = `${ captionHtml }`; + const rawContent = [ + ``, + ``, + captionHtml, + '' + ].join( '' ); return { blockType: 'image', - attrs: { /* caption: block.caption ,*/ align: block.align }, + attrs: { align: block.align }, rawContent }; }, diff --git a/tinymce-per-block/src/controls/figure-alignment-toolbar.js b/tinymce-per-block/src/controls/figure-alignment-toolbar.js new file mode 100644 index 0000000000000..3a985246ca6c7 --- /dev/null +++ b/tinymce-per-block/src/controls/figure-alignment-toolbar.js @@ -0,0 +1,44 @@ +/** + * External dependencies + */ +import { createElement, Component } from 'wp-elements'; +import classNames from 'classnames'; +import { + ImageAlignLeftIcon, + ImageAlignCenterIcon, + ImageAlignRightIcon, + ImageFullWidthIcon +} from 'dashicons'; + +export default class FigureAlignmentToolbar extends Component { + onClick = ( id ) => () => { + const newValue = id === this.props.value ? 'no-align' : id; + this.props.onChange( newValue ); + }; + + render() { + const { value } = this.props; + const alignments = [ + { id: 'align-left', icon: ImageAlignLeftIcon }, + { id: 'align-center', icon: ImageAlignCenterIcon }, + { id: 'align-right', icon: ImageAlignRightIcon }, + { id: 'align-full-width', icon: ImageFullWidthIcon }, + ]; + + return ( +
+ { alignments.map( ( { id, icon: Icon } ) => + + ) } +
+ ); + } +} diff --git a/tinymce-per-block/src/external/dashicons/icons/add-outline.js b/tinymce-per-block/src/external/dashicons/icons/add-outline.js index 2bba2ebfac1f2..c69805fde2465 100644 --- a/tinymce-per-block/src/external/dashicons/icons/add-outline.js +++ b/tinymce-per-block/src/external/dashicons/icons/add-outline.js @@ -5,7 +5,8 @@ import { createElement } from 'wp-elements'; export default () => ( - + diff --git a/tinymce-per-block/src/external/dashicons/icons/cloud-outline.js b/tinymce-per-block/src/external/dashicons/icons/cloud-outline.js new file mode 100644 index 0000000000000..328c9eaaae2cd --- /dev/null +++ b/tinymce-per-block/src/external/dashicons/icons/cloud-outline.js @@ -0,0 +1,20 @@ +/** + * External dependencies + */ +import { createElement } from 'wp-elements'; + +export default () => ( + + + + + + + +); diff --git a/tinymce-per-block/src/external/dashicons/icons/image-no-align.js b/tinymce-per-block/src/external/dashicons/icons/image-align-center.js similarity index 100% rename from tinymce-per-block/src/external/dashicons/icons/image-no-align.js rename to tinymce-per-block/src/external/dashicons/icons/image-align-center.js diff --git a/tinymce-per-block/src/external/dashicons/icons/image-full-width.js b/tinymce-per-block/src/external/dashicons/icons/image-full-width.js index db9dff825b40c..31b22d7843726 100644 --- a/tinymce-per-block/src/external/dashicons/icons/image-full-width.js +++ b/tinymce-per-block/src/external/dashicons/icons/image-full-width.js @@ -4,4 +4,8 @@ import { createElement } from 'wp-elements'; // This is a gridicon -export default () => Full Bleed; +export default () => ( + + + +); diff --git a/tinymce-per-block/src/external/dashicons/index.js b/tinymce-per-block/src/external/dashicons/index.js index 0793a58b3351e..50d2e8f7a32f1 100644 --- a/tinymce-per-block/src/external/dashicons/index.js +++ b/tinymce-per-block/src/external/dashicons/index.js @@ -14,10 +14,11 @@ export { default as FormatImageIcon } from './icons/format-image'; export { default as EditorBoldIcon } from './icons/editor-bold'; export { default as EditorItalicIcon } from './icons/editor-italic'; export { default as EditorStrikethroughIcon } from './icons/editor-strikethrough'; -export { default as ImageNoAlignIcon } from './icons/image-align-left'; +export { default as ImageAlignCenterIcon } from './icons/image-align-center'; export { default as ImageAlignLeftIcon } from './icons/image-align-left'; export { default as ImageAlignRightIcon } from './icons/image-align-right'; export { default as ImageFullWidthIcon } from './icons/image-full-width'; export { default as VideoAlt3Icon } from './icons/video-alt3'; export { default as AdminLinksIcon } from './icons/admin-links'; export { default as AddOutlineIcon } from './icons/add-outline'; +export { default as CloudOutline } from './icons/cloud-outline'; diff --git a/tinymce-per-block/src/inserter/style.scss b/tinymce-per-block/src/inserter/style.scss index 7b3ca2a451ab3..315b5980248b5 100644 --- a/tinymce-per-block/src/inserter/style.scss +++ b/tinymce-per-block/src/inserter/style.scss @@ -5,7 +5,7 @@ border: none; margin: 20px; padding: 0; - svg { + .dashicon { cursor: pointer; fill: #87919d; width: 24px; @@ -88,7 +88,7 @@ background: #f0f2f4; } - svg { + .dashicon { margin-right: 8px; fill: #191e23; width: 24px; diff --git a/tinymce-per-block/src/utils/figure-alignment.js b/tinymce-per-block/src/utils/figure-alignment.js new file mode 100644 index 0000000000000..2c637fd619ac3 --- /dev/null +++ b/tinymce-per-block/src/utils/figure-alignment.js @@ -0,0 +1,28 @@ +export const getFigureAlignmentStyles = ( align ) => { + const styles = { + 'align-left': { + figure: 'float: left;' + }, + 'align-right': { + figure: 'float: right;' + }, + 'align-center': { + figure: 'text-align: center;' + }, + 'align-full-width': { + figure: 'margin-left: calc(50% - 50vw);width: 100vw;max-width: none;padding-left: 0;padding-right: 0;', + content: 'width: 100%' + } + }; + const figure = styles[ align ] && styles[ align ].figure + ? ` style="${ styles[ align ].figure }"` + : ''; + const content = styles[ align ] && styles[ align ].content + ? ` style="${ styles[ align ].content }"` + : ''; + + return { + figure, + content + }; +};