diff --git a/components/animate/index.md b/components/animate/index.md
index e6a46574..6e372f5f 100644
--- a/components/animate/index.md
+++ b/components/animate/index.md
@@ -1,5 +1,4 @@
---
-category: Components
order: 1
chinese: Css样式动画
english: Animate
diff --git a/components/banner-anim/index.md b/components/banner-anim/index.md
index 6cc47e50..ca276ce0 100644
--- a/components/banner-anim/index.md
+++ b/components/banner-anim/index.md
@@ -1,5 +1,4 @@
---
-category: Components
order: 4
chinese: Banner动画
english: BannerAnim
diff --git a/components/icon-anim/index.md b/components/icon-anim/index.md
index 7a8f581a..c2d96ac5 100644
--- a/components/icon-anim/index.md
+++ b/components/icon-anim/index.md
@@ -1,5 +1,4 @@
---
-category: Components
order: 5
chinese: Icon 动画
disabled: true
diff --git a/components/queue-anim/index.md b/components/queue-anim/index.md
index fbd55b1e..24523103 100644
--- a/components/queue-anim/index.md
+++ b/components/queue-anim/index.md
@@ -1,5 +1,4 @@
---
-category: Components
chinese: 进出场动画
cols: 2
order: 2
diff --git a/components/scroll-anim/index.md b/components/scroll-anim/index.md
index 3b8f8795..db93c8f6 100644
--- a/components/scroll-anim/index.md
+++ b/components/scroll-anim/index.md
@@ -1,5 +1,4 @@
---
-category: Components
chinese: 页面滚动动画
order: 3
english: ScrollAnim
diff --git a/components/tween-one/demo/position.md b/components/tween-one/demo/position.md
index 71715cc6..ec621f6d 100644
--- a/components/tween-one/demo/position.md
+++ b/components/tween-one/demo/position.md
@@ -4,7 +4,7 @@ title: 基本动画效果
mouseEnter: true
---
-鼠标经过或手指按下可查看位移效果。如 x, y, z, scale, rotate, blur, marign等, 更多参数参考 [动画述语里](language/animate-term);
+鼠标经过或手指按下可查看位移效果。如 x, y, z, scale, rotate, blur, marign等, 更多参数参考 [动画术语](language/animate-term);
```jsx
diff --git a/components/tween-one/index.md b/components/tween-one/index.md
index af6511ba..255cc409 100644
--- a/components/tween-one/index.md
+++ b/components/tween-one/index.md
@@ -1,5 +1,4 @@
---
-category: Components
chinese: 单元素动画
order: 0
english: TweenOne
diff --git a/language/animate-term.md b/language/animate-term.md
index 86fb787c..ab2898d4 100644
--- a/language/animate-term.md
+++ b/language/animate-term.md
@@ -39,7 +39,7 @@ english: animate term
| borderWidth | `{ borderWidth: 2 }` 元素当前边框宽度到 2px,同样可用 `borderTopWidth` `borderRightWidth` `borderBottomWidth` `borderLeftWidth` |
| borderRadius | `{ borderRadius: 5 }` 元素当前圆角到 5px, 同上, 同样可用 `上 左 下 右` |
| borderColor | `{ borderColor: '#FFFFFF' }` 元素当前边框颜色到白色 |
-| boxShadow | `{ boxShadow: '0 0 10px #000' }` 元素当前阴影模糊到 10px |
+| boxShadow | `{ boxShadow: '0 0 10px #000' }` 元素当前阴影模糊到 10px |
| textShadow | `{ textShadow: '0 0 10px #000' }` 元素当前文字内容阴影模糊到 10px |
## transform 参数
diff --git a/language/aware.md b/language/aware.md
index 193bae7d..1da5d754 100644
--- a/language/aware.md
+++ b/language/aware.md
@@ -3,6 +3,7 @@ order: 5
chinese: 改善感知
disabled: true
english: Aware
+category: 设计语言
---
diff --git a/language/basic.md b/language/basic.md
index d9c1b273..e979bc17 100644
--- a/language/basic.md
+++ b/language/basic.md
@@ -6,38 +6,63 @@ english: Basic
Ant Motion 在界面里主要是来加强体验舒适度、描述层级关系、增加界面活力、反馈与意向等功能性的动效。
-## 主要原则
+### 动效重要性
-- 基本动画,动效的重要性与有意义的动效。
+- 让界面里的元素更加自然,贴近我们现实生活。
-- 时间栅格与缓动
+- 第一时间吸引注意力,突出重点。
-- 层级空间
+- 体现元素之间的层级与空间关系。
-- 巧用过渡
+- 提供反馈、体现意向性,增强用户操作感。
-- 增加示意
+### 有意义动效
-- 改善感知
+衡量一个动效是否有意义,我们以以下几个标准来考核:
-## 动效重要性
+- 添加动效后是否会提高产品的可用性,必须带有明确的目的性,提升用户的舒适度,不做多余或炫技的动效。
-- 让界面里的元素更加自然,贴近我们现实生活。
+- 以提升产品界面的灵动性、独特的气质和带入感,独特的动效可增强用户对产品的认知和情绪的带入。
-- 第一时间吸引注意力,突出重点。
+- 添加动效后是否影响到性能,保持 FPS 的稳定性,要求在 30 以上,不出现大幅度波动丢帧或者卡顿现象, 动效过渡必须流畅。
-- 体现元素之间的层级与空间关系。
-- 提供反馈、体现意向性,增强用户操作感。
+## 主要原则
+在 Ant Design 的中后台产品,让我们联想到的三个条件:
-## 有意义动效
+- 动效能够快速的完成;
+- 确定性非常强;
+- 幅度不能太大;
-衡量一个动效是否有意义,我们以以下几个标准来考核:
+所以在 Ant Design 的设计原则上再总结出三个动效原则: 自然,高效,克制。
-- 添加动效后是否影响到性能,保持 FPS 的稳定性,要求在 30 以上,不出现大幅度波动或者卡顿现象。
+```__react
+import Principle from '../src/theme/template/other/Principle';
+ReactDOM.render(, mountNode);
+```
-- 添加动效后是否会提高产品的可用性,必须带有明确的目的性,提升用户的舒适度,不做多余或炫技的动效。
+## 自然
-- 以提升产品界面的灵动性、独特的气质和带入感,独特的动效可增强用户对产品的认知和情绪的带入。
+自然原则里,根据现实物理原理,我们总结出了 4 个动效语言, 详细可点击左侧菜单查看。
+
+- 时间栅格
+
+- 层级空间
+
+- 巧用过渡
+
+- 增加示意
+
+## 高效
+
+在中后台里,我们在动画的过渡需要尽量节省时间,快速而确定性的去完成动画过渡效果,在理想的情况下,用户应当在 100 毫秒内得到操作的反馈,因为人体最快的潜意识动作 -- 一次眨眼的平均持续时间为 100 到 150 毫秒,100 毫秒的间隔给人的感觉就是瞬间。
+
+所以在 Ant Design 组件里,我们同样采用了以 100 毫秒为单位,下图为 ant deisgn 的组件动画时间用时。
+
+
+
+## 克制
+- 做最适合的动画,让元素在完成使命的同时尽量的不去做太多的修饰和干扰用户。
+- 在保证自然度的前提下,降底动效的幅度,在不经意间完成指定的效果。
\ No newline at end of file
diff --git a/language/interact.md b/language/interact.md
index 2c2f9d33..78132c59 100644
--- a/language/interact.md
+++ b/language/interact.md
@@ -2,12 +2,9 @@
order: 4
chinese: 增强示意
english: Interact
+category: 设计语言
---
-
-
将用户操作可视化, 来增强用户对操作行为的感知度, 同时也能对元素内容的认知;
## 操作后所发生的事件
diff --git a/language/space.md b/language/space.md
index 78646a42..e9ce2b5d 100644
--- a/language/space.md
+++ b/language/space.md
@@ -2,15 +2,12 @@
order: 2
chinese: 层级空间
english: Space
+category: 设计语言
---
+现实空间里,物体存在远小近大的原则,运动则有远慢近快;例如汽车在公路上行驶,离汽车越近的物体,移动速度越接近汽车的速率。所以以汽车点为X轴原点,那离原点越远Z轴越大时,速度就越慢。
-
-动效设计中存在Z轴向的空间距离来影响动画效果
-
-现实空间里,物体存在远小近大的原则,运动则有远慢近快;
-
-如汽车在公路上行驶,离汽车越近的物体,移动速度越接近汽车的速率。所以以汽车点为X轴原点,那离原点越远Z轴越大时,速度就越慢。
+那么动效设计中同样存在这个原则,Z轴向的空间距离来影响动画效果,可以使用时间的快慢或幅度的大小来体现。
## 空间示意图
@@ -27,3 +24,9 @@ english: Space
如果 banner 里加入跟随鼠标移动,加入空间层次,有效的给每层元素不同的参数,就能摸拟现实的视差效果。
+
+### 动态效果
+
+此效果由 banner-anim 实现。
+
+
\ No newline at end of file
diff --git a/language/time.md b/language/time.md
index 717ce8ac..1d2d609b 100644
--- a/language/time.md
+++ b/language/time.md
@@ -1,13 +1,27 @@
---
order: 1
chinese: 时间栅格
-index: true
english: Time
+category: 设计语言
---
+时间栅格是将每个动画的 timeline 栅格化,在动画的指定时间里,每个时间段的一个拆分;
+比如:一秒有30帧的动画,那么这动画就是由 30 张图片组成,只是每张图片里的元素指定的参数不同, 如下图:
-物体运动在时间栅格中具有不同运动速率和出场,动画停止与启动都不是瞬间完成的,因它需要一段缓冲的时间来加速或减速,因此当物体突然移动或停止,会显的很不自然。
+
+
![](https://gw.alipayobjects.com/zos/rmsportal/eZpnsUOxqIQZrAVEgbPC.png)
+
+
+结合自然运动的规律,那物体运动在时间栅格中具有不同运动速率和出场,动画停止与启动都不是瞬间完成的,当物体突然移动或停止,会显的很不自然,因它需要一段缓冲的时间来加速或减速,如下图:
+
+
+
![](https://gw.alipayobjects.com/zos/rmsportal/kbTlqDaubwgsBKFNoyGF.png)
+
+
+## 自然运动效果
+
+具体效果,可查看以下示例,鼠标 hover 时自动播放动画。
```__react
import EaseExplain from '../src/theme/template/other/EaseExplain';
@@ -48,6 +62,8 @@ ReactDOM.render(, mountNode);
```
+> 需要注意:是离开可视窗口,如果在窗口中消失的,建议使用前后缓动,同理窗口中出现也一样。
+
```__react
import QueueDemo from '../src/theme/template/other/QueueDemo';
ReactDOM.render(, mountNode);
diff --git a/language/transition.md b/language/transition.md
index 28e11fc7..d4fd9686 100644
--- a/language/transition.md
+++ b/language/transition.md
@@ -2,6 +2,7 @@
order: 3
chinese: 巧用过渡
english: Transition
+category: 设计语言
---
diff --git a/package.json b/package.json
index 5a5a3167..51faa80f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ant-motion",
- "version": "1.5.2",
+ "version": "1.6.0",
"dependencies": {
"antd": "~3.6.2",
"deepcopy": "^0.6.3",
@@ -14,11 +14,11 @@
"raw-js-loader": "^1.4.0",
"raw-loader": "^0.5.1",
"rc-animate": "~2.4.4",
- "rc-banner-anim": "~1.0.0",
- "rc-drawer": "^1.2.0",
+ "rc-banner-anim": "~2.0.0",
+ "rc-drawer": "^1.5.0",
"rc-queue-anim": "~1.6.0",
"rc-scroll-anim": "~2.5.0",
- "rc-tween-one": "~2.0.6",
+ "rc-tween-one": "~2.1.0",
"react": "^16.4.0",
"react-color": "^2.13.8",
"react-copy-to-clipboard": "~5.0.0",
diff --git a/src/theme/static/common.less b/src/theme/static/common.less
index 67822261..6fb9069a 100644
--- a/src/theme/static/common.less
+++ b/src/theme/static/common.less
@@ -118,13 +118,13 @@ body {
width: 100%;
}
-.content-wrapper>.tween-one-leaving,
+/* .content-wrapper>.tween-one-leaving,
.page-content>.tween-one-leaving,
.content-wrapper>.tween-one-entering,
.page-content>.tween-one-entering {
overflow: hidden;
height: 100vh;
-}
+} */
.home .queue-anim-leaving {
position: relative !important;
diff --git a/src/theme/static/page.less b/src/theme/static/page.less
index 4a885315..7579e4f1 100644
--- a/src/theme/static/page.less
+++ b/src/theme/static/page.less
@@ -4,18 +4,19 @@
margin-top: 64px;
}
-.@{contentPage} {
+.@{contentPage}-wrapper {
width: 100%;
overflow: hidden;
position: relative;
- &-nav {
+ .@{contentPage}-nav {
background: #fff;
box-shadow: 0 1px 0 #EEE;
overflow: hidden;
height: 80px;
position: relative;
& ul {
- max-width: 960px;
+ max-width: 1200px;
+ padding: 0 24px;
margin: auto;
position: relative;
& li {
@@ -63,41 +64,29 @@
}
}
}
- &-wrapper {
- width: 95%;
+ .@{contentPage} {
+ width: 100%;
border-radius: 6px;
- max-width: 1024px;
+ max-width: 1200px;
min-height: 800px;
- margin: 60px auto 0;
+ padding: 64px 24px 0;
+ margin: auto;
position: relative;
- &>section {
+ & .page-content-wrapper {
+ padding: 0 0 64px 64px;
+ border-left: 1px solid @line-color;
+ }
+ & .page-content {
position: relative;
- width: 100%;
- padding-left: 200px;
- padding-bottom: 60px;
- &:before {
- content: '';
- display: block;
- width: 1px;
- height: 100%;
- position: absolute;
- left: 150px;
- background: @line-color;
- }
- & .page-content {
- position: relative;
- }
}
}
}
.nav-list {
&-wrapper {
- width: 150px;
- position: absolute;
- z-index: 1;
- float: left;
height: 100%;
+ position: relative;
+ z-index: 1;
li {
&[disabled] {
cursor: not-allowed;
@@ -107,14 +96,14 @@
}
}
a {
- line-height: 30px;
- height: 30px;
display: block;
font-size: 14px;
- color: @text-color;
+ // color: @text-color;
+ overflow: hidden;
+ text-overflow: ellipsis;
transition: color @animate-duration @ease-out;
&:hover {
- color: @primary-color;
+ // color: @primary-color;
}
}
&.active a {
@@ -124,25 +113,29 @@
}
h2 {
font-size: 16px;
- margin-bottom: 10px;
+ margin-bottom: 32px;
position: absolute;
+ padding-left: 16px;
}
- ul {
- top: 30px;
+ >ul {
+ top: 48px;
position: absolute;
- >li {
- overflow: hidden;
- position: relative;
- z-index: 1;
- i {
- margin-left: 6px;
- opacity: .67;
- font-style: normal;
- font-size: 12px;
- }
- >div>ul {
- margin-left: 16px;
- }
+ }
+ .ant-menu-inline .ant-menu-item,
+ .ant-menu-inline .ant-menu-submenu-title {
+ width: ~"calc(100% + 1px)";
+ }
+ .ant-menu {
+ background: transparent;
+ &.ant-menu-inline {
+ border-right: none;
+ }
+ .ant-menu-item-selected {
+ background-color: transparent;
+ }
+ .ant-menu-item {
+ line-height: 32px;
+ height: 32px;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/theme/static/responsive.less b/src/theme/static/responsive.less
index 71b12d27..a7c304c4 100644
--- a/src/theme/static/responsive.less
+++ b/src/theme/static/responsive.less
@@ -110,8 +110,8 @@
top: 40%;
}
}
- .page {
- &-text {
+ .page-wrapper {
+ .page-text {
margin: auto;
}
.list-bg {
@@ -129,13 +129,11 @@
pointer-events: auto;
}
}
- &-wrapper {
- width: 90%;
- >section {
+ .page {
+ width: 100%;
+ .page-content-wrapper {
padding-left: 0;
- &:before {
- display: none;
- }
+ border: none;
}
}
}
@@ -145,12 +143,9 @@
justify-content: center;
}
.nav-list {
- display: inline-block;
&-wrapper {
width: 180px;
position: relative;
- float: left;
- text-align: center;
}
h2,
ul {
@@ -159,17 +154,9 @@
h2 {
line-height: 32px;
margin: 40px auto 20px;
- i {
- float: right;
- line-height: 32px;
- }
}
ul {
top: 0;
- li a {
- height: 36px;
- line-height: 36px;
- }
}
}
}
diff --git a/src/theme/template/Content/Page.jsx b/src/theme/template/Content/Page.jsx
index 3ea0c74e..59e110ee 100644
--- a/src/theme/template/Content/Page.jsx
+++ b/src/theme/template/Content/Page.jsx
@@ -3,16 +3,23 @@ import PropTypes from 'prop-types';
import { TweenOneGroup } from 'rc-tween-one';
import QueueAnim from 'rc-queue-anim';
import { Link } from 'react-router';
-import { Affix } from 'antd';
+import { Affix, Row, Col, Menu } from 'antd';
import MobileMenu from 'rc-drawer';
import nav from '../Layout/nav';
-import { scrollClick } from '../utils';
+import { scrollClick, getMenuItems } from '../utils';
+
+const { SubMenu, Item, ItemGroup } = Menu;
const title = {};
nav.forEach((item) => {
title[item.key] = item.name;
});
+function fileNameToPath(filename) {
+ const snippets = filename.replace(/(\/index)?((\.zh-CN)|(\.en-US))?\.md$/i, '').split('/');
+ return snippets[snippets.length - 1];
+}
+
class Page extends React.PureComponent {
static propTypes = {
className: PropTypes.string,
@@ -86,11 +93,12 @@ class Page extends React.PureComponent {
return moduleData;
};
+
getMenuItems(moduleData, pathNames, isComponent, isNav) {
if (!moduleData) {
return null;
}
- const splicingListArr = [];
+ /* const splicingListArr = [];
if (pathNames[0] === 'cases') {
// { meta: { filename: 'cases/full', english: 'Full', chinese: '完整模板选择', order: 2 } }
splicingListArr.push({
@@ -99,52 +107,35 @@ class Page extends React.PureComponent {
},
});
}
- const children = moduleData.concat(splicingListArr).filter(item => !item.meta.hidden)
- .sort((a, b) => a.meta.order - b.meta.order);
- return children.map((item, i) => {
- const meta = item.meta;
- let link = meta.filename.replace(/(\/index)|(.md)/g, '');
- const path = Array.isArray(pathNames) ? pathNames.join('/') : pathNames.replace('#', '');
- const hash = this.state.isHash && this.hash.replace('#', '');
- const className = hash === meta.id || path === link ||
- (!hash && ((!path && i === 0) || path === meta.id)) ? 'active' : '';
- // api 页面,链接把 components 转成 api
- link = this.props.pathname.match('api') ? link.replace('components', 'api') : link;
- let linkToChildren = link.split('/')[1] === pathNames[1] ?
- (
- {isNav ? meta.chinese : {meta.chinese || meta.english}}
- ) :
- (
- {isNav ? meta.chinese : {meta.chinese || meta.english}}
- );
- linkToChildren = isComponent ?
- (
- {meta.title}
- ) : linkToChildren;
- return (
- {linkToChildren}
- );
- });
- }
-
- getTransitionEnd = () => {
- const transEndEventNames = {
- transition: 'transitionend',
- WebkitTransition: 'webkitTransitionEnd',
- MozTransition: 'transitionend',
- OTransition: 'oTransitionEnd otransitionend',
- };
- return Object.keys(transEndEventNames).map((name) => {
- if (typeof document.body.style[name] === 'string') {
- return transEndEventNames[name];
+ const menuData = getMenuItems(moduleData.concat(splicingListArr)
+ .filter(item => !item.meta.hidden));
+ */
+ const menuData = getMenuItems(moduleData.filter(item => !item.meta.hidden));
+ this.openKeys = [];
+ return menuData.map((menuItem) => {
+ if (!menuItem.children) {
+ return this.generateMenuItem(menuItem, pathNames, isComponent, isNav, menuData.length);
}
- return null;
- }).filter(item => item)[0];
+ this.openKeys.push(menuItem.title);
+ return (
+ {menuItem.title}} key={menuItem.title}>
+ {menuItem.children.map((child) => {
+ if (child.type === 'type') {
+ return (
+
+ {child.children.sort((a, b) => a.title.charCodeAt(0) - b.title.charCodeAt(0))
+ .map(leaf => this.generateMenuItem(
+ leaf, pathNames,
+ isComponent, isNav, menuData.length
+ ))}
+
+ );
+ }
+ return this.generateMenuItem(child, pathNames, isComponent, isNav, menuData.length);
+ })}
+
+ );
+ });
}
getListChildren = (cPathNames, cModuleData, isComponent) => {
@@ -169,6 +160,22 @@ class Page extends React.PureComponent {
const listKey = pathNames[0] === 'components' && !pathname.match('api') ?
pathname : pathNames[0];
+ const getHashActive = () => {
+ const hashArray = this.hash.replace('#', '').split('-');
+ return hashArray[hashArray.length - 1];
+ };
+ const activeMenuItem = this.state.isHash ? getHashActive() : pathNames[1];
+ const menu = (
+
+ );
return (!isMobile ? (listToRender && (
{isComponent ? '范例' : title[pathNames[0]]}
-
+ {menu}
)) :
(
@@ -190,15 +195,54 @@ class Page extends React.PureComponent {
{isApi ? 'API' : title[pathNames[0]]}
-
+ {menu}
));
}
+ generateMenuItem = (meta, pathNames, isComponent, isNav, length) => {
+ let link = meta.filename.replace(/(\/index)|(.md)/g, '');
+ // const path = Array.isArray(pathNames) ? pathNames.join('/') : pathNames.replace('#', '');
+ // const hash = this.state.isHash && this.hash.replace('#', '');
+ const key = fileNameToPath(meta.filename);
+ /* const className = hash === meta.id || path === link ||
+ (!hash && ((!path && i === 0) || path === meta.id)) ? 'active' : ''; */
+ // api 页面,链接把 components 转成 api
+ link = this.props.pathname.match('api') ? link.replace('components', 'api') : link;
+ let linkToChildren = link.split('/')[1] === pathNames[1] ?
+ (
+ {isNav ? meta.chinese : {meta.chinese || meta.english}}
+ ) :
+ (
+ {isNav ? meta.chinese : {meta.chinese || meta.english}}
+ );
+ linkToChildren = isComponent ?
+ (
+ {meta.title}
+ ) : linkToChildren;
+ if (isNav) {
+ return (
+
+ {linkToChildren}
+
+ );
+ }
+ return (-
+ {linkToChildren}
+
);
+ }
+
cScrollClick = (e) => {
e.preventDefault();
scrollClick(e);
@@ -218,7 +262,7 @@ class Page extends React.PureComponent {
pageData.components[pathNames[1]].index : pageData;
const childrenToRender = pathname.match('api') ?
React.cloneElement(children, { pageData: pageDataNew }) : children;
- return (
+ return (
{!isMobile && (
- {listToRender}
-
+
+ {listToRender}
+
+
{childrenToRender}
-
+
);
}
}
-
export default Page;
diff --git a/src/theme/template/Exhibition/Details.jsx b/src/theme/template/Exhibition/Details.jsx
index 911580ef..7472786a 100644
--- a/src/theme/template/Exhibition/Details.jsx
+++ b/src/theme/template/Exhibition/Details.jsx
@@ -48,8 +48,8 @@ export default class Details extends React.Component {
title, subtitle, chinese, english,
} = meta;
return (
-
-
+
+
{!this.state.replay && preview(React, ReactDOM)}
diff --git a/src/theme/template/Exhibition/index.jsx b/src/theme/template/Exhibition/index.jsx
index 7fb60ac9..8cdd5cd4 100644
--- a/src/theme/template/Exhibition/index.jsx
+++ b/src/theme/template/Exhibition/index.jsx
@@ -29,8 +29,8 @@ export default class Exhibition extends React.Component {
{title}
);
});
- return (
-
+ return (
+
(
+
+
+
{item.title}
+
{item.content}
+
+
+ ));
+ return (
+
+ {childrenToRender}
+
+ );
+ }
+}
diff --git a/src/theme/template/other/principle.less b/src/theme/template/other/principle.less
new file mode 100644
index 00000000..100fa50c
--- /dev/null
+++ b/src/theme/template/other/principle.less
@@ -0,0 +1,25 @@
+@import "../../static/custom";
+
+.principle-wrapper {
+ width: 100%;
+ .principle {
+ width: 100%;
+ min-height: 180px;
+ display: inline-block;
+ margin-right: 12.5%;
+ text-align: center;
+ font-size: 24px;
+ border-radius: 4px;
+ border: 1px solid @line-color;
+ &:last-child {
+ margin-right: 0;
+ }
+ h2 {
+ margin: 32px 0;
+ }
+ p {
+ font-size: 12px;
+ padding: 0 24px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/theme/template/utils.jsx b/src/theme/template/utils.jsx
index bfd9a6e6..efce3fe7 100644
--- a/src/theme/template/utils.jsx
+++ b/src/theme/template/utils.jsx
@@ -42,3 +42,42 @@ export function scrollClick(e) {
scrollTo(toTop);
}
}
+
+const themeConfig = {
+ categoryOrder: {
+ 基本原则: 0,
+ 设计语言: 1,
+ 动画术语: 2,
+ },
+};
+
+export function getMenuItems(moduleData) {
+ const menuMeta = moduleData.map(item => item.meta);
+ const menuItems = [];
+ const sortFn = (a, b) => (a.order || 0) - (b.order || 0);
+ menuMeta.sort(sortFn).forEach((meta) => {
+ if (!meta.category) {
+ menuItems.push(meta);
+ } else {
+ const category = meta.category;
+ let group = menuItems.filter(i => i.title === category)[0];
+ if (!group) {
+ group = {
+ type: 'category',
+ title: category,
+ children: [],
+ order: themeConfig.categoryOrder[category],
+ };
+ menuItems.push(group);
+ }
+ group.children.push(meta);
+ }
+ });
+ return menuItems.map((i) => {
+ const item = i;
+ if (item.children) {
+ item.children = item.children.sort(sortFn);
+ }
+ return item;
+ }).sort(sortFn);
+}