Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
withstate cards
/**
* BLOCK: Card Block.
*
* Registering a basic block with Gutenberg.
* Simple block, renders and saves the same content without any interactivity.
*/
// Import CSS.
import './style.scss';
import './editor.scss';
import { TeamMemberIcon } from '../../icons'
import {
registerBlockType,
__,
PanelColor,
Button,
IconButton,
Dashicon,
withState,
SelectControl,
RangeControl,
Toolbar,
InspectorControls,
RichText,
ColorPalette,
MediaUpload,
BlockControls,
UrlInput,
AlignmentToolbar,
} from '../../wp-imports'
export const edit = ( props ) => {
const {
isSelected,
editable,
setState,
className,
setAttributes
} = props;
const {
heading,
tagline,
des,
mediaID,
mediaURL,
headingColor,
taglineColor,
desColor,
buttonURL,
buttonText,
buttonColor,
buttonTextColor,
size,
cornerButtonRadius,
contentAlign
} = props.attributes;
const onSetActiveEditable = ( newEditable ) => () => {
setState( { editable: newEditable } )
}
const imageClass = mediaURL ? 'has-image' : ''
const buttonSizes = [
{ value: 'small', label: __( 'Small' ) },
{ value: 'normal', label: __( 'Normal' ) },
{ value: 'medium', label: __( 'Medium' ) },
{ value: 'large', label: __( 'Large' ) },
];
return [
isSelected && (
<BlockControls key='controls'>
<AlignmentToolbar
value={ contentAlign }
onChange={ ( newAlign ) => setAttributes( { contentAlign: newAlign } ) }
/>
<Toolbar>
<MediaUpload
onSelect={ ( media ) => setAttributes( { mediaURL: media.url, mediaID: media.id } ) }
type="image"
value={ mediaID }
render={ ( { open } ) => (
<IconButton
className="components-toolbar__control"
label={ __( 'Edit image' ) }
icon="edit"
onClick={ open }
/>
) }
/>
</Toolbar>
</BlockControls>
),
isSelected && (
<InspectorControls key={ 'inspector' }>
<PanelColor
title={ __( 'Heading Color' ) }
colorValue={ headingColor }
initialOpen={ false }
>
<ColorPalette
value={ headingColor }
onChange={ ( colorValue ) => setAttributes( { headingColor: colorValue } ) }
/>
</PanelColor>
<PanelColor
title={ __( 'Tagline Color' ) }
colorValue={ taglineColor }
initialOpen={ false }
>
<ColorPalette
value={ taglineColor }
onChange={ ( colorValue ) => setAttributes( { taglineColor: colorValue } ) }
/>
</PanelColor>
<PanelColor
title={ __( 'Description Color' ) }
colorValue={ desColor }
initialOpen={ false }
>
<ColorPalette
value={ desColor }
onChange={ ( colorValue ) => setAttributes( { desColor: colorValue } ) }
/>
</PanelColor>
<h2>Button Settings</h2>
<SelectControl
label={ __( 'Button Size' ) }
value={ size }
options={ buttonSizes.map( ({ value, label }) => ( {
value: value,
label: label,
} ) ) }
onChange={ ( newSize ) => { setAttributes( { size: newSize } ) } }
/>
<RangeControl
label={ __( 'Corner Radius' ) }
value={ cornerButtonRadius }
min='1'
max='50'
onChange={ ( cornerRad ) => setAttributes( { cornerButtonRadius: cornerRad } ) }
/>
<PanelColor
title={ __( 'Button Color' ) }
colorValue={ buttonColor }
initialOpen={ false }
>
<ColorPalette
value={ buttonColor }
onChange={ ( colorValue ) => setAttributes( { buttonColor: colorValue } ) }
/>
</PanelColor>
<PanelColor
title={ __( 'Button Text Color' ) }
colorValue={ buttonTextColor }
initialOpen={ false }
>
<ColorPalette
value={ buttonTextColor }
onChange={ ( colorValue ) => setAttributes( { buttonTextColor: colorValue } ) }
/>
</PanelColor>
</InspectorControls>
),
<div key={'editable'} className={ `ugb-card ${imageClass}` }>
<div className='ugb-card-image-container' style={{ backgroundImage: `url(${mediaURL})`, textAlign: contentAlign }}>
<MediaUpload
onSelect={ ( media ) => setAttributes( { mediaURL: media.url, mediaID: media.id } ) }
type={'image'}
value={mediaID}
render={ function( obj ) {
return [
! mediaURL && (
<Button
className={ mediaID ? '' : 'button button-large' }
onClick={ obj.open }
>
{__('Upload Image')}
</Button>
)
]
} }
/>
</div>
<RichText
tagName={ 'h4' }
value={ heading }
className={ 'ugb-card-heading' }
onChange={ (text) => setAttributes( { heading: text } ) }
isSelected={ isSelected && editable === 'heading' }
onFocus={ onSetActiveEditable( 'heading' ) }
style={ {
color: headingColor,
textAlign: contentAlign
} }
keepPlaceholderOnFocus
/>
<RichText
tagName={'p'}
value={ tagline }
className={ 'ugb-tagline' }
onChange={ (text) => setAttributes( { tagline: text } ) }
isSelected={ isSelected && editable === 'tagline' }
onFocus={ onSetActiveEditable( 'tagline' ) }
style={ {
color: taglineColor,
textAlign: contentAlign
} }
keepPlaceholderOnFocus
/>
<RichText
tagName={'p'}
value={ des }
className={ 'ugb-card-des' }
onChange={ (text) => setAttributes( { des: text } ) }
isSelected={ isSelected && editable === 'des' }
onFocus={ onSetActiveEditable( 'des' ) }
style={ {
color: desColor,
textAlign: contentAlign
} }
keepPlaceholderOnFocus
/>
<span key={ 'button' }
className={ `wp-block-button ugb-button-${contentAlign}` }>
<RichText
tagName={ 'span' }
placeholder={ buttonText.default }
value={ buttonText }
onChange={ (text) => setAttributes( { buttonText: text } ) }
className={`wp-ugb-button ugb-button-${size}`}
style={ {
backgroundColor: buttonColor,
color: buttonTextColor,
borderRadius: cornerButtonRadius + 'px',
} }
isSelected={ isSelected && editable === 'buttonText' }
onFocus={ onSetActiveEditable( 'buttonText' ) }
keepPlaceholderOnFocus
/>
</span>
</div>,
isSelected && (
<form
key={ 'form-link' }
onSubmit={ ( event ) => event.preventDefault() }
className={ `blocks-button__inline-link ugb-button-${contentAlign}` }
style={{ marginTop: 10 }}
>
<Dashicon icon={ 'admin-links' } />
<UrlInput
value={ buttonURL }
onChange={ ( value ) => setAttributes( { buttonURL: value } ) }
/>
<IconButton
icon={ 'editor-break' }
label={ __( 'Apply' ) }
type={ 'submit' }
/>
</form>
)
];
}
export const save = ( props ) => {
const {
heading,
tagline,
des,
mediaURL,
mediaID,
headingColor,
taglineColor,
desColor,
buttonURL,
buttonText,
buttonColor,
buttonTextColor,
size,
cornerButtonRadius,
contentAlign
} = props.attributes;
const buttonStyle = {
backgroundColor: buttonColor,
color: buttonTextColor,
borderRadius: cornerButtonRadius + 'px',
}
const imageClass = mediaURL ? 'has-image' : ''
const displayNone = ( ! heading.length && ! tagline.length && ! des.length && ! buttonText.length ) ? 'has-no-content' : 'has-content'
return (
<div className={ `ugb-card ${imageClass} ${displayNone}` }>
{ mediaURL && <div className="ugb-card-image-container" style={{ backgroundImage: `url(${mediaURL})`, textAlign: contentAlign }} data-src={mediaURL}></div> }
{ heading && !! heading.length && (
<h4 style={ { color: headingColor, textAlign: contentAlign } }>
{ heading }
</h4>
) }
{ tagline && !! tagline.length && (
<p className={ 'ugb-tagline' } style={ { color: taglineColor, textAlign: contentAlign } }>
{ tagline }
</p>
) }
{ des && !! des.length && (
<p className={ 'ugb-card-des' } style={ { color: desColor, textAlign: contentAlign } }>
{ des }
</p>
) }
{ buttonText && !! buttonText.length && (
<a
href={ buttonURL }
className={ `wp-ugb-button wp-block-button ugb-button-${size} ugb-button-${contentAlign}` }
style={ buttonStyle }>
{ buttonText }
</a>
) }
</div>
);
}
/**
* Register: Gutenberg Block.
*
* Registers a new block provided a unique name and an object defining its
* behavior. Once registered, the block is made editor as an option to any
* editor interface where blocks are implemented.
*
* @param {string} name Block name.
* @param {Object} settings Block settings.
* @return {?WPBlock} The block, if it has been successfully
* registered; otherwise `undefined`.
*/
registerBlockType( 'ugb/card', {
// Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block.
title: __( 'Card' ), // Block title.
icon: TeamMemberIcon, // Block icon from Dashicons → https://developer.wordpress.org/resource/dashicons/.
category: 'common', // Block category — Group blocks together based on common traits E.g. common, formatting, layout widgets, embed.
keywords: [
__( 'Card' ),
__( 'Stackable' ),
],
attributes: {
mediaID: {
type: 'number',
},
mediaURL: {
type: 'string',
source: 'attribute',
selector: '.ugb-card-image-container',
attribute: 'data-src',
},
heading: {
type: 'array',
source: 'children',
selector: '.ugb-card h4',
default: __( 'Ben Adams' )
},
tagline: {
type: 'array',
source: 'children',
selector: '.ugb-tagline',
default: __( 'Ben is the head of our small team' )
},
des: {
type: 'array',
source: 'children',
selector: '.ugb-card-des',
default: __( 'Ben is the head of our small team. He loves walking his dog, Walter, when he has some free time.' )
},
headingColor: {
type: 'string',
},
taglineColor: {
type: 'string',
},
desColor: {
type: 'string',
},
buttonURL: {
type: 'string',
source: 'attribute',
selector: '.wp-ugb-button',
attribute: 'href',
},
buttonText: {
type: 'array',
source: 'children',
selector: '.wp-block-button',
default: __( 'Button' )
},
buttonColor: {
type: 'string',
default: '#2091e1',
},
buttonTextColor: {
type: 'string',
default: '#ffffff',
},
size: {
type: 'string',
default: 'normal',
},
cornerButtonRadius: {
type: 'number',
default: 4,
},
contentAlign: {
type: 'string',
default: 'left',
},
},
// The "edit" property must be a valid function.
edit: withState( { editable: 'content', } )( edit ),
// The "save" property must be specified and must be a valid function.
save: save,
} );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.