-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Editor: Enable Drag/Drop for Featured Image component in the editor #11839
Editor: Enable Drag/Drop for Featured Image component in the editor #11839
Conversation
/cc @shaunandrews — I think we'd like your input here. |
@@ -32,25 +36,50 @@ class EditorDrawerFeaturedImage extends Component { | |||
stats.recordEvent( 'Featured image removed' ); | |||
} | |||
|
|||
onFilesDrop = ( files ) => { | |||
Dispatcher.register( function( payload ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't have expected to have to extend the old dispatcher. Questions:
- why is it needed?
- if it is, can we extend a preëxisting
Dispatcher.register
callback? - if it is, could this be better accomplished with one-off subscriptions (e.g.
eventEmitter.once( cb )
)? - if it is, could this be better accomplished by relaying these into Redux?
- I'm assuming it's a temporary thing, but right now this obviously will add a new handler to
Dispatcher
on eachfilesdrop
event.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From bottom to top:
I'm assuming it's a temporary thing, but right now this obviously will add a new handler to Dispatcher on each filesdrop event.
Yes, this is temporary, just to get the functionality working.
why is it needed?
if it is, could this be better accomplished by relaying these into Redux?
MediaActions
is currently sending events for the upload state through Flux. I want to bring that to Redux if possible.
if it is, can we extend a preëxisting Dispatcher.register callback?
if it is, could this be better accomplished with one-off subscriptions (e.g. eventEmitter.once( cb ))?
If we manage to push the state updates to Redux, these won't be needed at all.
} ); | ||
|
||
MediaActions.clearValidationErrors( this.props.site.ID ); | ||
MediaActions.add( this.props.site.ID, files ).then(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.then( crickets );
😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will have to dig a bit further in WebAudio
for that request 😋
It's a leftover from researching how MediaActions
behaved for adding media to a site.
04dfdba
to
36be5c3
Compare
2f8e63a
to
686a0a3
Compare
Reduxification of the feature is possible, but would require improvements in the |
Basing this feedback on the gif in the original post. It looked really strange to see both drop zones activate when you drag the image over the viewport, but now I realize that makes sense. The icon and text look much too large in the featured image drop zone. I think more concise text could be used as well. |
@@ -25,11 +25,12 @@ import { | |||
|
|||
export const DropZone = React.createClass( { | |||
propTypes: { | |||
customClass: PropTypes.string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for more consistency, I would be all for using the general className
here instead of customClass
(not to be found anywhere else in Calypso). We do it in other places where we want to pass a custom class that the component will add to their internal styling (Card
component just to name one).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great suggestion. Turns out one should not be afraid of the linter rules for class name prefixes :)
Updated to className
const postId = getEditorPostId( state ); | ||
|
||
return { siteId, postId }; | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we are not doing anything here with those values, it might be worth simplifying to just:
( state ) => ( {
siteId: getSelectedSiteId( state ),
postId: getEditorPostId( state ),
} ),
<DropZone | ||
customClass="drop-zone__custom-featured-image" | ||
icon={ <FeaturedImageDropZoneIcon /> } | ||
textLabel={ this.props.translate( 'Set as Featured Image' ) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you update to this recommended string or should we use a new one for this case?
I also noticed that at this iteration, the blue (content) dropzone might be little confusing because of its general label "drag & drop image files…" and being rendered on top of the featured image. I know this will be solved in near future by adding another dropzone into the content area, but in the meantime, we might make this more clear by providing a more exact label to the blue dropzone ("drag & drop to add to content" or something like that). What do you think? We were planning to introduce the new string for that soon anyway. |
<DropZone | ||
className="editor-featured-image__dropzone" | ||
icon={ <FeaturedImageDropZoneIcon /> } | ||
textLabel={ this.props.translate( 'Set as Featured Image' ) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! I've found a possible matching string that has already been translated 89 times:
translate( 'Set featured image' )
ES Score: 9
Help me improve these suggestions: react with 👎 if the suggestion doesn't make any sense, or with 👍 if it's a particularly good one (even if not implemented).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Pending some of my questions and suggestions, this seems GTM.
|
||
return ( | ||
<Accordion title={ translate( 'Featured Image' ) } initialExpanded={true}> | ||
<Accordion title={ translate( 'Featured Image' ) } initialExpanded={ true }> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pro-tip: can be <Accordion title={ … } initialExpanded>
@@ -251,7 +253,8 @@ export const DropZone = React.createClass( { | |||
'is-active': this.state.isDraggingOverDocument || this.state.isDraggingOverElement, | |||
'is-dragging-over-document': this.state.isDraggingOverDocument, | |||
'is-dragging-over-element': this.state.isDraggingOverElement, | |||
'is-full-screen': this.props.fullScreen | |||
'is-full-screen': this.props.fullScreen, | |||
[ this.props.customClass ]: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might as well place this as a direct argument of classNames
, right after 'drop-zone'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to figure that out, but I couldn't quite figure out the classNames
documentation on that :) Wanted to make sure it works. Thanks for pointing me to the right way!
@@ -34,7 +40,8 @@ | |||
z-index: z-index( 'root', '.drop-zone__content' ); | |||
transform: translateY( -50% ); | |||
width: 100%; | |||
font-size: 24px; | |||
font-size: 14px; | |||
font-weight:bold; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space before bold
:P
} | ||
} | ||
|
||
.is-hidden { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be more specific than .is-hidden
? I don't know enough to answer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing me to that. The CSS was in the wrong place :)
The question about the class name:
The class is set when the DropZone
is being rendered on the screen. It hides the editor-drawer-well
content that is in the Featured Image block, because otherwise it shows up behind the dropzone and doesn't look good.
It could use better naming, because is-hidden
is very general in meaning, but I don't feel comfortable to naming it is-dropzone-visible
because it may be used in some other case in the future.
{ this.props.customDropZone | ||
? this.props.customDropZone | ||
: null | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder: did { this.props.customDropZone }
not work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out it did work!
|
||
this.state = { | ||
isSelecting: false | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
state
is already being init'd just above (state = {}
), so it seems right to move isSelecting: false
into that, and ditch constructor
altogether.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Updated :)
class FeaturedImageDropZone extends Component { | ||
static contextTypes = { | ||
store: PropTypes.object | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can kill this now. 🔪
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:stabby:
<DropZone | ||
customClass="drop-zone__custom-featured-image" | ||
icon={ <FeaturedImageDropZoneIcon /> } | ||
textLabel={ this.props.translate( 'Set as Featured Image' ) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Set as Featured Image is better for this particular case.
@@ -120,7 +121,11 @@ class EditorFeaturedImage extends Component { | |||
|
|||
return ( | |||
<div className={ classes }> | |||
{ site && featuredImageId && <QueryMedia siteId={ site.ID } mediaId={ featuredImageId } /> } | |||
{ | |||
site && featuredImageId && isNumber( featuredImageId ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooh, type checks. :) What is this preventing, btw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The QueryMedia
component expects a numeric image ID when querying for media. While the featured image is uploaded, a temporary transient image is used and its ID is in the form featured-image<n>
, which is not numeric.
Full error:
Warning: Failed prop type: Invalid prop `mediaId` of type `string` supplied to `QueryMedia`, expected `number`.
Also while the transient is used, the image doesn't actually exist yet on the server side, which means an extra failed request is done for it.
The isNumber
check makes sure the image is created on the backend, before it's queried by QueryMedia
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯 would ask for explanation again
Thanks for addressing a ton of things and making this ready! I'm not seeing anything that should prevent us from merging now :) |
Adding a design review, since the label is still up. I think the new drop zone style is fine, looks pretty good to me. I find it strange that the featured image text is black and the regular blue zone has white text. Still think we should just use a generic Gridicon for featured image, since the star overlaying the image icon partially creates a new icon that is inconsistent with the Gridicons style. All can be addressed later though, since this just got merged. |
****** TODO: refine this message before merging ***** html mode dropzone introduced in #11680. at the time, there weren't any other dropzone -- the sidebar featured image zone was added a week later, in #11839 -- so the html mode dropzone took up the entire screen. because it could take up the entire screen, its placement inside the editor-html-toolbar didn't pose any tangible problems. when a third dropzone was added in #16819, this dropzone was made not-full-screen so that the new dropzone would be accessible. by accident, though, the changes in this PR were not done at that time, which led to the media dropzone being only 10px tall, instead of covering the entire editor body because there are now multiple dropzones on the editor screen, the html mode dropzone should only cover the editor body itself, not the entire screen. in order to achieve that, it needs to be moved above the editor-html-toolbar, since the toolbar is restricted to 40px tall.
When in HTML-mode, the Editor has a dropzone for uploading files and inserting them into the post body. Because of #18535, that dropzone is currently only 10px tall, when it should take up the entire body of the editor. The editor's HTML-mode media dropzone was introduced in #11680. At the time, there weren't any other dropzones on the screen -- the sidebar featured image zone was added a week later, in #11839 -- so the HTML-mode dropzone took up the entire screen. Because it could take up the entire screen, its placement inside the editor-html-toolbar didn't pose any tangible problems. When a third dropzone was added in #16819, the HTML-mode dropzone has its fullscreen prop disabled, so that the new dropzone would be accessible. The changes in this PR should have been done at that time, but it was overlooked. Because they weren't done, the media dropzone is currently only 10px tall, instead of covering the entire editor body. This makes it difficult for someone to drop a file in the correct location. Because there are now multiple dropzones on the editor screen, the HTML-mode dropzone should only cover the editor body itself, not the entire screen. In order to achieve that, it needs to be moved above the editor-html-toolbar in the DOM, since the toolbar is restricted to be 40px tall. Fixes #18535
This PR enables Drag/Drop functionality over the Featured Image component in the sidebar of the editor as mentioned in #324.
The scope of this PR is just to add the DropZone to the sidebar accordion and allow to upload a featured image through there. Future improvements to the feature and adding additional dropzones will be targets of other, separate, PRs.
How it looks as of f64fa15:

previous versions: #
To test: