mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2026-10-19 16:14:39 +00:00
feature (lazy loading): as per: #7, lazy load stuff
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
||||
server/public/bundle.js
|
||||
server/public/js
|
||||
server/public/index.html
|
||||
node_modules/
|
||||
babel_cache/
|
||||
|
||||
@@ -6,7 +6,6 @@ import CodeMirror from 'codemirror/lib/codemirror';
|
||||
// keybinding
|
||||
import 'codemirror/keymap/emacs.js';
|
||||
|
||||
|
||||
// search
|
||||
import 'codemirror/addon/search/searchcursor.js';
|
||||
import 'codemirror/addon/search/search.js';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export { BreadCrumb } from './breadcrumb';
|
||||
export { Editor } from './editor';
|
||||
export { FileSystem } from './filesystem';
|
||||
export { Connect } from './connect';
|
||||
// Those are commented because they will delivered as a separate chunk
|
||||
// export { Editor } from './editor';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export { HomePage } from './homepage';
|
||||
export { ConnectPage } from './connectpage';
|
||||
export { LogoutPage } from './logout';
|
||||
export { FilesPage } from './filespage';
|
||||
export { ViewerPage } from './viewerpage';
|
||||
export { NotFoundPage } from './notfound';
|
||||
// Those are commented because they will delivered as a separate chunk
|
||||
// export { FilesPage } from './filespage';
|
||||
// export { ViewerPage } from './viewerpage';
|
||||
|
||||
+17
-288
@@ -1,16 +1,26 @@
|
||||
import React from 'react';
|
||||
import { BreadCrumb, Editor } from '../components/';
|
||||
import { debounce, throttle, NgIf, Loader, Error, Fab, Icon, Container } from '../utilities/';
|
||||
import { BreadCrumb } from '../components/';
|
||||
import { Bundle, debounce, NgIf, Loader, Error, Container } from '../utilities/';
|
||||
import { Files, opener, EventReceiver, EventEmitter } from '../data/';
|
||||
import { AudioPlayer, FileDownloader, ImageViewer, PDFViewer } from './viewerpage/';
|
||||
import Path from 'path';
|
||||
import { theme } from '../utilities';
|
||||
import WaveSurfer from 'wavesurfer.js';
|
||||
import videojs from 'video.js';
|
||||
|
||||
|
||||
const VideoPlayer = (props) => (
|
||||
<Bundle loader={import(/* webpackChunkName: "video" */"../pages/viewerpage/videoplayer")} symbol="VideoPlayer">
|
||||
{(Comp) => <Comp {...props}/>}
|
||||
</Bundle>
|
||||
);
|
||||
const IDE = (props) => (
|
||||
<Bundle loader={import(/* webpackChunkName: "ide" */"../pages/viewerpage/ide")} symbol="IDE">
|
||||
{(Comp) => <Comp {...props}/>}
|
||||
</Bundle>
|
||||
);
|
||||
|
||||
|
||||
@EventReceiver
|
||||
export class ViewerPage extends React.Component {
|
||||
constructor(props){
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
path: props.match.url.replace('/view', ''),
|
||||
@@ -83,6 +93,7 @@ export class ViewerPage extends React.Component {
|
||||
Files.url(this.state.path).then((url) => {
|
||||
this.setState({data: url, loading: false, opener: app});
|
||||
}).catch(err => {
|
||||
console.log("ERROR", err)
|
||||
if(err && err.code === 'CANCELLED'){ return }
|
||||
this.setState({error: err});
|
||||
});
|
||||
@@ -139,285 +150,3 @@ export class ViewerPage extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IDE extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
contentToSave: null
|
||||
}
|
||||
}
|
||||
|
||||
onContentUpdate(text){
|
||||
this.props.needSaving(true);
|
||||
this.setState({contentToSave: text})
|
||||
}
|
||||
|
||||
save(){
|
||||
let file, blob = new window.Blob([this.state.contentToSave], {type : 'text/plain'});
|
||||
try{
|
||||
file = new window.File([blob], 'test.txt');
|
||||
}catch(err){
|
||||
// for crappy browser:
|
||||
// https://stackoverflow.com/questions/33821631/alternative-for-file-constructor-for-safari
|
||||
file = blob;
|
||||
}
|
||||
this.props.onSave(file);
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{height: '100%'}}>
|
||||
<Editor onSave={this.save.bind(this)} filename={this.props.filename} content={this.props.content} onChange={this.onContentUpdate.bind(this)} height={this.state.height}/>
|
||||
<NgIf cond={!this.props.isSaving}>
|
||||
<Fab onClick={this.save.bind(this)}><Icon name="save" style={{height: '100%', width: '100%'}}/></Fab>
|
||||
</NgIf>
|
||||
<NgIf cond={this.props.isSaving}>
|
||||
<Fab><Icon name="loading_white" style={{height: '100%', width: '100%'}}/></Fab>
|
||||
</NgIf>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const ImageViewer = (props) => {
|
||||
return (
|
||||
<div style={{height: '100%'}}>
|
||||
<MenuBar title={props.filename} download={props.data} />
|
||||
<div style={{textAlign: 'center', background: '#525659', height: 'calc(100% - 34px)', overflow: 'hidden', padding: '20px', boxSizing: 'border-box'}}>
|
||||
<img src={props.data} style={{maxHeight: '100%', maxWidth: '100%', minHeight: '100px', background: '#f1f1f1', boxShadow: theme.effects.shadow}} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const PDFViewer = (props) => {
|
||||
return (
|
||||
<div style={{textAlign: 'center', background: '#525659', height: '100%'}}>
|
||||
<embed src={props.data} type="application/pdf" style={{height: '100%', width: '100%'}}></embed>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
class AudioPlayer extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
wafesurfer: null,
|
||||
loading: true,
|
||||
isPlaying: true,
|
||||
error: null
|
||||
}
|
||||
this.toggle = this.toggle.bind(this);
|
||||
window.addEventListener('keypress', this.toggle);
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
let $el = document.querySelector('.player');
|
||||
var wavesurfer = WaveSurfer.create({
|
||||
container: '#waveform',
|
||||
waveColor: '#323639',
|
||||
progressColor: '#6f6f6f',
|
||||
cursorColor: '#323639',
|
||||
cursorWidth: 2,
|
||||
height: 250,
|
||||
barWidth: 1
|
||||
});
|
||||
this.setState({wavesurfer: wavesurfer});
|
||||
wavesurfer.on('ready', () => {
|
||||
this.setState({loading: false});
|
||||
if(this.state.isPlaying === true){
|
||||
wavesurfer.play();
|
||||
}
|
||||
});
|
||||
wavesurfer.on('error', (err) => {
|
||||
this.setState({error: err, loading: false});
|
||||
});
|
||||
wavesurfer.load(this.props.data);
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
if(this.state.wavesurfer){
|
||||
this.state.wavesurfer.destroy();
|
||||
}
|
||||
window.removeEventListener('keypress', this.toggle);
|
||||
}
|
||||
|
||||
toggle(){
|
||||
if(this.state.isPlaying === true){
|
||||
this.setState({isPlaying: false});
|
||||
this.state.wavesurfer.pause();
|
||||
}else{
|
||||
this.setState({isPlaying: true});
|
||||
this.state.wavesurfer.play();
|
||||
}
|
||||
}
|
||||
|
||||
onPlay(e){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.setState({isPlaying: true})
|
||||
this.state.wavesurfer.play();
|
||||
}
|
||||
|
||||
onPause(e){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.setState({isPlaying: false});
|
||||
this.state.wavesurfer.pause();
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{height: '100%'}}>
|
||||
<MenuBar title={this.props.filename} download={this.props.data} />
|
||||
<div style={{textAlign: 'center', background: '#525659', height: '100%', overflow: 'hidden', padding: '20px', boxSizing: 'border-box'}}>
|
||||
<NgIf cond={this.state.error !== null} style={{color: 'white', marginTop: '30px'}}>
|
||||
{this.state.error}
|
||||
</NgIf>
|
||||
<NgIf cond={this.state.error === null}>
|
||||
<NgIf cond={this.state.loading === true}>
|
||||
<Icon name="loading" />
|
||||
</NgIf>
|
||||
<div style={{background: '#f1f1f1', boxShadow: theme.effects.shadow, opacity: this.state.loading? '0' : '1', position: 'relative'}}>
|
||||
<div style={{position: 'absolute', top: '10px', right: '10px', zIndex: '2', height: '30px'}}>
|
||||
<NgIf cond={this.state.isPlaying === false} style={{display: 'inline'}}>
|
||||
<span style={{cursor: 'pointer'}} onClick={this.onPlay.bind(this)}><Icon name="play"/></span>
|
||||
</NgIf>
|
||||
<NgIf cond={this.state.isPlaying === true} style={{display: 'inline'}}>
|
||||
<span style={{cursor: 'pointer'}} onClick={this.onPause.bind(this)}><Icon name="pause"/></span>
|
||||
</NgIf>
|
||||
</div>
|
||||
<div id="waveform"></div>
|
||||
</div>
|
||||
</NgIf>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class VideoPlayer extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.player = videojs(this.videoNode, {
|
||||
//autoplay: true,
|
||||
controls: true,
|
||||
aspectRatio: '16:9',
|
||||
fluid: false,
|
||||
sources: [{
|
||||
src: this.props.data
|
||||
}]
|
||||
}, function onPlayerReady() {
|
||||
//console.log('onPlayerReady', this)
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.player) {
|
||||
this.player.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{background: '#525659', height: '100%'}}>
|
||||
<MenuBar title={this.props.filename} download={this.props.data} />
|
||||
<div style={{padding: '20px'}}>
|
||||
<div style={{maxWidth: '800px', width: '100%', margin: '0 auto'}}>
|
||||
<video ref={ node => this.videoNode = node } className="video-js my-skin" style={{boxShadow: theme.effects.shadow}}></video>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class MenuBar extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {loading: false, id: null}
|
||||
}
|
||||
|
||||
onDownloadRequest(){
|
||||
this.setState({
|
||||
loading: true,
|
||||
id: window.setInterval(function(){
|
||||
if(document.cookie){
|
||||
this.setState({loading: false})
|
||||
window.clearInterval(this.state.id);
|
||||
}
|
||||
}.bind(this), 80)
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
window.clearInterval(this.state.id)
|
||||
}
|
||||
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{background: '#313538', color: '#f1f1f1', boxShadow: theme.effects.shadow_small}}>
|
||||
<Container style={{padding: '9px 0', textAlign: 'center', color: '#f1f1f1', fontSize: '0.9em'}}>
|
||||
<NgIf cond={this.props.hasOwnProperty('download')} style={{float: 'right', height: '1em'}}>
|
||||
<NgIf cond={!this.state.loading} style={{display: 'inline'}}>
|
||||
<a href={this.props.download} download={this.props.title} onClick={this.onDownloadRequest.bind(this)}>
|
||||
<Icon name="download" style={{width: '15px', height: '15px'}} />
|
||||
</a>
|
||||
</NgIf>
|
||||
<NgIf cond={this.state.loading} style={{display: 'inline'}}>
|
||||
<Icon name="loading" style={{width: '15px', height: '15px'}} />
|
||||
</NgIf>
|
||||
</NgIf>
|
||||
<span style={{letterSpacing: '0.3px'}}>{this.props.title}</span>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FileDownloader extends React.Component{
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {loading: false, id: null};
|
||||
}
|
||||
|
||||
onClick(){
|
||||
this.setState({
|
||||
loading: true,
|
||||
id: window.setInterval(function(){
|
||||
if(document.cookie){
|
||||
this.setState({loading: false})
|
||||
window.clearInterval(this.state.id);
|
||||
}
|
||||
}.bind(this), 80)
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
window.clearInterval(this.state.id)
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{textAlign: 'center', background: '#525659', height: '100%'}}>
|
||||
<div style={{padding: '15px 20px', background: '#323639', borderRadius: '2px', color: 'inherit', boxShadow: theme.effects.shadow, display: 'inline-block', marginTop: '50px'}}>
|
||||
<a download={this.props.filename} href={this.props.data}>
|
||||
<NgIf onClick={this.onClick.bind(this)} cond={!this.state.loading} style={{fontSize: '17px', display: 'inline-block'}}>
|
||||
DOWNLOAD
|
||||
</NgIf>
|
||||
</a>
|
||||
<NgIf cond={this.state.loading} style={{height: '20px', display: 'inline-block'}}>
|
||||
<Icon name="loading"/>
|
||||
</NgIf>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import React from 'react';
|
||||
import { MenuBar } from './menubar';
|
||||
import { NgIf, Icon, theme } from '../../utilities/'
|
||||
import WaveSurfer from 'wavesurfer.js';
|
||||
|
||||
export class AudioPlayer extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
wafesurfer: null,
|
||||
loading: true,
|
||||
isPlaying: true,
|
||||
error: null
|
||||
}
|
||||
this.toggle = this.toggle.bind(this);
|
||||
window.addEventListener('keypress', this.toggle);
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
let $el = document.querySelector('.player');
|
||||
var wavesurfer = WaveSurfer.create({
|
||||
container: '#waveform',
|
||||
waveColor: '#323639',
|
||||
progressColor: '#6f6f6f',
|
||||
cursorColor: '#323639',
|
||||
cursorWidth: 2,
|
||||
height: 250,
|
||||
barWidth: 1
|
||||
});
|
||||
this.setState({wavesurfer: wavesurfer});
|
||||
wavesurfer.on('ready', () => {
|
||||
this.setState({loading: false});
|
||||
if(this.state.isPlaying === true){
|
||||
wavesurfer.play();
|
||||
}
|
||||
});
|
||||
wavesurfer.on('error', (err) => {
|
||||
this.setState({error: err, loading: false});
|
||||
});
|
||||
wavesurfer.load(this.props.data);
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
if(this.state.wavesurfer){
|
||||
this.state.wavesurfer.destroy();
|
||||
}
|
||||
window.removeEventListener('keypress', this.toggle);
|
||||
}
|
||||
|
||||
toggle(){
|
||||
if(this.state.isPlaying === true){
|
||||
this.setState({isPlaying: false});
|
||||
this.state.wavesurfer.pause();
|
||||
}else{
|
||||
this.setState({isPlaying: true});
|
||||
this.state.wavesurfer.play();
|
||||
}
|
||||
}
|
||||
|
||||
onPlay(e){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.setState({isPlaying: true})
|
||||
this.state.wavesurfer.play();
|
||||
}
|
||||
|
||||
onPause(e){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.setState({isPlaying: false});
|
||||
this.state.wavesurfer.pause();
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{height: '100%'}}>
|
||||
<MenuBar title={this.props.filename} download={this.props.data} />
|
||||
<div style={{textAlign: 'center', background: '#525659', height: '100%', overflow: 'hidden', padding: '20px', boxSizing: 'border-box'}}>
|
||||
<NgIf cond={this.state.error !== null} style={{color: 'white', marginTop: '30px'}}>
|
||||
{this.state.error}
|
||||
</NgIf>
|
||||
<NgIf cond={this.state.error === null}>
|
||||
<NgIf cond={this.state.loading === true}>
|
||||
<Icon name="loading" />
|
||||
</NgIf>
|
||||
<div style={{background: '#f1f1f1', boxShadow: theme.effects.shadow, opacity: this.state.loading? '0' : '1', position: 'relative'}}>
|
||||
<div style={{position: 'absolute', top: '10px', right: '10px', zIndex: '2', height: '30px'}}>
|
||||
<NgIf cond={this.state.isPlaying === false} style={{display: 'inline'}}>
|
||||
<span style={{cursor: 'pointer'}} onClick={this.onPlay.bind(this)}><Icon name="play"/></span>
|
||||
</NgIf>
|
||||
<NgIf cond={this.state.isPlaying === true} style={{display: 'inline'}}>
|
||||
<span style={{cursor: 'pointer'}} onClick={this.onPause.bind(this)}><Icon name="pause"/></span>
|
||||
</NgIf>
|
||||
</div>
|
||||
<div id="waveform"></div>
|
||||
</div>
|
||||
</NgIf>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import { MenuBar } from './menubar';
|
||||
import { theme, NgIf, Icon } from '../../utilities/'
|
||||
|
||||
export class FileDownloader extends React.Component{
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {loading: false, id: null};
|
||||
}
|
||||
|
||||
onClick(){
|
||||
this.setState({
|
||||
loading: true,
|
||||
id: window.setInterval(function(){
|
||||
if(document.cookie){
|
||||
this.setState({loading: false})
|
||||
window.clearInterval(this.state.id);
|
||||
}
|
||||
}.bind(this), 80)
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
window.clearInterval(this.state.id)
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{textAlign: 'center', background: '#525659', height: '100%'}}>
|
||||
<div style={{padding: '15px 20px', background: '#323639', borderRadius: '2px', color: 'inherit', boxShadow: theme.effects.shadow, display: 'inline-block', marginTop: '50px'}}>
|
||||
<a download={this.props.filename} href={this.props.data}>
|
||||
<NgIf onClick={this.onClick.bind(this)} cond={!this.state.loading} style={{fontSize: '17px', display: 'inline-block'}}>
|
||||
DOWNLOAD
|
||||
</NgIf>
|
||||
</a>
|
||||
<NgIf cond={this.state.loading} style={{height: '20px', display: 'inline-block'}}>
|
||||
<Icon name="loading"/>
|
||||
</NgIf>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from 'react';
|
||||
import { Editor } from '../../components/editor';
|
||||
import { NgIf, Fab, Icon } from '../../utilities/'
|
||||
import { MenuBar } from './menubar';
|
||||
|
||||
|
||||
export class IDE extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
contentToSave: null
|
||||
}
|
||||
}
|
||||
|
||||
onContentUpdate(text){
|
||||
this.props.needSaving(true);
|
||||
this.setState({contentToSave: text})
|
||||
}
|
||||
|
||||
save(){
|
||||
let file, blob = new window.Blob([this.state.contentToSave], {type : 'text/plain'});
|
||||
try{
|
||||
file = new window.File([blob], 'test.txt');
|
||||
}catch(err){
|
||||
// for crappy browser:
|
||||
// https://stackoverflow.com/questions/33821631/alternative-for-file-constructor-for-safari
|
||||
file = blob;
|
||||
}
|
||||
this.props.onSave(file);
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{height: '100%'}}>
|
||||
<Editor onSave={this.save.bind(this)} filename={this.props.filename} content={this.props.content} onChange={this.onContentUpdate.bind(this)} height={this.state.height}/>
|
||||
<NgIf cond={!this.props.isSaving}>
|
||||
<Fab onClick={this.save.bind(this)}><Icon name="save" style={{height: '100%', width: '100%'}}/></Fab>
|
||||
</NgIf>
|
||||
<NgIf cond={this.props.isSaving}>
|
||||
<Fab><Icon name="loading_white" style={{height: '100%', width: '100%'}}/></Fab>
|
||||
</NgIf>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { theme } from '../../utilities/';
|
||||
import { MenuBar } from './menubar';
|
||||
|
||||
export const ImageViewer = (props) => {
|
||||
return (
|
||||
<div style={{height: '100%'}}>
|
||||
<MenuBar title={props.filename} download={props.data} />
|
||||
<div style={{textAlign: 'center', background: '#525659', height: 'calc(100% - 34px)', overflow: 'hidden', padding: '20px', boxSizing: 'border-box'}}>
|
||||
<img src={props.data} style={{maxHeight: '100%', maxWidth: '100%', minHeight: '100px', background: '#f1f1f1', boxShadow: theme.effects.shadow}} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
module.exports = {
|
||||
test: 'test'
|
||||
}
|
||||
|
||||
export { AudioPlayer } from './audioplayer';
|
||||
export { FileDownloader } from './filedownloader';
|
||||
export { ImageViewer } from './imageviewer';
|
||||
export { PDFViewer } from './pdfviewer';
|
||||
// Those are commented because they will delivered as a separate chunk
|
||||
// export { VideoPlayer } from './videoplayer';
|
||||
// export { IDE } from './ide';
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import { theme, Container, NgIf, Icon } from '../../utilities/';
|
||||
|
||||
export class MenuBar extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {loading: false, id: null}
|
||||
}
|
||||
|
||||
onDownloadRequest(){
|
||||
this.setState({
|
||||
loading: true,
|
||||
id: window.setInterval(function(){
|
||||
if(document.cookie){
|
||||
this.setState({loading: false})
|
||||
window.clearInterval(this.state.id);
|
||||
}
|
||||
}.bind(this), 80)
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
window.clearInterval(this.state.id)
|
||||
}
|
||||
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{background: '#313538', color: '#f1f1f1', boxShadow: theme.effects.shadow_small}}>
|
||||
<Container style={{padding: '9px 0', textAlign: 'center', color: '#f1f1f1', fontSize: '0.9em'}}>
|
||||
<NgIf cond={this.props.hasOwnProperty('download')} style={{float: 'right', height: '1em'}}>
|
||||
<NgIf cond={!this.state.loading} style={{display: 'inline'}}>
|
||||
<a href={this.props.download} download={this.props.title} onClick={this.onDownloadRequest.bind(this)}>
|
||||
<Icon name="download" style={{width: '15px', height: '15px'}} />
|
||||
</a>
|
||||
</NgIf>
|
||||
<NgIf cond={this.state.loading} style={{display: 'inline'}}>
|
||||
<Icon name="loading" style={{width: '15px', height: '15px'}} />
|
||||
</NgIf>
|
||||
</NgIf>
|
||||
<span style={{letterSpacing: '0.3px'}}>{this.props.title}</span>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
export const PDFViewer = (props) => {
|
||||
return (
|
||||
<div style={{textAlign: 'center', background: '#525659', height: '100%'}}>
|
||||
<embed src={props.data} type="application/pdf" style={{height: '100%', width: '100%'}}></embed>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import { MenuBar } from './menubar';
|
||||
import { theme } from '../../utilities/';
|
||||
import videojs from 'video.js';
|
||||
|
||||
export class VideoPlayer extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.player = videojs(this.videoNode, {
|
||||
//autoplay: true,
|
||||
controls: true,
|
||||
aspectRatio: '16:9',
|
||||
fluid: false,
|
||||
sources: [{
|
||||
src: this.props.data
|
||||
}]
|
||||
}, function onPlayerReady() {
|
||||
//console.log('onPlayerReady', this)
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.player) {
|
||||
this.player.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{background: '#525659', height: '100%'}}>
|
||||
<MenuBar title={this.props.filename} download={this.props.data} />
|
||||
<div style={{padding: '20px'}}>
|
||||
<div style={{maxWidth: '800px', width: '100%', margin: '0 auto'}}>
|
||||
<video ref={ node => this.videoNode = node } className="video-js my-skin" style={{boxShadow: theme.effects.shadow}}></video>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
+25
-15
@@ -1,24 +1,34 @@
|
||||
import React from 'react'
|
||||
import { BrowserRouter, Route, IndexRoute } from 'react-router-dom'
|
||||
import { NotFoundPage, ConnectPage, HomePage, FilesPage, ViewerPage, LogoutPage } from './pages/';
|
||||
import { URL_HOME, URL_FILES, URL_VIEWER, URL_LOGIN, URL_LOGOUT } from './utilities/';
|
||||
import { NotFoundPage, ConnectPage, HomePage, LogoutPage } from './pages/';
|
||||
import { Bundle, URL_HOME, URL_FILES, URL_VIEWER, URL_LOGIN, URL_LOGOUT } from './utilities/';
|
||||
import { createBrowserHistory } from 'history'
|
||||
|
||||
|
||||
const FilesPage = (props) => (
|
||||
<Bundle loader={import(/* webpackChunkName: "route" */ "./pages/filespage")} symbol="FilesPage">
|
||||
{(Comp) => <Comp {...props}/>}
|
||||
</Bundle>
|
||||
);
|
||||
const ViewerPage = (props) => (
|
||||
<Bundle loader={import(/* webpackChunkName: "route" */"./pages/viewerpage")} symbol="ViewerPage">
|
||||
{(Comp) => <Comp {...props}/>}
|
||||
</Bundle>
|
||||
);
|
||||
|
||||
export default class AppRouter extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<BrowserRouter history={createBrowserHistory()}>
|
||||
<div>
|
||||
<Route exact path="/" component={HomePage} />
|
||||
<Route path="/login" component={ConnectPage} />
|
||||
<Route path="/files/:path*" component={FilesPage} />
|
||||
<Route path="/view/:path*" component={ViewerPage} />
|
||||
<Route path="/logout" component={LogoutPage} />
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<BrowserRouter history={createBrowserHistory()}>
|
||||
<div>
|
||||
<Route exact path="/" component={HomePage} />
|
||||
<Route path="/login" component={ConnectPage} />
|
||||
<Route path="/files/:path*" component={FilesPage} />
|
||||
<Route path="/view/:path*" component={ViewerPage} />
|
||||
<Route path="/logout" component={LogoutPage} />
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// taken from https://reacttraining.com/react-router/web/guides/code-splitting
|
||||
import React from 'react';
|
||||
import Path from 'path';
|
||||
|
||||
export class Bundle extends React.Component {
|
||||
state = { mod: null };
|
||||
|
||||
componentWillMount() {
|
||||
this.load(this.props)
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if(nextProps.load !== this.props.load){ this.load(nextProps) }
|
||||
}
|
||||
|
||||
load(props) {
|
||||
this.setState({
|
||||
mod: null
|
||||
});
|
||||
props.loader
|
||||
.then((_mod) => {
|
||||
this.setState({
|
||||
mod: function(mod){
|
||||
if(mod['default']){
|
||||
return mod.default;
|
||||
}else if(mod['__esModule'] === true){
|
||||
return mod[props.symbol] ? mod[props.symbol] : null;
|
||||
}else{
|
||||
return mod;
|
||||
}
|
||||
}(_mod)
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn(err)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.mod ? this.props.children(this.state.mod) : null
|
||||
}
|
||||
}
|
||||
@@ -16,3 +16,4 @@ export { Uploader } from './uploader';
|
||||
export { theme, to_rgba } from './theme';
|
||||
export { encrypt, decrypt } from './crypto'
|
||||
export { pathBuilder } from './path';
|
||||
export { Bundle } from './bundle';
|
||||
|
||||
@@ -6,13 +6,14 @@ WORKDIR "/app"
|
||||
|
||||
RUN cd /app/ && \
|
||||
# remove dev stuff
|
||||
npm run clean && \
|
||||
npm run clear && \
|
||||
# build
|
||||
apt-get update -y && \
|
||||
apt install -y libssl-dev build-essential automake python libcurl3-dev && \
|
||||
npm install nodegit --build-from-source && \
|
||||
npm install && \
|
||||
npm run build && \
|
||||
# prepare for production
|
||||
npm prune --production && \
|
||||
apt-get -y clean && \
|
||||
apt-get -y purge --auto-remove build-essential automake python && \
|
||||
|
||||
+3
-1
@@ -11,7 +11,8 @@
|
||||
"publish": "docker tag nuage machines/nuage && docker push machines/nuage",
|
||||
"start": "cd docker && docker-compose up -d",
|
||||
"stop": "cd docker && docker-compose down",
|
||||
"clean": "rm -rf node_modules server/public/bundle.js server/public/index.html || true"
|
||||
"clean": "rm -rf server/public/js server/public/*.html || true",
|
||||
"clear": "npm run clean && rm -rf node_modules"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
@@ -72,6 +73,7 @@
|
||||
"html-webpack-plugin": "^2.28.0",
|
||||
"http-server": "^0.9.0",
|
||||
"nodemon": "^1.11.0",
|
||||
"webpack-bundle-analyzer": "^2.8.2",
|
||||
"webpack-dev-server": "^2.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
+12
-7
@@ -1,22 +1,25 @@
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
let config = {
|
||||
entry: [
|
||||
'babel-polyfill',
|
||||
path.join(__dirname, 'client', 'index.js')
|
||||
],
|
||||
entry: {
|
||||
polyfill: 'babel-polyfill',
|
||||
app: path.join(__dirname, 'client', 'index.js')
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, 'server', 'public'),
|
||||
publicPath: '/',
|
||||
filename: 'bundle.js'
|
||||
filename: 'js/[name].js',
|
||||
chunkFilename: "js/chunk.[name].[id].js"
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: path.join(__dirname, 'client'),
|
||||
loader: ['babel-loader']
|
||||
loader: ['babel-loader'],
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.html$/,
|
||||
@@ -32,7 +35,8 @@ let config = {
|
||||
new HtmlWebpackPlugin({
|
||||
template: path.join(__dirname, 'client', 'index.html'),
|
||||
inject:true
|
||||
})
|
||||
}),
|
||||
new webpack.optimize.CommonsChunkPlugin({name: "polyfill", filename: "js/polyfill.js"}),
|
||||
]
|
||||
};
|
||||
|
||||
@@ -59,5 +63,6 @@ if(process.env.NODE_ENV === 'production'){
|
||||
}
|
||||
|
||||
|
||||
//config.plugins.push(new BundleAnalyzerPlugin())
|
||||
|
||||
module.exports = config;
|
||||
|
||||
Reference in New Issue
Block a user