chore: upload dropzone style changes (#7932)

This commit is contained in:
Jarrod Flesch
2024-08-28 15:49:14 -04:00
committed by GitHub
parent 0962850086
commit 12fb691e4f
8 changed files with 143 additions and 87 deletions

View File

@@ -133,19 +133,31 @@ export const DefaultListView: React.FC = () => {
{Header || ( {Header || (
<ListHeader heading={getTranslation(labels?.plural, i18n)}> <ListHeader heading={getTranslation(labels?.plural, i18n)}>
{hasCreatePermission && ( {hasCreatePermission && (
<Button <>
Link={!isBulkUploadEnabled ? Link : undefined} <Button
aria-label={i18n.t('general:createNewLabel', { Link={Link}
label: getTranslation(labels?.singular, i18n), aria-label={i18n.t('general:createNewLabel', {
})} label: getTranslation(labels?.singular, i18n),
buttonStyle="pill" })}
el={!isBulkUploadEnabled ? 'link' : 'button'} buttonStyle="pill"
onClick={isBulkUploadEnabled ? openBulkUpload : undefined} el={'link'}
size="small" size="small"
to={!isBulkUploadEnabled ? newDocumentURL : undefined} to={newDocumentURL}
> >
{i18n.t('general:createNew')} {i18n.t('general:createNew')}
</Button> </Button>
{isBulkUploadEnabled && (
<Button
aria-label={t('upload:bulkUpload')}
buttonStyle="pill"
onClick={openBulkUpload}
size="small"
>
{t('upload:bulkUpload')}
</Button>
)}
</>
)} )}
{!smallBreak && ( {!smallBreak && (
<ListSelection label={getTranslation(collectionConfig.labels.plural, i18n)} /> <ListSelection label={getTranslation(collectionConfig.labels.plural, i18n)} />

View File

@@ -40,6 +40,7 @@ export function AddFilesView({ onCancel, onDrop }: Props) {
aria-hidden="true" aria-hidden="true"
className={`${baseClass}__hidden-input`} className={`${baseClass}__hidden-input`}
hidden hidden
multiple
onChange={(e) => { onChange={(e) => {
if (e.target.files && e.target.files.length > 0) { if (e.target.files && e.target.files.length > 0) {
onDrop(e.target.files) onDrop(e.target.files)
@@ -53,7 +54,6 @@ export function AddFilesView({ onCancel, onDrop }: Props) {
{t('general:or')} {t('upload:dragAndDrop')} {t('general:or')} {t('upload:dragAndDrop')}
</p> </p>
</Dropzone> </Dropzone>
{/* <Dropzone multipleFiles onChange={onDrop} /> */}
</div> </div>
</div> </div>
) )

View File

@@ -4,7 +4,7 @@
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
padding: calc(var(--base) * .9) calc(var(--base) / 2); padding: calc(var(--base) * .9) var(--base);
background: transparent; background: transparent;
border: 1px dotted var(--theme-elevation-400); border: 1px dotted var(--theme-elevation-400);
border-radius: var(--style-radius-s); border-radius: var(--style-radius-s);

View File

@@ -3,21 +3,21 @@
.file { .file {
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
margin: base(-0.25) 0;
&__thumbnail { &__thumbnail {
display: inline-block; display: inline-block;
max-width: base(3); max-width: calc(var(--base) * 2);
height: base(3); height: calc(var(--base) * 2);
border-radius: var(--style-radius-s);
} }
&__filename { &__filename {
align-self: center; align-self: center;
[dir='ltr'] & { [dir='ltr'] & {
margin-left: base(1); margin-left: var(--base);
} }
[dir='rtl'] & { [dir='rtl'] & {
margin-right: base(1); margin-right: var(--base);
} }
} }
} }

View File

@@ -28,6 +28,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: contain; object-fit: contain;
border-radius: var(--style-radius-s) 0 0 var(--style-radius-s);
} }
} }
@@ -85,11 +86,30 @@
.dropzone { .dropzone {
background-color: transparent; background-color: transparent;
padding-block: calc(var(--base) * 2.25);
}
&__dropzoneContent {
display: flex;
justify-content: space-between;
width: 100%;
} }
&__dropzoneButtons { &__dropzoneButtons {
display: flex; display: flex;
gap: var(--base); gap: calc(var(--base) * .5);
}
&__orText {
color: var(--theme-elevation-500);
text-transform: lowercase;
}
&__dragAndDropText {
margin: 0;
text-transform: lowercase;
align-self: center;
color: var(--theme-elevation-500);
} }
@include small-break { @include small-break {
@@ -123,4 +143,10 @@
display: none; display: none;
} }
} }
@include small-break {
&__dropzoneContent {
display: none;
}
}
} }

View File

@@ -235,43 +235,46 @@ export const Upload: React.FC<UploadProps> = (props) => {
<div className={`${baseClass}__upload`}> <div className={`${baseClass}__upload`}>
{!value && !showUrlInput && ( {!value && !showUrlInput && (
<Dropzone onChange={handleFileSelection}> <Dropzone onChange={handleFileSelection}>
<div className={`${baseClass}__dropzoneButtons`}> <div className={`${baseClass}__dropzoneContent`}>
<Button <div className={`${baseClass}__dropzoneButtons`}>
buttonStyle="icon-label" <Button
icon="plus" buttonStyle="pill"
iconPosition="left" onClick={() => {
onClick={() => { if (inputRef.current) {
if (inputRef.current) { inputRef.current.click()
inputRef.current.click() }
} }}
}} size="small"
size="small" >
> {t('upload:selectFile')}
{t('upload:selectFile')} </Button>
</Button> <input
<input aria-hidden="true"
aria-hidden="true" className={`${baseClass}__hidden-input`}
className={`${baseClass}__hidden-input`} hidden
hidden onChange={(e) => {
onChange={(e) => { if (e.target.files && e.target.files.length > 0) {
if (e.target.files && e.target.files.length > 0) { handleFileSelection(e.target.files)
handleFileSelection(e.target.files) }
} }}
}} ref={inputRef}
ref={inputRef} type="file"
type="file" />
/> <span className={`${baseClass}__orText`}>{t('general:or')}</span>
<Button <Button
buttonStyle="icon-label" buttonStyle="pill"
icon="link" onClick={() => {
iconPosition="left" setShowUrlInput(true)
onClick={() => { }}
setShowUrlInput(true) size="small"
}} >
size="small" {t('upload:pasteURL')}
> </Button>
{t('upload:pasteURL')} </div>
</Button>
<p className={`${baseClass}__dragAndDropText`}>
{t('general:or')} {t('upload:dragAndDrop')}
</p>
</div> </div>
</Dropzone> </Dropzone>
)} )}

View File

@@ -25,9 +25,11 @@ import type { ListDrawerProps } from '../../elements/ListDrawer/types.js'
import { useBulkUpload } from '../../elements/BulkUpload/index.js' import { useBulkUpload } from '../../elements/BulkUpload/index.js'
import { Button } from '../../elements/Button/index.js' import { Button } from '../../elements/Button/index.js'
import { useDocumentDrawer } from '../../elements/DocumentDrawer/index.js'
import { Dropzone } from '../../elements/Dropzone/index.js' import { Dropzone } from '../../elements/Dropzone/index.js'
import { useListDrawer } from '../../elements/ListDrawer/index.js' import { useListDrawer } from '../../elements/ListDrawer/index.js'
import { ShimmerEffect } from '../../elements/ShimmerEffect/index.js' import { ShimmerEffect } from '../../elements/ShimmerEffect/index.js'
import { PlusIcon } from '../../icons/Plus/index.js'
import { useAuth } from '../../providers/Auth/index.js' import { useAuth } from '../../providers/Auth/index.js'
import { useLocale } from '../../providers/Locale/index.js' import { useLocale } from '../../providers/Locale/index.js'
import { useTranslation } from '../../providers/Translation/index.js' import { useTranslation } from '../../providers/Translation/index.js'
@@ -143,8 +145,14 @@ export function UploadInput(props: UploadInputProps) {
collectionSlugs: typeof relationTo === 'string' ? [relationTo] : relationTo, collectionSlugs: typeof relationTo === 'string' ? [relationTo] : relationTo,
filterOptions, filterOptions,
}) })
const [
CreateDocDrawer,
_,
{ closeDrawer: closeCreateDocDrawer, openDrawer: openCreateDocDrawer },
] = useDocumentDrawer({
collectionSlug: activeRelationTo,
})
const inputRef = React.useRef<HTMLInputElement>(null)
const loadedValueDocsRef = React.useRef<boolean>(false) const loadedValueDocsRef = React.useRef<boolean>(false)
const canCreate = useMemo(() => { const canCreate = useMemo(() => {
@@ -242,7 +250,7 @@ export function UploadInput(props: UploadInputProps) {
[value, onChange, activeRelationTo, hasMany], [value, onChange, activeRelationTo, hasMany],
) )
const onFileSelection = React.useCallback( const onLocalFileSelection = React.useCallback(
(fileList?: FileList) => { (fileList?: FileList) => {
let fileListToUse = fileList let fileListToUse = fileList
if (!hasMany && fileList && fileList.length > 1) { if (!hasMany && fileList && fileList.length > 1) {
@@ -295,6 +303,24 @@ export function UploadInput(props: UploadInputProps) {
[activeRelationTo, closeListDrawer, onChange, populateDocs, value], [activeRelationTo, closeListDrawer, onChange, populateDocs, value],
) )
const onDocCreate = React.useCallback(
(data) => {
if (data.doc) {
setPopulatedDocs((currentDocs) => [
...(currentDocs || []),
{
relationTo: activeRelationTo,
value: data.doc,
},
])
onChange(data.doc.id)
}
closeCreateDocDrawer()
},
[closeCreateDocDrawer, activeRelationTo, onChange],
)
const onListSelect = React.useCallback<NonNullable<ListDrawerProps['onSelect']>>( const onListSelect = React.useCallback<NonNullable<ListDrawerProps['onSelect']>>(
async ({ collectionSlug, docID }) => { async ({ collectionSlug, docID }) => {
const loadedDocs = await populateDocs([docID], collectionSlug) const loadedDocs = await populateDocs([docID], collectionSlug)
@@ -445,20 +471,18 @@ export function UploadInput(props: UploadInputProps) {
) : null} ) : null}
{showDropzone ? ( {showDropzone ? (
<Dropzone multipleFiles={hasMany} onChange={onFileSelection}> <Dropzone multipleFiles={hasMany} onChange={onLocalFileSelection}>
<div className={`${baseClass}__dropzoneContent`}> <div className={`${baseClass}__dropzoneContent`}>
<div className={`${baseClass}__dropzoneContent__buttons`}> <div className={`${baseClass}__dropzoneContent__buttons`}>
<Button <Button
buttonStyle="icon-label" buttonStyle="pill"
disabled={readOnly || !canCreate} disabled={readOnly || !canCreate}
icon="plus"
iconPosition="left"
onClick={() => { onClick={() => {
if (!readOnly) { if (!readOnly) {
if (hasMany) { if (hasMany) {
onFileSelection() onLocalFileSelection()
} else if (inputRef.current) { } else {
inputRef.current.click() openCreateDocDrawer()
} }
} }
}} }}
@@ -466,25 +490,14 @@ export function UploadInput(props: UploadInputProps) {
> >
{t('general:createNew')} {t('general:createNew')}
</Button> </Button>
<input <span className={`${baseClass}__dropzoneContent__orText`}>{t('general:or')}</span>
aria-hidden="true"
className={`${baseClass}__hidden-input`}
disabled={readOnly}
hidden
multiple={hasMany}
onChange={(e) => {
if (e.target.files && e.target.files.length > 0) {
onFileSelection(e.target.files)
}
}}
ref={inputRef}
type="file"
/>
<ListDrawerToggler className={`${baseClass}__toggler`} disabled={readOnly}> <ListDrawerToggler className={`${baseClass}__toggler`} disabled={readOnly}>
<Button buttonStyle="icon-label" el="span" icon="plus" iconPosition="left"> <Button buttonStyle="pill" el="span" size="small">
{t('fields:chooseFromExisting')} {t('fields:chooseFromExisting')}
</Button> </Button>
</ListDrawerToggler> </ListDrawerToggler>
<CreateDocDrawer onSave={onDocCreate} />
<ListDrawer <ListDrawer
enableRowSelections={hasMany} enableRowSelections={hasMany}
onBulkSelect={onListBulkSelect} onBulkSelect={onListBulkSelect}

View File

@@ -1,10 +1,6 @@
@import '../../scss/styles.scss'; @import '../../scss/styles.scss';
.upload { .upload {
.dropzone {
padding-right: var(--base);
}
&__dropzoneAndUpload { &__dropzoneAndUpload {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -19,7 +15,7 @@
&__dropzoneContent__buttons { &__dropzoneContent__buttons {
display: flex; display: flex;
gap: var(--base); gap: calc(var(--base) / 2);
position: relative; position: relative;
left: -2px; left: -2px;
@@ -31,11 +27,17 @@
font-weight: 100; font-weight: 100;
} }
} }
&__dropzoneContent__orText {
color: var(--theme-elevation-500);
text-transform: lowercase;
}
&__dragAndDropText { &__dragAndDropText {
margin: 0; margin: 0;
text-transform: lowercase; text-transform: lowercase;
align-self: center; align-self: center;
color: var(--theme-elevation-500);
} }
&__loadingRows { &__loadingRows {