From 8b7b1677498ef0c12cf6284862c27ff62c04e136 Mon Sep 17 00:00:00 2001 From: David M Date: Tue, 29 Oct 2024 14:17:14 +0100 Subject: [PATCH] feat(components/molecule/photoUploader): add new view type list to photouploader --- .../photoUploader/src/PhotosPreview/index.js | 13 +++- .../photoUploader/src/ThumbCard/index.js | 22 ++++-- .../molecule/photoUploader/src/config.js | 7 ++ .../molecule/photoUploader/src/index.js | 30 ++++++-- .../photoUploader/src/styles/index.scss | 72 +++++++++++++++++++ .../photoUploader/src/styles/settings.scss | 2 + .../molecule/photoUploader/test/index.test.js | 8 ++- 7 files changed, 140 insertions(+), 14 deletions(-) diff --git a/components/molecule/photoUploader/src/PhotosPreview/index.js b/components/molecule/photoUploader/src/PhotosPreview/index.js index 9e7621cf2..c4b20c219 100644 --- a/components/molecule/photoUploader/src/PhotosPreview/index.js +++ b/components/molecule/photoUploader/src/PhotosPreview/index.js @@ -15,7 +15,8 @@ import { DEFAULT_NOTIFICATION_ERROR, ROTATION_DIRECTION, THUMB_CLASS_NAME, - THUMB_SORTABLE_CLASS_NAME + THUMB_SORTABLE_CLASS_NAME, + VIEW_TYPE } from '../config.js' import {callbackUploadPhotoHandler} from '../fileTools.js' import {base64ToBlob, cropAndRotateImage, formatToBase64} from '../photoTools.js' @@ -33,6 +34,7 @@ const PhotosPreview = ({ content, defaultFormatToBase64Options, deleteIcon, + dragIcon, dragDelay, errorInitialPhotoDownloadErrorText, files, @@ -46,7 +48,8 @@ const PhotosPreview = ({ setFiles, setIsLoading, setNotificationError, - thumbIconSize + thumbIconSize, + viewType }) => { const _onSortEnd = event => { _callbackPhotosUploaded(files, {action: ACTIONS.SORT, data: event}) @@ -169,9 +172,11 @@ const PhotosPreview = ({ content={content} rotateIcon={rotateIcon()} deleteIcon={deleteIcon()} + dragIcon={dragIcon()} retryIcon={retryIcon()} rejectPhotosIcon={rejectPhotosIcon()} outputImageAspectRatioDisabled={outputImageAspectRatioDisabled} + viewType={viewType} /> )} @@ -218,6 +223,7 @@ PhotosPreview.propTypes = { content: PropTypes.func, defaultFormatToBase64Options: PropTypes.object.isRequired, deleteIcon: PropTypes.node.isRequired, + dragIcon: PropTypes.node, dragDelay: PropTypes.number.isRequired, errorInitialPhotoDownloadErrorText: PropTypes.string.isRequired, files: PropTypes.array.isRequired, @@ -231,7 +237,8 @@ PhotosPreview.propTypes = { setFiles: PropTypes.func.isRequired, setIsLoading: PropTypes.func.isRequired, setNotificationError: PropTypes.func.isRequired, - thumbIconSize: PropTypes.oneOf(Object.keys(ATOM_ICON_SIZES)) + thumbIconSize: PropTypes.oneOf(Object.keys(ATOM_ICON_SIZES)), + viewType: PropTypes.oneOf(Object.keys(VIEW_TYPE)) } export default PhotosPreview diff --git a/components/molecule/photoUploader/src/ThumbCard/index.js b/components/molecule/photoUploader/src/ThumbCard/index.js index 1021c4ec7..f69f56704 100644 --- a/components/molecule/photoUploader/src/ThumbCard/index.js +++ b/components/molecule/photoUploader/src/ThumbCard/index.js @@ -12,6 +12,8 @@ import { THUMB_CARD_CLASS_NAME } from './config.js' +import {DEFAULT_VIEW_TYPE, VIEW_TYPE} from './../config.js' + const ThumbCard = ({ iconSize = ATOM_ICON_SIZES.small, callbackDeleteItem, @@ -19,18 +21,23 @@ const ThumbCard = ({ callbackRotateItem, content: Content = () => null, deleteIcon, + dragIcon, index, image, mainPhotoLabel, outputImageAspectRatioDisabled, rejectPhotosIcon, retryIcon, - rotateIcon + rotateIcon, + viewType }) => { const hasErrors = image.hasErrors + const isDefaultView = viewType === DEFAULT_VIEW_TYPE + const isListtView = viewType === VIEW_TYPE.LIST + const counterClass = cx(`${THUMB_CARD_CLASS_NAME}-counter`, { - [`${THUMB_CARD_CLASS_NAME}-mainCounter`]: index === 0 + [`${THUMB_CARD_CLASS_NAME}-mainCounter`]: index === 0 && isDefaultView }) const imageThumbClass = cx(IMAGE_THUMB_CARD_CLASS_NAME, { @@ -39,14 +46,17 @@ const ThumbCard = ({ return (
-
{index === 0 ? mainPhotoLabel : index + 1}
+
{index === 0 && isDefaultView ? mainPhotoLabel : index + 1}
{hasErrors ? (
{rejectPhotosIcon}
) : ( - + <> + {isListtView && {dragIcon}} + + )}
@@ -77,13 +87,15 @@ ThumbCard.propTypes = { callbackRotateItem: PropTypes.func, content: PropTypes.func, deleteIcon: PropTypes.node.isRequired, + dragIcon: PropTypes.node.isRequired, index: PropTypes.number, image: PropTypes.object.isRequired, mainPhotoLabel: PropTypes.string, outputImageAspectRatioDisabled: PropTypes.bool, rejectPhotosIcon: PropTypes.node.isRequired, retryIcon: PropTypes.node.isRequired, - rotateIcon: PropTypes.node.isRequired + rotateIcon: PropTypes.node.isRequired, + viewType: PropTypes.oneOf(Object.keys(VIEW_TYPE)) } export default ThumbCard diff --git a/components/molecule/photoUploader/src/config.js b/components/molecule/photoUploader/src/config.js index 03bd87ab7..7c4fd78cf 100644 --- a/components/molecule/photoUploader/src/config.js +++ b/components/molecule/photoUploader/src/config.js @@ -47,3 +47,10 @@ export const ACTIONS = { RETRY_UPLOAD: 'RETRY_UPLOAD', INITIAL_LOAD: 'INITIAL_LOAD' } + +export const VIEW_TYPE = { + GRID: 'grid', + LIST: 'list' +} + +export const DEFAULT_VIEW_TYPE = VIEW_TYPE.GRID diff --git a/components/molecule/photoUploader/src/index.js b/components/molecule/photoUploader/src/index.js index 8c3205f51..fab9acf9f 100644 --- a/components/molecule/photoUploader/src/index.js +++ b/components/molecule/photoUploader/src/index.js @@ -27,7 +27,9 @@ import { DRAG_STATE_STATUS_REJECTED, DROPZONE_CLASS_NAME, REJECT_FILES_REASONS, - ROTATION_DIRECTION + ROTATION_DIRECTION, + VIEW_TYPE, + DEFAULT_VIEW_TYPE } from './config.js' import {filterValidFiles, loadInitialPhotos, prepareFiles} from './fileTools.js' @@ -51,6 +53,7 @@ const MoleculePhotoUploader = forwardRef( callbackUploadPhoto, content, deleteIcon, + dragIcon, disableScrollToBottom = false, dragDelay = DEFAULT_DRAG_DELAY_TIME, dragPhotoDividerTextInitialContent, @@ -85,7 +88,8 @@ const MoleculePhotoUploader = forwardRef( rotationDirection = ROTATION_DIRECTION.counterclockwise, thumbIconSize, uploadingPhotosText, - isClickable = true + isClickable = true, + viewType = DEFAULT_VIEW_TYPE }, forwardedRef ) => { @@ -235,6 +239,10 @@ const MoleculePhotoUploader = forwardRef( const inputRef = useMergeRefs(dropzoneInputRef, forwardedRef) + const mainClassName = cx(BASE_CLASS_NAME, { + [`${BASE_CLASS_NAME}--${viewType}`]: viewType !== DEFAULT_VIEW_TYPE + }) + const dropzoneClassName = cx(DROPZONE_CLASS_NAME, { [`${DROPZONE_CLASS_NAME}--disabled`]: isPhotoUploaderFully(), [`${DROPZONE_CLASS_NAME}--empty`]: isPhotoUploaderEmpty @@ -260,7 +268,7 @@ const MoleculePhotoUploader = forwardRef( return ( <> -
+
{isPhotoUploaderEmpty && !isDragActive && ( @@ -288,6 +296,7 @@ const MoleculePhotoUploader = forwardRef( content={content} defaultFormatToBase64Options={DEFAULT_FORMAT_TO_BASE_64_OPTIONS} deleteIcon={deleteIcon} + dragIcon={dragIcon} dragDelay={dragDelay} errorInitialPhotoDownloadErrorText={errorInitialPhotoDownloadErrorText} files={files} @@ -302,6 +311,7 @@ const MoleculePhotoUploader = forwardRef( setIsLoading={setIsLoading} setNotificationError={setNotificationError} thumbIconSize={thumbIconSize} + viewType={viewType} /> )} {isDragAccept && !isPhotoUploaderFully() && !isLoading && ( @@ -394,6 +404,9 @@ MoleculePhotoUploader.propTypes = { /** Icon placed in the button that deletes image */ deleteIcon: PropTypes.func.isRequired, + /** Icon placed for draggable help in viewtype list */ + dragIcon: PropTypes.func, + /** A boolean to disable that the component scroll to bottom everytime the user add a photo or there's an error */ disableScrollToBottom: PropTypes.bool, @@ -526,9 +539,16 @@ MoleculePhotoUploader.propTypes = { onSortPhotoStart: PropTypes.func, /** A boolean to enable click in dropzone area */ - isClickable: PropTypes.bool + isClickable: PropTypes.bool, + + /** View types of the component */ + viewType: PropTypes.oneOf(Object.values(VIEW_TYPE)) } export default MoleculePhotoUploader -export {ROTATION_DIRECTION as MoleculePhotoUploaderRotationDirection, ACTIONS as MoleculePhotoUploaderActions} +export { + ROTATION_DIRECTION as MoleculePhotoUploaderRotationDirection, + ACTIONS as MoleculePhotoUploaderActions, + VIEW_TYPE as MoleculePhotoUploaderViewType +} diff --git a/components/molecule/photoUploader/src/styles/index.scss b/components/molecule/photoUploader/src/styles/index.scss index 4ac78b7c9..2e7ade6f7 100644 --- a/components/molecule/photoUploader/src/styles/index.scss +++ b/components/molecule/photoUploader/src/styles/index.scss @@ -128,6 +128,78 @@ $skeleton-class: '#{$base-class}-skeleton'; &-notification { margin-top: $m-m; } + + /** VIEW_TYPES */ + &--list { + #{$base-class}-dropzone { + background: none; + border: none; + padding: 0; + } + + #{$base-class}-preview { + grid-auto-rows: auto; + grid-gap: $g-l; + grid-template-columns: repeat(auto-fit, 100%); + } + + #{$base-class}-skeleton { + flex-direction: row; + padding: $p-m 0; + width: 100%; + + &-text { + margin-left: $m-l; + margin-top: 0; + } + } + + #{$base-class}-thumb { + background: $bg-photo-uploader; + } + + #{$base-class}-thumbCard { + flex-direction: row; + justify-content: space-between; + + &-actions { + display: flex; + flex-direction: row-reverse; + gap: $g-m; + width: auto; + } + + &-button { + background: none; + margin-right: $m-m; + &:hover { + @include media-breakpoint-up(m) { + background: none; + } + } + } + + &-counter { + left: -$m-m; + top: -$m-m; + } + + &-imageContainer { + align-items: center; + display: flex; + font-size: $fz-l; + padding-left: $p-m; + width: 100%; + } + + &-image { + border-radius: $bdrs-l; + height: $h-photo-uploader-thumb-image-list; + margin: $m-m; + width: $w-photo-uploader-thumb-image-list; + } + } + } } #{$thumb-class} { diff --git a/components/molecule/photoUploader/src/styles/settings.scss b/components/molecule/photoUploader/src/styles/settings.scss index 2e84ae8a5..ddeb7499d 100644 --- a/components/molecule/photoUploader/src/styles/settings.scss +++ b/components/molecule/photoUploader/src/styles/settings.scss @@ -45,6 +45,7 @@ $p-photo-uploader-desktop: $p-xl !default; $p-photo-uploader: $p-m !default; $s-photo-uploader-thumb-icons: 16px !default; $w-photo-uploader-thumb-image-desktop: 160px !default; +$w-photo-uploader-thumb-image-list: 60px !default; $w-photo-uploader-thumb-image: 100% !default; $p-photo-uploader-initial-state: 0 !default; @@ -54,6 +55,7 @@ $bgc-photo-uploader-counter: $c-primary !default; $bdrs-photo-uploader-counter: $bdrs-rounded !default; $h-photo-uploader-thumb-image: ($w-photo-uploader-thumb-image * 3) * 0.25; $h-photo-uploader-thumb-image-desktop: ($w-photo-uploader-thumb-image-desktop * 3) * 0.25; +$h-photo-uploader-thumb-image-list: ($w-photo-uploader-thumb-image-list * 3) * 0.25; $w-photo-uploader-skeleton: $w-photo-uploader-thumb-image; $w-photo-uploader-skeleton-desktop: $w-photo-uploader-thumb-image-desktop; $maw-photo-uploader-thumb-drag-text: 200px; diff --git a/components/molecule/photoUploader/test/index.test.js b/components/molecule/photoUploader/test/index.test.js index 957bd87a9..d71f65ac9 100644 --- a/components/molecule/photoUploader/test/index.test.js +++ b/components/molecule/photoUploader/test/index.test.js @@ -24,12 +24,18 @@ describe(json.name, () => { it('library should include defined exported elements', () => { // Given const library = pkg - const libraryExportedMembers = ['MoleculePhotoUploaderRotationDirection', 'MoleculePhotoUploaderActions', 'default'] + const libraryExportedMembers = [ + 'MoleculePhotoUploaderRotationDirection', + 'MoleculePhotoUploaderActions', + 'MoleculePhotoUploaderViewType', + 'default' + ] // When const { MoleculePhotoUploaderRotationDirection, MoleculePhotoUploaderActions, + MoleculePhotoUploaderViewType, default: MoleculePhotoUploader, ...others } = library