Added Loader to indicate loading of sketches (#880)
* Added Loader to indicate loading of sketches * Fixed styles * Changed styles * remove prefixes * Issues Fixed: * added Loader * Refactor * Issues Fixed * clean up loader functions
This commit is contained in:
parent
870d9ceded
commit
538a41c617
9 changed files with 110 additions and 10 deletions
|
@ -118,5 +118,8 @@ export const HIDE_RUNTIME_ERROR_WARNING = 'HIDE_RUNTIME_ERROR_WARNING';
|
||||||
export const SHOW_RUNTIME_ERROR_WARNING = 'SHOW_RUNTIME_ERROR_WARNING';
|
export const SHOW_RUNTIME_ERROR_WARNING = 'SHOW_RUNTIME_ERROR_WARNING';
|
||||||
export const SET_ASSETS = 'SET_ASSETS';
|
export const SET_ASSETS = 'SET_ASSETS';
|
||||||
|
|
||||||
|
export const START_LOADING = 'START_LOADING';
|
||||||
|
export const STOP_LOADING = 'STOP_LOADING';
|
||||||
|
|
||||||
export const START_SAVING_PROJECT = 'START_SAVING_PROJECT';
|
export const START_SAVING_PROJECT = 'START_SAVING_PROJECT';
|
||||||
export const END_SAVING_PROJECT = 'END_SAVING_PROJECT';
|
export const END_SAVING_PROJECT = 'END_SAVING_PROJECT';
|
||||||
|
|
9
client/modules/App/components/loader.jsx
Normal file
9
client/modules/App/components/loader.jsx
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const Loader = () => (
|
||||||
|
<div className="loader">
|
||||||
|
<div className="loader__circle1" />
|
||||||
|
<div className="loader__circle2" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
export default Loader;
|
9
client/modules/IDE/actions/loader.js
Normal file
9
client/modules/IDE/actions/loader.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
|
export function startLoader() {
|
||||||
|
return { type: ActionTypes.START_LOADING };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopLoader() {
|
||||||
|
return { type: ActionTypes.STOP_LOADING };
|
||||||
|
}
|
|
@ -2,12 +2,14 @@ import axios from 'axios';
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
import { showErrorModal, setPreviousPath } from './ide';
|
import { showErrorModal, setPreviousPath } from './ide';
|
||||||
import { resetProject } from './project';
|
import { resetProject } from './project';
|
||||||
|
import { startLoader, stopLoader } from './loader';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
const __process = (typeof global !== 'undefined' ? global : window).process;
|
||||||
const ROOT_URL = __process.env.API_URL;
|
const ROOT_URL = __process.env.API_URL;
|
||||||
|
|
||||||
export function getProjects(username) {
|
export function getProjects(username) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
|
dispatch(startLoader());
|
||||||
let url;
|
let url;
|
||||||
if (username) {
|
if (username) {
|
||||||
url = `${ROOT_URL}/${username}/projects`;
|
url = `${ROOT_URL}/${username}/projects`;
|
||||||
|
@ -20,11 +22,15 @@ export function getProjects(username) {
|
||||||
type: ActionTypes.SET_PROJECTS,
|
type: ActionTypes.SET_PROJECTS,
|
||||||
projects: response.data
|
projects: response.data
|
||||||
});
|
});
|
||||||
|
dispatch(stopLoader());
|
||||||
})
|
})
|
||||||
.catch(response => dispatch({
|
.catch((response) => {
|
||||||
type: ActionTypes.ERROR,
|
dispatch({
|
||||||
error: response.data
|
type: ActionTypes.ERROR,
|
||||||
}));
|
error: response.data
|
||||||
|
});
|
||||||
|
dispatch(stopLoader());
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { bindActionCreators } from 'redux';
|
||||||
import * as ProjectActions from '../actions/project';
|
import * as ProjectActions from '../actions/project';
|
||||||
import * as SketchActions from '../actions/projects';
|
import * as SketchActions from '../actions/projects';
|
||||||
import * as ToastActions from '../actions/toast';
|
import * as ToastActions from '../actions/toast';
|
||||||
|
import Loader from '../../App/components/loader';
|
||||||
|
|
||||||
const trashCan = require('../../../images/trash-can.svg');
|
const trashCan = require('../../../images/trash-can.svg');
|
||||||
|
|
||||||
|
@ -25,6 +26,20 @@ class SketchList extends React.Component {
|
||||||
return `p5.js Web Editor | ${this.props.username}'s sketches`;
|
return `p5.js Web Editor | ${this.props.username}'s sketches`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasSketches() {
|
||||||
|
return !this.props.loading && this.props.sketches.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLoader() {
|
||||||
|
if (this.props.loading) return <Loader />;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEmptyTable() {
|
||||||
|
if (!this.props.loading && this.props.sketches.length === 0) return (<p className="sketches-table__empty">No sketches.</p>);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const username = this.props.username !== undefined ? this.props.username : this.props.user.username;
|
const username = this.props.username !== undefined ? this.props.username : this.props.user.username;
|
||||||
return (
|
return (
|
||||||
|
@ -32,10 +47,9 @@ class SketchList extends React.Component {
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{this.getSketchesTitle()}</title>
|
<title>{this.getSketchesTitle()}</title>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
{ this.props.sketches.length === 0 &&
|
{this.renderLoader()}
|
||||||
<p className="sketches-table__empty">No sketches.</p>
|
{this.renderEmptyTable()}
|
||||||
}
|
{this.hasSketches() &&
|
||||||
{ this.props.sketches.length > 0 &&
|
|
||||||
<table className="sketches-table" summary="table containing all saved projects">
|
<table className="sketches-table" summary="table containing all saved projects">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -95,6 +109,7 @@ SketchList.propTypes = {
|
||||||
updatedAt: PropTypes.string.isRequired
|
updatedAt: PropTypes.string.isRequired
|
||||||
})).isRequired,
|
})).isRequired,
|
||||||
username: PropTypes.string,
|
username: PropTypes.string,
|
||||||
|
loading: PropTypes.bool.isRequired,
|
||||||
deleteProject: PropTypes.func.isRequired
|
deleteProject: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -105,7 +120,8 @@ SketchList.defaultProps = {
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
return {
|
return {
|
||||||
user: state.user,
|
user: state.user,
|
||||||
sketches: state.sketches
|
sketches: state.sketches,
|
||||||
|
loading: state.loading,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
client/modules/IDE/reducers/loading.js
Normal file
14
client/modules/IDE/reducers/loading.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
|
const loading = (state = false, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionTypes.START_LOADING:
|
||||||
|
return true;
|
||||||
|
case ActionTypes.STOP_LOADING:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default loading;
|
|
@ -10,6 +10,7 @@ import sketches from './modules/IDE/reducers/projects';
|
||||||
import toast from './modules/IDE/reducers/toast';
|
import toast from './modules/IDE/reducers/toast';
|
||||||
import console from './modules/IDE/reducers/console';
|
import console from './modules/IDE/reducers/console';
|
||||||
import assets from './modules/IDE/reducers/assets';
|
import assets from './modules/IDE/reducers/assets';
|
||||||
|
import loading from './modules/IDE/reducers/loading';
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
form,
|
form,
|
||||||
|
@ -22,7 +23,8 @@ const rootReducer = combineReducers({
|
||||||
editorAccessibility,
|
editorAccessibility,
|
||||||
toast,
|
toast,
|
||||||
console,
|
console,
|
||||||
assets
|
assets,
|
||||||
|
loading
|
||||||
});
|
});
|
||||||
|
|
||||||
export default rootReducer;
|
export default rootReducer;
|
||||||
|
|
40
client/styles/components/_loader.scss
Normal file
40
client/styles/components/_loader.scss
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
.loader {
|
||||||
|
width: #{80 / $base-font-size }rem;
|
||||||
|
height: #{80 / $base-font-size}rem;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
margin: #{100 / $base-font-size}rem auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader__circle1,
|
||||||
|
.loader__circle2 {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 80%;
|
||||||
|
|
||||||
|
@include themify() {
|
||||||
|
background-color: getThemifyVariable('logo-color');
|
||||||
|
}
|
||||||
|
|
||||||
|
opacity: 0.6;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
animation: sk-bounce 2.0s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader__circle2 {
|
||||||
|
animation-delay: -1.0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes sk-bounce {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: scale(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1.0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,6 +41,7 @@
|
||||||
@import 'components/keyboard-shortcuts';
|
@import 'components/keyboard-shortcuts';
|
||||||
@import 'components/copyable-input';
|
@import 'components/copyable-input';
|
||||||
@import 'components/feedback';
|
@import 'components/feedback';
|
||||||
|
@import 'components/loader';
|
||||||
@import 'components/uploader';
|
@import 'components/uploader';
|
||||||
|
|
||||||
@import 'layout/ide';
|
@import 'layout/ide';
|
||||||
|
|
Loading…
Reference in a new issue