initial
This commit is contained in:
commit
74ae93a96e
2 changed files with 94691 additions and 0 deletions
|
|
@ -0,0 +1,384 @@
|
|||
Drag and Drop File Upload
|
||||
|
||||
|
||||
|
||||
[react-drop-file-input-main.zip](../../../../_resources/react-drop-file-input-main.zip)
|
||||
|
||||
|
||||
- JSX
|
||||
|
||||
```JSX
|
||||
import React, { useRef, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import './drop-file-input.css';
|
||||
|
||||
import { ImageConfig } from '../../config/ImageConfig';
|
||||
import uploadImg from '../../assets/cloud-upload-regular-240.png';
|
||||
|
||||
const DropFileInput = props => {
|
||||
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
const [fileList, setFileList] = useState([]);
|
||||
|
||||
const onDragEnter = () => wrapperRef.current.classList.add('dragover');
|
||||
|
||||
const onDragLeave = () => wrapperRef.current.classList.remove('dragover');
|
||||
|
||||
const onDrop = () => wrapperRef.current.classList.remove('dragover');
|
||||
|
||||
const onFileDrop = (e) => {
|
||||
const newFile = e.target.files[0];
|
||||
if (newFile) {
|
||||
const updatedList = [...fileList, newFile];
|
||||
setFileList(updatedList);
|
||||
props.onFileChange(updatedList);
|
||||
}
|
||||
}
|
||||
|
||||
const fileRemove = (file) => {
|
||||
const updatedList = [...fileList];
|
||||
updatedList.splice(fileList.indexOf(file), 1);
|
||||
setFileList(updatedList);
|
||||
props.onFileChange(updatedList);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className="drop-file-input"
|
||||
onDragEnter={onDragEnter}
|
||||
onDragLeave={onDragLeave}
|
||||
onDrop={onDrop}
|
||||
>
|
||||
<div className="drop-file-input__label">
|
||||
<img src={uploadImg} alt="" />
|
||||
<p>Drag & Drop your files here</p>
|
||||
</div>
|
||||
<input type="file" value="" onChange={onFileDrop}/>
|
||||
</div>
|
||||
{
|
||||
fileList.length > 0 ? (
|
||||
<div className="drop-file-preview">
|
||||
<p className="drop-file-preview__title">
|
||||
Ready to upload
|
||||
</p>
|
||||
{
|
||||
fileList.map((item, index) => (
|
||||
<div key={index} className="drop-file-preview__item">
|
||||
<img src={ImageConfig[item.type.split('/')[1]] || ImageConfig['default']} alt="" />
|
||||
<div className="drop-file-preview__item__info">
|
||||
<p>{item.name}</p>
|
||||
<p>{item.size}B</p>
|
||||
</div>
|
||||
<span className="drop-file-preview__item__del" onClick={() => fileRemove(item)}>x</span>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
DropFileInput.propTypes = {
|
||||
onFileChange: PropTypes.func
|
||||
}
|
||||
|
||||
export default DropFileInput;
|
||||
```
|
||||
|
||||
|
||||
CSS
|
||||
|
||||
```css
|
||||
.drop-file-input {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
border: 2px dashed var(--border-color);
|
||||
border-radius: 20px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background-color: var(--input-bg);
|
||||
}
|
||||
|
||||
.drop-file-input input {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.drop-file-input:hover,
|
||||
.drop-file-input.dragover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.drop-file-input__label {
|
||||
text-align: center;
|
||||
color: var(--txt-second-color);
|
||||
font-weight: 600;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.drop-file-input__label img {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.drop-file-preview {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.drop-file-preview p {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.drop-file-preview__title {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
background-color: var(--input-bg);
|
||||
padding: 15px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item img {
|
||||
width: 50px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item__info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.drop-file-preview__item__del {
|
||||
background-color: var(--box-bg);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
box-shadow: var(--box-shadow);
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.drop-file-preview__item:hover .drop-file-preview__item__del {
|
||||
opacity: 1;
|
||||
}
|
||||
```
|
||||
---
|
||||
|
||||
- For multiple file uploading use this and to limit the height of preview file list:
|
||||
```jsx
|
||||
import React, { useRef, useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import "./drop-file-input.css";
|
||||
|
||||
import { ImageConfig } from "../../config/ImageConfig";
|
||||
import uploadImg from "../../assets/cloud-upload-regular-240.png";
|
||||
|
||||
const DropFileInput = (props) => {
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
const [fileList, setFileList] = useState([]);
|
||||
|
||||
const onDragEnter = () => wrapperRef.current.classList.add("dragover");
|
||||
|
||||
const onDragLeave = () => wrapperRef.current.classList.remove("dragover");
|
||||
|
||||
const onDrop = () => wrapperRef.current.classList.remove("dragover");
|
||||
|
||||
const onFileDrop = (e) => {
|
||||
const newFiles = e.target.files;
|
||||
if (newFiles.length !== 0) {
|
||||
const updatedList = [...fileList, ...newFiles];
|
||||
setFileList(updatedList);
|
||||
props.onFileChange(updatedList);
|
||||
}
|
||||
};
|
||||
|
||||
const fileRemove = (file) => {
|
||||
const updatedList = [...fileList];
|
||||
updatedList.splice(fileList.indexOf(file), 1);
|
||||
setFileList(updatedList);
|
||||
props.onFileChange(updatedList);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className="drop-file-input"
|
||||
onDragEnter={onDragEnter}
|
||||
onDragLeave={onDragLeave}
|
||||
onDrop={onDrop}
|
||||
>
|
||||
<div className="drop-file-input__label">
|
||||
<img src={uploadImg} alt="" />
|
||||
<p>Drag & Drop your files here</p>
|
||||
</div>
|
||||
<input type="file" value="" multiple onChange={onFileDrop} />
|
||||
</div>
|
||||
{fileList.length > 0 ? (
|
||||
<div className="drop-file-preview">
|
||||
<p className="drop-file-preview__title">Ready to upload</p>
|
||||
{fileList.map((item, index) => (
|
||||
<div key={index} className="drop-file-preview__item">
|
||||
<img
|
||||
src={
|
||||
ImageConfig[item.type.split("/")[1]] || ImageConfig["default"]
|
||||
}
|
||||
alt=""
|
||||
/>
|
||||
<div className="drop-file-preview__item__info">
|
||||
<p>{item.name}</p>
|
||||
<p>{item.size}B</p>
|
||||
</div>
|
||||
<span
|
||||
className="drop-file-preview__item__del"
|
||||
onClick={() => fileRemove(item)}
|
||||
>
|
||||
x
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
DropFileInput.propTypes = {
|
||||
onFileChange: PropTypes.func,
|
||||
};
|
||||
|
||||
export default DropFileInput;
|
||||
|
||||
```
|
||||
|
||||
|
||||
CSS
|
||||
```css
|
||||
.drop-file-input {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
border: 2px dashed var(--border-color);
|
||||
border-radius: 20px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background-color: var(--input-bg);
|
||||
}
|
||||
|
||||
.drop-file-input input {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.drop-file-input:hover,
|
||||
.drop-file-input.dragover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.drop-file-input__label {
|
||||
text-align: center;
|
||||
color: var(--txt-second-color);
|
||||
font-weight: 600;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.drop-file-input__label img {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.drop-file-preview {
|
||||
margin-top: 30px;
|
||||
max-height: 70%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.drop-file-preview p {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.drop-file-preview__title {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
background-color: var(--input-bg);
|
||||
padding: 15px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item img {
|
||||
width: 50px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item__info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.drop-file-preview__item__del {
|
||||
background-color: var(--box-bg);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
box-shadow: var(--box-shadow);
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.drop-file-preview__item:hover .drop-file-preview__item__del {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
Toast
|
||||
|
||||
|
||||
|
||||
https://primereact.org/toast/
|
||||
|
||||
Here package `primereact` is used so use `npm i primereact` to install it
|
||||
|
||||
In Toast.jsx
|
||||
```jsx
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { Toast } from "primereact/toast";
|
||||
// import { Button } from "primereact/button";
|
||||
|
||||
const ToastEle = (props) => {
|
||||
const toast = useRef(null);
|
||||
|
||||
const { errorMessage, errorVisibility, setErrorVisibility } = props;
|
||||
|
||||
const showError = () => {
|
||||
toast.current.show({ severity: "error", detail: errorMessage, life: 3000 });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (errorVisibility === true) {
|
||||
showError();
|
||||
setErrorVisibility(false);
|
||||
}
|
||||
}, [errorVisibility]);
|
||||
|
||||
return <Toast ref={toast} position="top-left" />;
|
||||
};
|
||||
|
||||
export default ToastEle;
|
||||
```
|
||||
|
||||
In App.jsx
|
||||
|
||||
```jsx
|
||||
import { PrimeReactProvider } from "primereact/api";
|
||||
import "primereact/resources/themes/lara-light-indigo/theme.css"; // theme
|
||||
// import "primeflex/primeflex.css"; // css utility
|
||||
// import "primeicons/primeicons.css";
|
||||
import "primereact/resources/primereact.css"; //
|
||||
import ToastEle from "./Components/Toast";
|
||||
|
||||
|
||||
function App() {
|
||||
|
||||
|
||||
// for error message at top
|
||||
const [errorVisibility, setErrorVisibility] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
|
||||
return(
|
||||
<PrimeReactProvider>
|
||||
<ToastEle
|
||||
errorVisibility={errorVisibility}
|
||||
errorMessage={errorMessage}
|
||||
setErrorVisibility={setErrorVisibility}
|
||||
/>
|
||||
</PrimeReactProvider>
|
||||
)
|
||||
|
||||
```
|
||||
Loading…
Reference in a new issue