Begins implementation of search bar gutenberg block.

This commit is contained in:
Mateus Machado Luna 2019-07-24 17:02:25 -03:00
parent c9794c84e7
commit 762eb5df9b
5 changed files with 1246 additions and 3 deletions

View File

@ -17,6 +17,7 @@ function tainacan_blocks_add_gutenberg_blocks_actions() {
add_action('init', 'tainacan_blocks_register_tainacan_items_list');
add_action('init', 'tainacan_blocks_register_tainacan_dynamic_items_list');
add_action('init', 'tainacan_blocks_register_tainacan_carousel_items_list');
add_action('init', 'tainacan_blocks_register_tainacan_search_bar');
add_action('init', 'tainacan_blocks_register_tainacan_collections_list');
add_action('init', 'tainacan_blocks_register_tainacan_facets_list');
@ -174,6 +175,29 @@ function tainacan_blocks_register_tainacan_carousel_items_list(){
}
}
function tainacan_blocks_register_tainacan_search_bar(){
global $TAINACAN_BASE_URL;
wp_register_script(
'search-bar',
$TAINACAN_BASE_URL . '/assets/gutenberg_search_bar-components.js',
array('wp-blocks', 'wp-element', 'wp-components', 'wp-editor')
);
wp_register_style(
'search-bar',
$TAINACAN_BASE_URL . '/assets/css/tainacan-gutenberg-block-search-bar.css',
array('wp-edit-blocks')
);
if (function_exists('register_block_type')) {
register_block_type( 'tainacan/search-bar', array(
'editor_script' => 'search-bar',
'style' => 'search-bar'
) );
}
}
function tainacan_blocks_register_tainacan_collections_list(){
global $TAINACAN_BASE_URL;
@ -220,6 +244,7 @@ function tainacan_blocks_add_plugin_settings() {
wp_localize_script( 'items-list', 'tainacan_plugin', $settings );
wp_localize_script( 'dynamic-items-list', 'tainacan_plugin', $settings );
wp_localize_script( 'carousel-items-list', 'tainacan_plugin', $settings );
wp_localize_script( 'search-bar', 'tainacan_plugin', $settings );
wp_localize_script( 'collections-list', 'tainacan_plugin', $settings );
wp_localize_script( 'facets-list', 'tainacan_plugin', $settings );
}

View File

@ -0,0 +1,562 @@
const { registerBlockType } = wp.blocks;
const { __ } = wp.i18n;
const { RangeControl, TextControl, Spinner, Button, ToggleControl, Tooltip, Placeholder, Toolbar, ColorPicker, ColorPalette, BaseControl, Panel, PanelBody, PanelRow } = wp.components;
const { InspectorControls } = wp.editor;
import SearchBarModal from './search-bar-modal.js';
import tainacan from '../../api-client/axios.js';
import axios from 'axios';
import qs from 'qs';
registerBlockType('tainacan/search-bar', {
title: __('Tainacan Search Bar', 'tainacan'),
icon:
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
height="24px"
width="24px">
<path
fill="#298596"
d="M14,2V4H7v7.24A5.33,5.33,0,0,0,5.5,11a4.07,4.07,0,0,0-.5,0V4A2,2,0,0,1,7,2Zm7,10v8a2,2,0,0,1-2,2H12l1-1-2.41-2.41A5.56,5.56,0,0,0,11,16.53a5.48,5.48,0,0,0-2-4.24V8a2,2,0,0,1,2-2h4Zm-2.52,0L14,7.5V12ZM11,21l-1,1L8.86,20.89,8,20H8l-.57-.57A3.42,3.42,0,0,1,5.5,20a3.5,3.5,0,0,1-.5-7,2.74,2.74,0,0,1,.5,0,3.41,3.41,0,0,1,1.5.34,3.5,3.5,0,0,1,2,3.16,3.42,3.42,0,0,1-.58,1.92L9,19H9l.85.85Zm-4-4.5A1.5,1.5,0,0,0,5.5,15a1.39,1.39,0,0,0-.5.09A1.5,1.5,0,0,0,5.5,18a1.48,1.48,0,0,0,1.42-1A1.5,1.5,0,0,0,7,16.53Z"/>
</svg>,
category: 'tainacan-blocks',
keywords: [ __( 'items', 'tainacan' ), __( 'search', 'tainacan' ), __( 'bar', 'tainacan' ) ],
attributes: {
content: {
type: 'array',
source: 'children',
selector: 'div'
},
collectionId: {
type: String,
default: undefined
},
collectionSlug: {
type: String,
default: undefined
},
items: {
type: Array,
default: []
},
showImage: {
type: Boolean,
default: true
},
showName: {
type: Boolean,
default: true
},
isModalOpen: {
type: Boolean,
default: false
},
gridMargin: {
type: Number,
default: 0
},
searchURL: {
type: String,
default: undefined
},
itemsRequestSource: {
type: String,
default: undefined
},
maxItemsNumber: {
type: Number,
value: undefined
},
isLoading: {
type: Boolean,
value: false
},
isLoadingCollection: {
type: Boolean,
value: false
},
showSearchBar: {
type: Boolean,
value: false
},
showCollectionHeader: {
type: Boolean,
value: false
},
showCollectionLabel: {
type: Boolean,
value: false
},
collection: {
type: Object,
value: undefined
},
searchString: {
type: String,
default: undefined
},
order: {
type: String,
default: undefined
},
blockId: {
type: String,
default: undefined
},
collectionBackgroundColor: {
type: String,
default: "#454647"
},
collectionTextColor: {
type: String,
default: "#ffffff"
}
},
supports: {
align: ['full', 'wide'],
html: false,
},
edit({ attributes, setAttributes, className, isSelected, clientId }){
let {
items,
content,
collectionId,
collectionSlug,
showImage,
showName,
isModalOpen,
gridMargin,
searchURL,
itemsRequestSource,
maxItemsNumber,
order,
searchString,
isLoading,
showSearchBar,
showCollectionHeader,
showCollectionLabel,
isLoadingCollection,
collection,
collectionBackgroundColor,
collectionTextColor
} = attributes;
// Obtains block's client id to render it on save function
setAttributes({ blockId: clientId });
function setContent(){
setAttributes({
content: (
<div class="tainacan-search-container">
<form action={ tainacan_plugin.site_url + '/' + collectionSlug + '/#/' } method='get'>
<input
label="Additional CSS Class"
name='search'
/>
<button type="submit">{ __('Search', 'tainacan') }</button>
</form>
</div>
)
});
}
function fetchCollectionForHeader() {
if (showCollectionHeader) {
isLoadingCollection = true;
setAttributes({
isLoadingCollection: isLoadingCollection
});
tainacan.get('/collections/' + collectionId + '?fetch_only=name,thumbnail,header_image')
.then(response => {
collection = response.data;
isLoadingCollection = false;
if (collection.tainacan_theme_collection_background_color)
collectionBackgroundColor = collection.tainacan_theme_collection_background_color;
else
collectionBackgroundColor = '#454647';
if (collection.tainacan_theme_collection_color)
collectionTextColor = collection.tainacan_theme_collection_color;
else
collectionTextColor = '#ffffff';
setAttributes({
content: <div></div>,
collection: collection,
isLoadingCollection: isLoadingCollection,
collectionBackgroundColor: collectionBackgroundColor,
collectionTextColor: collectionTextColor
});
});
}
}
function openSearchBarModal() {
isModalOpen = true;
setAttributes( {
isModalOpen: isModalOpen
} );
}
function applySearchString(event) {
let value = event.target.value;
if (searchString != value) {
searchString = value;
setAttributes({ searchString: searchString });
setContent();
}
}
// Executed only on the first load of page
if(content && content.length && content[0].type)
setContent();
return (
<div className={className}>
<div>
<InspectorControls>
<PanelBody
title={__('Collection header', 'tainacan')}
initialOpen={ false }
>
<ToggleControl
label={__('Display header', 'tainacan')}
help={ !showCollectionHeader ? __('Toggle to show collection header', 'tainacan') : __('Do not show collection header', 'tainacan')}
checked={ showCollectionHeader }
onChange={ ( isChecked ) => {
showCollectionHeader = isChecked;
if (isChecked) fetchCollectionForHeader();
setAttributes({ showCollectionHeader: showCollectionHeader });
}
}
/>
{ showCollectionHeader ?
<div style={{ margin: '6px' }}>
<ToggleControl
label={__('Display "Collection" label', 'tainacan')}
help={ !showCollectionLabel ? __('Toggle to show "Collection" label above header', 'tainacan') : __('Do not show "Collection" label', 'tainacan')}
checked={ showCollectionLabel }
onChange={ ( isChecked ) => {
showCollectionLabel = isChecked;
setAttributes({ showCollectionLabel: showCollectionLabel });
}
}
/>
<BaseControl
id="colorpicker"
label={ __('Background color', 'tainacan')}>
<ColorPicker
color={ collectionBackgroundColor }
onChangeComplete={ ( value ) => {
collectionBackgroundColor = value.hex;
setAttributes({ collectionBackgroundColor: collectionBackgroundColor })
}}
disableAlpha
/>
</BaseControl>
<BaseControl
id="colorpallete"
label={ __('Collection name color', 'tainacan')}>
<ColorPalette
colors={ [{ name: __('Black', 'tainacan'), color: '#000000'}, { name: __('White', 'tainacan'), color: '#ffffff'} ] }
value={ collectionTextColor }
onChange={ ( color ) => {
collectionTextColor = color;
setAttributes({ collectionTextColor: collectionTextColor })
}}
/>
</BaseControl>
</div>
: null
}
</PanelBody>
<PanelBody
title={__('Search bar', 'tainacan')}
initialOpen={ true }
>
<ToggleControl
label={__('Display bar', 'tainacan')}
help={ showSearchBar ? __('Toggle to show search bar on block', 'tainacan') : __('Do not show search bar', 'tainacan')}
checked={ showSearchBar }
onChange={ ( isChecked ) => {
showSearchBar = isChecked;
setAttributes({ showSearchBar: showSearchBar });
}
}
/>
</PanelBody>
<PanelBody
title={__('Items', 'tainacan')}
initialOpen={ true }
>
<div>
<RangeControl
label={__('Maximum number of items', 'tainacan')}
value={ maxItemsNumber }
onChange={ ( aMaxItemsNumber ) => {
maxItemsNumber = aMaxItemsNumber;
setAttributes( { maxItemsNumber: aMaxItemsNumber } )
setContent();
}}
min={ 1 }
max={ 96 }
/>
</div>
</PanelBody>
</InspectorControls>
</div>
{ isSelected ?
(
<div>
{ isModalOpen ?
<SearchBarModal
existingCollectionId={ collectionId }
existingCollectionSlug={ collectionSlug }
onSelectCollection={ (selectedCollection) => {
collectionId = selectedCollection.id;
collectionSlug = selectedCollection.slug;
setAttributes({
collectionId: collectionId,
collectionSlug: collectionSlug,
isModalOpen: false
});
fetchCollectionForHeader();
setContent();
}}
onCancelSelection={ () => setAttributes({ isModalOpen: false }) }/>
: null
}
{ items.length ? (
<div className="block-control">
<p>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
height="24px"
width="24px">
<path d="M14,2V4H7v7.24A5.33,5.33,0,0,0,5.5,11a4.07,4.07,0,0,0-.5,0V4A2,2,0,0,1,7,2Zm7,10v8a2,2,0,0,1-2,2H12l1-1-2.41-2.41A5.56,5.56,0,0,0,11,16.53a5.48,5.48,0,0,0-2-4.24V8a2,2,0,0,1,2-2h4Zm-2.52,0L14,7.5V12ZM11,21l-1,1L8.86,20.89,8,20H8l-.57-.57A3.42,3.42,0,0,1,5.5,20a3.5,3.5,0,0,1-.5-7,2.74,2.74,0,0,1,.5,0,3.41,3.41,0,0,1,1.5.34,3.5,3.5,0,0,1,2,3.16,3.42,3.42,0,0,1-.58,1.92L9,19H9l.85.85Zm-4-4.5A1.5,1.5,0,0,0,5.5,15a1.39,1.39,0,0,0-.5.09A1.5,1.5,0,0,0,5.5,18a1.48,1.48,0,0,0,1.42-1A1.5,1.5,0,0,0,7,16.53Z"/>
</svg>
{__('Dynamically list items from a Tainacan items search', 'tainacan')}
</p>
<Button
isPrimary
type="submit"
onClick={ () => openSearchBarModal() }>
{__('Configure search', 'tainacan')}
</Button>
</div>
): null
}
</div>
) : null
}
{
showCollectionHeader ?
<div> {
isLoadingCollection ?
<div class="spinner-container">
<Spinner />
</div>
:
<a
href={ collection.url ? collection.url : '' }
target="_blank"
class="search-bar-collection-header">
<div
style={{
backgroundColor: collectionBackgroundColor ? collectionBackgroundColor : '',
paddingRight: collection && collection.thumbnail && (collection.thumbnail['tainacan-medium'] || collection.thumbnail['medium']) ? '' : '20px',
paddingTop: (!collection || !collection.thumbnail || (!collection.thumbnail['tainacan-medium'] && !collection.thumbnail['medium'])) ? '1rem' : '',
width: collection && collection.header_image ? '' : '100%'
}}
className={
'collection-name ' +
((!collection || !collection.thumbnail || (!collection.thumbnail['tainacan-medium'] && !collection.thumbnail['medium'])) && (!collection || !collection.header_image) ? 'only-collection-name' : '')
}>
<h3 style={{ color: collectionTextColor ? collectionTextColor : '' }}>
{ showCollectionLabel ? <span class="label">{ __('Collection', 'tainacan') }<br/></span> : null }
{ collection && collection.name ? collection.name : '' }
</h3>
</div>
{
collection && collection.thumbnail && (collection.thumbnail['tainacan-medium'] || collection.thumbnail['medium']) ?
<div
class="collection-thumbnail"
style={{
backgroundImage: 'url(' + (collection.thumbnail['tainacan-medium'] != undefined ? (collection.thumbnail['tainacan-medium'][0]) : (collection.thumbnail['medium'][0])) + ')',
}}/>
: null
}
<div
class="collection-header-image"
style={{
backgroundImage: collection.header_image ? 'url(' + collection.header_image + ')' : '',
minHeight: collection && collection.header_image ? '' : '80px',
display: !(collection && collection.thumbnail && (collection.thumbnail['tainacan-medium'] || collection.thumbnail['medium'])) ? collection && collection.header_image ? '' : 'none' : ''
}}/>
</a>
}
</div>
: null
}
{
showSearchBar ?
<div class="search-bar-search-bar">
<Button
onClick={ () => { order = 'asc'; setAttributes({ order: order }); setContent(); }}
className={order == 'asc' ? 'sorting-button-selected' : ''}
label={__('Sort ascending', 'tainacan')}>
<span class="icon">
<i>
<svg width="24" height="24" viewBox="-2 -4 20 20">
<path d="M6.7,10.8l-3.3,3.3L0,10.8h2.5V0h1.7v10.8H6.7z M11.7,0.8H8.3v1.7h3.3V0.8z M14.2,5.8H8.3v1.7h5.8V5.8z M16.7,10.8H8.3v1.7 h8.3V10.8z"/>
</svg>
</i>
</span>
</Button>
<Button
onClick={ () => { order = 'desc'; setAttributes({ order: order }); setContent(); }}
className={order == 'desc' ? 'sorting-button-selected' : ''}
label={__('Sort descending', 'tainacan')}>
<span class="icon">
<i>
<svg width="24" height="24" viewBox="-2 -4 20 20">
<path d="M6.7,3.3H4.2v10.8H2.5V3.3H0L3.3,0L6.7,3.3z M11.6,2.5H8.3v1.7h3.3V2.5z M14.1,7.5H8.3v1.7h5.8V7.5z M16.6,12.5H8.3v1.7 h8.3V12.5z"/>
</svg>
</i>
</span>
</Button>
<Button
onClick={ () => { setContent(); }}
label={__('Search', 'tainacan')}>
<span class="icon">
<i>
<svg width="24" height="24" viewBox="-2 -4 20 20">
<path class="st0" d="M0,5.8C0,5,0.2,4.2,0.5,3.5s0.7-1.3,1.2-1.8s1.1-0.9,1.8-1.2C4.2,0.1,5,0,5.8,0S7.3,0.1,8,0.5
c0.7,0.3,1.3,0.7,1.8,1.2s0.9,1.1,1.2,1.8c0.5,1.2,0.5,2.5,0.2,3.7c0,0.2-0.1,0.4-0.2,0.6c0,0.1-0.2,0.6-0.2,0.6
c0.6,0.6,1.3,1.3,1.9,1.9c0.7,0.7,1.3,1.3,2,2c0,0,0.3,0.2,0.3,0.3c0,0.3-0.1,0.7-0.3,1c-0.2,0.6-0.8,1-1.4,1.2
c-0.1,0-0.6,0.2-0.6,0.1c0,0-4.2-4.2-4.2-4.2c0,0-0.8,0.3-0.8,0.4c-1.3,0.4-2.8,0.5-4.1-0.1c-0.7-0.3-1.3-0.7-1.8-1.2
C1.2,9.3,0.8,8.7,0.5,8S0,6.6,0,5.8z M1.6,5.8c0,0.4,0.1,0.9,0.2,1.3C2.1,8.2,3,9.2,4.1,9.6c0.5,0.2,1,0.3,1.6,0.3
c0.6,0,1.1-0.1,1.6-0.3C8.7,9,9.7,7.6,9.8,6c0.1-1.5-0.6-3.1-2-3.9c-0.9-0.5-2-0.6-3-0.4C4.6,1.8,4.4,1.9,4.1,2
c-0.5,0.2-1,0.5-1.4,0.9C2,3.7,1.6,4.7,1.6,5.8z"/>
</svg>
</i>
</span>
</Button>
<input
value={ searchString }
onChange={ (value) => { _.debounce(applySearchString(value), 300); } }
type="text"/>
<Tooltip text={__('If necessary, pagination will be available on post or page.', 'tainacan')}>
<button
class="previous-button"
disabled
label={__('Previous page', 'tainacan')}>
<span class="icon">
<i>
<svg
width="30"
height="30"
viewBox="0 2 20 20">
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
<path
d="M0 0h24v24H0z"
fill="none"/>
</svg>
</i>
</span>
</button>
</Tooltip>
<Tooltip text={__('If necessary, pagination will be available on post or page.', 'tainacan')}>
<button
class="next-button"
disabled
label={__('Next page', 'tainacan')}>
<span class="icon">
<i>
<svg
width="30"
height="30"
viewBox="0 2 20 20">
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
<path
d="M0 0h24v24H0z"
fill="none"/>
</svg>
</i>
</span>
</button>
</Tooltip>
</div>
: null
}
{ !collectionId && !isLoading ? (
<Placeholder
icon={(
<img
width={148}
src={ `${tainacan_plugin.base_url}/admin/images/tainacan_logo_header.svg` }
alt="Tainacan Logo"/>
)}>
<p>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
height="24px"
width="24px">
<path d="M14,2V4H7v7.24A5.33,5.33,0,0,0,5.5,11a4.07,4.07,0,0,0-.5,0V4A2,2,0,0,1,7,2Zm7,10v8a2,2,0,0,1-2,2H12l1-1-2.41-2.41A5.56,5.56,0,0,0,11,16.53a5.48,5.48,0,0,0-2-4.24V8a2,2,0,0,1,2-2h4Zm-2.52,0L14,7.5V12ZM11,21l-1,1L8.86,20.89,8,20H8l-.57-.57A3.42,3.42,0,0,1,5.5,20a3.5,3.5,0,0,1-.5-7,2.74,2.74,0,0,1,.5,0,3.41,3.41,0,0,1,1.5.34,3.5,3.5,0,0,1,2,3.16,3.42,3.42,0,0,1-.58,1.92L9,19H9l.85.85Zm-4-4.5A1.5,1.5,0,0,0,5.5,15a1.39,1.39,0,0,0-.5.09A1.5,1.5,0,0,0,5.5,18a1.48,1.48,0,0,0,1.42-1A1.5,1.5,0,0,0,7,16.53Z"/>
</svg>
{__('Dynamically list items from a Tainacan items search', 'tainacan')}
</p>
<Button
isPrimary
type="submit"
onClick={ () => openSearchBarModal() }>
{__('Select items', 'tainacan')}
</Button>
</Placeholder>
) : null
}
{ isLoading ?
<div class="spinner-container">
<Spinner />
</div> :
<div>
{ content }
</div>
}
</div>
);
},
save({ attributes, className }){
const {
content
} = attributes;
return <div className={ className }>{ content }</div>
}
});

View File

@ -0,0 +1,280 @@
import tainacan from '../../api-client/axios.js';
import axios from 'axios';
const { __ } = wp.i18n;
const { TextControl, Button, Modal, RadioControl, Spinner } = wp.components;
export default class SearchBarModal extends React.Component {
constructor(props) {
super(props);
// Initialize state
this.state = {
collectionsPerPage: 24,
collectionId: undefined,
collectionSlug: undefined,
collectionName: '',
isLoadingCollections: false,
modalCollections: [],
totalModalCollections: 0,
collectionPage: 1,
temporaryCollectionId: '',
searchCollectionName: '',
collections: [],
collectionsRequestSource: undefined
};
// Bind events
this.resetCollections = this.resetCollections.bind(this);
this.selectCollection = this.selectCollection.bind(this);
this.fetchCollections = this.fetchCollections.bind(this);
this.fetchModalCollections = this.fetchModalCollections.bind(this);
this.fetchCollection = this.fetchCollection.bind(this);
}
componentWillMount() {
this.setState({
collectionId: this.props.existingCollectionId,
collectionSlug: this.props.existingCollectionSlug
});
if (this.props.existingCollectionId != null && this.props.existingCollectionId != undefined) {
this.fetchCollection(this.props.existingCollectionId);
} else {
this.setState({ collectionPage: 1 });
this.fetchModalCollections();
}
}
// COLLECTIONS RELATED --------------------------------------------------
fetchModalCollections() {
let someModalCollections = this.state.modalCollections;
if (this.state.collectionPage <= 1)
someModalCollections = [];
let endpoint = '/collections/?orderby=title&order=asc&perpage=' + this.state.collectionsPerPage + '&paged=' + this.state.collectionPage;
this.setState({
isLoadingCollections: true,
collectionPage: this.state.collectionPage + 1,
modalCollections: someModalCollections
});
tainacan.get(endpoint)
.then(response => {
let otherModalCollections = this.state.modalCollections;
for (let collection of response.data) {
otherModalCollections.push({
name: collection.name,
id: collection.id,
slug: collection.slug
});
}
this.setState({
isLoadingCollections: false,
modalCollections: otherModalCollections,
totalModalCollections: response.headers['x-wp-total']
});
return otherModalCollections;
})
.catch(error => {
console.log('Error trying to fetch collections: ' + error);
});
}
fetchCollection(collectionId) {
tainacan.get('/collections/' + collectionId)
.then((response) => {
this.setState({ collectionName: response.data.name });
}).catch(error => {
console.log('Error trying to fetch collection: ' + error);
});
}
selectCollection(selectedCollectionId) {
let selectedCollection;
if (selectedCollectionId == 'default')
selectedCollection = { label: __('Repository items', 'tainacan'), id: 'default', slug: tainacan_plugin.theme_items_list_url.split('/')[tainacan_plugin.theme_items_list_url.split('/').length - 1] };
else {
selectedCollection = this.state.modalCollections.find((collection) => collection.id == selectedCollectionId)
if (selectedCollection == undefined)
selectedCollection = this.state.collections.find((collection) => collection.id == selectedCollectionId)
}
this.setState({
collectionId: selectedCollection.id,
collectionSlug: selectedCollection.slug
});
this.props.onSelectCollection(selectedCollection);
}
fetchCollections(name) {
if (this.state.collectionsRequestSource != undefined)
this.state.collectionsRequestSource.cancel('Previous collections search canceled.');
let aCollectionRequestSource = axios.CancelToken.source();
this.setState({
collectionsRequestSource: aCollectionRequestSource,
isLoadingCollections: true,
collections: [],
items: []
});
let endpoint = '/collections/?orderby=title&order=asc&perpage=' + this.state.collectionsPerPage;
if (name != undefined && name != '')
endpoint += '&search=' + name;
tainacan.get(endpoint, { cancelToken: aCollectionRequestSource.token })
.then(response => {
let someCollections = response.data.map((collection) => ({ name: collection.name, id: collection.id + '' }));
this.setState({
isLoadingCollections: false,
collections: someCollections
});
return someCollections;
})
.catch(error => {
console.log('Error trying to fetch collections: ' + error);
});
}
resetCollections() {
this.setState({
collectionId: null,
collectionPage: 1,
modalCollections: []
});
this.fetchModalCollections();
}
cancelSelection() {
this.setState({
modalCollections: []
});
this.props.onCancelSelection();
}
render() {
return <Modal
className="wp-block-tainacan-modal"
title={__('Select a search source fetch items from', 'tainacan')}
onRequestClose={ () => this.cancelSelection() }
contentLabel={__('Select search source', 'tainacan')}>
<div>
<div className="modal-search-area">
<TextControl
label={__('Search for a collection', 'tainacan')}
value={ this.state.searchCollectionName }
onChange={(value) => {
this.setState({
searchCollectionName: value
});
_.debounce(this.fetchCollections(value), 300);
}}/>
</div>
{(
this.state.searchCollectionName != '' ? (
this.state.collections.length > 0 ?
(
<div>
<div className="modal-radio-list">
{
<RadioControl
selected={ this.state.temporaryCollectionId }
options={
this.state.collections.map((collection) => {
return { label: collection.name, value: '' + collection.id }
})
}
onChange={ ( aCollectionId ) => {
this.setState({ temporaryCollectionId: aCollectionId });
} } />
}
</div>
</div>
) :
this.state.isLoadingCollections ? (
<Spinner />
) :
<div className="modal-loadmore-section">
<p>{ __('Sorry, no collection found.', 'tainacan') }</p>
</div>
):
this.state.modalCollections.length > 0 ?
(
<div>
<div className="modal-radio-list">
<p class="modal-radio-area-label">{__('Repository', 'tainacan')}</p>
<RadioControl
className={'repository-radio-option'}
selected={ this.state.temporaryCollectionId }
options={ [{ label: __('Repository items', 'tainacan'), value: 'default', slug: tainacan_plugin.theme_items_list_url.split('/')[tainacan_plugin.theme_items_list_url.split('/').length - 1] }] }
onChange={ ( aCollectionId ) => {
this.setState({ temporaryCollectionId: aCollectionId });
} } />
<hr/>
<p class="modal-radio-area-label">{__('Collections', 'tainacan')}</p>
<RadioControl
selected={ this.state.temporaryCollectionId }
options={
this.state.modalCollections.map((collection) => {
return { label: collection.name, value: '' + collection.id }
})
}
onChange={ ( aCollectionId ) => {
this.setState({ temporaryCollectionId: aCollectionId });
} } />
</div>
<div className="modal-loadmore-section">
<p>{ __('Showing', 'tainacan') + " " + this.state.modalCollections.length + " " + __('of', 'tainacan') + " " + this.state.totalModalCollections + " " + __('collections', 'tainacan') + "."}</p>
{
this.state.modalCollections.length < this.state.totalModalCollections ? (
<Button
isDefault
isSmall
onClick={ () => this.fetchModalCollections() }>
{__('Load more', 'tainacan')}
</Button>
) : null
}
</div>
</div>
) : this.state.isLoadingCollections ? <Spinner/> :
<div className="modal-loadmore-section">
<p>{ __('Sorry, no collection found.', 'tainacan') }</p>
</div>
)}
<div className="modal-footer-area">
<Button
isDefault
onClick={ () => { this.cancelSelection() }}>
{__('Cancel', 'tainacan')}
</Button>
<Button
isPrimary
disabled={ this.state.temporaryCollectionId == undefined || this.state.temporaryCollectionId == null || this.state.temporaryCollectionId == ''}
onClick={ () => { this.selectCollection(this.state.temporaryCollectionId); } }>
{__('Apply source', 'tainacan')}
</Button>
</div>
</div>
</Modal>
}
}

View File

@ -0,0 +1,371 @@
@import '../../gutenberg-blocks-style.scss';
.wp-block-tainacan-search-bar-list {
margin: 2rem 0px;
// Spinner
.spinner-container {
min-height: 56px;
padding: 1rem;
display: flex;
justify-content: center;
align-items: center;
color: #555758;
}
// Skeleton loading
@-webkit-keyframes skeleton-animation {
0%{opacity: 1.0}
50%{opacity: 0.2}
100%{opacity: 1.0}
}
@-moz-keyframes skeleton-animation {
0%{opacity: 1.0}
50%{opacity: 0.2}
100%{opacity: 1.0}
}
@-o-keyframes skeleton-animation {
0%{opacity: 1.0}
50%{opacity: 0.2}
100%{opacity: 1.0}
}
@keyframes skeleton-animation {
0%{opacity: 1.0}
50%{opacity: 0.2}
100%{opacity: 1.0}
}
.skeleton {
border-radius: 2px;
background: #f2f2f2;
-webkit-animation: skeleton-animation 1.8s ease infinite;
-moz-animation: skeleton-animation 1.8s ease infinite;
-o-animation: skeleton-animation 1.8s ease infinite;
animation: skeleton-animation 1.8s ease infinite;
}
// Collection header
.search-bar-collection-header {
display: flex;
width: 100%;
align-items: stretch;
text-decoration: none !important;
&:hover {
text-decoration: none;
}
.collection-name {
width: auto;
min-width: 350px;
flex-grow: 1;
padding: 1rem 100px 1rem 1rem;
text-align: right;
line-height: 1.5rem;
min-height: 165px;
display: flex;
justify-content: flex-end;
align-items: center;
background-color: #454647;
h3 {
color: white;
text-decoration: none;
font-size: 1.3rem;
&:hover {
text-decoration: none;
}
}
span.label {
font-weight: normal;
font-size: 1rem;
}
&.only-collection-name {
justify-content: center;
padding: 1rem;
h3 {
text-align: center;
font-size: 1.75rem;
}
}
}
.collection-thumbnail {
height: 145px;
width: 145px;
background-size: cover;
background-position: center;
border-radius: 80px;
border: 4px solid white;
margin: 10px;
flex-shrink: 0;
position: relative;
margin-left: -155px;
left: 82px;
background-color: #dbdbdb;
}
.collection-header-image {
width: auto;
min-width: 150px;
min-height: 165px;
flex-grow: 2;
background-size: cover;
background-position: center;
background-color: #dbdbdb;
}
@media only screen and (max-width: 1024px) {
flex-wrap: wrap-reverse;
.collection-name {
width: 100% !important;
min-width: 100% !important;
justify-content: center !important;
text-align: center !important;
padding: 64px 1rem 0rem 1rem;
h3 { margin-bottom: 1rem; }
}
.collection-thumbnail {
left: calc(-50% + 78px) !important;
top: -78px !important;
}
.collection-header-image {
background-color: transparent;
}
}
}
// Search control bar
.search-bar-search-bar {
width: 100%;
display: flex;
align-items: center;
border-bottom: 1px solid #cbcbcb;
padding: 1.00rem 0.5rem 0.75rem 0.5rem;
@media only screen and (max-width: 768px) {
flex-wrap: wrap;
.search-button {
order: 4;
position: absolute;
margin-top: 37px;
}
input {
width: 100% !important;
order: 5;
margin-top: 8px;
margin-left: 0px !important;
padding-left: 4px !important;
border-color: #dbdbdb !important;
}
}
button {
margin-right: 0.75rem;
padding: 0 0.35rem;
min-height: 28px;
z-index: 2;
border: none;
background: transparent;
cursor: pointer;
svg {
fill: #cbcbcb;
transition: fill 0.4s ease;
}
&:hover svg { fill: #545758; }
&:focus, &:active { border: none; box-shadow: none; }
&.sorting-button-selected svg {
fill: #545758;
}
&.next-button {
margin-right: 0rem;
padding: 0;
svg { fill: #298596; }
}
&.previous-button {
margin-left: auto;
margin-right: 1rem;
padding: 0;
svg { fill: #298596; }
}
&[disabled] svg {
fill: #f2f2f2;
cursor: not-allowed;
}
}
input {
height: 32px;
width: 20%;
border-radius: 0;
margin-left: -52px;
padding-left: 52px;
border: 1px solid white;
transition: border-color 0.7s ease, width 0.5s ease-in;
&:focus,
&:active,
&:hover {
width: 100%;
border: 1px solid #cbcbcb;
box-shadow: none;
}
}
}
// Grid View Mode ----------------------------------------------------
ul.items-list.items-list-without-margin,
ul.items-list-edit.items-list-without-margin {
grid-template-columns: repeat(auto-fill, 185px);
justify-content: center !important;
grid-template-rows: auto !important;
list-style: none;
li {
margin-top: 0 !important;
margin-right: 0 !important;
margin-left: 0 !important;
height: 185px !important;
img {
height: 185px !important;
margin-bottom: 0px !important;
}
}
}
ul.items-list.items-layout-grid,
ul.items-list-edit.items-layout-grid {
padding: 0;
display: -ms-grid;
display: grid;
grid-template-columns: repeat(auto-fill, 220px);
grid-gap: 0px;
justify-content: space-evenly;
list-style-type: none;
li.item-list-item {
position: relative;
display: block;
margin: 12px 12px 24px 12px;
margin-bottom: 12px;
width: 185px;
a {
color: #454647;
font-weight: bold;
line-height: normal;
}
img {
height: auto;
width: 185px;
min-width: 185px;
padding: 0px;
margin-bottom: 0.5rem;
}
a.item-without-title span {
display: none;
}
&:hover a {
color: #454647;
text-decoration: none;
}
}
}
ul.items-list-edit li.item-list-item {
display: flex;
align-items: flex-start;
button {
position: absolute !important;
background-color: rgba(255, 255, 255, 0.75);
color: #454647;
padding: 2px;
margin-left: 5px;
min-width: 14px;
visibility: hidden;
position: relative;
opacity: 0;
right: -14px;
top: 0px;
justify-content: center;
z-index: 999;
}
&:hover button {
visibility: visible;
background-color: rgba(255, 255, 255, 1) !important;
opacity: 1;
right: -8px;
top: -8px;
border: 1px solid #cbcbcb;
border-radius: 12px;
transition: opacity linear 0.15s, right linear 0.15s;
}
&:hover button:hover {
background-color: rgba(255, 255, 255, 1) !important;
border: 1px solid #cbcbcb !important;
}
}
@media only screen and (max-width: 498px) {
ul.items-list.items-layout-grid,
ul.items-list-edit.items-layout-grid {
grid-template-columns: repeat(auto-fill, 100%);
li.item-list-item {
width: 100%;
img { width: 100%; }
}
}
}
// List View Mode ----------------------------------------------------
ul.items-list.items-layout-list,
ul.items-list-edit.items-layout-list {
padding: 0;
display: block;
list-style-type: none;
li.item-list-item {
position: relative;
display: inline-block;
margin: 12px 12px 24px 12px;
margin-bottom: 12px;
min-height: 54px;
min-width: 22%;
width: 22%;
a {
color: #454647;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
display: flex;
align-items: center;
height: 54px;
}
img {
height: auto;
width: 54px;
min-width: 54px;
padding: 0px;
margin-right: 20px;
}
a.item-without-image img {
display: none;
}
&:hover a {
color: #454647;
text-decoration: none;
}
}
}
}

View File

@ -5,18 +5,23 @@ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPl
module.exports = {
entry: {
//dev_admin: './src/js/main.js',\
user_search: './src/admin/js/theme-main.js',
user_admin: './src/admin/js/main.js',
//gutenberg_collections_carousel: './src/gutenberg-blocks/tainacan-collections/collections-carousel/index.js',
// gutenberg_items_grid: './src/gutenberg-blocks/tainacan-items/items-grid/index.js',
gutenberg_terms_list: './src/gutenberg-blocks/tainacan-terms/terms-list/index.js',
gutenberg_items_list: './src/gutenberg-blocks/tainacan-items/items-list/index.js',
gutenberg_dynamic_items_list: './src/gutenberg-blocks/tainacan-items/dynamic-items-list/index.js',
gutenberg_dynamic_items_list_theme: './src/gutenberg-blocks/tainacan-items/dynamic-items-list/dynamic-items-list-theme.js',
gutenberg_carousel_items_list: './src/gutenberg-blocks/tainacan-items/carousel-items-list/index.js',
gutenberg_carousel_items_list_theme: './src/gutenberg-blocks/tainacan-items/carousel-items-list/carousel-items-list-theme.js',
gutenberg_search_bar: './src/gutenberg-blocks/tainacan-items/search-bar/index.js',
gutenberg_collections_list: './src/gutenberg-blocks/tainacan-collections/collections-list/index.js',
gutenberg_facets_list: './src/gutenberg-blocks/tainacan-facets/facets-list/index.js',
gutenberg_facets_list_theme: './src/gutenberg-blocks/tainacan-facets/facets-list/facets-list-theme.js'
},