diff --git a/src/components/Assets.jsx b/src/components/Assets.jsx index a78231a..7ebc433 100644 --- a/src/components/Assets.jsx +++ b/src/components/Assets.jsx @@ -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 ( -
+
{ - handleDragDropEvent(e); - // setFiles(e, 'a'); - }} > -

Drop file here to upload

- + {isUploading ?
: null} + +
+

Drop file here to upload

+ +
+ {isFetchingFiles &&

Fetching your files...

} {files.length ? ( - + + + + + ) : null} - +
); }; diff --git a/src/components/app.jsx b/src/components/app.jsx index 80bc72d..c77d598 100644 --- a/src/components/app.jsx +++ b/src/components/app.jsx @@ -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) { diff --git a/src/style.css b/src/style.css index cf78ee7..743f5de 100644 --- a/src/style.css +++ b/src/style.css @@ -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) {