From 83815ea05134f3d69b1c8c11937cd4cc5e43eb8c Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sun, 5 Aug 2018 22:59:53 +0800 Subject: [PATCH] feat: loading indicator --- src/components/FileExplorer.js | 68 +++++++++++++++++------------- src/components/LoadingIndicator.js | 13 ++++++ src/components/SideBar.js | 5 +-- src/content.less | 27 ++++++++++++ src/driver/core/FileExplorer.js | 11 +++++ src/driver/core/SideBar.js | 6 --- 6 files changed, 92 insertions(+), 38 deletions(-) create mode 100644 src/components/LoadingIndicator.js diff --git a/src/components/FileExplorer.js b/src/components/FileExplorer.js index 10930e8..fb56863 100644 --- a/src/components/FileExplorer.js +++ b/src/components/FileExplorer.js @@ -6,6 +6,7 @@ import { FileExplorer as FileExplorerCore } from '../driver/core' import SearchBar from './SearchBar' import Node from './Node' +import LoadingIndicator from './LoadingIndicator' import cx from '../utils/cx' @@ -45,44 +46,53 @@ export default class FileExplorer extends React.Component { execAfterRender() } + componentWillReceiveProps(nextProps) { + if (nextProps.treeData !== this.props.treeData) { + const { init } = nextProps + init() + } + } + componentDidUpdate() { const { execAfterRender } = this.props execAfterRender() } + renderFiles(visibleNodes, onNodeClick) { + const { nodes, depths, focusedNode, expandedNodes } = visibleNodes + if (nodes.length === 0) { + return ( + + ) + } + return ( +
+ {nodes.map(node => ( + + ))} +
+ ) + } + render() { - const { - visibleNodes, - freeze, - handleKeyDown, - handleSearchKeyChange, - onNodeClick - } = this.props - const { - nodes, - depths, - focusedNode, - expandedNodes, - } = visibleNodes || {} + const { stateText, visibleNodes, freeze, handleKeyDown, handleSearchKeyChange, onNodeClick } = this.props return (
- {!visibleNodes || !nodes || nodes.length === 0 ? ( - - ) : ( -
- {nodes.map(node => ( - - ))} -
- )} + { + !visibleNodes || stateText + ? + : this.renderFiles(visibleNodes, onNodeClick) + }
) } diff --git a/src/components/LoadingIndicator.js b/src/components/LoadingIndicator.js new file mode 100644 index 0000000..dfecccd --- /dev/null +++ b/src/components/LoadingIndicator.js @@ -0,0 +1,13 @@ +import React from 'react' +import Icon from './Icon'; + +export default function LoadingIndicator({ text }) { + return ( +
+
+ + {text} +
+
+ ) +} diff --git a/src/components/SideBar.js b/src/components/SideBar.js index b4158a9..43069b3 100644 --- a/src/components/SideBar.js +++ b/src/components/SideBar.js @@ -94,9 +94,8 @@ export default class Gitako extends React.PureComponent { {metaData && } {errorDueToAuth && this.renderAccessDeniedError()} {metaData && - treeData && ( - - )} + + } ) } diff --git a/src/content.less b/src/content.less index 99ab67b..5520364 100644 --- a/src/content.less +++ b/src/content.less @@ -215,6 +215,25 @@ padding: 4px 10px; } + .loading-indicator-container { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + + .loading-indicator { + display: flex; + align-items: center; + } + + .loading-indicator-icon { + width: 20px; + height: 20px; + animation: rotate 2s infinite linear; + } + } + .file-explorer { width: 100%; height: 100%; @@ -373,3 +392,11 @@ } } } + +@keyframes rotate { + from { + transform: rotateZ(0); + } to { + transform: rotateZ(360deg); + } +} diff --git a/src/driver/core/FileExplorer.js b/src/driver/core/FileExplorer.js index 12b5b8c..6db7b95 100644 --- a/src/driver/core/FileExplorer.js +++ b/src/driver/core/FileExplorer.js @@ -21,9 +21,15 @@ const tasksAfterRender = [] const visibleNodesGenerator = new VisibleNodesGenerator() const init = dispatch => () => dispatch(async (state, { treeData, metaData, compressSingletonFolder }) => { + if (!treeData) { + dispatch(setStateText, 'Fetching Tree Data...') + return + } + dispatch(setStateText, 'Rendering File List...') const { root } = treeParser.parse(treeData, metaData) visibleNodesGenerator.setCompress(compressSingletonFolder) await visibleNodesGenerator.plantTree(root) + dispatch(setStateText, null) const currentPath = URLHelper.getCurrentPath(true) if (currentPath.length) { const nodeExpandedTo = visibleNodesGenerator.expandTo(currentPath.join('/')) @@ -44,6 +50,10 @@ const execAfterRender = dispatch => () => { tasksAfterRender.length = 0 } +const setStateText = dispatch => text => dispatch({ + stateText: text, +}) + const handleKeyDown = dispatch => ({ key }) => dispatch(({ visibleNodes: { nodes, focusedNode, expandedNodes, depths } }) => { if (focusedNode) { const focusedNodeIndex = nodes.indexOf(focusedNode) @@ -174,6 +184,7 @@ const updateVisibleNodes = dispatch => () => { export default { init, execAfterRender, + setStateText, handleKeyDown, handleSearchKeyChange, setExpand, diff --git a/src/driver/core/SideBar.js b/src/driver/core/SideBar.js index df1ad1a..4bf3ae7 100644 --- a/src/driver/core/SideBar.js +++ b/src/driver/core/SideBar.js @@ -16,15 +16,9 @@ const init = dispatch => async () => { dispatch(setMetaData, metaData) const shouldShow = URLHelper.isInCodePage(metaData) dispatch(setShouldShow, shouldShow) - if (shouldShow) { - DOMHelper.mountTopProgressBar() - } const treeData = await GitHubHelper.getTreeData({ ...metaData, accessToken }) dispatch({ logoContainerElement: DOMHelper.insertLogoMountPoint() }) dispatch({ treeData }) - if (shouldShow) { - DOMHelper.unmountTopProgressBar() - } } catch (err) { // TODO: detect request time exceeds limit if (err.message === NOT_FOUND || err.message === BAD_CREDENTIALS) {