Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Implement Fixed image and Repeated image media controls for the `…
Browse files Browse the repository at this point in the history
…Featured Product` (#6344)

* Add `Fixed` and `Repeated` background controls to `Featured Product`

* Add `Repeated background` feature when the toggle is activated

* Extract `get_image_url` function

* Add the styles for rendering the repeated image on the frontend

* Add `hasParallax` and `isRepeated` to the `block.json` file

* Adjust styles

* Remove unused function, improve phpdoc

* Use alt and product name

Fix error rebasing master

* Hide alt if isRepeat is true

When isRepeated is true, the image is a background so it does not
make sense to have an alt attribute.

* Add `Fixed image` behaviour

* Remove unnecessary single quotes

* Remove duplicated const due to rebasing

* Fix focal point getting lost after enabling Fixed bg

* Fix duotone for fixed and repeated images

* Fix duotone for fixed and repeated images on the front end

* Don't allow alt if the image is a bg not an img element
  • Loading branch information
albarin authored May 18, 2022
1 parent ff59682 commit 1baee89
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 102 deletions.
2 changes: 1 addition & 1 deletion assets/js/blocks/featured-category/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ import {
dimRatioToClass,
getCategoryImageId,
getCategoryImageSrc,
calculateBackgroundImagePosition,
} from './utils';
import { withCategory } from '../../hocs';
import { calculateBackgroundImagePosition } from '../featured-product/utils';
import { ConstrainedResizable } from '../featured-product/block';

const DEFAULT_EDITOR_SIZE = {
Expand Down
11 changes: 11 additions & 0 deletions assets/js/blocks/featured-category/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,14 @@ export {
getBackgroundImageStyles,
dimRatioToClass,
};

export function calculateBackgroundImagePosition( coords ) {
if ( ! coords ) return {};

const x = Math.round( coords.x * 100 );
const y = Math.round( coords.y * 100 );

return {
objectPosition: `${ x }% ${ y }%`,
};
}
229 changes: 153 additions & 76 deletions assets/js/blocks/featured-product/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ import { crop, Icon, starEmpty } from '@wordpress/icons';
/**
* Internal dependencies
*/
import { calculateBackgroundImagePosition, dimRatioToClass } from './utils';
import {
backgroundImageStyles,
calculateImagePosition,
dimRatioToClass,
} from './utils';
import {
getImageSrcFromProduct,
getImageIdFromProduct,
Expand Down Expand Up @@ -265,11 +269,17 @@ const FeaturedProduct = ( {

const getInspectorControls = () => {
const url = attributes.mediaSrc || getImageSrcFromProduct( product );
const { focalPoint = { x: 0.5, y: 0.5 } } = attributes;
const {
focalPoint = { x: 0.5, y: 0.5 },
hasParallax,
isRepeated,
} = attributes;
// FocalPointPicker was introduced in Gutenberg 5.0 (WordPress 5.2),
// so we need to check if it exists before using it.
const focalPointPickerExists = typeof FocalPointPicker === 'function';

const isImgElement = ! isRepeated && ! hasParallax;

return (
<>
<InspectorControls key="inspector">
Expand Down Expand Up @@ -313,50 +323,76 @@ const FeaturedProduct = ( {
'woo-gutenberg-products-block'
) }
>
<ToggleGroupControl
help={
<>
<p>
{ __(
'Choose “Cover” if you want the image to scale automatically to always fit its container.',
'woo-gutenberg-products-block'
) }
</p>
<p>
{ __(
'Note: by choosing “Cover” you will lose the ability to freely move the focal point precisely.',
'woo-gutenberg-products-block'
) }
</p>
</>
}
<ToggleControl
label={ __(
'Image fit',
'Fixed background',
'woo-gutenberg-products-block'
) }
value={ attributes.imageFit }
onChange={ ( value ) =>
checked={ hasParallax }
onChange={ () => {
setAttributes( {
imageFit: value,
} )
}
>
<ToggleGroupControlOption
label={ __(
'None',
'woo-gutenberg-products-block'
) }
value="none"
/>
<ToggleGroupControlOption
/* translators: "Cover" is a verb that indicates an image covering the entire container. */
hasParallax: ! hasParallax,
} );
} }
/>
<ToggleControl
label={ __(
'Repeated background',
'woo-gutenberg-products-block'
) }
checked={ isRepeated }
onChange={ () => {
setAttributes( {
isRepeated: ! isRepeated,
} );
} }
/>
{ ! isRepeated && (
<ToggleGroupControl
help={
<>
<p>
{ __(
'Choose “Cover” if you want the image to scale automatically to always fit its container.',
'woo-gutenberg-products-block'
) }
</p>
<p>
{ __(
'Note: by choosing “Cover” you will lose the ability to freely move the focal point precisely.',
'woo-gutenberg-products-block'
) }
</p>
</>
}
label={ __(
'Cover',
'Image fit',
'woo-gutenberg-products-block'
) }
value="cover"
/>
</ToggleGroupControl>
value={ attributes.imageFit }
onChange={ ( value ) =>
setAttributes( {
imageFit: value,
} )
}
>
<ToggleGroupControlOption
label={ __(
'None',
'woo-gutenberg-products-block'
) }
value="none"
/>
<ToggleGroupControlOption
/* translators: "Cover" is a verb that indicates an image covering the entire container. */
label={ __(
'Cover',
'woo-gutenberg-products-block'
) }
value="cover"
/>
</ToggleGroupControl>
) }
<FocalPointPicker
label={ __(
'Focal Point Picker',
Expand All @@ -370,30 +406,32 @@ const FeaturedProduct = ( {
} )
}
/>
<TextareaControl
label={ __(
'Alt text (alternative text)',
'woo-gutenberg-products-block'
) }
value={ attributes.alt }
onChange={ ( alt ) => {
setAttributes( { alt } );
} }
help={
<>
<ExternalLink href="https://www.w3.org/WAI/tutorials/images/decision-tree">
{ isImgElement && (
<TextareaControl
label={ __(
'Alt text (alternative text)',
'woo-gutenberg-products-block'
) }
value={ attributes.alt }
onChange={ ( alt ) => {
setAttributes( { alt } );
} }
help={
<>
<ExternalLink href="https://www.w3.org/WAI/tutorials/images/decision-tree">
{ __(
'Describe the purpose of the image',
'woo-gutenberg-products-block'
) }
</ExternalLink>
{ __(
'Describe the purpose of the image',
'Leaving it empty will use the product name.',
'woo-gutenberg-products-block'
) }
</ExternalLink>
{ __(
'Leaving it empty will use the product name.',
'woo-gutenberg-products-block'
) }
</>
}
/>
</>
}
/>
) }
</PanelBody>
) }
<PanelColorGradientSettings
Expand Down Expand Up @@ -454,6 +492,8 @@ const FeaturedProduct = ( {
contentAlign,
dimRatio,
focalPoint,
hasParallax,
isRepeated,
imageFit,
minHeight,
overlayColor,
Expand All @@ -471,6 +511,7 @@ const FeaturedProduct = ( {
'is-loading': ! product && isLoading,
'is-not-found': ! product && ! isLoading,
'has-background-dim': dimRatio !== 0,
'is-repeated': isRepeated,
},
contentAlign !== 'center' && `has-${ contentAlign }-content`
);
Expand All @@ -479,14 +520,31 @@ const FeaturedProduct = ( {
borderRadius: style?.border?.radius,
};

const backgroundImageStyle = {
objectPosition: calculateImagePosition( focalPoint ),
objectFit: imageFit,
};

const isImgElement = ! isRepeated && ! hasParallax;

const wrapperStyle = {
...getSpacingClassesAndStyles( attributes ).style,
minHeight,
};

const backgroundImageStyle = {
...calculateBackgroundImagePosition( focalPoint ),
objectFit: imageFit,
const backgroundDivStyle = {
...( ! isImgElement
? {
...backgroundImageStyles( backgroundImageSrc ),
backgroundPosition: calculateImagePosition(
focalPoint
),
}
: undefined ),
...( ! isRepeated && {
backgroundRepeat: 'no-repeat',
backgroundSize: imageFit === 'cover' ? imageFit : 'auto',
} ),
};

const overlayStyle = {
Expand All @@ -504,25 +562,40 @@ const FeaturedProduct = ( {
/>
<div className={ classes } style={ containerStyle }>
<div
className="wc-block-featured-product__wrapper"
className={ classnames(
'wc-block-featured-product__wrapper'
) }
style={ wrapperStyle }
>
<div
className="wc-block-featured-product__overlay"
style={ overlayStyle }
/>
<img
alt={ product.short_description }
className="wc-block-featured-product__background-image"
src={ backgroundImageSrc }
style={ backgroundImageStyle }
onLoad={ ( e ) => {
setBackgroundImageSize( {
height: e.target?.naturalHeight,
width: e.target?.naturalWidth,
} );
} }
/>
{ isImgElement && (
<img
alt={ product.short_description }
className="wc-block-featured-product__background-image"
src={ backgroundImageSrc }
style={ backgroundImageStyle }
onLoad={ ( e ) => {
setBackgroundImageSize( {
height: e.target?.naturalHeight,
width: e.target?.naturalWidth,
} );
} }
/>
) }
{ ! isImgElement && (
<div
className={ classnames(
'wc-block-featured-product__background-image',
{
'has-parallax': hasParallax,
}
) }
style={ backgroundDivStyle }
/>
) }
<h2
className="wc-block-featured-product__title"
dangerouslySetInnerHTML={ {
Expand Down Expand Up @@ -736,6 +809,7 @@ export default compose( [
state = {
doUrlUpdate: false,
};

componentDidUpdate() {
const {
attributes,
Expand All @@ -757,9 +831,11 @@ export default compose( [
this.setState( { doUrlUpdate: false } );
}
}

triggerUrlUpdate = () => {
this.setState( { doUrlUpdate: true } );
};

render() {
return (
<ProductComponent
Expand All @@ -769,6 +845,7 @@ export default compose( [
);
}
}

return WrappedComponent;
}, 'withUpdateButtonAttributes' ),
] )( FeaturedProduct );
8 changes: 8 additions & 0 deletions assets/js/blocks/featured-product/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@
"type": "string",
"default": "none"
},
"hasParallax": {
"type": "boolean",
"default": false
},
"isRepeated": {
"type": "boolean",
"default": false
},
"mediaId": {
"type": "number",
"default": 0
Expand Down
2 changes: 2 additions & 0 deletions assets/js/blocks/featured-product/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const example = {
contentAlign: 'center',
dimRatio: 50,
editMode: false,
hasParallax: false,
isRepeated: false,
height: getSetting( 'default_height', 500 ),
mediaSrc: '',
overlayColor: '#000000',
Expand Down
Loading

0 comments on commit 1baee89

Please sign in to comment.