diff --git a/blocks/details/editor.scss b/blocks/details/editor.scss new file mode 100644 index 00000000..625fad40 --- /dev/null +++ b/blocks/details/editor.scss @@ -0,0 +1,6 @@ +/* Editor styles */ +.wp-block-a8c-details { + summary .rich-text { + display: inline; + } +} diff --git a/blocks/details/index.php b/blocks/details/index.php new file mode 100644 index 00000000..ad6ce843 --- /dev/null +++ b/blocks/details/index.php @@ -0,0 +1,9 @@ + 'block-experiments', + 'style' => 'block-experiments', + 'editor_style' => 'block-experiments-editor', + ] ); +} ); diff --git a/blocks/details/src/block.json b/blocks/details/src/block.json new file mode 100644 index 00000000..1d6cda81 --- /dev/null +++ b/blocks/details/src/block.json @@ -0,0 +1,13 @@ +{ + "name": "a8c/details", + "category": "layout", + "attributes": { + "initialOpen": { + "type": "boolean", + "default": false + }, + "summaryContent": { + "type": "string" + } + } +} \ No newline at end of file diff --git a/blocks/details/src/edit.js b/blocks/details/src/edit.js new file mode 100644 index 00000000..fe31c5db --- /dev/null +++ b/blocks/details/src/edit.js @@ -0,0 +1,94 @@ +/** + * WordPress dependencies + */ +import { + InnerBlocks, + RichText, + InspectorControls, +} from '@wordpress/block-editor'; +import { __ } from '@wordpress/i18n'; +import { useSelect } from '@wordpress/data'; +import { + ToggleControl, + Panel, + PanelBody, + PanelRow, +} from '@wordpress/components'; +import { useEffect, useRef } from '@wordpress/element'; +import { SPACE } from '@wordpress/keycodes'; + +export default function DetalsEdit( { + attributes, + className, + clientId, + isSelected, + setAttributes, +} ) { + const summaryRef = useRef( null ); + + const keyUpListener = ( e ) => { + if ( e.keyCode === SPACE ) { + e.preventDefault(); + } + }; + + const clickListener = ( e ) => e.preventDefault(); + + useEffect( () => { + if ( ! summaryRef.current ) { + return; + } + + summaryRef.current.addEventListener( 'keyup', keyUpListener ); + summaryRef.current.addEventListener( 'click', clickListener ); + return () => { + summaryRef.current.removeEventListener( 'keyup', keyUpListener ); + summaryRef.current.removeEventListener( 'click', clickListener ); + }; + }, [ summaryRef.current ] ); + + const isInnerBlockSelected = useSelect( + ( select ) => + select( 'core/block-editor' ).hasSelectedInnerBlock( clientId ), + [ clientId ] + ); + + const showInnerBlocks = + attributes.initialOpen || isSelected || isInnerBlockSelected; + + return ( + <> + + + + + + setAttributes( { initialOpen } ) + } + checked={ attributes.initialOpen } + /> + + + + +
+ + setAttributes( { summaryContent } ) + } + ref={ summaryRef } + placeholder={ __( 'Write a summary…' ) } + keepPlaceholderOnFocus + aria-label={ __( 'Summary text' ) } + /> +
+ +
+
+ + ); +} diff --git a/blocks/details/src/icon.js b/blocks/details/src/icon.js new file mode 100644 index 00000000..ef9d3c95 --- /dev/null +++ b/blocks/details/src/icon.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/primitives'; + +const details = ( + + + +); + +export default details; diff --git a/blocks/details/src/index.js b/blocks/details/src/index.js new file mode 100644 index 00000000..8e819e4a --- /dev/null +++ b/blocks/details/src/index.js @@ -0,0 +1,44 @@ +/** + * WordPress dependencies + */ +import { registerBlockType } from '@wordpress/blocks'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import edit from './edit'; +import metadata from './block.json'; +import save from './save'; +import icon from './icon'; + +const { name, category, attributes } = metadata; + +export { metadata, name }; + +export const settings = { + title: __( 'Details' ), + description: __( 'Create a toggle to show and hide content.' ), + icon, + category, + edit, + save, + // details and summary are not translated because they are the HTML tags + keywords: [ 'details', 'summary', __( 'faq' ), __( 'spoiler' ) ], + attributes, + styles: [ + { + name: 'disclosure', + label: __( 'Open / Close' ), + isDefault: true, + }, + { + name: 'flipcard', + label: __( 'Flip Card' ), + }, + ], +}; + +export function registerBlock() { + registerBlockType( name, settings ); +} diff --git a/blocks/details/src/save.js b/blocks/details/src/save.js new file mode 100644 index 00000000..38e90147 --- /dev/null +++ b/blocks/details/src/save.js @@ -0,0 +1,18 @@ +/** + * WordPress dependencies + */ +import { InnerBlocks, RichText } from '@wordpress/block-editor'; + +export default ( { attributes } ) => { + return ( +
+ +
+ +
+
+ ); +}; diff --git a/blocks/details/style.scss b/blocks/details/style.scss new file mode 100644 index 00000000..b96702b0 --- /dev/null +++ b/blocks/details/style.scss @@ -0,0 +1,60 @@ +// Front end and editor styles. + +$bgcolor: #efefef; // Be nice if this was customizable via a background color property. + +@keyframes open-card { + 0% { + transform: rotateX(-180deg); + opacity: 0; + } + 100% { + transform: rotateX(0deg); + opacity: 1; + } +} + +.wp-block-a8c-details { + + // 3D flip-card style. + &.is-style-flipcard { + margin-bottom: 1.5em; + + // Enable 3D perspective. + transform-style: preserve-3d; + perspective: 300px; + + + // Card front-face. + summary { + background: $bgcolor; + padding: 1em; + + // Allows a focus style on the summary to be uncropped. + position: relative; + } + + // Back-face regardless of opened or closed. + > *:not(summary) { + background: $bgcolor; + transform-origin: top center; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + + // Some baseline left and right padding. + padding-left: 1em; + padding-right: 1em; + } + + // Neutralize the top margin of the first innerblock, add padding. + > summary+*, // Frontend + > .block-editor-inner-blocks > .block-editor-block-list__layout > * { // Editor + margin-top: 0; + padding-top: 1em; + } + + // Back-face when opened. + &[open] > *:not(summary) { + animation: open-card .2s ease; + } + } +} diff --git a/bundler/bundles/details.json b/bundler/bundles/details.json new file mode 100644 index 00000000..141c110b --- /dev/null +++ b/bundler/bundles/details.json @@ -0,0 +1,9 @@ +{ + "blocks": [ + "details" + ], + "version": "0.0.1", + "name": "Details Block", + "description": "Create a toggle to show and hide content", + "resource": "a8c-details" +} diff --git a/editor.scss b/editor.scss index 64623338..e30c40cc 100644 --- a/editor.scss +++ b/editor.scss @@ -6,3 +6,4 @@ @import './blocks/starscape/editor.scss'; @import './blocks/waves/editor.scss'; @import './blocks/book/editor.scss'; +@import './blocks/details/editor.scss'; diff --git a/src/index.js b/src/index.js index c9317974..fdfb32ea 100644 --- a/src/index.js +++ b/src/index.js @@ -29,6 +29,7 @@ import * as motionBackgroundBlock from '../blocks/motion-background/src'; import * as starscapeBlock from '../blocks/starscape/src'; import * as wavesBlock from '../blocks/waves/src'; import * as bookBlock from '../blocks/book/src'; +import * as detailsBlock from '../blocks/details/src'; // Instantiate the blocks, adding them to our block category bauhausCentenaryBlock.registerBlock(); @@ -38,3 +39,4 @@ motionBackgroundBlock.registerBlock(); starscapeBlock.registerBlock(); wavesBlock.registerBlock(); bookBlock.registerBlock(); +detailsBlock.registerBlock(); diff --git a/style.scss b/style.scss index 1587de4a..6cb21273 100644 --- a/style.scss +++ b/style.scss @@ -6,3 +6,4 @@ @import './blocks/starscape/style.scss'; @import './blocks/waves/style.scss'; @import './blocks/book/style.scss'; +@import './blocks/details/style.scss';