mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-06 00:44:17 +08:00
site: SSR for official website (#3903)
* site: ssr for Layout * site: SSR for site * fix: ssr for Anchor * chore: add ssr test * chore: update deploy script * site: udpate detail * site: revert animation for site * site: fix loading animation
This commit is contained in:
parent
34f353deb0
commit
4ee2b9d930
@ -87,6 +87,10 @@ class AnchorHelper {
|
||||
|
||||
getCurrentAnchor(bounds = 5) {
|
||||
let activeAnchor = '';
|
||||
if (typeof document === 'undefined') {
|
||||
return activeAnchor;
|
||||
}
|
||||
|
||||
this.links.forEach(section => {
|
||||
const target = document.getElementById(section.substring(1));
|
||||
if (target) {
|
||||
|
19
package.json
19
package.json
@ -79,6 +79,10 @@
|
||||
"@types/react": "~0.14.41",
|
||||
"@types/react-dom": "~0.14.18",
|
||||
"antd-tools": "0.14.2",
|
||||
"babel-cli": "^6.18.0",
|
||||
"babel-preset-es2015": "^6.18.0",
|
||||
"babel-preset-react": "^6.16.0",
|
||||
"babel-preset-stage-0": "^6.16.0",
|
||||
"babel-eslint": "^7.1.0",
|
||||
"babel-jest": "^17.0.0",
|
||||
"babel-plugin-import": "^1.0.0",
|
||||
@ -131,8 +135,15 @@
|
||||
"typescript-babel-jest": "^0.1.5",
|
||||
"values.js": "^1.0.3"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"es2015",
|
||||
"react",
|
||||
"stage-0"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"test": "npm run lint && npm run dist && npm run jest",
|
||||
"test": "npm run lint && npm run dist && npm run jest && npm run site",
|
||||
"lint": "npm run tslint && npm run eslint && npm run demolint && npm run lesshint",
|
||||
"tslint": "antd-tools run ts-lint && npm run compile && rm -rf lib",
|
||||
"eslint": "eslint test site scripts ./.eslintrc.js ./webpack.config.js --ext '.js,.jsx,.tsx' --ignore-pattern '!.eslintrc.js'",
|
||||
@ -147,8 +158,10 @@
|
||||
"compile": "antd-tools run compile && node ./tests/dekko/lib.test.js",
|
||||
|
||||
"start": "bisheng start -c ./site/bisheng.config.js --no-livereload",
|
||||
"site": "bisheng build -c ./site/bisheng.config.js",
|
||||
"deploy": "npm run clean && bisheng gh-pages -c ./site/bisheng.config.js",
|
||||
"babel-site": "babel ./site/theme/template --out-dir ./site/theme/template",
|
||||
"clean-site": "rm site/theme/template/**/*.js site/theme/template/*.js",
|
||||
"site": "npm run babel-site && bisheng build --ssr -c ./site/bisheng.config.js && npm run clean-site",
|
||||
"deploy": "npm run clean && npm run site && bisheng gh-pages --push-only",
|
||||
|
||||
"pub": "antd-tools run update-self && antd-tools run pub",
|
||||
"prepublish": "antd-tools run guard",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import appLocaleData from 'react-intl/locale-data/en';
|
||||
const appLocaleData = require('react-intl/locale-data/en');
|
||||
|
||||
module.exports = {
|
||||
locale: 'en-US',
|
||||
|
@ -101,8 +101,11 @@ div.main-container {
|
||||
animation: loadTween 2s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
|
||||
}
|
||||
}
|
||||
#react-content:empty + .ant-site-loading {
|
||||
opacity: 1;
|
||||
#react-content[hidden] {
|
||||
display: none;
|
||||
+ .ant-site-loading {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#loading-text {
|
||||
|
@ -1 +1,2 @@
|
||||
import 'react-github-button/assets/style.css';
|
||||
import './index.less';
|
||||
|
@ -24,24 +24,28 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="react-content"></div>
|
||||
<div class="ant-site-loading" id="ant-site-loading">
|
||||
<img src='https://t.alipayobjects.com/images/rmsweb/T1B9hfXcdvXXXXXXXX.svg'/>
|
||||
<div id="loading-text">One Design Language</div>
|
||||
</div>
|
||||
<script>
|
||||
<div id="react-content" hidden>
|
||||
{{ content | safe }}
|
||||
</div>
|
||||
<div class="ant-site-loading" id="ant-site-loading">
|
||||
<img src='https://t.alipayobjects.com/images/rmsweb/T1B9hfXcdvXXXXXXXX.svg'/>
|
||||
<div id="loading-text">One Design Language</div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
var content = document.getElementById('loading-text');
|
||||
content.innerHTML = content.innerHTML.split('').map(function (letter, i) {
|
||||
var className;
|
||||
if (i > 0 && i < content.innerText.length - 1) {
|
||||
className = 'yoyo-x-' + (i % 6);
|
||||
}
|
||||
if (letter.trim() === '') {
|
||||
className += ' blank';
|
||||
}
|
||||
return '<span class="' + className + '">' + letter + '</span>';
|
||||
}).join('');
|
||||
if (content) {
|
||||
content.innerHTML = content.innerHTML.split('').map(function (letter, i) {
|
||||
var className;
|
||||
if (i > 0 && i < content.innerText.length - 1) {
|
||||
className = 'yoyo-x-' + (i % 6);
|
||||
}
|
||||
if (letter.trim() === '') {
|
||||
className += ' blank';
|
||||
}
|
||||
return '<span class="' + className + '">' + letter + '</span>';
|
||||
}).join('');
|
||||
}
|
||||
})();
|
||||
|
||||
// Enable Google Analytics
|
||||
@ -62,8 +66,8 @@
|
||||
ga('send', 'pageview');
|
||||
/* eslint-enable */
|
||||
}
|
||||
</script>
|
||||
<script src="{{ root }}common.js"></script>
|
||||
<script src="{{ root }}index.js"></script>
|
||||
</script>
|
||||
<script src="{{ root }}common.js"></script>
|
||||
<script src="{{ root }}index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -9,7 +9,7 @@ import config from '../../';
|
||||
const SubMenu = Menu.SubMenu;
|
||||
|
||||
function getActiveMenuItem(props) {
|
||||
return props.params.children || props.location.pathname;
|
||||
return props.params.children || props.location.pathname.replace(/^\//, '');
|
||||
}
|
||||
|
||||
function fileNameToPath(filename) {
|
||||
@ -120,8 +120,8 @@ export default class MainContent extends React.Component {
|
||||
|
||||
getModuleData(props) {
|
||||
const pathname = props.location.pathname;
|
||||
const moduleName = /^components/.test(pathname) ?
|
||||
'components' : pathname.split('/').slice(0, 2).join('/');
|
||||
const moduleName = /^\/?components/.test(pathname) ?
|
||||
'components' : pathname.split('/').filter(item => item).slice(0, 2).join('/');
|
||||
const moduleData = moduleName === 'components' || moduleName === 'changelog' || moduleName === 'docs/react' ?
|
||||
[...props.picked.components, ...props.picked['docs/react'], ...props.picked.changelog] :
|
||||
props.picked[moduleName];
|
||||
|
@ -5,7 +5,7 @@ import * as utils from '../utils';
|
||||
|
||||
const locale = utils.isZhCN() ? 'zh-CN' : 'en-US';
|
||||
export function collect(nextProps, callback) {
|
||||
const pageData = nextProps.location.pathname === 'changelog' ?
|
||||
const pageData = nextProps.location.pathname.endsWith('changelog') ?
|
||||
nextProps.data.CHANGELOG : nextProps.pageData;
|
||||
if (!pageData) {
|
||||
callback(404, nextProps);
|
||||
|
@ -3,7 +3,6 @@ import { Link } from 'react-router';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ScrollElement from 'rc-scroll-anim/lib/ScrollElement';
|
||||
import GitHubButton from 'react-github-button';
|
||||
import 'react-github-button/assets/style.css';
|
||||
import { Icon } from 'antd';
|
||||
import QueueAnim from 'rc-queue-anim';
|
||||
|
||||
|
@ -6,8 +6,8 @@ import ScrollOverPack from 'rc-scroll-anim/lib/ScrollOverPack';
|
||||
import { Icon, Button } from 'antd';
|
||||
import QueueAnim from 'rc-queue-anim';
|
||||
|
||||
const clientHeight = document.documentElement.clientHeight;
|
||||
function onScrollEvent(e) {
|
||||
const clientHeight = document.documentElement.clientHeight;
|
||||
const header = document.getElementById('header');
|
||||
if (e.pageY >= clientHeight) {
|
||||
if (header.className.indexOf('home-nav-bottom') < 0) {
|
||||
|
@ -30,8 +30,10 @@ class Footer extends React.Component {
|
||||
// 大版本发布后全局弹窗提示
|
||||
// 1. 点击『知道了』之后不再提示
|
||||
// 2. 超过截止日期后不再提示
|
||||
if (localStorage.getItem('antd@2.0.0-notification-sent') !== 'true' &&
|
||||
Date.now() < new Date('2016/10/14').getTime()) {
|
||||
if (
|
||||
localStorage.getItem('antd@2.0.0-notification-sent') !== 'true' &&
|
||||
Date.now() < new Date('2016/10/14').getTime()
|
||||
) {
|
||||
this.infoNewVersion();
|
||||
}
|
||||
}
|
||||
@ -65,9 +67,8 @@ class Footer extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const options = Object.keys(docVersions).map(version => (
|
||||
<Option value={docVersions[version]} key={version}>{version}</Option>
|
||||
));
|
||||
const options = Object.keys(docVersions)
|
||||
.map(version => <Option value={docVersions[version]} key={version}>{version}</Option>);
|
||||
return (
|
||||
<footer id="footer">
|
||||
<ul>
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import React, { PropTypes } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import enquire from 'enquire.js';
|
||||
import classNames from 'classnames';
|
||||
import { Select, Menu, Row, Col, Icon, Button, Popover } from 'antd';
|
||||
|
||||
@ -9,27 +8,26 @@ const Option = Select.Option;
|
||||
|
||||
export default class Header extends React.Component {
|
||||
static contextTypes = {
|
||||
router: React.PropTypes.object.isRequired,
|
||||
intl: React.PropTypes.object.isRequired,
|
||||
router: PropTypes.object.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
menuMode: 'horizontal',
|
||||
};
|
||||
}
|
||||
state = {
|
||||
menuMode: 'horizontal',
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
enquire.register('only screen and (min-width: 320px) and (max-width: 940px)', {
|
||||
match: () => {
|
||||
this.setState({ menuMode: 'inline' });
|
||||
},
|
||||
unmatch: () => {
|
||||
this.setState({ menuMode: 'horizontal' });
|
||||
},
|
||||
});
|
||||
/* eslint-disable global-require */
|
||||
require('enquire.js')
|
||||
.register('only screen and (min-width: 320px) and (max-width: 940px)', {
|
||||
match: () => {
|
||||
this.setState({ menuMode: 'inline' });
|
||||
},
|
||||
unmatch: () => {
|
||||
this.setState({ menuMode: 'horizontal' });
|
||||
},
|
||||
});
|
||||
/* eslint-enable global-require */
|
||||
}
|
||||
|
||||
handleSearch = (value) => {
|
||||
@ -51,7 +49,7 @@ export default class Header extends React.Component {
|
||||
render() {
|
||||
const { location, picked, isFirstScreen } = this.props;
|
||||
const components = picked.components;
|
||||
const module = location.pathname.replace(/\/$/, '').split('/').slice(0, -1).join('/');
|
||||
const module = location.pathname.replace(/(^\/|\/$)/g, '').split('/').slice(0, -1).join('/');
|
||||
let activeMenuItem = module || 'home';
|
||||
if (activeMenuItem === 'components' || location.pathname === 'changelog') {
|
||||
activeMenuItem = 'docs/react';
|
||||
@ -67,8 +65,8 @@ export default class Header extends React.Component {
|
||||
const subtitle = meta.subtitle;
|
||||
return (
|
||||
<Option value={url} key={url} data-label={`${meta.title.toLowerCase()} ${subtitle || ''}`}>
|
||||
<strong>{meta.title}</strong>
|
||||
{subtitle && <span className="ant-component-decs">{subtitle}</span>}
|
||||
<strong>{meta.title}</strong>
|
||||
{subtitle && <span className="ant-component-decs">{subtitle}</span>}
|
||||
</Option>
|
||||
);
|
||||
});
|
||||
|
@ -8,12 +8,17 @@ import Footer from './Footer';
|
||||
import enLocale from '../../en-US';
|
||||
import cnLocale from '../../zh-CN';
|
||||
import * as utils from '../utils';
|
||||
import '../../static/style';
|
||||
|
||||
// Expose to iframe
|
||||
window.react = React;
|
||||
window['react-dom'] = ReactDOM;
|
||||
window.antd = require('antd');
|
||||
if (typeof window !== 'undefined') {
|
||||
/* eslint-disable global-require */
|
||||
require('../../static/style');
|
||||
|
||||
// Expose to iframe
|
||||
window.react = React;
|
||||
window['react-dom'] = ReactDOM;
|
||||
window.antd = require('antd');
|
||||
/* eslint-enable global-require */
|
||||
}
|
||||
|
||||
const appLocale = utils.isZhCN() ? cnLocale : enLocale;
|
||||
addLocaleData(appLocale.data);
|
||||
@ -23,12 +28,9 @@ export default class Layout extends React.Component {
|
||||
router: React.PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isFirstScreen: true,
|
||||
};
|
||||
}
|
||||
state = {
|
||||
isFirstScreen: true,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if (typeof ga !== 'undefined') {
|
||||
@ -43,6 +45,7 @@ export default class Layout extends React.Component {
|
||||
loadingNode.parentNode.removeChild(loadingNode);
|
||||
}, 450);
|
||||
}
|
||||
document.getElementById('react-content').removeAttribute('hidden');
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -20,6 +20,10 @@ export function getMenuItems(moduleData, locale) {
|
||||
}
|
||||
|
||||
export function isZhCN() {
|
||||
if (typeof location === 'undefined') {
|
||||
// Use English in SSR.
|
||||
return false;
|
||||
}
|
||||
if (location.search.indexOf('locale=zh-CN') > -1) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import appLocaleData from 'react-intl/locale-data/zh';
|
||||
const appLocaleData = require('react-intl/locale-data/zh');
|
||||
|
||||
module.exports = {
|
||||
locale: 'zh-CN',
|
||||
|
Loading…
Reference in New Issue
Block a user