Port scroll improvements
This commit is contained in:
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset='utf-8' />
|
<meta charset='utf-8' />
|
||||||
<meta http-equiv='X-UA-Compatible' content='IE=11' />
|
<meta http-equiv='X-UA-Compatible' content='IE=11' />
|
||||||
<title>Mapbox</title>
|
<title>Docbox</title>
|
||||||
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
|
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
|
||||||
<link href='css/base.css' rel='stylesheet' />
|
<link href='css/base.css' rel='stylesheet' />
|
||||||
<link href='css/style.css' rel='stylesheet' />
|
<link href='css/style.css' rel='stylesheet' />
|
||||||
|
@ -68,25 +68,40 @@ var App = React.createClass({
|
|||||||
},
|
},
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.mediaQueryChanged();
|
this.mediaQueryChanged();
|
||||||
|
this.onScroll = debounce(this._onScroll, 100);
|
||||||
|
document.addEventListener('scroll', this.onScroll);
|
||||||
|
this._onScroll();
|
||||||
|
},
|
||||||
|
_onScroll() {
|
||||||
|
var sections = document.querySelectorAll('div.section');
|
||||||
|
if (!sections.length) return;
|
||||||
|
for (var i = 0; i < sections.length; i++) {
|
||||||
|
var rect = sections[i].getBoundingClientRect();
|
||||||
|
if (rect.bottom > 0) {
|
||||||
|
this.setState({
|
||||||
|
activeSection: sections[i].title
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mediaQueryChanged() {
|
mediaQueryChanged() {
|
||||||
var queries = {
|
this.setState({
|
||||||
mobile: this.state.mqls.mobile.matches,
|
queries: {
|
||||||
tablet: this.state.mqls.tablet.matches,
|
mobile: this.state.mqls.mobile.matches,
|
||||||
desktop: this.state.mqls.desktop.matches
|
tablet: this.state.mqls.tablet.matches,
|
||||||
};
|
desktop: this.state.mqls.desktop.matches
|
||||||
this.setState({ queries });
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
Object.keys(this.state.mqls).forEach(key =>
|
Object.keys(this.state.mqls).forEach(key =>
|
||||||
this.state.mqls[key].removeListener(this.mediaQueryChanged));
|
this.state.mqls[key].removeListener(this.mediaQueryChanged));
|
||||||
|
document.body.removeEventListener('scroll', this.onScroll);
|
||||||
},
|
},
|
||||||
onChangeLanguage(language) {
|
onChangeLanguage(language) {
|
||||||
this.setState({ language });
|
this.setState({ language });
|
||||||
},
|
},
|
||||||
onSpy(activeSection) {
|
|
||||||
this.setState({ activeSection });
|
|
||||||
},
|
|
||||||
componentDidUpdate(_, prevState) {
|
componentDidUpdate(_, prevState) {
|
||||||
if (prevState.activeSection !== this.state.activeSection) {
|
if (prevState.activeSection !== this.state.activeSection) {
|
||||||
// when the section changes, replace the hash
|
// when the section changes, replace the hash
|
||||||
@ -127,7 +142,6 @@ var App = React.createClass({
|
|||||||
<Content
|
<Content
|
||||||
ast={ast}
|
ast={ast}
|
||||||
queries={queries}
|
queries={queries}
|
||||||
onSpy={this.onSpy}
|
|
||||||
language={this.state.language}/>
|
language={this.state.language}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -143,10 +157,10 @@ var App = React.createClass({
|
|||||||
|
|
||||||
{/* Header */ }
|
{/* Header */ }
|
||||||
<div className={`fill-gray fixed-top ${queries.tablet ? 'pad1y pad2x col6' : 'pad0 width16'}`}>
|
<div className={`fill-gray fixed-top ${queries.tablet ? 'pad1y pad2x col6' : 'pad0 width16'}`}>
|
||||||
<a href='/' className='active space-top1 space-left1 pin-topleft icon round fill-red dark pad0'></a>
|
<a href='/' className='active space-top1 space-left1 pin-topleft icon round fill-blue dark pad0 mapbox'></a>
|
||||||
<div className={`strong small pad0 ${queries.mobile && 'space-left3'} ${queries.tablet ? 'space-left2' : 'space-left4 line-height15' }`}>
|
<div className={`strong small pad0 ${queries.mobile && 'space-left3'} ${queries.tablet ? 'space-left2' : 'space-left4 line-height15' }`}>
|
||||||
{queries.desktop ? 'Example API Documentation' :
|
{queries.desktop ? 'API Documentation' :
|
||||||
queries.mobile ? 'API Docs' : 'Example API Docs'}
|
queries.mobile ? 'API Docs' : 'API Docs'}
|
||||||
</div>
|
</div>
|
||||||
{queries.tablet && <div>
|
{queries.tablet && <div>
|
||||||
<button
|
<button
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Section from './section';
|
import Section from './section';
|
||||||
import PureRenderMixin from 'react-pure-render/mixin';
|
import PureRenderMixin from 'react-pure-render/mixin';
|
||||||
|
import GithubSlugger from 'github-slugger';
|
||||||
|
let slugger = new GithubSlugger();
|
||||||
|
let slug = title => { slugger.reset(); return slugger.slug(title); };
|
||||||
|
|
||||||
function highlightTokens(str) {
|
function highlightTokens(str) {
|
||||||
return str.replace(/{[\w_]+}/g,
|
return str.replace(/{[\w_]+}/g,
|
||||||
@ -92,7 +95,7 @@ function chunkifyAST(ast, language) {
|
|||||||
left.push(node);
|
left.push(node);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { left, right, title, preview };
|
return { left, right, title, preview, slug: slug(title) };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,13 +103,11 @@ var Content = React.createClass({
|
|||||||
mixins: [PureRenderMixin],
|
mixins: [PureRenderMixin],
|
||||||
propTypes: {
|
propTypes: {
|
||||||
ast: React.PropTypes.object.isRequired,
|
ast: React.PropTypes.object.isRequired,
|
||||||
language: React.PropTypes.string.isRequired,
|
language: React.PropTypes.string.isRequired
|
||||||
onSpy: React.PropTypes.func.isRequired
|
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
return (<div className='clearfix'>
|
return (<div className='clearfix'>
|
||||||
{chunkifyAST(this.props.ast, this.props.language).map((chunk, i) => <Section
|
{chunkifyAST(this.props.ast, this.props.language).map((chunk, i) => <Section
|
||||||
onSpy={this.props.onSpy}
|
|
||||||
chunk={chunk}
|
chunk={chunk}
|
||||||
key={i} />)}
|
key={i} />)}
|
||||||
</div>);
|
</div>);
|
||||||
|
@ -2,7 +2,6 @@ import React from 'react';
|
|||||||
import remark from 'remark';
|
import remark from 'remark';
|
||||||
import remarkHTML from 'remark-html';
|
import remarkHTML from 'remark-html';
|
||||||
import remarkHighlight from 'remark-highlight.js';
|
import remarkHighlight from 'remark-highlight.js';
|
||||||
import Waypoint from 'react-waypoint';
|
|
||||||
import PureRenderMixin from 'react-pure-render/mixin';
|
import PureRenderMixin from 'react-pure-render/mixin';
|
||||||
|
|
||||||
function renderHighlighted(nodes) {
|
function renderHighlighted(nodes) {
|
||||||
@ -22,33 +21,20 @@ function renderHighlighted(nodes) {
|
|||||||
var Section = React.createClass({
|
var Section = React.createClass({
|
||||||
mixins: [PureRenderMixin],
|
mixins: [PureRenderMixin],
|
||||||
propTypes: {
|
propTypes: {
|
||||||
chunk: React.PropTypes.object.isRequired,
|
chunk: React.PropTypes.object.isRequired
|
||||||
onSpy: React.PropTypes.func.isRequired
|
|
||||||
},
|
|
||||||
waypointEnterFromAbove(e, direction) {
|
|
||||||
if (direction === 'above') {
|
|
||||||
this.props.onSpy(this.props.chunk.title);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
waypointEnterFromBelow(e, direction) {
|
|
||||||
if (direction === 'below') {
|
|
||||||
this.props.onSpy(this.props.chunk.title);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
let { chunk } = this.props;
|
let { chunk } = this.props;
|
||||||
let { left, right, preview } = chunk;
|
let { left, right, preview } = chunk;
|
||||||
return (<div className={`contain clearfix ${preview ? 'preview' : ''}`}>
|
return (<div
|
||||||
<Waypoint onEnter={this.waypointEnterFromBelow} />
|
title={chunk.title}
|
||||||
|
className={`section pad2y contain clearfix ${preview ? 'preview' : ''}`}>
|
||||||
<div
|
<div
|
||||||
className='col6 pad2x prose clip'
|
className='col6 pad2x prose clip'
|
||||||
dangerouslySetInnerHTML={renderHighlighted(left)} />
|
dangerouslySetInnerHTML={renderHighlighted(left)} />
|
||||||
{(right.length > 0) && <div
|
{right.length > 0 && <div
|
||||||
className='col6 pad2 prose dark space-top5 clip keyline-top fill-dark'
|
className='col6 pad2 prose dark space-top5 clip keyline-top fill-dark'
|
||||||
dangerouslySetInnerHTML={renderHighlighted(right)} />}
|
dangerouslySetInnerHTML={renderHighlighted(right)} />}
|
||||||
<div className='pin-bottom'>
|
|
||||||
<Waypoint onEnter={this.waypointEnterFromAbove} />
|
|
||||||
</div>
|
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user