1
0
mirror of https://github.com/chinchang/web-maker.git synced 2025-07-10 00:16:18 +02:00

drag n drop in assets modal

This commit is contained in:
Kushagra Gour
2023-08-17 23:03:45 +05:30
parent 84b23a302e
commit 317d803a18
3 changed files with 220 additions and 48 deletions

View File

@ -1,37 +1,64 @@
import React, { useState, useEffect } from 'react';
import firebase from 'firebase/app';
import 'firebase/storage';
import { Stack } from './Stack';
const Assets = () => {
const [files, setFiles] = useState([]);
const [isFetchingFiles, setIsFetchingFiles] = useState(false);
const [searchTerm, setSearchTerm] = useState('');
const [filteredFiles, setFilteredFiles] = useState([]);
const [isUploading, setIsUploading] = useState(false);
const [uploadProgress, setUploadProgress] = useState();
const [listType, setListType] = useState('grid');
const storageRef = firebase.storage().ref(`assets/${window.user.uid}`);
// Function to handle file upload
const handleFileUpload = e => {
const file = e.target.files[0];
const uploadFile = file => {
if (file.size > 5 * 1024 * 1024) {
// 5MB limit
alert('File size must be less than 5MB');
return;
}
setIsUploading(true);
const fileRef = storageRef.child(file.name);
fileRef
.put(file)
.then(() => {
alert('File uploaded successfully');
fetchFiles();
})
.catch(error => {
const task = fileRef.put(file);
task.on(
'state_changed',
snapshot => {
// Observe state change events such as progress, pause, and resume
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log('Upload is ' + progress + '% done');
},
error => {
// Handle unsuccessful uploads
setIsUploading(false);
console.error('File upload error:', error);
});
},
() => {
// uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
// console.log('File available at', downloadURL);
// });
alertsService.add('File uploaded successfully');
fetchFiles();
setIsUploading(false);
}
);
};
// Function to handle file upload
const handleFileUpload = e => {
const file = e.target.files[0];
uploadFile(file);
};
// Function to fetch existing files
const fetchFiles = () => {
setIsFetchingFiles(true);
storageRef
.listAll()
.then(result => {
@ -42,9 +69,11 @@ const Assets = () => {
});
Promise.all(filePromises).then(setFiles);
setIsFetchingFiles(false);
})
.catch(error => {
console.error('File fetch error:', error);
setIsFetchingFiles(false);
});
};
@ -73,56 +102,99 @@ const Assets = () => {
const [isDropTarget, setIsDropTarget] = useState(false);
const handleDragDropEvent = e => {
console.log('drag event, ', e.type);
if (e.type === 'dragleave' || e.type === 'drop') {
if (e.type === 'dragover') {
// required for drop to work
e.preventDefault();
} else if (e.type === 'dragleave') {
e.preventDefault();
setIsDropTarget(false);
}
if (e.type === 'dragenter') {
} else if (e.type === 'dragenter') {
setIsDropTarget(true);
ode;
console.log(999, e.type);
}
};
const handleDrop = e => {
e.preventDefault();
console.log('drop');
setIsDropTarget(false);
if (e.dataTransfer.items) {
const file = e.dataTransfer.items[0].getAsFile();
uploadFile(file);
}
};
const copyFileUrl = url => {
const input = document.createElement('input');
input.value = url;
input.style.opacity = 0;
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
alertsService.add('File URL copied!');
};
return (
<div>
<div
onDragEnter={handleDragDropEvent}
onDragLeave={handleDragDropEvent}
onDragOver={handleDragDropEvent}
onDrop={handleDrop}
>
<div
class="asset_manager__upload-box"
class="asset-manager__upload-box"
style={{
background: isDropTarget ? '#19a61940' : 'transparent',
borderColor: isDropTarget ? 'limegreen' : null
}}
onDragEnter={handleDragDropEvent}
onDragOver={handleDragDropEvent}
onDrop={e => {
handleDragDropEvent(e);
// setFiles(e, 'a');
}}
>
<p>Drop file here to upload</p>
<input
type="file"
onChange={handleFileUpload}
style={{ marginTop: 'auto' }}
/>
{isUploading ? <div class="asset-manager__progress-bar"></div> : null}
<div style={{ visibility: isUploading ? 'hidden' : 'visible' }}>
<p>Drop file here to upload</p>
<input
type="file"
onChange={handleFileUpload}
style={{ marginTop: 'auto' }}
/>
</div>
</div>
{isFetchingFiles && <p>Fetching your files...</p>}
{files.length ? (
<input
type="text"
placeholder="Search files"
value={searchTerm}
onChange={handleSearchChange}
style={{ width: '100%' }}
/>
<Stack>
<input
type="text"
placeholder="Search files"
value={searchTerm}
onChange={handleSearchChange}
style={{ width: '100%' }}
/>
<button onClick={() => setListType('list')}>List</button>
<button onClick={() => setListType('grid')}>Grid</button>
</Stack>
) : null}
<ul>
<div
class={`asset-manager__file-container ${
listType === 'grid' ? 'asset-manager__file-container--grid' : ''
}`}
>
{filteredFiles.map((file, index) => (
<li key={index}>
<a href={file.url} target="_blank" rel="noopener noreferrer">
<img src={file.url} height="20" /> {file.name}
</a>
</li>
<button
type="button"
key={index}
onClick={() => copyFileUrl(file.url)}
class={`asset-manager__file ${
listType === 'grid' ? 'asset-manager__file--grid' : ''
}`}
>
{/* <a href={file.url} target="_blank" rel="noopener noreferrer"> */}
<img src={file.url} />{' '}
<span class="asset-manager__file-name">{file.name}</span>
{/* </a> */}
</button>
))}
</ul>
</div>
</div>
);
};

View File

@ -100,6 +100,7 @@ export default class App extends Component {
constructor() {
super();
this.AUTO_SAVE_INTERVAL = 15000; // 15 seconds
const savedUser = window.localStorage.getItem('user');
this.modalDefaultStates = {
isModalOpen: false,
isAddLibraryModalOpen: false,
@ -125,7 +126,8 @@ export default class App extends Component {
title: '',
externalLibs: { js: '', css: '' }
},
catalogs: {}
catalogs: {},
user: savedUser
};
this.defaultSettings = {
preserveLastCode: true,
@ -158,6 +160,10 @@ export default class App extends Component {
};
this.prefs = {};
if (savedUser) {
window.user = savedUser;
}
firebase.auth().onAuthStateChanged(user => {
this.setState({ isLoginModalOpen: false });
if (user) {
@ -165,6 +171,7 @@ export default class App extends Component {
alertsService.add('You are now logged in!');
this.setState({ user });
window.user = user;
window.localStorage.setItem('user', user);
if (!window.localStorage[LocalStorageKeys.ASKED_TO_IMPORT_CREATIONS]) {
this.fetchItems(false, true).then(items => {
if (!items.length) {

View File

@ -85,6 +85,7 @@ p {
button {
font-family: inherit;
font-size: 100%;
cursor: pointer;
}
.hide {
@ -571,7 +572,9 @@ body:not(.light-version).overlay-visible .main-container {
overflow: hidden;
position: relative;
background: var(--color-bg);
transition: height 0.3s ease, width 0.3s ease;
transition:
height 0.3s ease,
width 0.3s ease;
will-change: height;
}
@ -2002,13 +2005,103 @@ while the theme CSS file is loading */
justify-content: center;
}
.asset_manager__upload-box {
.asset-manager__upload-box {
padding: 1rem 2rem;
border: 3px dashed rgb(255 255 255 / 10%);
border-radius: 1rem;
text-align: center;
margin-bottom: 1rem;
transition: 0.3s ease;
position: relative;
}
@keyframes move {
0% {
background-position: 0 0;
}
100% {
background-position: 50px 50px;
}
}
.asset-manager__progress-bar {
position: absolute;
inset: 1rem;
/* height: 2rem; */
background-image: linear-gradient(
-45deg,
rgba(255, 255, 255, 0.2) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0.2) 50%,
rgba(255, 255, 255, 0.2) 75%,
transparent 75%,
transparent
);
z-index: 1;
background-size: 50px 50px;
animation: move 2s linear infinite;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-top-left-radius: 20px;
border-bottom-left-radius: 20px;
overflow: hidden;
}
.asset-manager__file {
/* list-style: none; */
/* padding: 0; */
/* margin: 0; */
display: flex;
background: rgb(255 255 255 / 4%);
gap: 0.5rem;
padding: 0.2rem;
border-radius: 0.4rem;
color: inherit;
border: 0;
transition: 0.3s ease;
/* align-items: center; */
}
.asset-manager__file:hover {
background: rgb(255 255 255 / 7%);
}
.asset-manager__file--grid {
display: flex;
flex-direction: column;
/* align-items: flex-start; */
}
.asset-manager__file-container {
padding: 0;
gap: 0.3rem;
}
.asset-manager__file-container--grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
}
.asset-manager__file {
display: flex;
gap: 0.5rem;
}
.asset-manager__file-name {
max-width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.asset-manager__file img {
height: 1.5rem;
aspect-ratio: 1;
/* border-radius: 0.5rem; */
object-fit: cover;
}
.asset-manager__file--grid img {
height: 80px;
}
.stack {
display: flex;
}
.stack > * {
margin: 0;
}
@media screen and (max-width: 600px) {