diff options
author | Samy Pesse <samypesse@gmail.com> | 2016-10-13 16:17:00 +0200 |
---|---|---|
committer | Samy Pesse <samypesse@gmail.com> | 2016-10-13 16:17:00 +0200 |
commit | 05646996c0ef2f1a474bd547153b8ef87f89ac6e (patch) | |
tree | b76ed08d1ae1410334bb0f0c7131b1ab2d9abdfe | |
parent | c439cf851380da27ebaa0edce5fff99f8fb93d65 (diff) | |
download | gitbook-05646996c0ef2f1a474bd547153b8ef87f89ac6e.zip gitbook-05646996c0ef2f1a474bd547153b8ef87f89ac6e.tar.gz gitbook-05646996c0ef2f1a474bd547153b8ef87f89ac6e.tar.bz2 |
Rename "navigation" to "history" and add loading bar
16 files changed, 239 insertions, 55 deletions
diff --git a/packages/gitbook-core/src/actions/TYPES.js b/packages/gitbook-core/src/actions/TYPES.js index f49b4bb..9876057 100644 --- a/packages/gitbook-core/src/actions/TYPES.js +++ b/packages/gitbook-core/src/actions/TYPES.js @@ -1,16 +1,16 @@ module.exports = { // Components - REGISTER_COMPONENT: 'components/register', - UNREGISTER_COMPONENT: 'components/unregister', + REGISTER_COMPONENT: 'components/register', + UNREGISTER_COMPONENT: 'components/unregister', // Navigation - NAVIGATION_ACTIVATE: 'navigation/activate', - NAVIGATION_DEACTIVATE: 'navigation/deactivate', - NAVIGATION_LISTEN: 'navigation/listen', - NAVIGATION_UPDATE: 'navigation/update', - PAGE_FETCH_START: 'navigation/fetch:start', - PAGE_FETCH_END: 'navigation/fetch:end', - PAGE_FETCH_ERROR: 'navigation/fetch:error', + HISTORY_ACTIVATE: 'history/activate', + HISTORY_DEACTIVATE: 'history/deactivate', + HISTORY_LISTEN: 'history/listen', + HISTORY_UPDATE: 'history/update', + PAGE_FETCH_START: 'history/fetch:start', + PAGE_FETCH_END: 'history/fetch:end', + PAGE_FETCH_ERROR: 'history/fetch:error', // i18n - I18N_REGISTER_LOCALE: 'i18n/register:locale' + I18N_REGISTER_LOCALE: 'i18n/register:locale' }; diff --git a/packages/gitbook-core/src/actions/navigation.js b/packages/gitbook-core/src/actions/history.js index 26bfa59..a7cf228 100644 --- a/packages/gitbook-core/src/actions/navigation.js +++ b/packages/gitbook-core/src/actions/history.js @@ -10,16 +10,16 @@ const SUPPORTED = ( ); /** - * Initialize the navigation + * Initialize the history */ function activate() { return (dispatch, getState) => { dispatch({ - type: ACTION_TYPES.NAVIGATION_ACTIVATE, + type: ACTION_TYPES.HISTORY_ACTIVATE, listener: (location) => { location = Location.fromNative(location); - const prevLocation = getState().navigation.location; + const prevLocation = getState().history.location; // Fetch page if required if (!prevLocation || location.pathname !== prevLocation.pathname) { @@ -31,7 +31,7 @@ function activate() { // Update the location dispatch({ - type: ACTION_TYPES.NAVIGATION_UPDATE, + type: ACTION_TYPES.HISTORY_UPDATE, location }); } @@ -48,13 +48,13 @@ function activate() { */ function emit(to) { return (dispatch, getState) => { - const { listeners, history } = getState().navigation; + const { listeners, client } = getState().history; - if (!history) { + if (!client) { return; } - const location = Location.fromNative(history.location); + const location = Location.fromNative(client.location); to = to || listeners; @@ -65,24 +65,24 @@ function emit(to) { } /** - * Cleanup the navigation + * Cleanup the history */ function deactivate() { - return { type: ACTION_TYPES.NAVIGATION_DEACTIVATE }; + return { type: ACTION_TYPES.HISTORY_DEACTIVATE }; } /** - * Push a new url into the navigation + * Push a new url into the history * @param {String|Location} location * @return {Action} action */ function push(location) { return (dispatch, getState) => { - const { history } = getState().navigation; + const { client } = getState().history; location = Location.fromNative(location); if (SUPPORTED) { - history.push(location.toNative()); + client.push(location.toNative()); } else { redirect(location.toString()); } @@ -90,17 +90,17 @@ function push(location) { } /** - * Replace current state in navigation + * Replace current state in history * @param {String|Location} location * @return {Action} action */ function replace(location) { return (dispatch, getState) => { - const { history } = getState().navigation; + const { client } = getState().history; location = Location.fromNative(location); if (SUPPORTED) { - history.replace(location.toNative()); + client.replace(location.toNative()); } else { redirect(location.toString()); } @@ -125,7 +125,7 @@ function redirect(uri) { */ function listen(listener) { return (dispatch, getState) => { - dispatch({ type: ACTION_TYPES.NAVIGATION_LISTEN, listener }); + dispatch({ type: ACTION_TYPES.HISTORY_LISTEN, listener }); // Trigger for existing listeners dispatch(emit([ listener ])); @@ -163,7 +163,6 @@ function fetchPage(pathname) { .catch( error => { // dispatch(redirect(pathname)); - console.error(error); dispatch({ type: ACTION_TYPES.PAGE_FETCH_ERROR, error }); } ); diff --git a/packages/gitbook-core/src/components/PJAXWrapper.js b/packages/gitbook-core/src/components/PJAXWrapper.js index d2eb456..6ed0697 100644 --- a/packages/gitbook-core/src/components/PJAXWrapper.js +++ b/packages/gitbook-core/src/components/PJAXWrapper.js @@ -1,6 +1,6 @@ const React = require('react'); const ReactRedux = require('react-redux'); -const Navigation = require('../actions/navigation'); +const History = require('../actions/history'); /** * Check if an element is inside a link @@ -83,7 +83,7 @@ const PJAXWrapper = React.createClass({ } event.preventDefault(); - dispatch(Navigation.push(href)); + dispatch(History.push(href)); }, componentDidMount() { diff --git a/packages/gitbook-core/src/lib/createContext.js b/packages/gitbook-core/src/lib/createContext.js index 87593e3..ba0c7e1 100644 --- a/packages/gitbook-core/src/lib/createContext.js +++ b/packages/gitbook-core/src/lib/createContext.js @@ -9,7 +9,7 @@ const composeReducer = require('./composeReducer'); const Components = require('../actions/components'); const I18n = require('../actions/i18n'); -const Navigation = require('../actions/navigation'); +const History = require('../actions/history'); const isBrowser = (typeof window !== 'undefined'); @@ -21,7 +21,7 @@ const isBrowser = (typeof window !== 'undefined'); const corePlugin = new Plugin({ reduce: coreReducers, actions: { - Components, I18n, Navigation + Components, I18n, History } }); diff --git a/packages/gitbook-core/src/lib/renderWithContext.js b/packages/gitbook-core/src/lib/renderWithContext.js index f9a093c..c84c221 100644 --- a/packages/gitbook-core/src/lib/renderWithContext.js +++ b/packages/gitbook-core/src/lib/renderWithContext.js @@ -4,7 +4,7 @@ const { InjectedComponent } = require('../components/InjectedComponent'); const PJAXWrapper = require('../components/PJAXWrapper'); const I18nProvider = require('../components/I18nProvider'); const ContextProvider = require('../components/ContextProvider'); -const Navigation = require('../actions/navigation'); +const History = require('../actions/history'); const contextShape = require('../shapes/context'); const GitBookApplication = React.createClass({ @@ -15,12 +15,12 @@ const GitBookApplication = React.createClass({ componentDidMount() { const { context } = this.props; - context.dispatch(Navigation.activate()); + context.dispatch(History.activate()); }, componentWillUnmount() { const { context } = this.props; - context.dispatch(Navigation.deactivate()); + context.dispatch(History.deactivate()); }, render() { diff --git a/packages/gitbook-core/src/reducers/navigation.js b/packages/gitbook-core/src/reducers/history.js index 11774de..d78b158 100644 --- a/packages/gitbook-core/src/reducers/navigation.js +++ b/packages/gitbook-core/src/reducers/history.js @@ -4,7 +4,7 @@ const ACTION_TYPES = require('../actions/TYPES'); const isServerSide = (typeof window === 'undefined'); -const NavigationState = Record({ +const HistoryState = Record({ // Current location location: null, // Are we loading a new page @@ -15,12 +15,12 @@ const NavigationState = Record({ listeners: List(), // Function to call to stop listening unlisten: null, - // History instance - history: null + // HistoryJS instance + client: null }); -function reduceNavigation(state, action) { - state = state || NavigationState(); +function reduceHistory(state, action) { + state = state || HistoryState(); switch (action.type) { case ACTION_TYPES.PAGE_FETCH_START: @@ -39,33 +39,33 @@ function reduceNavigation(state, action) { error: action.error }); - case ACTION_TYPES.NAVIGATION_ACTIVATE: - const history = isServerSide ? createMemoryHistory() : createBrowserHistory(); - const unlisten = history.listen(action.listener); + case ACTION_TYPES.HISTORY_ACTIVATE: + const client = isServerSide ? createMemoryHistory() : createBrowserHistory(); + const unlisten = client.listen(action.listener); // We can't use .merge since it convert history to an immutable const newState = state - .set('history', history) + .set('client', client) .set('unlisten', unlisten); return newState; - case ACTION_TYPES.NAVIGATION_DEACTIVATE: + case ACTION_TYPES.HISTORY_DEACTIVATE: if (state.unlisten) { state.unlisten(); } return state.merge({ - history: null, + client: null, unlisten: null }); - case ACTION_TYPES.NAVIGATION_UPDATE: + case ACTION_TYPES.HISTORY_UPDATE: return state.merge({ location: action.location }); - case ACTION_TYPES.NAVIGATION_LISTEN: + case ACTION_TYPES.HISTORY_LISTEN: return state.merge({ listeners: state.listeners.push(action.listener) }); @@ -76,4 +76,4 @@ function reduceNavigation(state, action) { } } -module.exports = reduceNavigation; +module.exports = reduceHistory; diff --git a/packages/gitbook-core/src/reducers/index.js b/packages/gitbook-core/src/reducers/index.js index 335a1cf..fc80b4a 100644 --- a/packages/gitbook-core/src/reducers/index.js +++ b/packages/gitbook-core/src/reducers/index.js @@ -3,7 +3,7 @@ const createReducer = require('../lib/createReducer'); module.exports = composeReducer( createReducer('components', require('./components')), - createReducer('navigation', require('./navigation')), + createReducer('history', require('./history')), createReducer('i18n', require('./i18n')), // GitBook JSON createReducer('config', require('./config')), diff --git a/packages/gitbook-core/src/shapes/History.js b/packages/gitbook-core/src/shapes/History.js new file mode 100644 index 0000000..1b59ea0 --- /dev/null +++ b/packages/gitbook-core/src/shapes/History.js @@ -0,0 +1,11 @@ +const React = require('react'); +const locationShape = require('./Location'); +const { + bool, + shape +} = React.PropTypes; + +module.exports = shape({ + loading: bool, + location: locationShape +}); diff --git a/packages/gitbook-core/src/shapes/Location.js b/packages/gitbook-core/src/shapes/Location.js new file mode 100644 index 0000000..13e0a34 --- /dev/null +++ b/packages/gitbook-core/src/shapes/Location.js @@ -0,0 +1,12 @@ +const React = require('react'); +const { map } = require('react-immutable-proptypes'); +const { + string, + shape +} = React.PropTypes; + +module.exports = shape({ + pathname: string, + hash: string, + query: map +}); diff --git a/packages/gitbook-core/src/shapes/index.js b/packages/gitbook-core/src/shapes/index.js index 2faddbc..8b28842 100644 --- a/packages/gitbook-core/src/shapes/index.js +++ b/packages/gitbook-core/src/shapes/index.js @@ -8,6 +8,8 @@ module.exports = { Context: require('./Context'), Page: require('./Page'), File: require('./File'), + History: require('./History'), + Location: require('./Location'), Readme: require('./Readme'), Summary: require('./Summary'), SummaryPart: require('./SummaryPart'), diff --git a/packages/gitbook-plugin-search/src/index.js b/packages/gitbook-plugin-search/src/index.js index bc6c406..298c088 100644 --- a/packages/gitbook-plugin-search/src/index.js +++ b/packages/gitbook-plugin-search/src/index.js @@ -18,9 +18,9 @@ const onLocationChange = (location, dispatch) => { }; module.exports = GitBook.createPlugin({ - activate: (dispatch, getState, { Navigation, Components }) => { + activate: (dispatch, getState, { History, Components }) => { // Register the navigation handler - dispatch(Navigation.listen(onLocationChange)); + dispatch(History.listen(onLocationChange)); // Register components dispatch(Components.registerComponent(SearchInput, { role: 'search:input' })); diff --git a/packages/gitbook-plugin-theme-default/less/LoadingBar.less b/packages/gitbook-plugin-theme-default/less/LoadingBar.less new file mode 100644 index 0000000..1fca2ea --- /dev/null +++ b/packages/gitbook-plugin-theme-default/less/LoadingBar.less @@ -0,0 +1,30 @@ +.LoadingBar { + pointer-events: none; + transition: 400ms linear all; + + .LoadingBar-Bar { + background: @color-primary; + height: 2px; + + position: fixed; + top: 0; + left: 0; + z-index: 10000; + display: none; + width: 100%; + border-radius: 0 1px 1px 0; + transition: width 350ms; + } + + .LoadingBar-Shadow { + content: ''; + position: absolute; + top: 0; + right: 0; + width: 70px; + height: 2px; + border-radius: 50%; + opacity: .45; + box-shadow: @color-primary 1px 0 6px 1px; + } +} diff --git a/packages/gitbook-plugin-theme-default/less/main.less b/packages/gitbook-plugin-theme-default/less/main.less index 6b50858..960477d 100644 --- a/packages/gitbook-plugin-theme-default/less/main.less +++ b/packages/gitbook-plugin-theme-default/less/main.less @@ -14,6 +14,7 @@ @import "Search.less"; @import "Body.less"; @import "Dropdown.less"; +@import "LoadingBar.less"; * { .box-sizing(border-box); diff --git a/packages/gitbook-plugin-theme-default/less/variables.less b/packages/gitbook-plugin-theme-default/less/variables.less index c8dc452..62f4f52 100644 --- a/packages/gitbook-plugin-theme-default/less/variables.less +++ b/packages/gitbook-plugin-theme-default/less/variables.less @@ -1,3 +1,5 @@ +// Colors +@color-primary: hsl(207, 100%, 50%); // rgb(44, 106, 254); // Fonts @font-family-serif: Georgia, serif; @font-family-sans: "Helvetica Neue", Helvetica, Arial, sans-serif; @@ -16,7 +18,7 @@ @summary-article-padding-v: 10px; @summary-article-padding-h: 15px; @summary-article-color: hsl(207, 15%, 25%); -@summary-article-hover-color: hsl(207, 100%, 50%); +@summary-article-hover-color: @color-primary; @summary-article-active-color: @summary-article-color; @summary-article-active-background: #f5f5f5; // Page diff --git a/packages/gitbook-plugin-theme-default/src/components/LoadingBar.js b/packages/gitbook-plugin-theme-default/src/components/LoadingBar.js new file mode 100644 index 0000000..11e1ddb --- /dev/null +++ b/packages/gitbook-plugin-theme-default/src/components/LoadingBar.js @@ -0,0 +1,124 @@ +const GitBook = require('gitbook-core'); +const { React } = GitBook; + +/** + * Displays a progress bar (YouTube-like) at the top of container + * Based on https://github.com/lonelyclick/react-loading-bar/blob/master/src/Loading.jsx + */ +const LoadingBar = React.createClass({ + propTypes: { + show: React.PropTypes.bool + }, + + getDefaultProps() { + return { + show: false + }; + }, + + getInitialState() { + return { + size: 0, + disappearDelayHide: false, // when dispappear, first transition then display none + percent: 0, + appearDelayWidth: 0 // when appear, first display block then transition width + }; + }, + + componentWillReceiveProps(nextProps) { + const { show } = nextProps; + + if (show) { + this.show(); + } else { + this.hide(); + } + }, + + shouldComponentUpdate(nextProps, nextState) { + return true; // !shallowEqual(nextState, this.state) + }, + + show() { + let { size, percent } = this.state; + + const appearDelayWidth = size === 0; + percent = calculatePercent(percent); + + this.setState({ + size: ++size, + appearDelayWidth, + percent + }); + + if (appearDelayWidth) { + setTimeout(() => { + this.setState({ + appearDelayWidth: false + }); + }); + } + }, + + hide() { + let { size } = this.state; + + if (--size < 0) { + this.setState({ size: 0 }); + return; + } + + this.setState({ + size: 0, + disappearDelayHide: true, + percent: 1 + }); + + setTimeout(() => { + this.setState({ + disappearDelayHide: false, + percent: 0 + }); + }, 500); + }, + + getBarStyle() { + const { disappearDelayHide, appearDelayWidth, percent } = this.state; + + return { + width: appearDelayWidth ? 0 : percent * 100 + '%', + display: disappearDelayHide || percent > 0 ? 'block' : 'none' + }; + }, + + getShadowStyle() { + const { percent, disappearDelayHide } = this.state; + + return { + display: disappearDelayHide || percent > 0 ? 'block' : 'none' + }; + }, + + render() { + return ( + <div className="LoadingBar"> + <div className="LoadingBar-Bar" style={this.getBarStyle()}> + <div className="LoadingBar-Shadow" + style={this.getShadowStyle()}> + </div> + </div> + </div> + ); + } +}); + +function calculatePercent(percent) { + percent = percent || 0; + + // How much of remaining bar we advance + const progress = 0.1 + Math.random() * 0.3; + + return percent + progress * (1 - percent); +} + +module.exports = LoadingBar; diff --git a/packages/gitbook-plugin-theme-default/src/components/Theme.js b/packages/gitbook-plugin-theme-default/src/components/Theme.js index bf00502..741b3cc 100644 --- a/packages/gitbook-plugin-theme-default/src/components/Theme.js +++ b/packages/gitbook-plugin-theme-default/src/components/Theme.js @@ -3,6 +3,7 @@ const { React } = GitBook; const Sidebar = require('./Sidebar'); const Body = require('./Body'); +const LoadingBar = require('./LoadingBar'); const Theme = React.createClass({ propTypes: { @@ -10,16 +11,18 @@ const Theme = React.createClass({ page: GitBook.Shapes.Page, summary: GitBook.Shapes.Summary, readme: GitBook.Shapes.Readme, + history: GitBook.Shapes.History, sidebar: React.PropTypes.object, // Other props children: React.PropTypes.node }, render() { - const { page, summary, children, sidebar, readme } = this.props; + const { page, summary, children, sidebar, readme, history } = this.props; return ( <GitBook.FlexLayout column className="GitBook book"> + <LoadingBar show={history.loading} /> <GitBook.Head title={page.title} titleTemplate="%s - GitBook" /> @@ -43,6 +46,6 @@ const Theme = React.createClass({ } }); -module.exports = GitBook.connect(Theme, ({page, summary, sidebar, readme}) => { - return { page, summary, sidebar, readme }; +module.exports = GitBook.connect(Theme, ({page, summary, sidebar, readme, history}) => { + return { page, summary, sidebar, readme, history }; }); |