FEAT: Working on the uploading modal, most everything on the frontend is complete. Just need some handling and a backend!
This commit is contained in:
parent
cf886b8983
commit
d9ade304ba
@ -39,12 +39,13 @@ function DownloadButton({downloadFiles}) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload button
|
* Upload button
|
||||||
|
* @param uploadFiles {function}
|
||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function UploadButton() {
|
function UploadButton({uploadFiles}) {
|
||||||
return (
|
return (
|
||||||
<button className="text-black" title="Upload files">
|
<button className="text-black" title="Upload files" onClick={uploadFiles}>
|
||||||
<svg className="hover:bg-gray-300 mx-1 transition-colors duration-200 p-1.5 rounded-full font-semibold h-8"
|
<svg className="hover:bg-gray-300 mx-1 transition-colors duration-200 p-1.5 rounded-full font-semibold h-8"
|
||||||
viewBox="0 0 24 24" fill="currentColor"
|
viewBox="0 0 24 24" fill="currentColor"
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
@ -140,7 +141,7 @@ function SearchBar() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Navbar({downloadFiles}) {
|
export default function Navbar({downloadFiles, uploadFiles}) {
|
||||||
return <nav className="absolute w-full p-2 flex items-center border-b-1 border-gray-400 bg-gray-100">
|
return <nav className="absolute w-full p-2 flex items-center border-b-1 border-gray-400 bg-gray-100">
|
||||||
<MainIcon/>
|
<MainIcon/>
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ export default function Navbar({downloadFiles}) {
|
|||||||
|
|
||||||
<div className="min-h-fit ml-auto flex">
|
<div className="min-h-fit ml-auto flex">
|
||||||
<DownloadButton downloadFiles={downloadFiles}/>
|
<DownloadButton downloadFiles={downloadFiles}/>
|
||||||
<UploadButton/>
|
<UploadButton uploadFiles={uploadFiles}/>
|
||||||
<InfoButton/>
|
<InfoButton/>
|
||||||
<LogoutButton/>
|
<LogoutButton/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
127
frontend/src/components/Uploader.jsx
Normal file
127
frontend/src/components/Uploader.jsx
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import "../index.css"
|
||||||
|
import {useEffect, useRef, useState} from "react";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of files that the user is attempting to upload.
|
||||||
|
* @param files {object[]}
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function FileList({files}) {
|
||||||
|
return (
|
||||||
|
<ul className="text-xs overflow-auto max-h-[200px] italic">
|
||||||
|
{files.map((file) => <li className="py-0.5">{file.name}</li>)}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Uploader({close, upload}) {
|
||||||
|
const [files, setFiles] = useState([]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* References to the elements.
|
||||||
|
* @type {React.RefObject<null>}
|
||||||
|
*/
|
||||||
|
const inputElement = useRef(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent the default drag behavior and apply visual classes.
|
||||||
|
* @param e {object} Event object from the div wrapper.
|
||||||
|
*/
|
||||||
|
const dragEnter = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.target.classList.add('border-blue-500', 'bg-blue-100');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent the default drag behavior and apply visual classes.
|
||||||
|
* @param e {object} Event object from the div wrapper.
|
||||||
|
*/
|
||||||
|
const dragLeave = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.target.classList.remove('border-blue-500', 'bg-blue-100');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent the default drag behavior.
|
||||||
|
* @param e {object} Event object from the div wrapper.
|
||||||
|
*/
|
||||||
|
const dragOver = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When files are dropped into the div, this will be called, to append the files.
|
||||||
|
* @param e {object} Event object from the div wrapper.
|
||||||
|
*/
|
||||||
|
const drop = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.target.classList.remove('border-blue-500', 'bg-blue-100');
|
||||||
|
setFiles([...files, ...e.dataTransfer.files]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Click event for the input element.
|
||||||
|
* Uses the ref hook to access the element.
|
||||||
|
*/
|
||||||
|
const click = () => {
|
||||||
|
inputElement.current.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the input changes, append the new files.
|
||||||
|
* @param e {object} Event object from the input.
|
||||||
|
*/
|
||||||
|
const inputChange = (e) => {
|
||||||
|
setFiles([...files, ...e.target.files]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const uploadFiles = () => {
|
||||||
|
upload(files);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debugging
|
||||||
|
*/
|
||||||
|
useEffect(() => {
|
||||||
|
files.forEach((file) => {
|
||||||
|
console.log(file)
|
||||||
|
});
|
||||||
|
}, [files]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
|
<div className="fixed -inset-10 bg-black opacity-50 blur-lg"></div>
|
||||||
|
<div className="relative z-50 bg-white p-8 rounded-lg shadow-lg w-2/5 border-1 border-gray-400">
|
||||||
|
<h2 className="text-2xl font-semibold mb-2 text-blue-400">Upload Files</h2>
|
||||||
|
<p className="text-sm">
|
||||||
|
Files uploaded will be added to the current directory. Currently, directory
|
||||||
|
uploads are not supported. If you want to upload a directory you can create a new one and upload the
|
||||||
|
files into it.
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
className="my-5 border-2 border-dashed p-8 rounded-md text-center cursor-pointer border-gray-400 hover:bg-blue-100 hover:border-blue-500 transition-all duration-100"
|
||||||
|
onDragEnter={dragEnter} onDragLeave={dragLeave} onDragOver={dragOver} onDrop={drop} onClick={click}
|
||||||
|
>
|
||||||
|
<input multiple type="file" className="hidden" ref={inputElement} onChange={inputChange}/>
|
||||||
|
<p className="italic">Drag and drop files here or click to select</p>
|
||||||
|
</div>
|
||||||
|
<FileList files={files}/>
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<button
|
||||||
|
onClick={close}
|
||||||
|
title="Close without uploading"
|
||||||
|
className="bg-red-500 hover:bg-red-600 duration-100 text-white text-sm font-semibold py-1.5 px-3 mt-2 mx-2 rounded hover:cursor-pointer">
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={uploadFiles}
|
||||||
|
title="Upload times"
|
||||||
|
className="bg-blue-400 hover:bg-blue-500 duration-100 text-white text-sm font-semibold py-1.5 px-3 mt-2 rounded hover:cursor-pointer">
|
||||||
|
Upload
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@ import Error from "../components/Error.jsx";
|
|||||||
import Editor from "../components/Editor.jsx";
|
import Editor from "../components/Editor.jsx";
|
||||||
import ChildrenLoading from "../components/ChildrenLoading.jsx";
|
import ChildrenLoading from "../components/ChildrenLoading.jsx";
|
||||||
import DownloadLoading from "../components/DownloadLoading.jsx";
|
import DownloadLoading from "../components/DownloadLoading.jsx";
|
||||||
|
import Uploader from "../components/Uploader.jsx";
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
// Store the default path
|
// Store the default path
|
||||||
@ -28,6 +29,7 @@ export default function Dashboard() {
|
|||||||
const [files, setFiles] = useState([]);
|
const [files, setFiles] = useState([]);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
const [editing, setEditing] = useState("");
|
const [editing, setEditing] = useState("");
|
||||||
|
const [uploading, setUploading] = useState(false);
|
||||||
const [childrenLoading, setChildrenLoading] = useState(false);
|
const [childrenLoading, setChildrenLoading] = useState(false);
|
||||||
const [downloadLoading, setDownloadLoading] = useState(false);
|
const [downloadLoading, setDownloadLoading] = useState(false);
|
||||||
const [contentLoading, setContentLoading] = useState(false);
|
const [contentLoading, setContentLoading] = useState(false);
|
||||||
@ -207,6 +209,10 @@ export default function Dashboard() {
|
|||||||
setError(null);
|
setError(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle editing of a file.
|
||||||
|
* @param path {string}
|
||||||
|
*/
|
||||||
const toggleEditing = (path) => {
|
const toggleEditing = (path) => {
|
||||||
setEditing(path);
|
setEditing(path);
|
||||||
};
|
};
|
||||||
@ -238,7 +244,6 @@ export default function Dashboard() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the state for the content being modified in the text editor.
|
* Handle the state for the content being modified in the text editor.
|
||||||
*/
|
*/
|
||||||
@ -282,11 +287,29 @@ export default function Dashboard() {
|
|||||||
setShowHidden(e.target.checked);
|
setShowHidden(e.target.checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the upload modal.
|
||||||
|
* This can be used in the navbar and the close button!
|
||||||
|
*/
|
||||||
|
const toggleUploading = () => {
|
||||||
|
setUploading(!uploading);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will be where the magic happens, where the files are upload
|
||||||
|
* @param files {object[]}
|
||||||
|
* TODO: Actually do something here...
|
||||||
|
*/
|
||||||
|
const upload = (files) => {
|
||||||
|
console.log(files);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full min-h-screen h-screen pb-8">
|
<div className="w-full min-h-screen h-screen pb-8">
|
||||||
<Navbar downloadFiles={downloadFiles}/>
|
<Navbar downloadFiles={downloadFiles} uploadFiles={toggleUploading}/>
|
||||||
<div className="h-full w-full flex flex-col items-center justify-center pb-8">
|
<div className="h-full w-full flex flex-col items-center justify-center pb-8">
|
||||||
{downloadLoading && <DownloadLoading/>}
|
{downloadLoading && <DownloadLoading/>}
|
||||||
|
{uploading && <Uploader close={toggleUploading} upload={upload}/>}
|
||||||
|
|
||||||
{error && <Error error={error} clear={clearError}/>}
|
{error && <Error error={error} clear={clearError}/>}
|
||||||
{(editing !== "" && !error) &&
|
{(editing !== "" && !error) &&
|
||||||
|
|||||||
Reference in New Issue
Block a user