Skip to content

Commit

Permalink
feat: handle custom styling of layouts (#238)
Browse files Browse the repository at this point in the history
Closes #225
  • Loading branch information
adekbadek authored Jun 26, 2020
1 parent 20b08bc commit 2ba844d
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 21 deletions.
42 changes: 41 additions & 1 deletion includes/class-newspack-newsletters-layouts.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public static function instance() {
*/
public function __construct() {
add_action( 'init', [ __CLASS__, 'register_layout_cpt' ] );
add_action( 'init', [ __CLASS__, 'register_meta' ] );
}

/**
Expand All @@ -55,12 +56,51 @@ public static function register_layout_cpt() {
$cpt_args = [
'public' => false,
'show_in_rest' => true,
'supports' => [ 'editor', 'title' ],
'supports' => [ 'editor', 'title', 'custom-fields' ],
'taxonomies' => [],
];
\register_post_type( self::NEWSPACK_NEWSLETTERS_LAYOUT_CPT, $cpt_args );
}

/**
* Register custom fields.
*/
public static function register_meta() {
\register_meta(
'post',
'font_header',
[
'object_subtype' => self::NEWSPACK_NEWSLETTERS_LAYOUT_CPT,
'show_in_rest' => true,
'type' => 'string',
'single' => true,
'auth_callback' => '__return_true',
]
);
\register_meta(
'post',
'font_body',
[
'object_subtype' => self::NEWSPACK_NEWSLETTERS_LAYOUT_CPT,
'show_in_rest' => true,
'type' => 'string',
'single' => true,
'auth_callback' => '__return_true',
]
);
\register_meta(
'post',
'background_color',
[
'object_subtype' => self::NEWSPACK_NEWSLETTERS_LAYOUT_CPT,
'show_in_rest' => true,
'type' => 'string',
'single' => true,
'auth_callback' => '__return_true',
]
);
}

/**
* Token replacement for newsletter layouts.
*
Expand Down
13 changes: 12 additions & 1 deletion includes/class-newspack-newsletters.php
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,19 @@ public static function api_get_layouts() {
'posts_per_page' => -1,
)
);
$user_layouts = array_map(
function ( $post ) {
$post->meta = [
'background_color' => get_post_meta( $post->ID, 'background_color', true ),
'font_body' => get_post_meta( $post->ID, 'font_body', true ),
'font_header' => get_post_meta( $post->ID, 'font_header', true ),
];
return $post;
},
$layouts_query->get_posts()
);
$layouts = array_merge(
$layouts_query->get_posts(),
$user_layouts,
Newspack_Newsletters_Layouts::get_default_layouts(),
apply_filters( 'newspack_newsletters_templates', [] )
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import { parse } from '@wordpress/blocks';
import { useState, useMemo } from '@wordpress/element';
import { Button, TextControl } from '@wordpress/components';
import { ENTER, SPACE } from '@wordpress/keycodes';
import { BlockPreview } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { LAYOUT_CPT_SLUG } from '../../../../utils/consts';
import { setPreventDeduplicationForPostsInserter } from '../../../../editor/blocks/posts-inserter/utils';
import NewsletterPreview from '../../../newsletter-preview';

const SingleLayoutPreview = ( {
isEditable,
Expand All @@ -29,6 +29,7 @@ const SingleLayoutPreview = ( {
ID,
post_title: title,
post_content: content,
meta,
} ) => {
const handleDelete = () => {
// eslint-disable-next-line no-alert
Expand Down Expand Up @@ -75,7 +76,7 @@ const SingleLayoutPreview = ( {
aria-label={ title }
>
{ '' === content ? null : (
<BlockPreview blocks={ blockPreviewBlocks } viewportWidth={ 600 } />
<NewsletterPreview meta={ meta } blocks={ blockPreviewBlocks } viewportWidth={ 600 } />
) }
</div>
{ isEditable ? (
Expand Down
28 changes: 19 additions & 9 deletions src/components/init-modal/screens/layout-picker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { compose } from '@wordpress/compose';
import { withSelect, withDispatch } from '@wordpress/data';
import { Button, Spinner } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { BlockPreview } from '@wordpress/block-editor';

/**
* Internal dependencies
Expand All @@ -22,6 +21,7 @@ import { BLANK_LAYOUT_ID } from '../../../../utils/consts';
import { isUserDefinedLayout } from '../../../../utils';
import { useLayoutsState } from '../../../../utils/hooks';
import SingleLayoutPreview from './SingleLayoutPreview';
import NewsletterPreview from '../../../newsletter-preview';

const LAYOUTS_TABS = [
{
Expand All @@ -35,33 +35,43 @@ const LAYOUTS_TABS = [
},
];

const LayoutPicker = ( { getBlocks, insertBlocks, replaceBlocks, savePost, setLayoutIdMeta } ) => {
const LayoutPicker = ( {
getBlocks,
insertBlocks,
replaceBlocks,
savePost,
setNewsletterMeta,
} ) => {
const { layouts, isFetchingLayouts, deleteLayoutPost } = useLayoutsState();

const insertLayout = layoutId => {
const { post_content: content } = find( layouts, { ID: layoutId } ) || {};
const { post_content: content, meta = {} } = find( layouts, { ID: layoutId } ) || {};
const blocksToInsert = content ? parse( content ) : [];
const existingBlocksIds = getBlocks().map( ( { clientId } ) => clientId );
if ( existingBlocksIds.length ) {
replaceBlocks( existingBlocksIds, blocksToInsert );
} else {
insertBlocks( blocksToInsert );
}
setLayoutIdMeta( layoutId );
const metaPayload = {
template_id: layoutId,
...meta,
};
setNewsletterMeta( metaPayload );
setTimeout( savePost, 1 );
};

const [ selectedLayoutId, setSelectedLayoutId ] = useState( null );
const layoutBlocks = useMemo(() => {
const layoutPreviewProps = useMemo(() => {
const layout = selectedLayoutId && find( layouts, { ID: selectedLayoutId } );
return layout ? parse( layout.post_content ) : null;
return layout ? { blocks: parse( layout.post_content ), meta: layout.meta } : null;
}, [ selectedLayoutId, layouts.length ]);

const canRenderPreview = layoutBlocks && layoutBlocks.length > 0;
const canRenderPreview = layoutPreviewProps && layoutPreviewProps.blocks.length > 0;

const renderPreview = () =>
canRenderPreview ? (
<BlockPreview blocks={ layoutBlocks } viewportWidth={ 600 } />
<NewsletterPreview { ...layoutPreviewProps } viewportWidth={ 600 } />
) : (
<p>{ __( 'Select a layout to preview.', 'newspack-newsletters' ) }</p>
);
Expand Down Expand Up @@ -166,7 +176,7 @@ export default compose( [
savePost,
insertBlocks,
replaceBlocks,
setLayoutIdMeta: id => editPost( { meta: { template_id: id } } ),
setNewsletterMeta: meta => editPost( { meta } ),
};
} ),
] )( LayoutPicker );
45 changes: 45 additions & 0 deletions src/components/newsletter-preview/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* WordPress dependencies
*/
import { BlockPreview } from '@wordpress/block-editor';
import { Fragment, useMemo } from '@wordpress/element';

/**
* Internal dependencies
*/
import './style.scss';

const NewsletterPreview = ( { meta = {}, ...props } ) => {
const ELEMENT_ID = useMemo( () => `preview-${ Math.round( Math.random() * 1000 ) }`, [] );

return (
<Fragment>
<style>{ `${
meta.font_body
? `
#${ ELEMENT_ID } *:not( code ) {
font-family: ${ meta.font_body };
}`
: ' '
}${
meta.font_header
? `
#${ ELEMENT_ID } h1, #${ ELEMENT_ID } h2, #${ ELEMENT_ID } h3, #${ ELEMENT_ID } h4, #${ ELEMENT_ID } h5, #${ ELEMENT_ID } h6 {
font-family: ${ meta.font_header };
}`
: ' '
}` }</style>
<div
id={ ELEMENT_ID }
className="newspack-newsletters__layout-preview"
style={ {
backgroundColor: meta.background_color,
} }
>
<BlockPreview { ...props } />
</div>
</Fragment>
);
};

export default NewsletterPreview;
5 changes: 5 additions & 0 deletions src/components/newsletter-preview/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.newspack-newsletters__layout-preview {
width: 100%;
height: 100%;
position: absolute;
}
26 changes: 18 additions & 8 deletions src/newsletter-editor/layout/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
/**
* External dependencies
*/
import { find } from 'lodash';
import { isEqual, find } from 'lodash';

/**
* WordPress dependencies
*/
import { compose } from '@wordpress/compose';
import { parse, serialize } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { BlockPreview } from '@wordpress/block-editor';
import { withDispatch, withSelect } from '@wordpress/data';
import { Fragment, useState, useEffect, useMemo } from '@wordpress/element';
import { Button, Modal, TextControl, Spinner } from '@wordpress/components';
Expand All @@ -22,22 +21,28 @@ import { LAYOUT_CPT_SLUG, NEWSLETTER_CPT_SLUG } from '../../utils/consts';
import { isUserDefinedLayout } from '../../utils';
import './style.scss';
import { setPreventDeduplicationForPostsInserter } from '../../editor/blocks/posts-inserter/utils';
import NewsletterPreview from '../../components/newsletter-preview';

export default compose( [
withSelect( select => {
const { getEditedPostAttribute, isEditedPostEmpty, getCurrentPostId } = select( 'core/editor' );
const { getBlocks } = select( 'core/block-editor' );
const meta = getEditedPostAttribute( 'meta' );
const { template_id: layoutId } = meta;
const { template_id: layoutId, background_color, font_body, font_header } = meta;
return {
layoutId,
postTitle: getEditedPostAttribute( 'title' ),
postBlocks: getBlocks(),
isEditedPostEmpty: isEditedPostEmpty(),
currentPostId: getCurrentPostId(),
stylingMeta: {
background_color,
font_body,
font_header,
},
};
} ),
withDispatch( ( dispatch, { currentPostId } ) => {
withDispatch( ( dispatch, { currentPostId, stylingMeta } ) => {
const { replaceBlocks } = dispatch( 'core/block-editor' );
const { editPost } = dispatch( 'core/editor' );
const { saveEntityRecord } = dispatch( 'core' );
Expand All @@ -48,7 +53,7 @@ export default compose( [
editPost( { meta: { template_id: id } } );
saveEntityRecord( 'postType', NEWSLETTER_CPT_SLUG, {
id: currentPostId,
meta: { template_id: id },
meta: { template_id: id, ...stylingMeta },
} );
},
saveLayout: payload =>
Expand All @@ -67,6 +72,7 @@ export default compose( [
postBlocks,
postTitle,
isEditedPostEmpty,
stylingMeta,
} ) => {
const [ warningModalVisible, setWarningModalVisible ] = useState( false );
const { layouts, isFetchingLayouts } = useLayoutsState();
Expand Down Expand Up @@ -108,13 +114,15 @@ export default compose( [
};

const postContent = useMemo( () => serialize( postBlocks ), [ postBlocks ] );
const isPostContentSameAsLayout = postContent === usedLayout.post_content;
const isPostContentSameAsLayout =
postContent === usedLayout.post_content && isEqual( usedLayout.meta, stylingMeta );

const handleSaveAsLayout = () => {
setIsSavingLayout( true );
const updatePayload = {
title: newLayoutName,
content: postContent,
meta: stylingMeta,
};
saveLayout( updatePayload ).then( newLayout => {
setIsManageModalVisible( false );
Expand All @@ -130,8 +138,9 @@ export default compose( [
) {
setIsSavingLayout( true );
const updatePayload = {
content: postContent,
id: usedLayout.ID,
content: postContent,
meta: stylingMeta,
};
saveLayout( updatePayload ).then( handleLayoutUpdate );
}
Expand All @@ -150,7 +159,8 @@ export default compose( [
<div className="newspack-newsletters-layouts">
<div className="newspack-newsletters-layouts__item">
<div className="newspack-newsletters-layouts__item-preview">
<BlockPreview
<NewsletterPreview
meta={ usedLayout.meta }
blocks={ setPreventDeduplicationForPostsInserter( blockPreview ) }
viewportWidth={ 600 }
/>
Expand Down

0 comments on commit 2ba844d

Please sign in to comment.