Add fluid loading animation when notes are loading

This commit is contained in:
Joey Payne 2016-03-18 07:29:54 -06:00
commit 14b0e61373
4 changed files with 185 additions and 33 deletions

View file

@ -0,0 +1,111 @@
import React from 'react'
import ReactDOM from 'react-dom'
import mui from 'material-ui'
import getMuiTheme from 'material-ui/lib/styles/getMuiTheme'
import RefreshIndicator from 'material-ui/lib/refresh-indicator'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
const style = {
container: {
position: 'relative',
},
refresh: {
display: 'inline-block',
position: 'relative',
},
}
const {
Styles
} = mui
const Colors = Styles.Colors
const DefaultRawTheme = Styles.LightRawTheme
export default class EntryLoader extends React.Component {
constructor(props, context){
super(props, context)
this.state = {loaded: false}
}
static get childContextTypes(){
return {muiTheme: React.PropTypes.object}
}
getChildContext() {
return {
muiTheme: this.context.muiTheme || getMuiTheme(DefaultRawTheme)
}
}
componentDidMount() {
this.updateState(this.props)
}
componentWillReceiveProps(nextProps) {
this.updateState(nextProps)
}
updateState = (props) => {
props || (props = {})
var loaded = this.state.loaded
// update loaded state, if supplied
if ('loaded' in props) {
loaded = !!props.loaded
}
this.setState({loaded: loaded})
};
getContent = () => {
return this.props.children
}
getLoader = () => {
if(!this.state.loaded){
return (
<div key="loader">
<div className="loader">
<div className="spinner">
<RefreshIndicator
size={50}
left={0}
top={0}
loadingColor={"#FF9800"}
status="loading"
style={style.refresh}
/>
</div>
</div>
</div>
)
}
else{
return (<div key="loaded"></div>)
}
};
render(){
return (
<div
id={this.props.id || "entry-loader"}
style={style.container}
>
<ReactCSSTransitionGroup
transitionName="entry-loader"
transitionLeaveTimeout={200}
transitionEnterTimeout={200}
>
{this.getLoader()}
</ReactCSSTransitionGroup>
{this.getContent()}
</div>
)
}
}

View file

@ -12,6 +12,7 @@ import Tag from 'material-ui/lib/svg-icons/maps/local-offer'
import SearchBar from 'SearchBar'
import SelectableList from 'SelectableList'
import Item from 'Item'
import EntryLoader from 'EntryLoader'
import uuid from 'node-uuid'
import path from 'path-extra'
@ -44,7 +45,7 @@ export default class EntrySelector extends React.Component {
constructor(props, context){
super(props, context)
this.state = {notes: []}
this.state = {notes: [], loaded: false}
this.loadNotes()
const { store } = this.context
store.subscribe(this.stateChanged)
@ -75,18 +76,19 @@ export default class EntrySelector extends React.Component {
loadNotes = () => {
var notebook = this.props.navigation.selection
if(!utils.isEmpty(notebook)){
var notes = utils.loadNotes(notebook)
notes.sort(utils.compareNotes())
this.state.notes = notes
var notes = utils.loadNotesAsync(notebook, (notes)=>{
notes.sort(utils.compareNotes())
this.setState({notes: notes, loaded: true})
})
}
}
reloadNotes = (selection) => {
this.setState({notes: []}, ()=>{
this.setState({loaded: false}, ()=>{
var notebook = selection || this.props.navigation.selection
utils.loadNotesAsync(notebook, (notes) => {
notes.sort(utils.compareNotes())
this.setState({notes: notes})
this.setState({notes: notes, loaded: true})
})
})
};
@ -168,7 +170,7 @@ export default class EntrySelector extends React.Component {
addNoteTapped = () => {
this.createNewNote((note, err)=>{
this.props.refreshNavigation()
this.props.noteAdded()
})
};
@ -209,6 +211,32 @@ export default class EntrySelector extends React.Component {
</div>)
};
renderNotes = () => {
return this.state.notes.map((note, i) =>{
return (<ListItem
key={i}
value={i}
leftIcon={<Description color={Colors.grey600}/>}
innerDivStyle={{paddingBottom: 40}}
style={{borderBottom: '1px solid #F1F1F1'}}
secondaryText={
<p>
{note.summary}
</p>
}
secondaryTextLines={2}
>
<div>
{note.title || "Untitled Note"}
</div>
{this.renderNoteInfo(note)}
</ListItem>
)
})
};
render(){
return (
<Paper id={this.props.id} className={this.props.className+ " noselect"} zDepth={0}>
@ -230,32 +258,12 @@ export default class EntrySelector extends React.Component {
<SelectableList
id="entry-list"
ref="entryList"
selectedItemStyle={{backgroundColor: colors.grey300}}>
{this.state.notes.map((note, i) =>{
return (<ListItem
key={i}
value={i}
leftIcon={<Description color={colors.grey600}/>}
innerDivStyle={{paddingBottom: 40}}
style={{borderBottom: '1px solid #F1F1F1'}}
secondaryText={
<p>
{note.summary}
</p>
}
secondaryTextLines={2}
>
<div>
{note.title || "Untitled Note"}
</div>
{this.renderNoteInfo(note)}
</ListItem>
)
})
}
selectedItemStyle={{backgroundColor: Colors.grey100}}>
<EntryLoader
loaded={this.state.loaded}
>
{this.renderNotes()}
</EntryLoader>
</SelectableList>
</Paper>
)

View file

@ -65,6 +65,7 @@
"node-uuid": "^1.4.7",
"path-extra": "^3.0.0",
"react": "^0.14.7",
"react-addons-css-transition-group": "^0.14.7",
"react-dom": "^0.14.7",
"react-quill": "^0.4.1",
"react-redux": "^4.4.0",

View file

@ -17,6 +17,38 @@ body, html{
padding-bottom: 0px !important;
}
.entry-loader-enter {
opacity: 0.01;
}
.entry-loader-enter.entry-loader-enter-active {
opacity: 1;
transition: opacity 200ms ease-in;
}
.entry-loader-leave {
opacity: 1;
}
.entry-loader-leave.entry-loader-leave-active {
opacity: 0.01;
transition: opacity 200ms ease-in;
}
#entry-list .loader{
height: 100% !important;
position: fixed;
width: 338px;
background-color: rgba(0,0,0, 0.1);
z-index: 100;
}
#entry-list .loader .spinner{
position: relative !important;
top: -webkit-calc(50% - 50px);
left: -webkit-calc(50% - 25px);
}
.list {
background-color: #EFEFEF !important;
}