mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-16 05:18:38 +01:00
feature (upload): upload button for phone and tablets
This commit is contained in:
parent
6c5771c4f5
commit
8afd06e055
6 changed files with 175 additions and 14 deletions
68
client/assets/img/upload_white.svg
Normal file
68
client/assets/img/upload_white.svg
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
aria-hidden="true"
|
||||
data-prefix="fas"
|
||||
data-icon="arrow-alt-to-bottom"
|
||||
role="img"
|
||||
viewBox="0 0 384 512"
|
||||
class="svg-inline--fa fa-arrow-alt-to-bottom fa-w-12 fa-9x"
|
||||
version="1.1"
|
||||
id="svg7697"
|
||||
sodipodi:docname="upload_white.svg"
|
||||
inkscape:version="0.92.4 5da689c313, 2019-01-14">
|
||||
<metadata
|
||||
id="metadata7703">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs7701" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1894"
|
||||
inkscape:window-height="1027"
|
||||
id="namedview7699"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.92187498"
|
||||
inkscape:cx="217.54882"
|
||||
inkscape:cy="144.42132"
|
||||
inkscape:window-x="10"
|
||||
inkscape:window-y="37"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg7697" />
|
||||
<path
|
||||
d="m 157.23297,360.4641 v -186 H 57.532969 c -17.8,0 -28.174568,-11.17176 -14.1,-22.1 L 177.63297,48.164103 c 8.37772,-6.50491 18.92228,-6.50491 27.3,0 l 134.2,104.199997 c 14.07457,10.92824 3.7,22.1 -14.1,22.1 h -99.8 v 186 c 0,13.3 -13.5475,19.67043 -24,24 -6.1592,2.55123 -20,0 -20,0 -13.3,0 -23.86429,-10.70069 -24,-24 z"
|
||||
class=""
|
||||
id="path7695"
|
||||
style="fill:#f2f2f2;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="scsssssscsass" />
|
||||
<path
|
||||
d="M 360.22371,413.25476 H 24.223716 c -13.3,0 -23.9999994,6.7 -23.9999994,20 v 12 c 0,13.3 10.6999994,20 23.9999994,20 H 360.22371 c 13.3,0 24,-6.7 24,-20 v -12 c 0,-13.3 -10.7,-20 -24,-20 z"
|
||||
class=""
|
||||
id="path7695-3"
|
||||
style="fill:#f2f2f2;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sssssssss" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
|
|
@ -12,6 +12,7 @@ import img_pause from "../assets/img/pause.svg";
|
|||
import img_error from "../assets/img/error.svg";
|
||||
import img_loading_white from "../assets/img/loader_white.svg";
|
||||
import img_download_white from "../assets/img/download_white.svg";
|
||||
import img_upload_white from "../assets/img/upload_white.svg";
|
||||
import img_todo_white from '../assets/img/todo_white.svg';
|
||||
import img_calendar_white from '../assets/img/calendar_white.svg';
|
||||
import img_calendar from '../assets/img/calendar.svg';
|
||||
|
|
@ -68,6 +69,8 @@ export const Icon = (props) => {
|
|||
img = img_loader;
|
||||
}else if(props.name === 'download_white'){
|
||||
img = img_download_white;
|
||||
}else if(props.name === 'upload_white'){
|
||||
img = img_upload_white;
|
||||
}else if(props.name === 'play'){
|
||||
img = img_play;
|
||||
}else if(props.name === 'pause'){
|
||||
|
|
|
|||
|
|
@ -102,22 +102,35 @@ export const onDelete = function(path, type){
|
|||
.catch((err) => notify.send(err, 'error'));
|
||||
};
|
||||
|
||||
/*
|
||||
* The upload method has a few strategies:
|
||||
* 1. user is coming from drag and drop + browser provides support to read entire folders
|
||||
* 2. user is coming from drag and drop + browser DOES NOT provides support to read entire folders
|
||||
* 3. user is coming from a upload form button as he doesn't have drag and drop with files
|
||||
*/
|
||||
export const onUpload = function(path, e){
|
||||
const MAX_POOL_SIZE = 15;
|
||||
let PRIOR_STATUS = {};
|
||||
if(e.dataTransfer.types && e.dataTransfer.types.length >= 0){
|
||||
if(e.dataTransfer.types[0] === "text/uri-list"){
|
||||
return
|
||||
}
|
||||
}
|
||||
extract_upload_directory_the_way_that_works_but_non_official(e.dataTransfer.items || [], [])
|
||||
.then((files) => {
|
||||
if(files.length === 0){
|
||||
return extract_upload_crappy_hack_but_official_way(e.dataTransfer);
|
||||
|
||||
let extractFiles = null;
|
||||
if(e.dataTransfer === undefined){ // case 3
|
||||
extractFiles = extract_upload_crappy_hack_but_official_way(e.target);
|
||||
} else {
|
||||
if(e.dataTransfer.types && e.dataTransfer.types.length >= 0){
|
||||
if(e.dataTransfer.types[0] === "text/uri-list"){
|
||||
return
|
||||
}
|
||||
return Promise.resolve(files);
|
||||
})
|
||||
.then((files) => {
|
||||
}
|
||||
extractFiles = extract_upload_directory_the_way_that_works_but_non_official(e.dataTransfer.items || [], []) // case 1
|
||||
.then((files) => {
|
||||
if(files.length === 0){ // case 2
|
||||
return extract_upload_crappy_hack_but_official_way(e.dataTransfer);
|
||||
}
|
||||
return Promise.resolve(files);
|
||||
})
|
||||
}
|
||||
|
||||
extractFiles.then((files) => {
|
||||
var failed = [],
|
||||
currents = [];
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { sort, onCreate, onRename, onDelete, onUpload, onSearch, createLink } fr
|
|||
import { NgIf, Loader, EventReceiver, LoggedInOnly, ErrorPage } from '../components/';
|
||||
import { notify, debounce, goToFiles, goToViewer, event, settings_get, settings_put } from '../helpers/';
|
||||
import { BreadCrumb, FileSystem, FrequentlyAccess, Submenu } from './filespage/';
|
||||
import { MobileFileUpload } from './filespage/filezone';
|
||||
import InfiniteScroll from 'react-infinite-scroller';
|
||||
|
||||
const PAGE_NUMBER_INIT = 2;
|
||||
|
|
@ -252,6 +253,7 @@ export class FilesPage extends React.Component {
|
|||
<NgIf cond={!!this.state.loading}>
|
||||
<Loader/>
|
||||
</NgIf>
|
||||
<MobileFileUpload path={this.state.path} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="upload-footer">
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
||||
import { DropTarget } from 'react-dnd';
|
||||
|
||||
import { EventEmitter } from '../../components/';
|
||||
import { EventEmitter, Icon } from '../../components/';
|
||||
import './filezone.scss';
|
||||
|
||||
@EventEmitter
|
||||
|
|
@ -27,7 +28,35 @@ export class FileZone extends React.Component{
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
FileZone.propTypes = {
|
||||
path: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
@EventEmitter
|
||||
export class MobileFileUpload extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
onUpload(e){
|
||||
this.props.emit("file.upload", this.props.path, e);
|
||||
}
|
||||
render(){
|
||||
if(/(Android|iPad|iPhone)/.test(navigator.userAgent) === false){
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ReactCSSTransitionGroup transitionName="mobilefileupload" transitionLeave={false} transitionEnter={false} transitionAppear={true} transitionAppearTimeout={550}>
|
||||
<div className="component_mobilefileupload">
|
||||
<form>
|
||||
<input onChange={this.onUpload.bind(this)} type="file" name="file" id="mobilefileupload" multiple/>
|
||||
<label htmlFor="mobilefileupload">
|
||||
<Icon name="upload_white"/>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
</ReactCSSTransitionGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
@import "../../assets/css/mixin.scss";
|
||||
|
||||
.component_filezone{
|
||||
border: 2px dashed;
|
||||
padding: 25px 0;
|
||||
|
|
@ -9,3 +11,47 @@
|
|||
border: 2px dashed var(--primary);
|
||||
}
|
||||
}
|
||||
|
||||
.component_mobilefileupload{
|
||||
display: inline;
|
||||
position: fixed;
|
||||
bottom: 25px;
|
||||
right: 25px;
|
||||
|
||||
input[type="file"]{
|
||||
width: 0.1px;
|
||||
height: 0.1px;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
input[type="file"]:focus + label, input[type="file"] + label:hover {
|
||||
opacity: 0.95;
|
||||
}
|
||||
input[type="file"] + label {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
background: var(--color);
|
||||
border-radius: 50%;
|
||||
@include ripple(var(--emphasis-secondary), var(--primary));
|
||||
box-shadow: rgba(0, 0, 0, 0.14) 0px 4px 5px 0px, rgba(0, 0, 0, 0.12) 0px 1px 10px 0px, rgba(0, 0, 0, 0.2) 0px 2px 4px -1px;
|
||||
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
.component_icon{
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mobilefileupload-appear{
|
||||
transform: translateX(75px);
|
||||
transition: transform 0.25s ease;
|
||||
}
|
||||
.mobilefileupload-appear-active{
|
||||
transition-delay: 0.3s;
|
||||
transform: translateX(0px);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue