Merge pull request #911 from tainacan/feature/910

Creates option to display items carousel with variable width. #910.
This commit is contained in:
Mateus Machado Luna 2024-07-25 09:11:41 -03:00 committed by GitHub
commit d835725409
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 248 additions and 29 deletions

View File

@ -540,10 +540,14 @@
min-width: calc(14.285% - var(--spaceBetweenItems, var(--spaceBetweenItems, 32px) ) ); min-width: calc(14.285% - var(--spaceBetweenItems, var(--spaceBetweenItems, 32px) ) );
scroll-snap-align: start; scroll-snap-align: start;
scroll-margin: 0 calc(var(--spaceBetweenItems, 32px) / 2 ); } scroll-margin: 0 calc(var(--spaceBetweenItems, 32px) / 2 ); }
.wp-block-tainacan-carousel-items-list ul.items-list-edit li.item-list-item.variable-item-width {
min-width: unset !important;
width: auto !important; }
.wp-block-tainacan-carousel-items-list ul.items-list-edit li.item-list-item a { .wp-block-tainacan-carousel-items-list ul.items-list-edit li.item-list-item a {
color: inherit; color: inherit;
font-weight: bold; font-weight: bold;
line-height: normal; } line-height: normal;
pointer-events: none; }
.wp-block-tainacan-carousel-items-list ul.items-list-edit li.item-list-item a > span { .wp-block-tainacan-carousel-items-list ul.items-list-edit li.item-list-item a > span {
color: inherit; color: inherit;
font-weight: bold; font-weight: bold;

File diff suppressed because one or more lines are too long

View File

@ -1076,7 +1076,8 @@ class Theme_Helper {
'data-max-items-per-screen' => true, 'data-max-items-per-screen' => true,
'data-space-between-items' => true, 'data-space-between-items' => true,
'data-space-around-carousel' => true, 'data-space-around-carousel' => true,
'data-tainacan-api-root' => true 'data-tainacan-api-root' => true,
'data-variable-items-width' => true
] ]
]; ];

View File

@ -125,6 +125,10 @@
"collectionTextColor": { "collectionTextColor": {
"type": "string", "type": "string",
"default": "#ffffff" "default": "#ffffff"
},
"variableItemsWidth": {
"type": "boolean",
"default": false
} }
}, },
"supports": { "supports": {

View File

@ -1,6 +1,181 @@
const { useBlockProps } = (tainacan_blocks.wp_version < '5.2' ? wp.editor : wp.blockEditor ); const { useBlockProps } = (tainacan_blocks.wp_version < '5.2' ? wp.editor : wp.blockEditor );
export default [ export default [
/* Deprecated on version 0.21.7 to add variableItemsWidth feature */
{
"attributes": {
"content": {
"type": "array",
"source": "children",
"selector": "div"
},
"collectionId": {
"type": "string",
"default": ""
},
"items": {
"type": "array",
"default": []
},
"isModalOpen": {
"type": "boolean",
"default": false
},
"searchURL": {
"type": "string",
"default": ""
},
"selectedItems": {
"type": "array",
"default": []
},
"itemsRequestSource": {
"type": "string",
"default": ""
},
"maxItemsNumber": {
"type": "number",
"default": 12
},
"maxItemsPerScreen": {
"type": "number",
"default": 7
},
"spaceBetweenItems": {
"type": "number",
"default": 32
},
"spaceAroundCarousel": {
"type": "number",
"default": 50
},
"isLoading": {
"type": "boolean",
"default": false
},
"isLoadingCollection": {
"type": "boolean",
"default": false
},
"loadStrategy": {
"type": "string",
"default": "search"
},
"arrowsPosition": {
"type": "string",
"default": "around"
},
"largeArrows": {
"type": "boolean",
"default": false
},
"arrowsStyle": {
"type": "string",
"default": "type-1"
},
"autoPlay": {
"type": "boolean",
"default": false
},
"autoPlaySpeed": {
"type": "number",
"default": 3
},
"loopSlides": {
"type": "boolean",
"default": false
},
"hideTitle": {
"type": "boolean",
"default": true
},
"showCollectionHeader": {
"type": "boolean",
"default": false
},
"showCollectionLabel": {
"type": "boolean",
"default": false
},
"imageSize": {
"type": "string",
"default": "tainacan-medium"
},
"collection": {
"type": "object",
"default": {}
},
"blockId": {
"type": "string",
"default": ""
},
"collectionBackgroundColor": {
"type": "string",
"default": "#373839"
},
"collectionTextColor": {
"type": "string",
"default": "#ffffff"
}
},
save: function ({ attributes }) {
const {
content,
blockId,
collectionId,
searchURL,
selectedItems,
arrowsPosition,
largeArrows,
arrowsStyle,
loadStrategy,
maxItemsNumber,
maxItemsPerScreen,
spaceBetweenItems,
spaceAroundCarousel,
autoPlay,
autoPlaySpeed,
loopSlides,
hideTitle,
imageSize,
showCollectionHeader,
showCollectionLabel,
collectionBackgroundColor,
collectionTextColor
} = attributes;
// Gets attributes such as style, that are automatically added by the editor hook
const blockProps = useBlockProps.save();
return <div
{ ...blockProps }
data-module="carousel-items-list"
data-search-url={ searchURL }
data-selected-items={ JSON.stringify(selectedItems) }
data-arrows-position={ arrowsPosition }
data-load-strategy={ loadStrategy }
data-collection-id={ collectionId }
data-auto-play={ '' + autoPlay }
data-auto-play-speed={ autoPlaySpeed }
data-loop-slides={ '' + loopSlides }
data-hide-title={ '' + hideTitle }
data-large-arrows={ '' + largeArrows }
data-arrows-style={ arrowsStyle }
data-image-size={ imageSize }
data-show-collection-header={ '' + showCollectionHeader }
data-show-collection-label={ '' + showCollectionLabel }
data-collection-background-color={ collectionBackgroundColor }
data-collection-text-color={ collectionTextColor }
data-max-items-number={ maxItemsNumber }
data-max-items-per-screen={ maxItemsPerScreen }
data-space-between-items={ spaceBetweenItems }
data-space-around-carousel={ spaceAroundCarousel }
data-tainacan-api-root={ tainacan_blocks.root }
id={ 'wp-block-tainacan-carousel-items-list_' + blockId }>
{ content }
</div>
}
},
/* Deprecated during Vue 3 migration to prepend attributes with data- */ /* Deprecated during Vue 3 migration to prepend attributes with data- */
{ {
"attributes": { "attributes": {

View File

@ -43,7 +43,8 @@ export default function({ attributes, setAttributes, isSelected, clientId }){
isLoadingCollection, isLoadingCollection,
collection, collection,
collectionBackgroundColor, collectionBackgroundColor,
collectionTextColor collectionTextColor,
variableItemsWidth
} = attributes; } = attributes;
// Gets blocks props from hook // Gets blocks props from hook
@ -67,6 +68,10 @@ export default function({ attributes, setAttributes, isSelected, clientId }){
imageSize = 'tainacan-medium'; imageSize = 'tainacan-medium';
setAttributes({ imageSize: imageSize }); setAttributes({ imageSize: imageSize });
} }
if (variableItemsWidth === undefined) {
variableItemsWidth = false;
setAttributes({ variableItemsWidth: variableItemsWidth });
}
// Get available image sizes // Get available image sizes
const { imageSizes } = useSelect( const { imageSizes } = useSelect(
@ -89,7 +94,7 @@ export default function({ attributes, setAttributes, isSelected, clientId }){
return ( return (
<li <li
key={ item.id } key={ item.id }
className={ 'swiper-slide item-list-item ' + (maxItemsPerScreen ? ' max-items-per-screen-' + maxItemsPerScreen : '') + (['tainacan-medium', 'tainacan-small'].indexOf(imageSize) > -1 ? ' is-forced-square' : '') }> className={ 'swiper-slide item-list-item ' + ( variableItemsWidth ? ' variable-item-width' : '') + (!variableItemsWidth && maxItemsPerScreen ? ' max-items-per-screen-' + maxItemsPerScreen : '') + (['tainacan-medium', 'tainacan-small'].indexOf(imageSize) > -1 ? ' is-forced-square' : '') }>
{ loadStrategy == 'selection' ? { loadStrategy == 'selection' ?
<Button <Button
onClick={ () => removeItemOfId(item.id) } onClick={ () => removeItemOfId(item.id) }
@ -105,11 +110,13 @@ export default function({ attributes, setAttributes, isSelected, clientId }){
href={ item.url }> href={ item.url }>
<div className="items-list-item--image-wrap"> <div className="items-list-item--image-wrap">
<img <img
height={ thumbHelper.getHeight(item['thumbnail'], imageSize) }
width={ thumbHelper.getWidth(item['thumbnail'], imageSize) }
src={ thumbHelper.getSrc(item['thumbnail'], imageSize, item['document_mimetype']) } src={ thumbHelper.getSrc(item['thumbnail'], imageSize, item['document_mimetype']) }
srcSet={ thumbHelper.getSrcSet(item['thumbnail'], imageSize, item['document_mimetype']) } srcSet={ thumbHelper.getSrcSet(item['thumbnail'], imageSize, item['document_mimetype']) }
alt={ item.thumbnail_alt ? item.thumbnail_alt : (item && item.title ? item.title : __( 'Thumbnail', 'tainacan' )) }/> alt={ item.thumbnail_alt ? item.thumbnail_alt : (item && item.title ? item.title : __( 'Thumbnail', 'tainacan' )) }/>
</div> </div>
{ !hideTitle ? <span>{ item.title ? item.title : '' }</span> : null } { !hideTitle ? <span style={{ maxWidth: variableItemsWidth ? thumbHelper.getWidth(item['thumbnail'], imageSize) + 'px' : 'unset' }}>{ item.title ? item.title : '' }</span> : null }
</a> </a>
</li> </li>
); );
@ -375,8 +382,19 @@ export default function({ attributes, setAttributes, isSelected, clientId }){
initialOpen={ true } initialOpen={ true }
> >
<div> <div>
<ToggleControl
label={__('Variable items width', 'tainacan')}
help={ !variableItemsWidth ? __('Toggle to define each slide size based on its content natural width.', 'tainacan') : __('Toggle to define a fixed amount of items that should appear per screen size.', 'tainacan')}
checked={ variableItemsWidth }
onChange={ ( isChecked ) => {
variableItemsWidth = isChecked;
setAttributes({ variableItemsWidth: variableItemsWidth });
setContent();
}
}
/>
{ {
loadStrategy != 'parent' ? loadStrategy != 'parent' && variableItemsWidth !== true ?
<RangeControl <RangeControl
label={ __('Maximum items per slide on a wide screen', 'tainacan') } label={ __('Maximum items per slide on a wide screen', 'tainacan') }
help={ maxItemsPerScreen <= 4 ? __('Warning: with such a small number of items per slide, the image size is greater, thus the cropped version of the thumbnail won\'t be used.', 'tainacan') : null } help={ maxItemsPerScreen <= 4 ? __('Warning: with such a small number of items per slide, the image size is greater, thus the cropped version of the thumbnail won\'t be used.', 'tainacan') : null }

View File

@ -23,7 +23,8 @@ export default function ({ attributes }) {
showCollectionHeader, showCollectionHeader,
showCollectionLabel, showCollectionLabel,
collectionBackgroundColor, collectionBackgroundColor,
collectionTextColor collectionTextColor,
variableItemsWidth
} = attributes; } = attributes;
// Gets attributes such as style, that are automatically added by the editor hook // Gets attributes such as style, that are automatically added by the editor hook
@ -53,6 +54,7 @@ export default function ({ attributes }) {
data-space-between-items={ spaceBetweenItems } data-space-between-items={ spaceBetweenItems }
data-space-around-carousel={ spaceAroundCarousel } data-space-around-carousel={ spaceAroundCarousel }
data-tainacan-api-root={ tainacan_blocks.root } data-tainacan-api-root={ tainacan_blocks.root }
data-variable-items-width={ '' + variableItemsWidth }
id={ 'wp-block-tainacan-carousel-items-list_' + blockId }> id={ 'wp-block-tainacan-carousel-items-list_' + blockId }>
{ content } { content }
</div> </div>

View File

@ -302,10 +302,16 @@
scroll-snap-align: start; scroll-snap-align: start;
scroll-margin: 0 calc(var(--spaceBetweenItems, 32px) / 2 ); scroll-margin: 0 calc(var(--spaceBetweenItems, 32px) / 2 );
&.variable-item-width {
min-width: unset !important;
width: auto !important;
}
a { a {
color: inherit; color: inherit;
font-weight: bold; font-weight: bold;
line-height: normal; line-height: normal;
pointer-events: none;
&>span { &>span {
color: inherit; color: inherit;

View File

@ -44,7 +44,8 @@ export default (element) => {
showCollectionLabel: getDataAttribute(block, 'show-collection-label', false) == 'true', showCollectionLabel: getDataAttribute(block, 'show-collection-label', false) == 'true',
collectionBackgroundColor: getDataAttribute(block, 'collection-background-color', '#373839'), collectionBackgroundColor: getDataAttribute(block, 'collection-background-color', '#373839'),
collectionTextColor: getDataAttribute(block, 'collection-text-color', '#ffffff'), collectionTextColor: getDataAttribute(block, 'collection-text-color', '#ffffff'),
tainacanApiRoot: getDataAttribute(block, 'tainacan-api-root') tainacanApiRoot: getDataAttribute(block, 'tainacan-api-root'),
variableItemsWidth: getDataAttribute(block, 'variable-items-width', false) == 'true',
}); });
}, },
mounted() { mounted() {

View File

@ -62,6 +62,7 @@
v-for="index in 18" v-for="index in 18"
:key="index" :key="index"
role="listitem" role="listitem"
:style="variableItemsWidth ? 'width: auto;' : ''"
class="swiper-slide collection-list-item skeleton"> class="swiper-slide collection-list-item skeleton">
<a> <a>
<img> <img>
@ -80,6 +81,7 @@
v-for="(item, index) of items" v-for="(item, index) of items"
:key="index" :key="index"
role="listitem" role="listitem"
:style="variableItemsWidth ? 'width: auto;' : ''"
class="swiper-slide item-list-item" class="swiper-slide item-list-item"
:class="{ 'is-forced-square': ['tainacan-medium', 'tainacan-small'].indexOf(imageSize) > -1 }"> :class="{ 'is-forced-square': ['tainacan-medium', 'tainacan-small'].indexOf(imageSize) > -1 }">
<a <a
@ -93,7 +95,11 @@
:hash="$thumbHelper.getBlurhashString(item['thumbnail'], imageSize)" :hash="$thumbHelper.getBlurhashString(item['thumbnail'], imageSize)"
:alt="item.thumbnail_alt ? item.thumbnail_alt : (item && item.title ? item.title : wpI18n( 'Thumbnail', 'tainacan' ))" :alt="item.thumbnail_alt ? item.thumbnail_alt : (item && item.title ? item.title : wpI18n( 'Thumbnail', 'tainacan' ))"
:transition-duration="500" /> :transition-duration="500" />
<span v-if="!hideTitle">{{ item.title ? item.title : '' }}</span> <span
v-if="!hideTitle"
:style="variableItemsWidth ? ('max-width: ' + $thumbHelper.getWidth(item['thumbnail'], imageSize) + 'px') : ''">
{{ item.title ? item.title : '' }}
</span>
</a> </a>
</li> </li>
</ul> </ul>
@ -179,7 +185,8 @@ export default {
showCollectionLabel: Boolean, showCollectionLabel: Boolean,
collectionBackgroundColor: String, collectionBackgroundColor: String,
collectionTextColor: String, collectionTextColor: String,
tainacanApiRoot: String tainacanApiRoot: String,
variableItemsWidth: Boolean
}, },
data() { data() {
return { return {
@ -334,7 +341,7 @@ export default {
const self = this; const self = this;
const spaceBetween = Number(self.spaceBetweenItems); const spaceBetween = Number(self.spaceBetweenItems);
const slidesPerView = Number(self.maxItemsPerScreen); const slidesPerView = Number(self.maxItemsPerScreen);
this.swiper = new Swiper('#' + self.blockId + '-carousel', { let swiperOptions = {
watchOverflow: true, watchOverflow: true,
mousewheel: { mousewheel: {
forceToAxis: true forceToAxis: true
@ -343,7 +350,7 @@ export default {
preventInteractionOnTransition: true, preventInteractionOnTransition: true,
allowClick: true, allowClick: true,
allowTouchMove: true, allowTouchMove: true,
slidesPerView: 1, slidesPerView: self.variableItemsWidth ? 'auto' : 1,
slidesPerGroup: 1, slidesPerGroup: 1,
spaceBetween: spaceBetween, spaceBetween: spaceBetween,
slideToClickedSlide: true, slideToClickedSlide: true,
@ -351,7 +358,18 @@ export default {
nextEl: '#' + self.blockId + '-next', nextEl: '#' + self.blockId + '-next',
prevEl: '#' + self.blockId + '-prev', prevEl: '#' + self.blockId + '-prev',
}, },
breakpoints: (!isNaN(self.maxItemsPerScreen) && self.maxItemsPerScreen != 6) ? { autoplay: self.autoPlay ? { delay: self.autoPlaySpeed*1000 } : false,
loop: self.loopSlides ? self.loopSlides : false,
a11y: {
prevSlideMessage: wp.i18n.__( 'Previous slide', 'tainacan'),
nextSlideMessage: wp.i18n.__( 'Next slide', 'tainacan'),
firstSlideMessage: wp.i18n.__('This is the first slide', 'tainacan'),
lastSlideMessage: wp.i18n.__('This is the last slide', 'tainacan')
},
modules: [Autoplay, Navigation, A11y]
}
if ( !self.variableItemsWidth ) {
swiperOptions.breakpoints = (!isNaN(self.maxItemsPerScreen) && self.maxItemsPerScreen != 6) ? {
498: { slidesPerView: slidesPerView - 4 > 0 ? slidesPerView - 4 : 1, spaceBetween: spaceBetween }, 498: { slidesPerView: slidesPerView - 4 > 0 ? slidesPerView - 4 : 1, spaceBetween: spaceBetween },
768: { slidesPerView: slidesPerView - 3 > 0 ? slidesPerView - 3 : 1, spaceBetween: spaceBetween }, 768: { slidesPerView: slidesPerView - 3 > 0 ? slidesPerView - 3 : 1, spaceBetween: spaceBetween },
1024: { slidesPerView: slidesPerView - 2 > 0 ? slidesPerView - 2 : 1, spaceBetween: spaceBetween }, 1024: { slidesPerView: slidesPerView - 2 > 0 ? slidesPerView - 2 : 1, spaceBetween: spaceBetween },
@ -363,17 +381,9 @@ export default {
1024: { slidesPerView: 4, spaceBetween: spaceBetween }, 1024: { slidesPerView: 4, spaceBetween: spaceBetween },
1366: { slidesPerView: 5, spaceBetween: spaceBetween }, 1366: { slidesPerView: 5, spaceBetween: spaceBetween },
1600: { slidesPerView: 6, spaceBetween: spaceBetween } 1600: { slidesPerView: 6, spaceBetween: spaceBetween }
}, }
autoplay: self.autoPlay ? { delay: self.autoPlaySpeed*1000 } : false, }
loop: self.loopSlides ? self.loopSlides : false, this.swiper = new Swiper('#' + self.blockId + '-carousel', swiperOptions);
a11y: {
prevSlideMessage: wp.i18n.__( 'Previous slide', 'tainacan'),
nextSlideMessage: wp.i18n.__( 'Next slide', 'tainacan'),
firstSlideMessage: wp.i18n.__('This is the first slide', 'tainacan'),
lastSlideMessage: wp.i18n.__('This is the last slide', 'tainacan')
},
modules: [Autoplay, Navigation, A11y]
});
} }
} }
} }

View File

@ -1201,12 +1201,10 @@ export default {
return this.conditionalSections[sectionId] && this.conditionalSections[sectionId].hide; return this.conditionalSections[sectionId] && this.conditionalSections[sectionId].hide;
}, },
getMetadatumOrderInSection(sectionIndex, metadatum) { getMetadatumOrderInSection(sectionIndex, metadatum) {
if ( !this.collectionMetadataSectionOrder || !Array.isArray(this.collectionMetadataSectionOrder) || !this.collectionMetadataSectionOrder[sectionIndex] || !Array.isArray(this.collectionMetadataSectionOrder[sectionIndex]['metadata_order']) )
if ( !this.collection || !Array.isArray(this.collection['metadata_section_order']) || !this.collection['metadata_section_order'][sectionIndex] || !Array.isArray(this.collection['metadata_section_order'][sectionIndex]['metadata_order']) )
return -1; return -1;
let enabledMetadataInSection = []; let enabledMetadataInSection = [];
for (let metadatum of this.collection['metadata_section_order'][sectionIndex]['metadata_order']) { for (let metadatum of this.collectionMetadataSectionOrder[sectionIndex]['metadata_order']) {
if ( metadatum.enabled ) if ( metadatum.enabled )
enabledMetadataInSection.push(metadatum.id); enabledMetadataInSection.push(metadatum.id);
} }