Skip to content

Commit

Permalink
Merge pull request #134 from Automattic/add/book-block
Browse files Browse the repository at this point in the history
Create a Book block
  • Loading branch information
vcanales committed Aug 21, 2020
2 parents a2ed78a + a7e5bf9 commit 04d53e3
Show file tree
Hide file tree
Showing 16 changed files with 2,546 additions and 125 deletions.
27 changes: 27 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab

[*.yml]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false

[*.{gradle,java,kt}]
indent_style = space

[packages/react-native-*/**.xml]
indent_style = space
4 changes: 4 additions & 0 deletions .wp-env.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"core": "WordPress/WordPress#master",
"plugins": [ "." ]
}
61 changes: 61 additions & 0 deletions blocks/book/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* The following styles get applied inside the editor only.
*
* Replace them with your own styles or remove the file completely.
*/

// This selector should be revisited if/when we can leverage lightBlockWrapper.
.wp-block-a8c-book {
.wp-block-a8c-book__cover {
// Ensure the correct aspect ratio of the cover image, even when the source image is way too big.
height: 100% !important; // Needs high specificity to override an inline style. Would be nice if this could be output by the component itself instead.

// Make the placeholder look like a book.
.components-placeholder {
box-shadow: none;
height: 100%;
}
}

.wp-block-a8c-book__cover-placeholder {
// Default to 33% width.
min-width: 140px;
min-height: 230px;
width: 33% !important;
padding-top: 50%;

.components-placeholder {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}

// Hide the resize handles on the placeholder.
.components-resizable-box__handle {
display: none;
}
}
}

.wp-block[data-align='center'] > .wp-block-a8c-book {
display: flex;
flex-direction: column;
align-items: center;
}
.wp-block[data-align='left'] > .wp-block-a8c-book {
margin-right: 1em;
}

.wp-block[data-align='right'] > .wp-block-a8c-book {
margin-left: 1em;
}

.wp-block[data-align='left'],
.wp-block[data-align='right'] {
> .wp-block-a8c-book {
margin-top: 0;
margin-bottom: 0;
}
}
9 changes: 9 additions & 0 deletions blocks/book/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

add_action( 'init', function() {
register_block_type( 'a8c/book', [
'editor_script' => 'wpcom-blocks',
'style' => 'wpcom-blocks',
'editor_style' => 'wpcom-blocks-editor',
] );
} );
207 changes: 207 additions & 0 deletions blocks/book/src/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import {
BlockControls,
MediaPlaceholder,
MediaUpload,
RichText,
__experimentalBlock as Block,
} from '@wordpress/block-editor';
import { Button, ResizableBox, Toolbar } from '@wordpress/components';
/**
* Retrieves the translation of text.
*
* @see https://developer.wordpress.org/block-editor/packages/packages-i18n/
*/
import { __ } from '@wordpress/i18n';
import { isEmpty } from 'lodash';

import classnames from 'classnames';
import prefixClasses from './prefixClasses';

/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @see https://developer.wordpress.org/block-editor/developers/block-api/block-edit-save/#edit
*
* @param {Object} [props] Properties passed from the editor.
* @param {string} [props.className] Class name generated for the block.
*
* @return {WPElement} Element to render.
*/

export default function Edit( {
className,
isSelected,
setAttributes,
attributes,
} ) {
const {
author,
align,
height,
imageId,
imageUrl,
publicationDate,
publisher,
title,
width,
} = attributes;
const hasMedia = !! imageId;

const handleResize = ( event, direction, elt, delta ) =>
setAttributes( {
height: parseInt( height + delta.height, 10 ),
width: parseInt( width + delta.width, 10 ),
} );

const handleSelectCoverImage = ( media ) =>
setAttributes( { imageId: media.id, imageUrl: media.url } );

const handleImageLoad = ( event ) => {
const { currentTarget } = event;
const { naturalHeight, naturalWidth } = currentTarget;

setAttributes( { height: naturalHeight, width: naturalWidth } );
};

const classes = classnames( 'wp-block-a8c-book', className );

/**
* Function that creates an event handler for the RichText element,
* which will update the given `attribute`.
*
* @param {String} attribute
*/
const updateAttribute = ( attribute ) => ( value ) =>
setAttributes( { [ attribute ]: value } );

const enabledHandles = {
top: false,
right: align === 'left' || ! align || align === 'center',
left: align === 'right' || align === 'center',
bottom: true,
topRight: false,
bottomRight: false,
bottomLeft: false,
topLeft: false,
};

const resizableBoxClasses = classnames( prefixClasses( '__cover' ), {
[ `${ prefixClasses( '__cover-placeholder' ) }` ]: ! hasMedia,
} );

const shouldDisplayField = ( field ) =>
! RichText.isEmpty( field ) || isSelected;
const shouldDisplayMetadata =
title || author || publisher || publicationDate || isSelected;

return (
<Block.div className={ classes }>
{ hasMedia && (
<BlockControls>
<Toolbar>
<MediaUpload
onSelect={ handleSelectCoverImage }
allowedTypes={ [ 'image' ] }
value={ imageId }
render={ ( { open } ) => (
<Button
className="components-toolbar__control"
onClick={ open }
>
{ __( 'Replace' ) }
</Button>
) }
/>
</Toolbar>
</BlockControls>
) }
<ResizableBox
enable={ enabledHandles }
className={ resizableBoxClasses }
size={ {
height,
width,
} }
defaultSize={ { width: '100%' } }
maxWidth="100%"
onResizeStop={ handleResize }
showHandle={ isSelected }
lockAspectRatio
>
{ hasMedia ? (
<img
src={ imageUrl }
alt={ title }
onLoad={ handleImageLoad }
/>
) : (
<MediaPlaceholder
allowedTypes={ [ 'image' ] }
onSelect={ handleSelectCoverImage }
labels={ {
title: __( 'Book cover image' ),
instructions: __(
"Upload the book's cover image."
),
} }
value={ { id: imageId } }
/>
) }
</ResizableBox>

{ shouldDisplayMetadata && (
<section
className={ prefixClasses( '__meta' ) }
style={ { width } }
>
{ shouldDisplayField( title ) && (
<RichText
keepPlaceholderOnFocus
name="title"
tagName="p"
value={ title }
placeholder="Book title"
className={ prefixClasses( '__title' ) }
onChange={ updateAttribute( 'title' ) }
/>
) }
{ shouldDisplayField( author ) && (
<RichText
keepPlaceholderOnFocus
name="author"
tagName="p"
value={ author }
placeholder="Author name"
onChange={ updateAttribute( 'author' ) }
/>
) }
<p className={ prefixClasses( '__publication' ) }>
{ shouldDisplayField( publisher ) && (
<RichText
keepPlaceholderOnFocus
name="publisher"
tagName="span"
value={ publisher }
placeholder="Publisher"
onChange={ updateAttribute( 'publisher' ) }
/>
) }
{ shouldDisplayField( publicationDate ) && (
<RichText
keepPlaceholderOnFocus
name="publicationDate"
tagName="span"
value={ publicationDate }
placeholder="Publication date"
onChange={ updateAttribute(
'publicationDate'
) }
/>
) }
</p>
</section>
) }
</Block.div>
);
}
14 changes: 14 additions & 0 deletions blocks/book/src/icon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* WordPress depedencies
*/

import { Path, SVG } from '@wordpress/components';

export const BookIcon = () => (
<SVG xmlns="http://www.w3.org/2000/svg"
width="24" height="24"
viewBox="0 0 24 24"
>
<Path d="M5 5v14c0 1.1.9 2 2 2h10V3H7c-1.1 0-2 .9-2 2zm7 2.5l2 2.5V4.5h1.5v15H7c-.3 0-.5-.2-.5-.5V5c0-.3.2-.5.5-.5h3V10l2-2.5zM18.5 3v18H20V3h-1.5z" />
</SVG>
);
Loading

0 comments on commit 04d53e3

Please sign in to comment.