diff --git a/src/components/Inputs/Error.tsx b/src/components/Inputs/Error.tsx new file mode 100644 index 0000000..ce22262 --- /dev/null +++ b/src/components/Inputs/Error.tsx @@ -0,0 +1,14 @@ +type InputErrorProps = { + message: string +} + +export const InputError = ({ message }: InputErrorProps) => { + if (!message) return null + + return ( +
+
+

{message}

+
+ ) +} diff --git a/src/components/Inputs/MediaInputError.module.scss b/src/components/Inputs/MediaInputError.module.scss new file mode 100644 index 0000000..29853ea --- /dev/null +++ b/src/components/Inputs/MediaInputError.module.scss @@ -0,0 +1,14 @@ +.accordion-button::after { + position: absolute; + right: 0.75rem; + color: rgba(255, 255, 255, 0.5) !important; + + top: unset !important; + bottom: unset !important; +} +.accordion-body > * { + margin-top: 10px; +} +.accordion-item + .accordion-item { + margin-top: 10px; +} diff --git a/src/components/Inputs/MediaInputError.tsx b/src/components/Inputs/MediaInputError.tsx new file mode 100644 index 0000000..6d76baa --- /dev/null +++ b/src/components/Inputs/MediaInputError.tsx @@ -0,0 +1,64 @@ +import { FileError } from 'react-dropzone' +import styles from './MediaInputError.module.scss' + +type MediaInputErrorProps = { + rootId: string + index: number + message: string + errors?: readonly FileError[] | undefined +} + +export const MediaInputError = ({ + rootId, + index, + message, + errors +}: MediaInputErrorProps) => { + if (!message) return null + + return ( +
+

+ +

+ {errors && ( +
+
+ {errors.map((e) => { + return typeof e === 'string' ? ( +
+ {e} +
+ ) : ( +
+ {e.message} +
+ ) + })} +
+
+ )} +
+ ) +} diff --git a/src/components/Inputs/MediaInputPopover.module.scss b/src/components/Inputs/MediaInputPopover.module.scss new file mode 100644 index 0000000..0eab1d8 --- /dev/null +++ b/src/components/Inputs/MediaInputPopover.module.scss @@ -0,0 +1,45 @@ +.popover { + border-radius: 15px; + box-shadow: 0 0 16px 0px rgb(0 0 0 / 15%); + background: #232323; + z-index: 2; +} +.content { + max-height: 500px; + overflow-y: auto; + padding: 25px; + > *:not(:first-child) { + margin-top: 10px; + } +} +.trigger { + position: absolute; + top: 25px; + right: 25px; + color: rgba(255, 255, 255, 0.5); +} + +.mediaInputError { + --bs-accordion-color: unset; + --bs-accordion-bg: unset; + --bs-accordion-transition: unset; + --bs-accordion-border-color: unset; + --bs-accordion-border-width: unset; + --bs-accordion-border-radius: unset; + --bs-accordion-inner-border-radius: unset; + --bs-accordion-btn-padding-x: unset; + --bs-accordion-btn-padding-y: unset; + --bs-accordion-btn-color: unset; + --bs-accordion-btn-bg: unset; + --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='gray'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-icon-width: 1.25rem; + --bs-accordion-btn-icon-transform: rotate(-180deg); + --bs-accordion-btn-icon-transition: transform 0.2s ease-in-out; + --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='gray'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-focus-border-color: unset; + --bs-accordion-btn-focus-box-shadow: unset; + --bs-accordion-body-padding-x: unset; + --bs-accordion-body-padding-y: unset; + --bs-accordion-active-color: unset; + --bs-accordion-active-bg: unset; +} diff --git a/src/components/Inputs/MediaInputPopover.tsx b/src/components/Inputs/MediaInputPopover.tsx new file mode 100644 index 0000000..1f98de6 --- /dev/null +++ b/src/components/Inputs/MediaInputPopover.tsx @@ -0,0 +1,108 @@ +import * as Popover from '@radix-ui/react-popover' +import { useMemo } from 'react' +import { FileRejection, FileWithPath } from 'react-dropzone' +import { MediaInputError } from './MediaInputError' +import { InputSuccess } from './Success' +import styles from './MediaInputPopover.module.scss' + +interface MediaInputPopoverProps { + name: string + acceptedFiles: readonly FileWithPath[] + fileRejections: readonly FileRejection[] +} + +export const MediaInputPopover = ({ + name, + acceptedFiles, + fileRejections +}: MediaInputPopoverProps) => { + const acceptedFileItems = useMemo( + () => + acceptedFiles.map((file) => ( + + )), + [acceptedFiles] + ) + const fileRejectionItems = useMemo(() => { + const id = `${name}-errors` + return ( +
+ {fileRejections.map(({ file, errors }, index) => ( + + ))} +
+ ) + }, [fileRejections, name]) + + if (acceptedFiles.length === 0 && fileRejections.length === 0) return null + + return ( + + +
+ {acceptedFiles.length > 0 ? ( + + + + ) : ( + + + + )} +
+
+ + +
+
+

Selected files

+
+ +
+ + + +
+
+
+
+ {acceptedFileItems} + {fileRejectionItems} +
+
+
+
+ ) +} diff --git a/src/components/Inputs/Success.tsx b/src/components/Inputs/Success.tsx new file mode 100644 index 0000000..40cd216 --- /dev/null +++ b/src/components/Inputs/Success.tsx @@ -0,0 +1,14 @@ +type InputSuccessProps = { + message: string +} + +export const InputSuccess = ({ message }: InputSuccessProps) => { + if (!message) return null + + return ( +
+
+

{message}

+
+ ) +} diff --git a/src/styles/styles.css b/src/styles/styles.css index de6f31d..d4b0247 100644 --- a/src/styles/styles.css +++ b/src/styles/styles.css @@ -661,6 +661,7 @@ a:hover { padding-right: 50px; } +.successMain, .errorMain { width: 100%; border-radius: 10px; @@ -671,13 +672,17 @@ a:hover { flex-direction: row; grid-gap: 10px; } - +.successMainColor, .errorMainColor { width: 5px; border-radius: 2px; +} +.errorMainColor { background: tomato; } - +.successMainColor { + background: #60ae60; +} .errorMainText { } @@ -709,12 +714,14 @@ a:hover { .uploadBoxMain { background: hsl(0deg 0% 0% / 10%); border-radius: 10px; - height: 10px; + height: 150px; padding: 10px; border: solid 1px hsl(0deg 0% 100% / 5%); + transition: padding ease-in-out 0.4s; + position: relative; } -.uploadBoxMain:hover > .uploadBoxMainInside { +.uploadBoxMain:hover { padding: 5px; } @@ -729,4 +736,5 @@ a:hover { align-items: center; color: hsl(0deg 0% 100% / 20%); grid-gap: 10px; -} \ No newline at end of file + cursor: pointer; +}