fix(media-library): prevent buttons from overlapping #3639 (#3784)

This commit is contained in:
Kunal Kundu 2020-05-25 15:37:01 +05:30 committed by GitHub
parent 2aa2fbdf3d
commit 6056424a2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 218 additions and 198 deletions

View File

@ -1,144 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/core';
import styled from '@emotion/styled';
import { FileUploadButton } from 'UI';
import { buttons, colors, colorsRaw, shadows, zIndex } from 'netlify-cms-ui-default';
const styles = {
button: css`
${buttons.button};
${buttons.default};
display: inline-block;
margin-left: 15px;
margin-right: 2px;
&[disabled] {
${buttons.disabled};
cursor: default;
}
`,
};
const ActionsContainer = styled.div`
text-align: right;
`;
const StyledUploadButton = styled(FileUploadButton)`
${styles.button};
${buttons.gray};
${shadows.dropMain};
margin-bottom: 0;
span {
font-size: 14px;
font-weight: 500;
display: flex;
justify-content: center;
align-items: center;
}
input {
height: 0.1px;
width: 0.1px;
margin: 0;
padding: 0;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: ${zIndex.zIndex0};
outline: none;
}
`;
const DeleteButton = styled.button`
${styles.button};
${buttons.lightRed};
`;
const InsertButton = styled.button`
${styles.button};
${buttons.green};
`;
const DownloadButton = styled.button`
${styles.button};
background-color: ${colors.button};
color: ${colors.buttonText};
${props =>
props.focused === true &&
css`
&:focus,
&:hover {
color: ${colorsRaw.white};
background-color: #555a65;
}
`}
`;
const UpperActionsContainer = styled.div``;
const LowerActionsContainer = styled.div`
margin-top: 30px;
`;
const MediaLibraryActions = ({
uploadButtonLabel,
deleteButtonLabel,
insertButtonLabel,
downloadButtonLabel,
uploadEnabled,
deleteEnabled,
insertEnabled,
downloadEnabled,
insertVisible,
imagesOnly,
onPersist,
onDelete,
onInsert,
onDownload,
}) => (
<ActionsContainer>
<UpperActionsContainer>
<DownloadButton onClick={onDownload} disabled={!downloadEnabled} focused={downloadEnabled}>
{downloadButtonLabel}
</DownloadButton>
<StyledUploadButton
label={uploadButtonLabel}
imagesOnly={imagesOnly}
onChange={onPersist}
disabled={!uploadEnabled}
/>
</UpperActionsContainer>
<LowerActionsContainer>
<DeleteButton onClick={onDelete} disabled={!deleteEnabled}>
{deleteButtonLabel}
</DeleteButton>
{!insertVisible ? null : (
<InsertButton onClick={onInsert} disabled={!insertEnabled}>
{insertButtonLabel}
</InsertButton>
)}
</LowerActionsContainer>
</ActionsContainer>
);
MediaLibraryActions.propTypes = {
uploadButtonLabel: PropTypes.string.isRequired,
deleteButtonLabel: PropTypes.string.isRequired,
insertButtonLabel: PropTypes.string.isRequired,
downloadButtonLabel: PropTypes.string.isRequired,
uploadEnabled: PropTypes.bool,
deleteEnabled: PropTypes.bool,
insertEnabled: PropTypes.bool,
insertVisible: PropTypes.bool,
downloadEnabled: PropTypes.bool,
imagesOnly: PropTypes.bool,
onPersist: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired,
onInsert: PropTypes.func.isRequired,
onDownload: PropTypes.func.isRequired,
};
export default MediaLibraryActions;

View File

@ -0,0 +1,72 @@
import { css } from '@emotion/core';
import styled from '@emotion/styled';
import { FileUploadButton } from 'UI';
import { buttons, colors, colorsRaw, shadows, zIndex } from 'netlify-cms-ui-default';
const styles = {
button: css`
${buttons.button};
${buttons.default};
display: inline-block;
margin-left: 15px;
margin-right: 2px;
&[disabled] {
${buttons.disabled};
cursor: default;
}
`,
};
export const UploadButton = styled(FileUploadButton)`
${styles.button};
${buttons.gray};
${shadows.dropMain};
margin-bottom: 0;
span {
font-size: 14px;
font-weight: 500;
display: flex;
justify-content: center;
align-items: center;
}
input {
height: 0.1px;
width: 0.1px;
margin: 0;
padding: 0;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: ${zIndex.zIndex0};
outline: none;
}
`;
export const DeleteButton = styled.button`
${styles.button};
${buttons.lightRed};
`;
export const InsertButton = styled.button`
${styles.button};
${buttons.green};
`;
export const DownloadButton = styled.button`
${styles.button};
background-color: ${colors.button};
color: ${colors.buttonText};
${props =>
props.focused === true &&
css`
&:focus,
&:hover {
color: ${colorsRaw.white};
background-color: #555a65;
}
`}
`;

View File

@ -5,9 +5,7 @@ import { Map } from 'immutable';
import { isEmpty } from 'lodash';
import { translate } from 'react-polyglot';
import { Modal } from 'UI';
import MediaLibrarySearch from './MediaLibrarySearch';
import MediaLibraryHeader from './MediaLibraryHeader';
import MediaLibraryActions from './MediaLibraryActions';
import MediaLibraryTop from './MediaLibraryTop';
import MediaLibraryCardGrid from './MediaLibraryCardGrid';
import EmptyMessage from './EmptyMessage';
import { colors } from 'netlify-cms-ui-default';
@ -26,12 +24,6 @@ const cardMargin = `10px`;
*/
const cardOutsideWidth = `300px`;
const LibraryTop = styled.div`
position: relative;
display: flex;
justify-content: space-between;
`;
const StyledModal = styled(Modal)`
display: grid;
grid-template-rows: 120px auto;
@ -114,55 +106,29 @@ const MediaLibraryModal = ({
(!hasFiles && t('mediaLibrary.mediaLibraryModal.noAssetsFound')) ||
(!hasFilteredFiles && t('mediaLibrary.mediaLibraryModal.noImagesFound')) ||
(!hasSearchResults && t('mediaLibrary.mediaLibraryModal.noResults'));
const hasSelection = hasMedia && !isEmpty(selectedFile);
const shouldShowButtonLoader = isPersisting || isDeleting;
return (
<StyledModal isOpen={isVisible} onClose={handleClose} isPrivate={privateUpload}>
<LibraryTop>
<div>
<MediaLibraryHeader
onClose={handleClose}
title={`${privateUpload ? t('mediaLibrary.mediaLibraryModal.private') : ''}${
forImage
? t('mediaLibrary.mediaLibraryModal.images')
: t('mediaLibrary.mediaLibraryModal.mediaAssets')
}`}
isPrivate={privateUpload}
/>
<MediaLibrarySearch
value={query}
onChange={handleSearchChange}
onKeyDown={handleSearchKeyDown}
placeholder={t('mediaLibrary.mediaLibraryModal.search')}
disabled={!dynamicSearchActive && !hasFilteredFiles}
/>
</div>
<MediaLibraryActions
uploadButtonLabel={
isPersisting
? t('mediaLibrary.mediaLibraryModal.uploading')
: t('mediaLibrary.mediaLibraryModal.upload')
}
deleteButtonLabel={
isDeleting
? t('mediaLibrary.mediaLibraryModal.deleting')
: t('mediaLibrary.mediaLibraryModal.deleteSelected')
}
downloadButtonLabel={t('mediaLibrary.mediaLibraryModal.download')}
insertButtonLabel={t('mediaLibrary.mediaLibraryModal.chooseSelected')}
uploadEnabled={!shouldShowButtonLoader}
deleteEnabled={!shouldShowButtonLoader && hasSelection}
insertEnabled={hasSelection}
downloadEnabled={hasSelection}
insertVisible={canInsert}
imagesOnly={forImage}
onPersist={handlePersist}
onDelete={handleDelete}
onInsert={handleInsert}
onDownload={handleDownload}
/>
</LibraryTop>
<MediaLibraryTop
t={t}
onClose={handleClose}
privateUpload={privateUpload}
forImage={forImage}
onDownload={handleDownload}
onUpload={handlePersist}
query={query}
onSearchChange={handleSearchChange}
onSearchKeyDown={handleSearchKeyDown}
searchDisabled={!dynamicSearchActive && !hasFilteredFiles}
onDelete={handleDelete}
canInsert={canInsert}
onInsert={handleInsert}
hasSelection={hasSelection}
isPersisting={isPersisting}
isDeleting={isDeleting}
/>
{!shouldShowEmptyMessage ? null : (
<EmptyMessage content={emptyMessage} isPrivate={privateUpload} />
)}

View File

@ -0,0 +1,126 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import MediaLibrarySearch from './MediaLibrarySearch';
import MediaLibraryHeader from './MediaLibraryHeader';
import { UploadButton, DeleteButton, DownloadButton, InsertButton } from './MediaLibraryButtons';
const LibraryTop = styled.div`
position: relative;
display: flex;
flex-direction: column;
`;
const RowContainer = styled.div`
display: flex;
justify-content: space-between;
`;
const ButtonsContainer = styled.div`
flex-shrink: 0;
`;
const MediaLibraryTop = ({
t,
onClose,
privateUpload,
forImage,
onDownload,
onUpload,
query,
onSearchChange,
onSearchKeyDown,
searchDisabled,
onDelete,
canInsert,
onInsert,
hasSelection,
isPersisting,
isDeleting,
}) => {
const shouldShowButtonLoader = isPersisting || isDeleting;
const uploadEnabled = !shouldShowButtonLoader;
const deleteEnabled = !shouldShowButtonLoader && hasSelection;
const downloadEnabled = hasSelection;
const insertEnabled = hasSelection;
const uploadButtonLabel = isPersisting
? t('mediaLibrary.mediaLibraryModal.uploading')
: t('mediaLibrary.mediaLibraryModal.upload');
const deleteButtonLabel = isDeleting
? t('mediaLibrary.mediaLibraryModal.deleting')
: t('mediaLibrary.mediaLibraryModal.deleteSelected');
const downloadButtonLabel = t('mediaLibrary.mediaLibraryModal.download');
const insertButtonLabel = t('mediaLibrary.mediaLibraryModal.chooseSelected');
return (
<LibraryTop>
<RowContainer>
<MediaLibraryHeader
onClose={onClose}
title={`${privateUpload ? t('mediaLibrary.mediaLibraryModal.private') : ''}${
forImage
? t('mediaLibrary.mediaLibraryModal.images')
: t('mediaLibrary.mediaLibraryModal.mediaAssets')
}`}
isPrivate={privateUpload}
/>
<ButtonsContainer>
<DownloadButton
onClick={onDownload}
disabled={!downloadEnabled}
focused={downloadEnabled}
>
{downloadButtonLabel}
</DownloadButton>
<UploadButton
label={uploadButtonLabel}
imagesOnly={forImage}
onChange={onUpload}
disabled={!uploadEnabled}
/>
</ButtonsContainer>
</RowContainer>
<RowContainer>
<MediaLibrarySearch
value={query}
onChange={onSearchChange}
onKeyDown={onSearchKeyDown}
placeholder={t('mediaLibrary.mediaLibraryModal.search')}
disabled={searchDisabled}
/>
<ButtonsContainer>
<DeleteButton onClick={onDelete} disabled={!deleteEnabled}>
{deleteButtonLabel}
</DeleteButton>
{!canInsert ? null : (
<InsertButton onClick={onInsert} disabled={!insertEnabled}>
{insertButtonLabel}
</InsertButton>
)}
</ButtonsContainer>
</RowContainer>
</LibraryTop>
);
};
MediaLibraryTop.propTypes = {
t: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
privateUpload: PropTypes.bool,
forImage: PropTypes.bool,
onDownload: PropTypes.func.isRequired,
onUpload: PropTypes.func.isRequired,
query: PropTypes.string,
onSearchChange: PropTypes.func.isRequired,
onSearchKeyDown: PropTypes.func.isRequired,
searchDisabled: PropTypes.bool.isRequired,
onDelete: PropTypes.func.isRequired,
canInsert: PropTypes.bool,
onInsert: PropTypes.func.isRequired,
hasSelection: PropTypes.bool.isRequired,
isPersisting: PropTypes.bool,
isDeleting: PropTypes.bool,
};
export default MediaLibraryTop;