Skip to content

Commit 23f11a1

Browse files
cbravobernalmichalczaplinskicarolinanjarcosockham
authored
[ New block ] - Create a Generic Avatar block for Authors (#38591)
Co-authored-by: Michal Czaplinski <mmczaplinski@gmail.com> Co-authored-by: Carolina Nymark <myazalea@hotmail.com> Co-authored-by: José Arcos <hello@josearcos.me> Co-authored-by: Bernie Reiter <ockham@raz.or.at>
1 parent 3739bd7 commit 23f11a1

File tree

17 files changed

+670
-3
lines changed

17 files changed

+670
-3
lines changed

docs/reference-guides/core-blocks.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ Embed a simple audio player. ([Source](https://github.com/WordPress/gutenberg/tr
2626
- **Supports:** align, anchor
2727
- **Attributes:** autoplay, caption, id, loop, preload, src
2828

29+
## Avatar
30+
31+
Add a user's avatar. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/avatar))
32+
33+
- **Name:** core/avatar
34+
- **Category:** theme
35+
- **Supports:** align, color (~~background~~, ~~text~~), spacing (margin), ~~alignWide~~, ~~html~~
36+
- **Attributes:** isLink, linkTarget, size, userId
37+
2938
## Reusable block
3039

3140
Create and save content to reuse across your site. Update the block, and the changes apply everywhere it’s used. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/block))
@@ -104,7 +113,7 @@ Add the avatar of this comment's author. ([Source](https://github.com/WordPress/
104113

105114
- **Name:** core/comment-author-avatar
106115
- **Category:** theme
107-
- **Supports:** color (background, ~~text~~), spacing (margin, padding), ~~html~~
116+
- **Supports:** color (background, ~~text~~), spacing (margin, padding), ~~html~~, ~~inserter~~
108117
- **Attributes:** height, width
109118

110119
## Comment Author Name

lib/blocks.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ function gutenberg_reregister_core_block_types() {
5353
),
5454
'block_names' => array(
5555
'archives.php' => 'core/archives',
56+
'avatar.php' => 'core/avatar',
5657
'block.php' => 'core/block',
5758
'calendar.php' => 'core/calendar',
5859
'categories.php' => 'core/categories',
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"$schema": "https://schemas.wp.org/trunk/block.json",
3+
"apiVersion": 2,
4+
"name": "core/avatar",
5+
"title": "Avatar",
6+
"category": "theme",
7+
"description": "Add a user's avatar.",
8+
"textdomain": "default",
9+
"attributes": {
10+
"userId": {
11+
"type": "number"
12+
},
13+
"size": {
14+
"type": "number",
15+
"default": 96
16+
},
17+
"isLink": {
18+
"type": "boolean",
19+
"default": false
20+
},
21+
"linkTarget": {
22+
"type": "string",
23+
"default": "_self"
24+
}
25+
26+
},
27+
"usesContext": [ "postType", "postId", "commentId" ],
28+
"supports": {
29+
"html": false,
30+
"align": true,
31+
"alignWide": false,
32+
"spacing": {
33+
"margin": true
34+
},
35+
"__experimentalBorder": {
36+
"__experimentalSkipSerialization": true,
37+
"radius": true,
38+
"width": true,
39+
"color": true,
40+
"style": true,
41+
"__experimentalDefaultControls": {
42+
"radius": true
43+
}
44+
},
45+
"color": {
46+
"text": false,
47+
"background": false,
48+
"__experimentalDuotone": "img"
49+
}
50+
},
51+
"editorStyle": "wp-block-avatar",
52+
"style": "wp-block-avatar"
53+
}
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import classnames from 'classnames';
5+
6+
/**
7+
* WordPress dependencies
8+
*/
9+
import {
10+
InspectorControls,
11+
useBlockProps,
12+
__experimentalUseBorderProps as useBorderProps,
13+
} from '@wordpress/block-editor';
14+
import {
15+
PanelBody,
16+
RangeControl,
17+
ResizableBox,
18+
ToggleControl,
19+
} from '@wordpress/components';
20+
import { __, isRTL } from '@wordpress/i18n';
21+
22+
/**
23+
* Internal dependencies
24+
*/
25+
import { useUserAvatar, useCommentAvatar } from './hooks';
26+
import UserControl from './user-control';
27+
28+
const AvatarInspectorControls = ( {
29+
setAttributes,
30+
avatar,
31+
attributes,
32+
selectUser,
33+
} ) => (
34+
<InspectorControls>
35+
<PanelBody title={ __( 'Avatar Settings' ) }>
36+
<RangeControl
37+
label={ __( 'Image size' ) }
38+
onChange={ ( newSize ) =>
39+
setAttributes( {
40+
size: newSize,
41+
} )
42+
}
43+
min={ avatar.minSize }
44+
max={ avatar.maxSize }
45+
initialPosition={ attributes?.size }
46+
value={ attributes?.size }
47+
/>
48+
{ selectUser && (
49+
<UserControl
50+
value={ attributes?.userId }
51+
onChange={ ( value ) => {
52+
setAttributes( {
53+
userId: value,
54+
} );
55+
} }
56+
/>
57+
) }
58+
<ToggleControl
59+
label={ __( 'Link to user profile' ) }
60+
onChange={ () =>
61+
setAttributes( { isLink: ! attributes.isLink } )
62+
}
63+
checked={ attributes.isLink }
64+
/>
65+
{ attributes.isLink && (
66+
<ToggleControl
67+
label={ __( 'Open in new tab' ) }
68+
onChange={ ( value ) =>
69+
setAttributes( {
70+
linkTarget: value ? '_blank' : '_self',
71+
} )
72+
}
73+
checked={ attributes.linkTarget === '_blank' }
74+
/>
75+
) }
76+
</PanelBody>
77+
</InspectorControls>
78+
);
79+
80+
const ResizableAvatar = ( {
81+
setAttributes,
82+
attributes,
83+
avatar,
84+
blockProps,
85+
isSelected,
86+
} ) => {
87+
const borderProps = useBorderProps( attributes );
88+
return (
89+
<div { ...blockProps }>
90+
<ResizableBox
91+
size={ {
92+
width: attributes.size,
93+
height: attributes.size,
94+
} }
95+
showHandle={ isSelected }
96+
onResizeStop={ ( event, direction, elt, delta ) => {
97+
setAttributes( {
98+
size: parseInt(
99+
attributes.size + ( delta.height || delta.width ),
100+
10
101+
),
102+
} );
103+
} }
104+
lockAspectRatio
105+
enable={ {
106+
top: false,
107+
right: ! isRTL(),
108+
bottom: true,
109+
left: isRTL(),
110+
} }
111+
minWidth={ avatar.minSize }
112+
maxWidth={ avatar.maxSize }
113+
>
114+
<img
115+
src={ avatar.src }
116+
alt={ avatar.alt }
117+
{ ...borderProps }
118+
className={ classnames(
119+
'avatar',
120+
'avatar-' + attributes.size,
121+
'photo',
122+
'wp-block-avatar__image',
123+
borderProps.className
124+
) }
125+
style={ {
126+
...borderProps.style, // Border radius, width and style.
127+
} }
128+
/>
129+
</ResizableBox>
130+
</div>
131+
);
132+
};
133+
const CommentEdit = ( { attributes, context, setAttributes, isSelected } ) => {
134+
const { commentId } = context;
135+
const blockProps = useBlockProps();
136+
const avatar = useCommentAvatar( { commentId } );
137+
return (
138+
<>
139+
<AvatarInspectorControls
140+
avatar={ avatar }
141+
setAttributes={ setAttributes }
142+
attributes={ attributes }
143+
selectUser={ false }
144+
/>
145+
{ attributes.isLink ? (
146+
<a
147+
href="#avatar-pseudo-link"
148+
className="wp-block-avatar__link"
149+
onClick={ ( event ) => event.preventDefault() }
150+
>
151+
<ResizableAvatar
152+
attributes={ attributes }
153+
avatar={ avatar }
154+
blockProps={ blockProps }
155+
isSelected={ isSelected }
156+
setAttributes={ setAttributes }
157+
/>
158+
</a>
159+
) : (
160+
<ResizableAvatar
161+
attributes={ attributes }
162+
avatar={ avatar }
163+
blockProps={ blockProps }
164+
isSelected={ isSelected }
165+
setAttributes={ setAttributes }
166+
/>
167+
) }
168+
</>
169+
);
170+
};
171+
172+
const UserEdit = ( { attributes, context, setAttributes, isSelected } ) => {
173+
const { postId, postType } = context;
174+
const avatar = useUserAvatar( {
175+
userId: attributes?.userId,
176+
postId,
177+
postType,
178+
} );
179+
const blockProps = useBlockProps();
180+
return (
181+
<>
182+
<AvatarInspectorControls
183+
selectUser={ true }
184+
attributes={ attributes }
185+
avatar={ avatar }
186+
setAttributes={ setAttributes }
187+
/>
188+
<div>
189+
{ attributes.isLink ? (
190+
<a
191+
href="#avatar-pseudo-link"
192+
className="wp-block-avatar__link"
193+
onClick={ ( event ) => event.preventDefault() }
194+
>
195+
<ResizableAvatar
196+
attributes={ attributes }
197+
avatar={ avatar }
198+
blockProps={ blockProps }
199+
isSelected={ isSelected }
200+
setAttributes={ setAttributes }
201+
/>
202+
</a>
203+
) : (
204+
<ResizableAvatar
205+
attributes={ attributes }
206+
avatar={ avatar }
207+
blockProps={ blockProps }
208+
isSelected={ isSelected }
209+
setAttributes={ setAttributes }
210+
/>
211+
) }
212+
</div>
213+
</>
214+
);
215+
};
216+
217+
export default function Edit( props ) {
218+
if ( props?.context?.commentId ) {
219+
return <CommentEdit { ...props } />;
220+
}
221+
return <UserEdit { ...props } />;
222+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.wp-block-avatar__image img {
2+
width: 100%;
3+
}

0 commit comments

Comments
 (0)