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 (
+
+ )
+}
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 (
+
+ )
+}
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;
+}