2019-06-11 17:00:02 +08:00
|
|
|
import React from 'react';
|
2019-04-30 11:11:25 +08:00
|
|
|
import NotFound from '../../src/components/404';
|
|
|
|
import Layout from '../../src/components/Layout';
|
|
|
|
import AsideNav from '../../src/components/AsideNav';
|
|
|
|
import {AlertComponent, ToastComponent} from '../../src/components/index';
|
2019-09-09 00:53:39 +08:00
|
|
|
import {mapTree} from '../../src/utils/helper';
|
2020-06-15 14:50:45 +08:00
|
|
|
import {Icon} from '../../src/components/icons';
|
2020-06-02 20:41:51 +08:00
|
|
|
import '../../src/locale/en';
|
2019-11-07 10:41:14 +08:00
|
|
|
import {
|
|
|
|
Router,
|
|
|
|
Route,
|
|
|
|
IndexRoute,
|
|
|
|
browserHistory,
|
|
|
|
hashHistory,
|
|
|
|
Link,
|
|
|
|
Redirect,
|
|
|
|
withRouter
|
|
|
|
} from 'react-router';
|
2019-04-30 11:11:25 +08:00
|
|
|
import Select from '../../src/components/Select';
|
2019-06-04 16:24:09 +08:00
|
|
|
import DocSearch from './DocSearch';
|
2020-07-23 20:31:51 +08:00
|
|
|
import {groupBy} from 'lodash';
|
|
|
|
import classnames from 'classnames';
|
2020-07-24 17:20:08 +08:00
|
|
|
import Doc, {docs} from './Doc';
|
|
|
|
import Example, {examples} from './Example';
|
2019-04-30 11:11:25 +08:00
|
|
|
|
|
|
|
let PathPrefix = '/examples';
|
2019-06-04 20:13:40 +08:00
|
|
|
let ContextPath = '';
|
2019-04-30 11:11:25 +08:00
|
|
|
|
2019-05-09 19:40:59 +08:00
|
|
|
if (process.env.NODE_ENV === 'production') {
|
2019-11-07 10:41:14 +08:00
|
|
|
PathPrefix = '';
|
|
|
|
ContextPath = '/amis';
|
2019-05-09 19:40:59 +08:00
|
|
|
}
|
|
|
|
|
2019-04-30 11:11:25 +08:00
|
|
|
const themes = [
|
2019-11-07 10:41:14 +08:00
|
|
|
{
|
|
|
|
label: '默认主题',
|
|
|
|
ns: 'a-',
|
|
|
|
value: 'default'
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
label: '百度云舍',
|
|
|
|
ns: 'cxd-',
|
|
|
|
value: 'cxd'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'Dark',
|
|
|
|
ns: 'dark-',
|
|
|
|
value: 'dark'
|
|
|
|
}
|
2019-04-30 11:11:25 +08:00
|
|
|
];
|
|
|
|
|
2020-06-02 20:41:51 +08:00
|
|
|
const locales = [
|
|
|
|
{
|
2020-07-23 20:31:51 +08:00
|
|
|
label: '中文',
|
2020-06-02 20:41:51 +08:00
|
|
|
value: 'zh-cn'
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
label: 'English',
|
|
|
|
value: 'en'
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
2019-05-20 12:03:25 +08:00
|
|
|
@withRouter
|
2019-04-30 11:11:25 +08:00
|
|
|
export class App extends React.PureComponent {
|
2019-11-07 10:41:14 +08:00
|
|
|
state = {
|
|
|
|
asideFolded: localStorage.getItem('asideFolded') === 'true',
|
|
|
|
offScreen: false,
|
|
|
|
headerVisible: true,
|
|
|
|
themeIndex: 0,
|
|
|
|
themes: themes,
|
2020-06-02 20:41:51 +08:00
|
|
|
theme: themes[localStorage.getItem('themeIndex') || 0],
|
2020-07-23 20:31:51 +08:00
|
|
|
locale: localStorage.getItem('locale') || '',
|
2020-07-28 18:23:02 +08:00
|
|
|
navigations: [],
|
|
|
|
scrollTop: 0
|
2019-11-07 10:41:14 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.toggleAside = this.toggleAside.bind(this);
|
|
|
|
this.setAsideFolded = this.setAsideFolded.bind(this);
|
|
|
|
this.setHeaderVisible = this.setHeaderVisible.bind(this);
|
2020-07-24 17:20:08 +08:00
|
|
|
this.setNavigations = this.setNavigations.bind(this);
|
2019-11-07 10:41:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
if (this.state.theme.value !== 'default') {
|
|
|
|
document.querySelectorAll('link[title]').forEach(item => {
|
|
|
|
item.disabled = true;
|
|
|
|
});
|
|
|
|
document.querySelector(
|
|
|
|
`link[title=${this.state.theme.value}]`
|
|
|
|
).disabled = false;
|
2020-07-29 20:25:04 +08:00
|
|
|
|
|
|
|
if (this.state.theme.value === 'dark') {
|
|
|
|
document.querySelector('body').classList.add('dark');
|
|
|
|
}
|
2019-11-07 10:41:14 +08:00
|
|
|
}
|
2020-07-28 18:23:02 +08:00
|
|
|
document.addEventListener('scroll', this.handleScroll.bind(this));
|
2019-11-07 10:41:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate(preProps, preState) {
|
|
|
|
const props = this.props;
|
|
|
|
|
|
|
|
if (preState.theme.value !== this.state.theme.value) {
|
|
|
|
document.querySelector(
|
|
|
|
`link[title=${preState.theme.value}]`
|
|
|
|
).disabled = true;
|
|
|
|
document.querySelector(
|
|
|
|
`link[title=${this.state.theme.value}]`
|
|
|
|
).disabled = false;
|
2019-09-09 00:53:39 +08:00
|
|
|
}
|
2019-04-30 11:11:25 +08:00
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
if (props.location.pathname !== preProps.location.pathname) {
|
|
|
|
this.setState(
|
|
|
|
{
|
|
|
|
offScreen: false
|
|
|
|
},
|
|
|
|
() => window.scrollTo(0, 0)
|
|
|
|
);
|
|
|
|
|
|
|
|
const pageURL = props.location.pathname;
|
|
|
|
_hmt && _hmt.push(['_trackPageview', pageURL]);
|
2019-09-09 00:53:39 +08:00
|
|
|
}
|
2019-11-07 10:41:14 +08:00
|
|
|
}
|
2019-04-30 11:11:25 +08:00
|
|
|
|
2020-07-28 18:23:02 +08:00
|
|
|
componentWillUnmount() {
|
|
|
|
document.removeEventListener('scroll', this.handleScroll.bind(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
handleScroll(e) {
|
|
|
|
this.setState({
|
|
|
|
scrollTop: e.target.scrollingElement.scrollTop
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
toggleAside() {
|
|
|
|
this.setAsideFolded(!this.state.asideFolded);
|
|
|
|
}
|
2019-05-20 12:03:25 +08:00
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
setAsideFolded(folded = false) {
|
|
|
|
localStorage.setItem('asideFolded', JSON.stringify(folded));
|
|
|
|
this.setState({
|
|
|
|
asideFolded: folded
|
|
|
|
});
|
|
|
|
}
|
2019-05-20 12:03:25 +08:00
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
setHeaderVisible(visible = false) {
|
|
|
|
this.setState({
|
|
|
|
headerVisible: visible
|
|
|
|
});
|
|
|
|
}
|
2019-04-30 11:11:25 +08:00
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
renderAside() {
|
|
|
|
return (
|
|
|
|
<AsideNav
|
2020-07-23 20:31:51 +08:00
|
|
|
renderLink={() => {
|
|
|
|
return null;
|
2019-11-07 10:41:14 +08:00
|
|
|
}}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-07-24 17:20:08 +08:00
|
|
|
setNavigations(items) {
|
|
|
|
this.setState({
|
|
|
|
navigations: items
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
toggleOpen(e, item) {
|
|
|
|
e.stopPropagation();
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
const navigations = mapTree(this.state.navigations, i => {
|
|
|
|
const defaultOpen =
|
|
|
|
i.isOpen ??
|
|
|
|
(Array.isArray(i.children) &&
|
|
|
|
i.children.length &&
|
|
|
|
!!~i.children.findIndex(item => item.path === location.pathname));
|
|
|
|
return {
|
|
|
|
...i,
|
|
|
|
isOpen: item.label === i.label ? !defaultOpen : defaultOpen
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
navigations
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
renderHeader() {
|
|
|
|
const location = this.props.location;
|
|
|
|
const theme = this.state.theme;
|
|
|
|
|
|
|
|
if (location.pathname === '/edit') {
|
|
|
|
return (
|
|
|
|
<div id="headerBar" className="box-shadow bg-dark">
|
|
|
|
<div className={`${theme.ns}Layout-brand`}>AMis 可视化编辑器</div>
|
|
|
|
</div>
|
|
|
|
);
|
2019-09-09 00:53:39 +08:00
|
|
|
}
|
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
return (
|
2020-07-23 20:31:51 +08:00
|
|
|
<>
|
2019-11-07 10:41:14 +08:00
|
|
|
<div className={`${theme.ns}Layout-brandBar`}>
|
2020-07-29 19:35:01 +08:00
|
|
|
{/* <button
|
2019-11-07 10:41:14 +08:00
|
|
|
onClick={() => this.setState({offScreen: !this.state.offScreen})}
|
|
|
|
className="pull-right visible-xs"
|
|
|
|
>
|
|
|
|
<i className="glyphicon glyphicon-align-justify" />
|
2020-07-29 19:35:01 +08:00
|
|
|
</button> */}
|
2020-07-23 20:31:51 +08:00
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
<div className={`${theme.ns}Layout-brand`}>
|
|
|
|
<i className="fa fa-paw" />
|
2020-07-23 20:31:51 +08:00
|
|
|
<span className="hidden-folded m-l-sm">AMIS</span>
|
2019-11-07 10:41:14 +08:00
|
|
|
</div>
|
|
|
|
</div>
|
2019-09-09 00:53:39 +08:00
|
|
|
|
2020-07-23 20:31:51 +08:00
|
|
|
<div className={`${theme.ns}Layout-headerBar`}>
|
|
|
|
<ul className={`${theme.ns}Layout-headerBar-links pull-left`}>
|
2020-07-24 17:20:08 +08:00
|
|
|
<Link to="/docs" activeClassName="is-active">
|
|
|
|
文档
|
|
|
|
</Link>
|
|
|
|
<Link to="/examples" activeClassName="is-active">
|
|
|
|
示例
|
|
|
|
</Link>
|
2020-07-23 20:31:51 +08:00
|
|
|
</ul>
|
|
|
|
|
|
|
|
<div className="hidden-xs p-t pull-right m-l-sm">
|
|
|
|
<Select
|
|
|
|
clearable={false}
|
|
|
|
theme={this.state.theme.value}
|
|
|
|
value={this.state.locale || 'zh-cn'}
|
|
|
|
options={locales}
|
|
|
|
onChange={locale => {
|
|
|
|
this.setState({locale: locale.value});
|
|
|
|
localStorage.setItem('locale', locale.value);
|
|
|
|
}}
|
|
|
|
/>
|
2020-06-02 20:41:51 +08:00
|
|
|
</div>
|
|
|
|
|
2020-07-23 20:31:51 +08:00
|
|
|
<div className="hidden-xs p-t pull-right">
|
|
|
|
<Select
|
|
|
|
clearable={false}
|
|
|
|
theme={this.state.theme.value}
|
|
|
|
value={this.state.theme}
|
|
|
|
options={this.state.themes}
|
|
|
|
onChange={theme => {
|
|
|
|
this.setState({theme});
|
|
|
|
localStorage.setItem(
|
|
|
|
'themeIndex',
|
|
|
|
this.state.themes.indexOf(theme)
|
|
|
|
);
|
2020-07-29 20:25:04 +08:00
|
|
|
document
|
|
|
|
.querySelector('body')
|
|
|
|
.classList[theme.value === 'dark' ? 'add' : 'remove']('dark');
|
2020-07-23 20:31:51 +08:00
|
|
|
}}
|
|
|
|
/>
|
2019-11-07 10:41:14 +08:00
|
|
|
</div>
|
2020-07-29 19:35:01 +08:00
|
|
|
</div>
|
|
|
|
<div className={`${theme.ns}Layout-searchBar`}>
|
2019-11-07 10:41:14 +08:00
|
|
|
<DocSearch theme={this.state.theme.value} />
|
|
|
|
</div>
|
2020-07-23 20:31:51 +08:00
|
|
|
</>
|
2019-11-07 10:41:14 +08:00
|
|
|
);
|
|
|
|
}
|
2019-04-30 11:11:25 +08:00
|
|
|
|
2020-07-24 17:20:08 +08:00
|
|
|
renderNavigation(navs, parent?: any) {
|
|
|
|
const pathname = location.pathname;
|
|
|
|
return navs.map(nav => {
|
|
|
|
const path = nav.path;
|
|
|
|
const hasChildren = Array.isArray(nav.children) && nav.children.length;
|
|
|
|
const isOpen =
|
|
|
|
nav.isOpen ||
|
|
|
|
(nav.isOpen !== false &&
|
|
|
|
hasChildren &&
|
|
|
|
!!~nav.children.findIndex(item => item.path === pathname));
|
2020-07-23 20:31:51 +08:00
|
|
|
|
|
|
|
return (
|
|
|
|
<div
|
2020-07-24 17:20:08 +08:00
|
|
|
key={nav.label}
|
2020-07-23 20:31:51 +08:00
|
|
|
className={classnames('Doc-navigation-item', {
|
|
|
|
'is-active': path === location.pathname,
|
|
|
|
'is-top': !parent,
|
2020-07-24 17:20:08 +08:00
|
|
|
'is-open': isOpen
|
2020-07-23 20:31:51 +08:00
|
|
|
})}
|
|
|
|
>
|
2020-07-28 14:55:49 +08:00
|
|
|
<Link
|
|
|
|
onClick={e => {
|
|
|
|
browserHistory.push(
|
|
|
|
`${path || (hasChildren && nav.children[0].path)}`
|
|
|
|
);
|
2020-07-29 15:33:25 +08:00
|
|
|
!isOpen && this.toggleOpen(e, nav);
|
2020-07-28 14:55:49 +08:00
|
|
|
}}
|
|
|
|
// to={`${path || (hasChildren && nav.children[0].path)}`}
|
|
|
|
>
|
2020-07-24 17:20:08 +08:00
|
|
|
{nav.label}
|
2020-07-23 20:31:51 +08:00
|
|
|
{hasChildren ? (
|
|
|
|
<i
|
2020-07-30 10:18:04 +08:00
|
|
|
className={`iconfont icon-xialajiantou ${
|
2020-07-24 17:20:08 +08:00
|
|
|
isOpen ? '' : 'is-flipped'
|
2020-07-23 20:31:51 +08:00
|
|
|
}`}
|
2020-07-24 17:20:08 +08:00
|
|
|
onClick={e => this.toggleOpen(e, nav)}
|
2020-07-23 20:31:51 +08:00
|
|
|
></i>
|
|
|
|
) : null}
|
|
|
|
</Link>
|
|
|
|
|
2020-07-24 17:20:08 +08:00
|
|
|
{isOpen
|
|
|
|
? this.renderNavigation(nav.children || [], {
|
|
|
|
...nav,
|
2020-07-23 20:31:51 +08:00
|
|
|
path
|
|
|
|
})
|
|
|
|
: null}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
render() {
|
|
|
|
const theme = this.state.theme;
|
2020-07-24 17:20:08 +08:00
|
|
|
const navigations = this.state.navigations;
|
2020-07-23 20:31:51 +08:00
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
return (
|
|
|
|
<Layout
|
|
|
|
theme={theme.value}
|
2020-07-23 20:31:51 +08:00
|
|
|
boxed={true}
|
2019-11-07 10:41:14 +08:00
|
|
|
offScreen={this.state.offScreen}
|
|
|
|
header={this.state.headerVisible ? this.renderHeader() : null}
|
2020-07-23 20:31:51 +08:00
|
|
|
// folded={this.state.asideFolded}
|
|
|
|
// aside={this.renderAside()}
|
2019-11-07 10:41:14 +08:00
|
|
|
>
|
2020-06-02 20:41:51 +08:00
|
|
|
<ToastComponent theme={theme.value} locale={this.state.locale} />
|
|
|
|
<AlertComponent theme={theme.value} locale={this.state.locale} />
|
2020-07-23 20:31:51 +08:00
|
|
|
|
|
|
|
<div className="Doc">
|
|
|
|
<div className="Doc-nav">
|
|
|
|
<div className="Doc-navigation">
|
2020-07-24 17:20:08 +08:00
|
|
|
{navigations.map(item => (
|
|
|
|
<div className="Doc-navigationGroup" key={item.label}>
|
2020-07-23 20:31:51 +08:00
|
|
|
<div className="Doc-navigationGroup-name">
|
2020-07-24 17:20:08 +08:00
|
|
|
{item.label || '其他'}
|
2020-07-23 20:31:51 +08:00
|
|
|
</div>
|
2020-07-24 17:20:08 +08:00
|
|
|
{this.renderNavigation(item.children)}
|
2020-07-23 20:31:51 +08:00
|
|
|
</div>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2020-07-28 18:23:02 +08:00
|
|
|
{/* 完了加个动画吧 */}
|
|
|
|
<div
|
|
|
|
className={`Backtop ${this.state.scrollTop > 450 ? 'visible' : ''}`}
|
|
|
|
onClick={() => scrollTo({top: 0})}
|
|
|
|
>
|
|
|
|
<i className="fa fa-rocket"></i>
|
|
|
|
</div>
|
|
|
|
|
2020-07-23 20:31:51 +08:00
|
|
|
{React.cloneElement(this.props.children, {
|
|
|
|
...this.props.children.props,
|
2020-07-24 17:20:08 +08:00
|
|
|
setNavigations: this.setNavigations,
|
2020-07-23 20:31:51 +08:00
|
|
|
setAsideFolded: this.setAsideFolded,
|
|
|
|
setHeaderVisible: this.setHeaderVisible,
|
|
|
|
theme: theme.value,
|
|
|
|
classPrefix: theme.ns,
|
|
|
|
locale: this.state.locale
|
|
|
|
})}
|
|
|
|
</div>
|
2019-11-07 10:41:14 +08:00
|
|
|
</Layout>
|
|
|
|
);
|
|
|
|
}
|
2019-09-09 00:53:39 +08:00
|
|
|
}
|
2019-04-30 11:11:25 +08:00
|
|
|
|
2020-07-24 17:20:08 +08:00
|
|
|
function navigations2route(pathPrefix = PathPrefix, navigations) {
|
2019-11-07 10:41:14 +08:00
|
|
|
let routes = [];
|
|
|
|
|
|
|
|
navigations.forEach(root => {
|
|
|
|
root.children &&
|
|
|
|
mapTree(root.children, item => {
|
|
|
|
if (item.path && item.component) {
|
|
|
|
routes.push(
|
|
|
|
<Route
|
|
|
|
key={routes.length + 1}
|
|
|
|
path={
|
|
|
|
item.path[0] === '/'
|
|
|
|
? ContextPath + item.path
|
|
|
|
: `${ContextPath}${pathPrefix}/${item.path}`
|
|
|
|
}
|
|
|
|
component={item.component}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
} else if (item.path && item.getComponent) {
|
|
|
|
routes.push(
|
|
|
|
<Route
|
|
|
|
key={routes.length + 1}
|
|
|
|
path={
|
|
|
|
item.path[0] === '/'
|
|
|
|
? ContextPath + item.path
|
|
|
|
: `${ContextPath}${pathPrefix}/${item.path}`
|
|
|
|
}
|
|
|
|
getComponent={item.getComponent}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2019-04-30 11:11:25 +08:00
|
|
|
|
2019-11-07 10:41:14 +08:00
|
|
|
return routes;
|
2019-09-09 00:53:39 +08:00
|
|
|
}
|
2019-04-30 11:11:25 +08:00
|
|
|
|
2019-09-09 00:53:39 +08:00
|
|
|
export default function entry({pathPrefix}) {
|
2019-11-07 10:41:14 +08:00
|
|
|
PathPrefix = pathPrefix || PathPrefix;
|
|
|
|
return (
|
2020-07-24 17:20:08 +08:00
|
|
|
<Router history={browserHistory}>
|
2019-11-07 10:41:14 +08:00
|
|
|
<Route component={App}>
|
2020-07-29 15:33:25 +08:00
|
|
|
<Redirect from={`${ContextPath}/`} to={`${ContextPath}/docs/index`} />
|
2020-07-24 17:20:08 +08:00
|
|
|
<Redirect from={`/examples`} to={`/examples/pages/simple`} />
|
2020-07-28 10:03:53 +08:00
|
|
|
<Redirect from={`/docs`} to={`/docs/index`} />
|
|
|
|
|
2020-07-24 17:20:08 +08:00
|
|
|
<Route path="/docs" component={Doc}>
|
|
|
|
{navigations2route('/docs', docs)}
|
|
|
|
</Route>
|
|
|
|
<Route path="/examples" component={Example}>
|
|
|
|
{navigations2route('/examples', examples)}
|
|
|
|
</Route>
|
2019-11-07 10:41:14 +08:00
|
|
|
</Route>
|
2020-07-24 17:20:08 +08:00
|
|
|
|
|
|
|
<Route path="*" component={NotFound} />
|
2019-11-07 10:41:14 +08:00
|
|
|
</Router>
|
|
|
|
);
|
2019-09-09 00:53:39 +08:00
|
|
|
}
|