Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public function earlyEnqeueueBlockStyles(): void
{
render_block(['blockName' => 'core/heading']);
render_block(['blockName' => 'core/paragraph']);
render_block(['blockName' => 'core/buttons']);
render_block(['blockName' => 'core/button']);

// Enqeueue stylesheets of the firt block.
if (is_singular() && $post = get_post()) {
Expand Down
17 changes: 0 additions & 17 deletions web/app/themes/gds/app/setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,6 @@
echo app(GoogleFonts::class)->load()->toHtml();
}, 7);

/**
* Always enqueue stylesheets for the following blocks in the <head>
*/
add_action('wp_enqueue_scripts', function () {
render_block(['blockName' => 'core/heading']);
render_block(['blockName' => 'core/paragraph']);

// Enqeueue stylesheets of the first block.
if (is_singular() && $post = get_post()) {
$blocks = parse_blocks($post->post_content);
render_block($blocks[0]);
if ($blocks = parse_blocks($post->post_content)) {
render_block($blocks[0]);
}
}
}, 9);

/**
* Register the theme assets with the block editor.
*
Expand Down
22 changes: 22 additions & 0 deletions web/app/themes/gds/resources/blocks/tab/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "gds/tab",
"title": "Tab",
"description": "",
"icon": "plus-alt2",
"category": "layout",
"parent": ["gds/tabs"],
"attributes": {
"label": {
"type": "string"
}
},
"supports": {
"html": false,
"color": {}
},
"editorScript": "file:./index.js",
"editorStyle": "file:./editor.css",
"style": "file:./style.css"
}
38 changes: 38 additions & 0 deletions web/app/themes/gds/resources/blocks/tab/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
InnerBlocks,
} from '@wordpress/block-editor';
import {
useBlockProps,
useInnerBlocksProps,
} from '@wordpress/block-editor';
import {useSelect} from '@wordpress/data';

const Edit = (props) => {
const {clientId} = props;

const hasInnerBlocks = useSelect(select => {
const {getBlock} = select('core/block-editor');
const block = getBlock(clientId);

return !!(block && block.innerBlocks.length);
}, [clientId]);

const blockProps = useBlockProps({
className: '',
});

const innerBlocksProps = useInnerBlocksProps({
ref: blockProps.ref,
className: 'wp-block-gds-tab__content',
}, {
renderAppender: hasInnerBlocks ? undefined : InnerBlocks.ButtonBlockAppender,
});

return (
<div {...blockProps}>
<div {...innerBlocksProps}/>
</div>
);
};

export default Edit;
11 changes: 11 additions & 0 deletions web/app/themes/gds/resources/blocks/tab/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.wp-block-gds-tab {
display: block;

&__content {
display: none;

&.active {
display: block;
}
}
}
14 changes: 14 additions & 0 deletions web/app/themes/gds/resources/blocks/tab/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/** @wordpress */
import { registerBlockType } from '@wordpress/blocks'
import { InnerBlocks } from '@wordpress/block-editor'

import edit from './edit'
import meta from './block.json';

registerBlockType(meta.name, {
...meta,
edit,
save() {
return <InnerBlocks.Content />;
},
});
11 changes: 11 additions & 0 deletions web/app/themes/gds/resources/blocks/tab/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.wp-block-gds-tab {
display: none;

&.active {
display: block;
}

&__content {
padding-top: var(--block-gutter-s);
}
}
11 changes: 11 additions & 0 deletions web/app/themes/gds/resources/blocks/tab/tab.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div {!! get_block_wrapper_attributes([
'class' => ($index === 0 ? 'active' : ''),
'id' => 'tabpanel-' . $uid . '-' . $index,
'role' => 'tabpanel',
'aria-labelledby' => 'tab-' . $uid . '-' . $index,
]) !!}
>
<div class="wp-block-gds-tab__content">
{!! $content !!}
</div>
</div>
19 changes: 19 additions & 0 deletions web/app/themes/gds/resources/blocks/tab/tab.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace blocks\tab;

use WP_Block;

register_block_type(asset('blocks/tab/block.json')->path(), [
'render_callback' => function (array $attributes, string $content, $block) {
$attributes = (object) $attributes;

return view('blocks::tab.tab', [
'attributes' => $attributes,
'content' => $content,
'block' => $block,
'index' => $attributes->index ?? 0,
'uid' => $attributes->uid ?? 0,
]);
}
]);
17 changes: 17 additions & 0 deletions web/app/themes/gds/resources/blocks/tabs/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "gds/tabs",
"title": "Tabs",
"description": "",
"category": "layout",
"icon": "welcome-widgets-menus",
"attributes": {
},
"supports": {
"html": false,
"color": {}
},
"editorScript": "file:./index.js",
"script": "file:/script.js"
}
185 changes: 185 additions & 0 deletions web/app/themes/gds/resources/blocks/tabs/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import classnames from 'classnames';
import {__, sprintf} from '@wordpress/i18n';
import {
RichText,
useBlockProps,
useInnerBlocksProps,
BlockControls,
} from '@wordpress/block-editor';
import {
Icon,
ToolbarButton,
ToolbarGroup,
} from '@wordpress/components';
import {createBlock} from '@wordpress/blocks';
import {useSelect, useDispatch} from '@wordpress/data';
import {useEffect, useState, useRef} from '@wordpress/element';

const Edit = (props) => {
const {isSelected, clientId} = props;
const contentRef = useRef(null);
const [activeTab, setActiveTab] = useState('');

const children = useSelect(select => {
const {getBlock} = select('core/block-editor');
return getBlock(clientId).innerBlocks;
});

const isParentOfSelectedBlock = useSelect(
(select) => select('core/block-editor').hasSelectedInnerBlock(clientId, true),
);

const {
insertBlock,
removeBlock,
// selectBlock,
moveBlockToPosition,
updateBlockAttributes,
} = useDispatch('core/block-editor');

// const selectTab = (blockId) => {
// if (0 < children?.length) {
// const block = children.filter(block => block.clientId === blockId)[0];
// selectBlock(block.clientId);
// }
// };

const toggleActiveTab = (blockId) => {
if (contentRef.current) {
children.forEach(block => {
const blockContent = contentRef.current.querySelector(`#block-${block.clientId} .wp-block-gds-tab__content`);
blockContent?.classList.toggle('active', block.clientId === blockId);
});

setActiveTab(blockId);
}
};

const moveTab = (blockId, position) => {
const blockClientId = children.filter(block => block.clientId === blockId)[0]?.clientId;
if (blockClientId) {
moveBlockToPosition(blockClientId, clientId, clientId, position);
}
};

const deleteTab = (blockId) => {
if (0 < children?.length) {
const block = children.filter(block => block.clientId === blockId)[0];
removeBlock(block.clientId, false);
if (activeTab === blockId) {
setActiveTab('');
}
}
};

const addTab = () => {
const itemBlock = createBlock('gds/tab', {label: sprintf(__('Tab #%d'), children.length + 1)});
insertBlock(itemBlock, (children?.length) || 0, clientId, false);
};

useEffect(() => {
// Handle breakpoint
const activeContent = contentRef.current.querySelector(`#block-${activeTab} .wp-block-gds-tab__content.active`)

if (activeTab && !activeContent) {
toggleActiveTab(activeTab);
}
});

useEffect(() => {
// Activate the first tab when no tabs are selected
if (0 < children?.length && ('' === activeTab || 0 === children?.filter(block => block.clientId === activeTab).length)) {
toggleActiveTab(children[0].clientId);
}
}, [children]);

const Controls = () => {
const index = children?.findIndex(({clientId}) => clientId === activeTab);

return (
<BlockControls>
<ToolbarGroup>
<ToolbarButton
label={__('Delete tab')}
icon="trash"
disabled={children?.length < 2}
onClick={() => deleteTab(activeTab)}
/>

<ToolbarButton
label={__('Move tab left')}
icon="arrow-left-alt2"
disabled={0 === index}
onClick={() => moveTab(activeTab, index - 1)}
/>

<ToolbarButton
label={__('Move tab right')}
icon="arrow-right-alt2"
disabled={children?.length - 1 === index}
onClick={() => moveTab(activeTab, index + 1)}
/>
</ToolbarGroup>
</BlockControls>
);
};

const blockProps = useBlockProps({
className: '',
});

const innerBlocksProps = useInnerBlocksProps({
ref: contentRef,
className: 'wp-block-gds-tabs__panels',
}, {
orientation: 'horizontal',
renderAppender: false,
allowedBlocks: ['gds/tab'],
template: [
['gds/tab', {label: sprintf(__('Tab #%d'), 1)}],
],
});

return (
<>
<Controls/>

<div {...blockProps}>
<div className="wp-block-buttons">
{children?.map((tab, index) => {
return (
<div className="wp-block-button" key={index}>
<button
className={classnames('wp-block-button__link', {'active': tab.clientId === activeTab})}
onClick={() => toggleActiveTab(tab.clientId)}
>
<RichText
tagName="span"
value={tab.attributes.label}
allowedFormats={[]}
onChange={nextLabel => {
updateBlockAttributes(tab.clientId, {label: nextLabel});
}}
placeholder={__('Enter label')}
/>
</button>
</div>
);
}) || ''}

{(isSelected || isParentOfSelectedBlock || 0 === children.length) && (
<li className="wp-block-button">
<button className="wp-block-button__link has-secondary-background-color has-background" onClick={addTab}>
<Icon icon="plus-alt2"/>
</button>
</li>
)}
</div>

<div {...innerBlocksProps}/>
</div>
</>
);
};

export default Edit;
14 changes: 14 additions & 0 deletions web/app/themes/gds/resources/blocks/tabs/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/** @wordpress */
import { registerBlockType } from '@wordpress/blocks'
import { InnerBlocks } from '@wordpress/block-editor'

import edit from './edit'
import meta from './block.json';

registerBlockType(meta.name, {
...meta,
edit,
save() {
return <InnerBlocks.Content />;
},
});
Loading