Browse Source

docs: Site with single paging (#21360)

* patch route

* use data for promise

* rename Article file

* Article in TS

* clean up

* use collect

* adjust css

* card it

* listing

* res

* hiring

* add footer

* english it

* rm others

* fix lint

* fix navigation

* add dropdown button

* Header with TS

* split input & logo

* navigation out

* use flex

* flex everything

* stretch

* hide search when narrow

* init category

* global rules

* more cat

* pages

* level 2 width

* level 3

* level 4

* skip before ready

* clean up

* unqiue shadow variable

* update eslintignore

* update ignore

* fix ssr

* fix location param

* replace images

* shake more

* fix top of navigation

* remove home

* reorder nav & adjust padding style

* narrow res style

* Update research-form-page.zh-CN.md (#21426)

Co-authored-by: Golevka <huangsamfisher@163.com>

* rm skip

* narrow merge in

* reset p style

* update svg

* fix lint

* update ignore

* update lint ignore

* Update research-result-page.zh-CN.md (#21432)

Co-authored-by: mihaideyu <zxy1010414746@163.com>

* Update research-result-page.zh-CN.md

* Update research-workbench.zh-CN.md (#21438)

Co-authored-by: yingxirz <inseeing@gmail.com>

* Update research-workbench.zh-CN.md

* Update research-list-page.zh-CN.md (#21441)

Co-authored-by: yingxirz <inseeing@gmail.com>

* Update research-list-page.zh-CN.md

* padding use 40px

* add responsive of ref

* fix p margin

* Update research-workbench.zh-CN.md

* Update buttons.md (#21456)

Co-authored-by: yingxirz <inseeing@gmail.com>

* Update resources.en-US.md (#21457)

* Update research-navigation.zh-CN.md (#21453)

* Update research-navigation.zh-CN.md

* Update research-navigation.zh-CN.md

* Update research-navigation.zh-CN.md

* Update research-empty.zh-CN.md (#21451)

* Update research-empty.zh-CN.md

* Update research-empty.zh-CN.md

* Update research-empty.zh-CN.md

* Update research-empty.zh-CN.md

Co-authored-by: 二货机器人 <smith3816@gmail.com>

* Update research-exception-page.zh-CN.md (#21452)

* Update research-exception-page.zh-CN.md

* Update research-exception-page.zh-CN.md

* Update research-message-and-feedback.zh-CN.md (#21463)

* Update research-message-and-feedback.zh-CN.md (#21467)

* Update research-message-and-feedback.zh-CN.md

* Update research-message-and-feedback.zh-CN.md

* Update research-message-and-feedback.zh-CN.md

* Update research-message-and-feedback.zh-CN.md

* replace background

* fix lines margin

* home padding

* patch minTilda doc

* Update resources.zh-CN.md (#21503)

* clean up

* Update research-workbench.zh-CN.md (#21512)

Co-authored-by: yingxirz <inseeing@gmail.com>

* Update research-overview.zh-CN.md (#21513)

Co-authored-by: yingxirz <inseeing@gmail.com>

* Update research-result-page.zh-CN.md (#21514)

Co-authored-by: mihaideyu <zxy1010414746@163.com>

* Update research-list-page.zh-CN.md (#21515)

Co-authored-by: yingxirz <inseeing@gmail.com>

* fix doc

* Update research-message-and-feedback.zh-CN.md (#21516)

* adjust home nav width

* Update research-message-and-feedback.zh-CN.md (#21535)

* Update research-form-page.zh-CN.md (#21554)

Co-authored-by: Golevka <huangsamfisher@163.com>

* patch file

* clean up

* update shadow.zh-CN

update shadow.zh-CN

* add shadow table

* Update visual.zh-CN.md (#21577)

Co-authored-by: shuwenliu0116 <33922479+shuwenliu0116@users.noreply.github.com>

* Update docs/spec/shadow.zh-CN.md

Co-Authored-By: 偏右 <afc163@gmail.com>

* Update docs/spec/shadow.zh-CN.md

Co-Authored-By: 偏右 <afc163@gmail.com>

* Update docs/spec/shadow.zh-CN.md

Co-Authored-By: 偏右 <afc163@gmail.com>

* Update docs/spec/shadow.zh-CN.md

Co-Authored-By: 偏右 <afc163@gmail.com>

* Update docs/spec/shadow.zh-CN.md

Co-Authored-By: 偏右 <afc163@gmail.com>

* patch docs

* fix doc

* rm page suffix

* fix style

* mobile it

* Update resources.en-US.md (#21561)

* chart res

* add qr code

* adjust qr

* Update visual.zh-CN.md (#21603)

Co-authored-by: shuwenliu0116 <33922479+shuwenliu0116@users.noreply.github.com>

* fix site qr

* mobile height of it

* book update

* 3.x site link

* isMobile is new cnotext

* Update research-form.zh-CN.md (#21604)

Co-authored-by: Golevka <huangsamfisher@163.com>

* adjust form doc

* mobile use link

* adjust order

* flush

* fix ts

* Update research-navigation.zh-CN.md (#21606)

* Update research-navigation.zh-CN.md (#21609)

* rm useless lines

* add mobile icon

* Update research-exception.zh-CN.md (#21612)

* Update research-empty.zh-CN.md (#21610)

* Update research-workbench.zh-CN.md

* Update visual.zh-CN.md

* adjust mobile icon

* Update research-message-and-feedback.zh-CN.md (#21613)

* Update research-list.zh-CN.md (#21617)

Co-authored-by: yingxirz <inseeing@gmail.com>

* Update research-workbench.zh-CN.md (#21618)

Co-authored-by: yingxirz <inseeing@gmail.com>

* Update visual.zh-CN.md (#21619)

Co-authored-by: shuwenliu0116 <33922479+shuwenliu0116@users.noreply.github.com>

* Update research-result.zh-CN.md (#21620)

Co-authored-by: mihaideyu <zxy1010414746@163.com>

* Update research-form.zh-CN.md (#21615)

* Update research-message-and-feedback.zh-CN.md (#21616)

* Update research-list.zh-CN.md (#21621)

Co-authored-by: yingxirz <inseeing@gmail.com>

* Update research-result.zh-CN.md (#21624)

Co-authored-by: mihaideyu <zxy1010414746@163.com>

* update ref color

* update zip file

* fix mobile icon

* rm skip dark

* fix cat

* update zip link

* update zip link

Co-authored-by: Golevka <huangsamfisher@163.com>
Co-authored-by: mihaideyu <zxy1010414746@163.com>
Co-authored-by: yingxirz <inseeing@gmail.com>
Co-authored-by: 偏右 <afc163@gmail.com>
Co-authored-by: myeunhyuk <39618466+myeunhyuk@users.noreply.github.com>
Co-authored-by: minTilda <31951290+minTilda@users.noreply.github.com>
Co-authored-by: ziyuan-174774 <61226089+ziyuan-174774@users.noreply.github.com>
Co-authored-by: 竹尔 <54707870+AntDesigners@users.noreply.github.com>
Co-authored-by: shuwenliu0116 <33922479+shuwenliu0116@users.noreply.github.com>
pull/21642/head
二货机器人 5 years ago
committed by GitHub
parent
commit
afedb4127f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .eslintignore
  2. 4
      .github/PULL_REQUEST_TEMPLATE/pr_cn.md
  3. 6
      .gitignore
  4. 4
      README-zh_CN.md
  5. 4
      README.md
  6. 17
      azure-pipelines.yml
  7. 11
      components/upload/__tests__/upload.test.js
  8. 119
      docs/resources.en-US.md
  9. 181
      docs/resources.zh-CN.md
  10. 30
      docs/spec/article.en-US.md
  11. 31
      docs/spec/article.zh-CN.md
  12. 12
      docs/spec/buttons.md
  13. 5
      docs/spec/dark.md
  14. 113
      docs/spec/download.en-US.md
  15. 103
      docs/spec/download.zh-CN.md
  16. 1
      docs/spec/feedback.en-US.md
  17. 1
      docs/spec/feedback.zh-CN.md
  18. 1
      docs/spec/navigation.en-US.md
  19. 1
      docs/spec/navigation.zh-CN.md
  20. 80
      docs/spec/reference.en-US.md
  21. 87
      docs/spec/reference.zh-CN.md
  22. 9
      docs/spec/research-empty.en-US.md
  23. 78
      docs/spec/research-empty.zh-CN.md
  24. 7
      docs/spec/research-exception.en-US.md
  25. 130
      docs/spec/research-exception.zh-CN.md
  26. 7
      docs/spec/research-form.en-US.md
  27. 223
      docs/spec/research-form.zh-CN.md
  28. 7
      docs/spec/research-list.en-US.md
  29. 117
      docs/spec/research-list.zh-CN.md
  30. 9
      docs/spec/research-message-and-feedback.en-US.md
  31. 124
      docs/spec/research-message-and-feedback.zh-CN.md
  32. 9
      docs/spec/research-navigation.en-US.md
  33. 285
      docs/spec/research-navigation.zh-CN.md
  34. 8
      docs/spec/research-overview.en-US.md
  35. 9
      docs/spec/research-overview.zh-CN.md
  36. 7
      docs/spec/research-result.en-US.md
  37. 120
      docs/spec/research-result.zh-CN.md
  38. 7
      docs/spec/research-workbench.en-US.md
  39. 98
      docs/spec/research-workbench.zh-CN.md
  40. 6
      docs/spec/shadow.en-US.md
  41. 8
      docs/spec/shadow.md
  42. 344
      docs/spec/shadow.zh-CN.md
  43. 172
      docs/spec/visual.zh-CN.md
  44. 86
      docs/spec/work-with-us.en-US.md
  45. 65
      docs/spec/work-with-us.zh-CN.md
  46. 6
      site/bisheng.config.js
  47. 4
      site/theme/en-US.js
  48. 9
      site/theme/index.js
  49. 3
      site/theme/static/common.less
  50. 258
      site/theme/static/header.less
  51. 1
      site/theme/static/index.less
  52. 82
      site/theme/static/resource.less
  53. 65
      site/theme/static/responsive.less
  54. 75
      site/theme/template/Content/Article.tsx
  55. 7
      site/theme/template/Content/EditButton.tsx
  56. 221
      site/theme/template/Content/MainContent.jsx
  57. 24
      site/theme/template/Home/Banner/Background.tsx
  58. 35
      site/theme/template/Home/Banner/index.less
  59. 39
      site/theme/template/Home/Banner/index.tsx
  60. 3
      site/theme/template/Home/DesignPage/index.less
  61. 3
      site/theme/template/Home/MorePage.less
  62. 11
      site/theme/template/Home/index.less
  63. 343
      site/theme/template/Layout/Header.jsx
  64. 50
      site/theme/template/Layout/Header/Github.less
  65. 23
      site/theme/template/Layout/Header/Github.tsx
  66. 40
      site/theme/template/Layout/Header/Logo.less
  67. 15
      site/theme/template/Layout/Header/Logo.tsx
  68. 67
      site/theme/template/Layout/Header/More.tsx
  69. 86
      site/theme/template/Layout/Header/Navigation.less
  70. 102
      site/theme/template/Layout/Header/Navigation.tsx
  71. 133
      site/theme/template/Layout/Header/SearchBox.less
  72. 56
      site/theme/template/Layout/Header/SearchBox.tsx
  73. 54
      site/theme/template/Layout/Header/index.less
  74. 318
      site/theme/template/Layout/Header/index.tsx
  75. 3
      site/theme/template/Layout/Header/interface.tsx
  76. 11
      site/theme/template/Layout/SiteContext.tsx
  77. 94
      site/theme/template/Layout/index.jsx
  78. 35
      site/theme/template/Resources/AffixTabs.less
  79. 79
      site/theme/template/Resources/AffixTabs.tsx
  80. 137
      site/theme/template/Resources/index.less
  81. 152
      site/theme/template/Resources/index.tsx
  82. 4
      site/theme/template/utils.tsx
  83. 4
      site/theme/zh-CN.js
  84. 6
      typings/custom-typings.d.ts

5
.eslintignore

@ -10,7 +10,12 @@ site/theme/template/IconDisplay/*.jsx
site/theme/template/IconDisplay/fields.js
site/theme/template/Home/**/*.jsx
site/theme/template/utils.jsx
site/theme/template/Layout/**/*.jsx
site/theme/template/Layout/Footer.jsx
site/theme/template/Content/Article.jsx
site/theme/template/Content/EditButton.jsx
site/theme/template/Resources/*.jsx
site/theme/template/Resources/**/*.jsx
typings
es/**/*
lib/**/*

4
.github/PULL_REQUEST_TEMPLATE/pr_cn.md

@ -41,8 +41,8 @@
> 从用户角度描述具体变化,以及可能的 breaking change 和其他风险?
-->
| 语言 | 更新描述 |
| ------ | -------- |
| 语言 | 更新描述 |
| ------- | -------- |
| 🇺🇸 英文 | |
| 🇨🇳 中文 | |

6
.gitignore

@ -48,3 +48,9 @@ site/theme/template/IconDisplay/fields.js
site/theme/template/Home/**/*.jsx
site/theme/template/utils.jsx
site/theme/template/Layout/Footer.jsx
site/theme/template/Layout/Header/**/*.jsx
site/theme/template/Layout/SiteContext.jsx
site/theme/template/Content/Article.jsx
site/theme/template/Content/EditButton.jsx
site/theme/template/Resources/*.jsx
site/theme/template/Resources/**/*.jsx

4
README-zh_CN.md

@ -38,8 +38,8 @@
- [Electron](https://www.electronjs.org/)
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Electron |
| --------- | --------- | --------- | --------- | --------- |
| IE11, Edge| last 2 versions| last 2 versions| last 2 versions| last 2 versions
| --- | --- | --- | --- | --- |
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 📦 安装

4
README.md

@ -38,8 +38,8 @@ English | [Português](./README-pt_BR.md) | [简体中文](./README-zh_CN.md)
- [Electron](https://www.electronjs.org/)
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)<br>Electron |
| --------- | --------- | --------- | --------- | --------- |
| IE11, Edge| last 2 versions| last 2 versions| last 2 versions| last 2 versions
| --- | --- | --- | --- | --- |
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 📦 Install

17
azure-pipelines.yml

@ -42,3 +42,20 @@ stages:
export DEPLOY_DOMAIN=https://preview-${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}-ant-design.surge.sh
node ./scripts/azure-github-comment.js "[<img width="306" src="https://user-images.githubusercontent.com/5378891/72400743-23dbb200-3785-11ea-9d13-1a2d92743846.png">]($DEPLOY_DOMAIN)"
displayName: 'Update comment on github'
- job: Build_Site_Failed
dependsOn: Build_Site
condition: failed()
steps:
- checkout: self
displayName: 'Checkout'
clean: true
fetchDepth: 1
- task: NodeTool@0
displayName: 'Install Node.js'
inputs:
versionSpec: '12.13.1'
- script: npm install
displayName: 'Install modules'
- script: |
node ./scripts/azure-github-comment.js "[<img width="534" src="https://user-images.githubusercontent.com/5378891/75333447-1e63a280-58c1-11ea-975d-235367fd1522.png">](https://dev.azure.com/ant-design/ant-design/_build/results?buildId=$(Build.BuildId))"
displayName: 'Comment on github'

11
components/upload/__tests__/upload.test.js

@ -503,10 +503,13 @@ describe('Upload', () => {
});
it('it should be treated as file but not an image', () => {
const file = { status: 'done', uid: '-1', type: 'video/mp4', url: 'https://zos.alipayobjects.com/rmsportal/IQKRngzUuFzJzGzRJXUs.png' };
const wrapper = mount(
<Upload listType="picture-card" fileList={[file]} />,
);
const file = {
status: 'done',
uid: '-1',
type: 'video/mp4',
url: 'https://zos.alipayobjects.com/rmsportal/IQKRngzUuFzJzGzRJXUs.png',
};
const wrapper = mount(<Upload listType="picture-card" fileList={[file]} />);
expect(wrapper.find('img').length).toBe(0);
});
});

119
docs/resources.en-US.md

@ -0,0 +1,119 @@
---
order: 1
title: Resources
toc: false
---
Here list all the resources that related with Ant Design.
---
## Design Resources
Please find below some of the design resources and tools about Ant Design that we consider valuable. More of this is still being collected. You can leave feedback about Sketch Symbols [here](https://www.yuque.com/kitchen/topics/216).
<div class="next-block-use-cards"></div>
- RENEW Sketch Symbols
- https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg
- Sketch Symbols for Desktop
- https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Components.4.0.zip
- Mobile Components
- https://gw.alipayobjects.com/zos/basement_prod/c0c3852c-d245-4330-886b-cb02ef49eb6d.svg
- Sketch Symbols File for Mobile
- http://p.tb.cn/rmsportal_3436_AntDesignMobile_20Template_20V1.0.sketch
- Ant Design Pro
- https://gw.alipayobjects.com/zos/basement_prod/5edc7f4d-3302-4710-963b-7b6c77ea8d06.svg
- Common Templates and Pages
- https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Pro.sketch
- Ant Design Library
- https://gw.alipayobjects.com/zos/basement_prod/90740380-bbb7-4329-95e5-64533934c6cf.svg
- A powerful Axure library
- http://library.ant.design
- Kitchen
- https://gw.alipayobjects.com/zos/basement_prod/d475d063-2754-4442-b9db-5d164e06acc9.svg
- A Sketch plugin collection
- http://kitchen.alipay.com
- Ant Design Landing
- https://gw.alipayobjects.com/zos/basement_prod/b443f4be-5116-49b7-873f-a7c8502b8f0e.svg
- Landing Templates
- https://landing.ant.design/docs/download-cn
- Ant UX
- https://gw.alipayobjects.com/zos/basement_prod/51682163-e01a-46fe-810c-ac0062379717.svg
- A set of page logic prototype libraries
- http://ux.ant.design
- Ant Design Prototype (xiaopiu)
- https://gw.alipayobjects.com/zos/basement_prod/77e6a9ae-24a9-4be6-be42-f7fa8ee0eecf.svg
- Online library and prototype
- https://www.xiaopiu.com/topic/ant-design
- UI Kit for Figma
- https://gw.alipayobjects.com/zos/basement_prod/7b9ed3f2-6f05-4ddb-bac3-d55feb71e0ac.svg
- Library of components for Desktop
- https://www.antforfigma.com
- Ant Design Chart
- https://gw.alipayobjects.com/zos/basement_prod/a9dc586a-fe0a-4c7d-ab4f-f5ed779b963d.svg
- Sketch Symbols for Chart
- https://gw.alipayobjects.com/os/basement_prod/862ee74f-4ac5-482c-b1ae-3165684cedbe.sketch
## Articles
Do you want to know the story behind the Ant Design design system? How can I better apply Ant Design? You can check out our well selected articles below. Also welcome to follow [Ant Design Official Column](https://zhuanlan.zhihu.com/antdesign). There are often the latest sharing and discussions on related topics under the Ant Design design system, such as Ant Design, AntV visualization, Kitchen design Plug-ins, B-side product design, SaaS product design, natural interaction, growth design, intelligent design, design engineering, etc.
### Design
- [解放图形化设计生产力 - HiTu](https://zhuanlan.zhihu.com/p/100925117)
- [「自然交互」Ant Design 设计价值观解析](https://zhuanlan.zhihu.com/p/44809866)
- [「自然交互 1」前馈:让功能找到用户;让用户体验美好](https://zhuanlan.zhihu.com/p/41952711)
- [「自然交互 4」理解元数据,让人机自然交互](https://zhuanlan.zhihu.com/p/43613398)
- [「自然交互 5」传感器——系统的五感【上】](https://zhuanlan.zhihu.com/p/52648777)
- [1 块钱 6 周 DAU 增长翻倍:Ant Design 设计工具 Kitchen 获客增长实践](https://zhuanlan.zhihu.com/p/68707241)
- [专访蚂蚁金服体验技术 UED:Ant Design 希望成为世界级设计体系](https://zhuanlan.zhihu.com/p/66781635)
- [写给设计师的 Ant Design 栅格指南](https://zhuanlan.zhihu.com/p/63580649)
- [Ant Design 情感化设计](https://zhuanlan.zhihu.com/p/55364776)
- [Ant Design 资产一起造 工作坊(上)](https://zhuanlan.zhihu.com/p/54887681)
- [Ant Design 资产一起造 工作坊(下)](https://zhuanlan.zhihu.com/p/54901534)
- [轻推转型之门:Ant Design Pro 在企业级产品的实践(附演讲视频)](https://zhuanlan.zhihu.com/p/32771546)
- [Ant Design 3.0 背后的故事(附演讲视频)](https://zhuanlan.zhihu.com/p/32746810)
- [用户故事地图浅析](https://zhuanlan.zhihu.com/p/31503749)
- [体验,不只是用户的!Ant Design 在蚂蚁中台的应用](https://zhuanlan.zhihu.com/p/26846739)
- [在用 Sketch 和 iconfont?试试 Kitchen 吧!](https://zhuanlan.zhihu.com/p/36657030)
### Technology
- [Ant Design 色板生成算法演进之路](https://zhuanlan.zhihu.com/p/32422584)
- [如何向开源项目提交无法解答的问题](https://zhuanlan.zhihu.com/p/25795393)
## Reference
Please find below the books that inspired us, saved our time and helped us to overcome difficulties when designing components and patterns. If you want to know more about UI design, we recommend you these awesome design systems: [Fiori Design](https://experience.sap.com/fiori-design-web/)、 [Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/overview/themes/)、 [Lightning Design System](https://lightningdesignsystem.com/getting-started/)、 [Material Design](https://material.io/)
<div class="next-block-use-cards"></div>
- About Face 4 #C7EBD6
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*GA-CRIRqKjgAAAAAAAAAAABkARQnAQ
- The Interactive Design Guide for Digital Products and System
- https://www.wiley.com/en-sg/About+Face%3A+The+Essentials+of+Interaction+Design%2C+4th+Edition-p-9781118766576
- Designing Web Interfaces #009C94
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*KK2xSJu0M80AAAAAAAAAAABkARQnAQ
- Best Practice, Patterns and Principles for Web Interface
- http://shop.oreilly.com/product/9780596516253.do
- Designing Interfaces #9489CF
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*slN2QpTvIs0AAAAAAAAAAABkARQnAQ
- Interface Design Guidelines
- https://www.amazon.com/Designing-Interfaces-Patterns-Effective-Interaction/dp/1449379702/ref=pd_sbs_14_t_1/131-2623973-6077764?_encoding=UTF8&pd_rd_i=1449379702&pd_rd_r=ebe12a8d-435f-474b-a593-72aadf26c45a&pd_rd_w=18rob&pd_rd_wg=bhRFl&pf_rd_p=5cfcfe89-300f-47d2-b1ad-a4e27203a02a&pf_rd_r=8V8CD0EE336ZZEG15DEN&psc=1&refRID=8V8CD0EE336ZZEG15DEN
- Non-Designer's Design Book, The, 4th Edition #FAF0CD
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*1HbNSIju7pEAAAAAAAAAAABkARQnAQ
- Basic Principles of Good Design
- http://www.peachpit.com/store/non-designers-design-book-9780133966152
- The Design of Everyday Things #F8F3D1
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*4woBSLvOjfMAAAAAAAAAAABkARQnAQ
- About the People-oriented Design Philosophy
- https://jnd.org/the-design-of-everyday-things-revised-and-expanded-edition/
- Emotional Design #E8EEB4
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*6ZQJQoKRORsAAAAAAAAAAABkARQnAQ
- Explain the Role of Emotional Factors in Design
- https://www.amazon.com/Emotional-Design-Love-Everyday-Things/dp/0465051367
- Web Form Design #C2DAED
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*VhhwRo7axKQAAAAAAAAAAABkARQnAQ
- The Essence of Form Design
- https://rosenfeldmedia.com/books/web-form-design/

181
docs/resources.zh-CN.md

@ -0,0 +1,181 @@
---
order: 1
title: 资源
toc: false
---
这里汇总了与 Ant Design 相关的所有资源。
---
## 设计资源
这里提供 Ant Design 相关设计资源和设计工具的下载,更多设计资源正在整理和完善中。你可以在这个[地址](https://www.yuque.com/kitchen/topics/216)中反馈对新版本 Sketch Symbols 组件的意见。
<div class="next-block-use-cards"></div>
- 全新 Sketch 组件包
- https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg
- 桌面组件 Sketch 模板包
- https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Components.4.0.zip
- Mobile Components
- https://gw.alipayobjects.com/zos/basement_prod/c0c3852c-d245-4330-886b-cb02ef49eb6d.svg
- 移动组件 Sketch 模板
- http://p.tb.cn/rmsportal_3436_AntDesignMobile_20Template_20V1.0.sketch
- Ant Design Pro
- https://gw.alipayobjects.com/zos/basement_prod/5edc7f4d-3302-4710-963b-7b6c77ea8d06.svg
- 典型页面 + 通用业务模板
- https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Pro.sketch
- Ant Design Library
- https://gw.alipayobjects.com/zos/basement_prod/90740380-bbb7-4329-95e5-64533934c6cf.svg
- 一套强大的 Axure 部件库
- http://library.ant.design
- Kitchen
- https://gw.alipayobjects.com/zos/basement_prod/d475d063-2754-4442-b9db-5d164e06acc9.svg
- Sketch 工具集
- http://kitchen.alipay.com
- Ant Design Landing
- https://gw.alipayobjects.com/zos/basement_prod/b443f4be-5116-49b7-873f-a7c8502b8f0e.svg
- 首页模板集
- https://landing.ant.design/docs/download-cn
- Ant UX
- https://gw.alipayobjects.com/zos/basement_prod/51682163-e01a-46fe-810c-ac0062379717.svg
- 一套页面逻辑原型库
- http://ux.ant.design
- Ant Design 原型 (xiaopiu)
- https://gw.alipayobjects.com/zos/basement_prod/77e6a9ae-24a9-4be6-be42-f7fa8ee0eecf.svg
- 可在线编辑的组件库和交互原型
- https://www.xiaopiu.com/topic/ant-design
- Figma 组件包
- https://gw.alipayobjects.com/zos/basement_prod/7b9ed3f2-6f05-4ddb-bac3-d55feb71e0ac.svg
- 在 Figma 使用 Ant Design 进行设计
- https://www.antforfigma.com
- 全新 Chart 组件包
- https://gw.alipayobjects.com/zos/basement_prod/a9dc586a-fe0a-4c7d-ab4f-f5ed779b963d.svg
- 桌面组件 Chart 模板包
- https://gw.alipayobjects.com/os/basement_prod/862ee74f-4ac5-482c-b1ae-3165684cedbe.sketch
## 文章
想要了解 Ant Design 设计体系背后的故事?如何才能更好的应用 Ant Design?你可以查阅下述我们为你精挑细选的文章。也欢迎关注 [Ant Design 官方专栏](https://zhuanlan.zhihu.com/antdesign),这里常有关于 Ant Design 设计体系下相关话题内容的最新分享和讨论,如 Ant Design、AntV 可视化、Kitchen 设计插件、B 端产品设计、SaaS 产品设计、自然交互、增长设计、智能设计、设计工程化等。
### 设计
- [解放图形化设计生产力 - HiTu](https://zhuanlan.zhihu.com/p/100925117)
- [「自然交互」Ant Design 设计价值观解析](https://zhuanlan.zhihu.com/p/44809866)
- [「自然交互 1」前馈:让功能找到用户;让用户体验美好](https://zhuanlan.zhihu.com/p/41952711)
- [「自然交互 4」理解元数据,让人机自然交互](https://zhuanlan.zhihu.com/p/43613398)
- [「自然交互 5」传感器——系统的五感【上】](https://zhuanlan.zhihu.com/p/52648777)
- [1 块钱 6 周 DAU 增长翻倍:Ant Design 设计工具 Kitchen 获客增长实践](https://zhuanlan.zhihu.com/p/68707241)
- [专访蚂蚁金服体验技术 UED:Ant Design 希望成为世界级设计体系](https://zhuanlan.zhihu.com/p/66781635)
- [写给设计师的 Ant Design 栅格指南](https://zhuanlan.zhihu.com/p/63580649)
- [Ant Design 情感化设计](https://zhuanlan.zhihu.com/p/55364776)
- [Ant Design 资产一起造 工作坊(上)](https://zhuanlan.zhihu.com/p/54887681)
- [Ant Design 资产一起造 工作坊(下)](https://zhuanlan.zhihu.com/p/54901534)
- [轻推转型之门:Ant Design Pro 在企业级产品的实践(附演讲视频)](https://zhuanlan.zhihu.com/p/32771546)
- [Ant Design 3.0 背后的故事(附演讲视频)](https://zhuanlan.zhihu.com/p/32746810)
- [用户故事地图浅析](https://zhuanlan.zhihu.com/p/31503749)
- [体验,不只是用户的!Ant Design 在蚂蚁中台的应用](https://zhuanlan.zhihu.com/p/26846739)
- [在用 Sketch 和 iconfont?试试 Kitchen 吧!](https://zhuanlan.zhihu.com/p/36657030)
### 技术
- [Ant Design 色板生成算法演进之路](https://zhuanlan.zhihu.com/p/32422584)
- [如何向开源项目提交无法解答的问题](https://zhuanlan.zhihu.com/p/25795393)
## 致敬
在 Ant Design 4.0 的改版中,我们汲取顶级设计体系的精华,同时结合我们自身业务特性做了大量优化。我们希望通过不断努力和打磨,成为世界级设计体系的一份子,为「用户」和「设计者」带来极致体验。如果你也想追求卓越,建议去研究这些体系: [Fiori Design](https://experience.sap.com/fiori-design-web/)、 [Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/overview/themes/)、 [Lightning Design System](https://lightningdesignsystem.com/getting-started/)、 [Material Design](https://material.io/)
<div class="next-block-use-cards"></div>
- About Face 4 #E1E8B7
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*KKZWRozT8D8AAAAAAAAAAABkARQnAQ
- 一本数字产品和系统的交互设计指南
- http://book.douban.com/subject/26642302/
- Web 界面设计 #009C94
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*yB0oQ42f0kEAAAAAAAAAAABkARQnAQ
- Web 界面的最佳实践、模式和原理
- http://book.douban.com/subject/3821157/
- 界面设计模式 #9489CF
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*aFAfTKIjR_IAAAAAAAAAAABkARQnAQ
- 界面设计总体思路指引
- http://book.douban.com/subject/25716088/
- 写给大家看的设计书 #AFBCC8
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*tTvXQYApsIIAAAAAAAAAAABkARQnAQ
- 优秀设计所必须遵循的基本原则
- http://book.douban.com/subject/3323633/
- 设计心理学 1 #B7D9B7
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*12W8R7nPxxUAAAAAAAAAAABkARQnAQ
- 强调以人为本的设计哲学
- http://book.douban.com/subject/26102860/
- 设计心理学 3 #EFBDB5
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*a5VNSamt2EIAAAAAAAAAAABkARQnAQ
- 解释情感因素在设计领域扮演的角色
- http://book.douban.com/subject/26424688/
- Web 表单设计 #C2DAED
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*vXfQS7sStNYAAAAAAAAAAABkARQnAQ
- 表单设计的真谛
- http://book.douban.com/subject/4886100/
## 加入我们
我们(蚂蚁金服体验技术部)是一支兼具设计视角和工程视角的团队,服务蚂蚁金服上百个中后台系统,主打产品 Ant Design 服务全球 100 万设计师和工程师,是西湖区学院路西侧最具影响力的设计语言。欢迎来这里和我们一起打造优雅高效的人机设计/研发体系。
### UI/UE 设计师
简历和作品集请投递:lindong.lld#alipay.com
> 注明简历来自 ant.design 官网
- 岗位级别:P6/P7/P8
- 岗位地点:杭州
- 岗位要求:
- 至少 3-5 年的工作经验,扎实设计功底;
- 抽象能力强,善于透过表象找本质;
- 沟通能力佳,善于自我管理;
- 有企业级设计实战经验,加分;
- 有数据驱动的增长设计实践,加分;
- 深度理解 SAP、Salesforce、Google 等设计体系,能提出自己独到见解并落实到实践中,加加加分。
- 岗位职责:
- 参与[蚂蚁金融科技](https://tech.antfin.com/)、[区块链](https://tech.antfin.com/blockchain)、人工智能等企业级产品的设计工作;
- 参与[语雀](https://www.yuque.com/)、[云凤蝶](https://www.yunfengdie.com/)等创新产品的设计工作;
- 参与 Ant Design 的打磨,将其建设成全球卓越的设计体系。
- 参与 AntV 的打磨,将其建设成全球一流的数据可视化体系。
- One More Thing ❤️ :
- 你们总是为世界带去美好,但总是忘却你们也需要美好。我们正在努力打造 [🍳 Kitchen:一款为设计师提效的 Sketch 工具集](https://kitchen.alipay.com/)、[语雀画板](https://yuque.com/) 等专属设计师的产品,让设计真正变成财富。期待志同道合的你,一道给设计行业带来「微小而美好的改变」。
### 前端工程师
简历请投递:afc163+antd@gmail.com
> 注明简历来自 ant.design 官网
- 岗位级别:P6/P7/P8
- 岗位地点:杭州
- 岗位要求:
- 在 React 技术栈持续耕耘,情有独钟。
- 热爱开源。
- 坚持和善于用技术和工具解决其他问题。
- 丰富的中后台前端研发经验。
- 爱 🐱。
- 岗位职责:
- 负责 Ant Design 前端基础设施研发。
- 负责中后台设计/前端工具体系建设。
### ADI(Artificial Design Intelligence) 工程师
简历和作品集请投递:lindong.lld#alipay.com
> 注明简历来自 ant.design 官网
- 岗位级别:P7/P8
- 岗位地点:杭州
- 岗位要求:
- 有良好的工程师背景,善于学习和使用各类工具、框架解决研发问题;
- 对人工智能应用在设计行业,有坚定的信心和意愿;
- 已经有相关实践工作,优先考虑。
- 岗位职责:
- 负责 Ant Design 工具体系和智能设计的研发,并配合团队成员进行商业化实践,把设计做成业务;
- 组建和培养有梯度的研发团队。

30
docs/spec/article.en-US.md

@ -1,30 +0,0 @@
---
order: 2
category: Other
title: Articles
---
想要了解 Ant Design 设计体系背后的故事?如何才能更好的应用 Ant Design?你可以查阅下述我们为你精挑细选的文章。也欢迎关注 [Ant Design 官方专栏](https://zhuanlan.zhihu.com/antdesign),这里常有关于 Ant Design 设计体系下相关话题内容的最新分享和讨论,如 Ant Design、AntV 可视化、Kitchen 设计插件、B 端产品设计、SaaS 产品设计、自然交互、增长设计、智能设计、设计工程化等。
## 设计
- [「自然交互」Ant Design 设计价值观解析](https://zhuanlan.zhihu.com/p/44809866)
- [「自然交互 1」前馈:让功能找到用户;让用户体验美好](https://zhuanlan.zhihu.com/p/41952711)
- [「自然交互 4」理解元数据,让人机自然交互](https://zhuanlan.zhihu.com/p/43613398)
- [「自然交互 5」传感器——系统的五感【上】](https://zhuanlan.zhihu.com/p/52648777)
- [1 块钱 6 周 DAU 增长翻倍:Ant Design 设计工具 Kitchen 获客增长实践](https://zhuanlan.zhihu.com/p/68707241)
- [专访蚂蚁金服体验技术 UED:Ant Design 希望成为世界级设计体系](https://zhuanlan.zhihu.com/p/66781635)
- [写给设计师的 Ant Design 栅格指南](https://zhuanlan.zhihu.com/p/63580649)
- [Ant Design 情感化设计](https://zhuanlan.zhihu.com/p/55364776)
- [Ant Design 资产一起造 工作坊(上)](https://zhuanlan.zhihu.com/p/54887681)
- [Ant Design 资产一起造 工作坊(下)](https://zhuanlan.zhihu.com/p/54901534)
- [轻推转型之门:Ant Design Pro 在企业级产品的实践(附演讲视频)](https://zhuanlan.zhihu.com/p/32771546)
- [Ant Design 3.0 背后的故事(附演讲视频)](https://zhuanlan.zhihu.com/p/32746810)
- [用户故事地图浅析](https://zhuanlan.zhihu.com/p/31503749)
- [体验,不只是用户的!Ant Design 在蚂蚁中台的应用](https://zhuanlan.zhihu.com/p/26846739)
- [在用 Sketch 和 iconfont?试试 Kitchen 吧!](https://zhuanlan.zhihu.com/p/36657030)
## 技术
- [Ant Design 色板生成算法演进之路](https://zhuanlan.zhihu.com/p/32422584)
- [如何向开源项目提交无法解答的问题](https://zhuanlan.zhihu.com/p/25795393)

31
docs/spec/article.zh-CN.md

@ -1,31 +0,0 @@
---
order: 2
category: 其他
title: 文章
---
想要了解 Ant Design 设计体系背后的故事?如何才能更好的应用 Ant Design?你可以查阅下述我们为你精挑细选的文章。也欢迎关注 [Ant Design 官方专栏](https://zhuanlan.zhihu.com/antdesign),这里常有关于 Ant Design 设计体系下相关话题内容的最新分享和讨论,如 Ant Design、AntV 可视化、Kitchen 设计插件、B 端产品设计、SaaS 产品设计、自然交互、增长设计、智能设计、设计工程化等。
## 设计
- [解放图形化设计生产力 - HiTu](https://zhuanlan.zhihu.com/p/100925117)
- [「自然交互」Ant Design 设计价值观解析](https://zhuanlan.zhihu.com/p/44809866)
- [「自然交互 1」前馈:让功能找到用户;让用户体验美好](https://zhuanlan.zhihu.com/p/41952711)
- [「自然交互 4」理解元数据,让人机自然交互](https://zhuanlan.zhihu.com/p/43613398)
- [「自然交互 5」传感器——系统的五感【上】](https://zhuanlan.zhihu.com/p/52648777)
- [1 块钱 6 周 DAU 增长翻倍:Ant Design 设计工具 Kitchen 获客增长实践](https://zhuanlan.zhihu.com/p/68707241)
- [专访蚂蚁金服体验技术 UED:Ant Design 希望成为世界级设计体系](https://zhuanlan.zhihu.com/p/66781635)
- [写给设计师的 Ant Design 栅格指南](https://zhuanlan.zhihu.com/p/63580649)
- [Ant Design 情感化设计](https://zhuanlan.zhihu.com/p/55364776)
- [Ant Design 资产一起造 工作坊(上)](https://zhuanlan.zhihu.com/p/54887681)
- [Ant Design 资产一起造 工作坊(下)](https://zhuanlan.zhihu.com/p/54901534)
- [轻推转型之门:Ant Design Pro 在企业级产品的实践(附演讲视频)](https://zhuanlan.zhihu.com/p/32771546)
- [Ant Design 3.0 背后的故事(附演讲视频)](https://zhuanlan.zhihu.com/p/32746810)
- [用户故事地图浅析](https://zhuanlan.zhihu.com/p/31503749)
- [体验,不只是用户的!Ant Design 在蚂蚁中台的应用](https://zhuanlan.zhihu.com/p/26846739)
- [在用 Sketch 和 iconfont?试试 Kitchen 吧!](https://zhuanlan.zhihu.com/p/36657030)
## 技术
- [Ant Design 色板生成算法演进之路](https://zhuanlan.zhihu.com/p/32422584)
- [如何向开源项目提交无法解答的问题](https://zhuanlan.zhihu.com/p/25795393)

12
docs/spec/buttons.md

@ -26,7 +26,7 @@ title:
#### ① 次按钮
常规按钮,用于非主要动作。
常规按钮,用于非主要动作。如果不确定选择哪种按钮,次按钮永远是最安全的选择。
#### ② 主按钮
@ -55,8 +55,14 @@ title:
### Do&Don't
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*di8jS5EWYSIAAAAAAAAAAABkARQnAQ" alt="错误示范" description="不要在一个按钮区放置超过一个主按钮">
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*3WUkT5pD1SUAAAAAAAAAAABkARQnAQ" alt="正确示范" description="1、强调一个主要操作;<br/>2、操作无主次,次按钮是最安全的选择。。">
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zBtTRq2xbTYAAAAAAAAAAABkARQnAQ" alt="错误示范" description="不要在按钮中放置两个图标。">
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*EpwSTpaGPBgAAAAAAAAAAABkARQnAQ" alt="正确示范" description="按照主次展示全部操作。<br>将次要操作收纳至右侧下拉按钮中。">
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*EpwSTpaGPBgAAAAAAAAAAABkARQnAQ" alt="正确示范" description="按照主次展示全部操作。<br/>将次要操作收纳至右侧下拉按钮中。">
### 特殊按钮
@ -86,7 +92,7 @@ title:
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*32zdRqTjDhYAAAAAAAAAAABkARQnAQ">
经常独立出现,行动号召按钮就像是电脑在对用户大声说“跟我来吧”,有点命令用户点击的意味,通常出现于 landing page 或者 一些引导性场景。最大可以将按钮放宽到与父区域等宽。
经常独立出现,行动号召按钮就像是电脑在对用户大声说“跟我来吧”,有点命令用户点击的意味,通常出现于 landing page 或者 一些引导性场景。最大可以将按钮放宽到与父区域等宽。一个屏幕空间中,建议只有一个行动号召按钮。
## 位置

5
docs/spec/dark.md

@ -1,10 +1,11 @@
---
category: 全局样式
category:
zh-CN: 全局样式
en-US: Global Styles
order: 6
title:
zh-CN: 暗黑模式
en-US: Dark Theme
skip: true
---
暗黑模式是指把所有 UI 换成黑色或者深色的一个主题模式。

113
docs/spec/download.en-US.md

@ -1,113 +0,0 @@
---
category: Other
order: 0
title: Resources
---
Please find below some of the design resources and tools about Ant Design that we consider valuable. More of this is still being collected.
<div class="resource-cards">
<a target="_blank" href="https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Components.4.0.Beta.sketch" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*XsDPQrwQZwEAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">
RENEW Sketch Symbols
</span>
<span class="resource-card-description">Sketch Symbols for Desktop</span>
</div>
</a>
<a target="_blank" href="https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Mobile.Template.sketch" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*CBq9R5XenxEAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Mobile Components</span>
<span class="resource-card-description">Sketch Symbols File for Mobile</span>
</div>
</a>
<a target="_blank" href="https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Pro.sketch" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*JL4NSrPh8QsAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Ant Design Pro</span>
<span class="resource-card-description">Common Templates and Pages</span>
</div>
</a>
<a target="_blank" href="http://library.ant.design" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*7-yRTpL6l0MAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Ant Design Library</span>
<span class="resource-card-description">A powerful Axure library of Ant Design</span>
</div>
</a>
<a target="_blank" href="http://kitchen.alipay.com" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*JSzfToJBU_8AAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">
Kitchen
<span class="resource-card-hot-badge">HOT</span>
</span>
<span class="resource-card-description">A Sketch plugin with a collection of great tools</span>
</div>
</a>
<a target="_blank" href="https://landing.ant.design/docs/download" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*On5cQ7NoNL8AAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">
Ant Design Landing
</span>
<span class="resource-card-description">Landing Templates</span>
</div>
</a>
<a target="_blank" href="http://ux.ant.design" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*l_PmRLizBTMAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Ant UX</span>
<span class="resource-card-description">A series prototypes that help creating application structure and user flow</span>
</div>
</a>
<a target="_blank" href="https://www.xiaopiu.com/topic/ant-design" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zPTWTLt72YIAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Ant Design Prototype (xiaopiu)</span>
<span class="resource-card-description">Online Ant Design library and interactive prototype</span>
</div>
</a>
<a target="_blank" href="https://www.antforfigma.com" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://antforfigma.com/images/antforfigma-icon.png">
</div>
<div class="resource-card-content">
<span class="resource-card-title">
UI Kit for Figma
<span class="resource-card-hot-badge">NEW</span>
</span>
<span class="resource-card-description">Large library of components and styles for Desktop</span>
</div>
</a>
<a target="_blank" href="https://store.framer.com/package/bhaveshchow/ant-design-system" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*W5TbRLtV1YYAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">
UI Kit for Framer X
<span class="resource-card-hot-badge">NEW</span>
</span>
<span class="resource-card-description">Library of fully customizable components</span>
</div>
</a>
</div>

103
docs/spec/download.zh-CN.md

@ -1,103 +0,0 @@
---
category: 其他
order: 0
title: 设计资源
---
这里提供 Ant Design 相关设计资源和设计工具的下载,更多设计资源正在整理和完善中。
- 新版本 Sketch Symbols 组件反馈地址:[🦜 反馈地址](https://www.yuque.com/kitchen/topics/51)
<div class="resource-cards">
<a target="_blank" href="https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Components.4.0.Beta.sketch" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*XsDPQrwQZwEAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">
全新 Sketch 组件包
</span>
<span class="resource-card-description">桌面组件 Sketch 模板包</span>
</div>
</a>
<a target="_blank" href="http://p.tb.cn/rmsportal_3436_AntDesignMobile_20Template_20V1.0.sketch" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*CBq9R5XenxEAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Mobile Components</span>
<span class="resource-card-description">移动组件 Sketch 模板</span>
</div>
</a>
<a target="_blank" href="https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Pro.sketch" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*JL4NSrPh8QsAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Ant Design Pro</span>
<span class="resource-card-description">典型页面 + 通用业务模板</span>
</div>
</a>
<a target="_blank" href="http://library.ant.design" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*7-yRTpL6l0MAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Ant Design Library @Axure</span>
<span class="resource-card-description">一套强大的 Axure 部件库</span>
</div>
</a>
<a target="_blank" href="http://kitchen.alipay.com" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*JSzfToJBU_8AAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">
Kitchen
<span class="resource-card-hot-badge">HOT</span>
</span>
<span class="resource-card-description">Sketch 工具集</span>
</div>
</a>
<a target="_blank" href="https://landing.ant.design/docs/download-cn" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*On5cQ7NoNL8AAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">
Ant Design Landing
</span>
<span class="resource-card-description">首页模板集</span>
</div>
</a>
<a target="_blank" href="http://ux.ant.design" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*l_PmRLizBTMAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Ant UX</span>
<span class="resource-card-description">一套页面逻辑原型库,帮你梳理页面逻辑</span>
</div>
</a>
<a target="_blank" href="https://www.xiaopiu.com/topic/ant-design" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zPTWTLt72YIAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Ant Design 原型(xiaopiu)</span>
<span class="resource-card-description">可在线编辑的 Ant Design 组件库和交互原型</span>
</div>
</a>
<a target="_blank" href="https://www.antforfigma.com" class="resource-card">
<div class="resource-card-icon">
<img width="65" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*W5TbRLtV1YYAAAAAAAAAAABkARQnAQ">
</div>
<div class="resource-card-content">
<span class="resource-card-title">
Figma 组件包
<span class="resource-card-hot-badge">NEW</span>
</span>
<span class="resource-card-description">在 Figma 使用 Ant Design 进行设计</span>
</div>
</a>
</div>

1
docs/spec/feedback.en-US.md

@ -3,6 +3,7 @@ category: Design Patterns
type: Global Rules
order: 1
title: Feedback
skip: true
---
In order to help users understand what the application is currently doing, and to refer to the user's next behavior, and to understand the results of the operation, when the user need to interact with the system , use different modes to feedback information or results. When the designer uses feedback or customizes some feedback, please note:

1
docs/spec/feedback.zh-CN.md

@ -3,6 +3,7 @@ category: 设计模式
type: 全局规则
order: 1
title: 反馈
skip: true
---
为了帮助用户了解应用当前要做什么,也给用户的下一步行为做参考,以及了解操作后所产生的结果 ,当用户和系统需要交互时,使用不同的模式来反馈信息或结果。当设计者使用反馈或者自定义一些反馈时,请注意:

1
docs/spec/navigation.en-US.md

@ -3,6 +3,7 @@ category: Design Patterns
type: Global Rules
order: 2
title: Navigation
skip: true
---
Broadly speaking, anything telling users where they are, where to go and how to get there can be called navigation. When using navigation or customizing navigational structures, please pay attention to following common pitfalls:

1
docs/spec/navigation.zh-CN.md

@ -3,6 +3,7 @@ category: 设计模式
type: 全局规则
order: 2
title: 导航
skip: true
---
在广义上,任何告知用户他在哪里,他能去什么地方以及如何到达那里的方式,都可以称之为导航。当设计者使用导航或者自定义一些导航结构时,请注意:

80
docs/spec/reference.en-US.md

@ -1,80 +0,0 @@
---
category: Other
order: 1
title: Reference
---
Please find below the books that inspired us, saved our time and helped us to overcome difficulties when designing components and patterns. If you want to know more about UI design, we recommend you these awesome books.
<div class="resource-cards">
<a target="_blank" href="http://as.wiley.com/WileyCDA/WileyTitle/productCd-1118766571.html" class="resource-card">
<div class="resource-card-cover">
<img src="https://gw.alipayobjects.com/zos/rmsportal/HJstCPuYGIrazrMAmhNK.jpg">
</div>
<div class="resource-card-content">
<span class="resource-card-title">About Face</span>
<span class="resource-card-description">Author: Alan Cooper, Robert Reimann, David Cronin, Christopher Noessel</span>
<span class="resource-card-description">Publisher: Wiley</span>
</div>
</a>
<a target="_blank" href="http://shop.oreilly.com/product/9780596516253.do" class="resource-card">
<div class="resource-card-cover">
<img src="https://gw.alipayobjects.com/zos/rmsportal/XiifUfeQjuSovafhDkjO.gif">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Designing Web Interfaces</span>
<span class="resource-card-description">Author: Bill Scott, Theresa Neil</span>
<span class="resource-card-description">Publisher: O'Reilly Media</span>
</div>
</a>
<a target="_blank" href="http://shop.oreilly.com/product/0636920000556.do" class="resource-card">
<div class="resource-card-cover">
<img src="https://gw.alipayobjects.com/zos/rmsportal/LstmXRKzPTtIEwoltxYt.gif">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Designing Interfaces</span>
<span class="resource-card-description">Author: Jenifer Tidwell</span>
<span class="resource-card-description">Publisher: O'Reilly Media</span>
</div>
</a>
<a target="_blank" href="http://www.peachpit.com/store/non-designers-design-book-9780133966152" class="resource-card">
<div class="resource-card-cover">
<img src="https://gw.alipayobjects.com/zos/rmsportal/gfgFaAsDZtdsAGuncBIP.jpeg">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Non-Designer's Design Book</span>
<span class="resource-card-description">Author: Robin Williams</span>
<span class="resource-card-description">Publisher: Peachpit Press</span>
</div>
</a>
<a target="_blank" href="http://www.jnd.org/books/design-of-everyday-things-revised.html" class="resource-card">
<div class="resource-card-cover">
<img src="https://gw.alipayobjects.com/zos/rmsportal/rOfwJaScZsvNXvcoZhot.jpg">
</div>
<div class="resource-card-content">
<span class="resource-card-title">The Design of Everyday Things</span>
<span class="resource-card-description">Author: Don Norman</span>
<span class="resource-card-description">Publisher: Basic Books, A Member of the Perseus Books Group</span>
</div>
</a>
<a target="_blank" href="https://www.amazon.com/Emotional-Design-Love-Everyday-Things/dp/0465051367" class="resource-card">
<div class="resource-card-cover">
<img src="https://gw.alipayobjects.com/zos/rmsportal/qEYOzzydzyZRRxjfVBKj.jpg">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Emotional Design</span>
<span class="resource-card-description">Author: Don Norman</span>
<span class="resource-card-description">Publisher: Basic Books, A Member of the Perseus Books Group</span>
</div>
</a>
<a target="_blank" href="http://rosenfeldmedia.com/books/web-form-design/" class="resource-card">
<div class="resource-card-cover">
<img src="https://gw.alipayobjects.com/zos/rmsportal/rFFScFeWuEHtFuWNvtZd.jpg">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Web Form Design</span>
<span class="resource-card-description">Author: Luke Wroblewski</span>
<span class="resource-card-description">Publisher: Rosenfeld Media</span>
</div>
</a>
</div>

87
docs/spec/reference.zh-CN.md

@ -1,87 +0,0 @@
---
category: 其他
order: 1
title: 致敬
---
## 设计体系
在 Ant Design 3.0 的改版中,我们汲取顶级设计体系的精华,同时结合我们自身业务特性做了大量优化。我们希望通过不断努力和打磨,成为世界级设计体系的一份子,为「用户」和「设计者」带来极致体验。如果你也想追求卓越,建议去研究这些体系。
- [Fiori Design](https://experience.sap.com/fiori-design-web/)
- [Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/overview/themes/)
- [Lightning Design System](https://lightningdesignsystem.com/getting-started/)
- [Material Design](https://material.io/)
<div class="resource-cards">
<a target="_blank" href="http://book.douban.com/subject/26642302/" class="resource-card">
<div class="resource-card-cover">
<img src="https://os.alipayobjects.com/rmsportal/PeeRQQIGQJCswxe.png">
</div>
<div class="resource-card-content">
<span class="resource-card-title">About Face 4</span>
<span class="resource-card-description">作者: Alan.cooper</span>
<span class="resource-card-description">出版社: 电子工业出版社</span>
</div>
</a>
<a target="_blank" href="http://book.douban.com/subject/3821157/" class="resource-card">
<div class="resource-card-cover">
<img src="https://os.alipayobjects.com/rmsportal/CoojVXLtoWrUSmI.png">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Web 界面设计</span>
<span class="resource-card-description">作者: Bill Scott / Theresa Neil</span>
<span class="resource-card-description">出版社: 电子工业出版社</span>
</div>
</a>
<a target="_blank" href="http://book.douban.com/subject/25716088/" class="resource-card">
<div class="resource-card-cover">
<img src="https://os.alipayobjects.com/rmsportal/oRxdwgZMwfEFeJa.png">
</div>
<div class="resource-card-content">
<span class="resource-card-title">界面设计模式</span>
<span class="resource-card-description">作者: Tidwell,J.</span>
<span class="resource-card-description">出版社: 电子工业出版社</span>
</div>
</a>
<a target="_blank" href="http://book.douban.com/subject/3323633/" class="resource-card">
<div class="resource-card-cover">
<img src="https://os.alipayobjects.com/rmsportal/SNdJVyZaZwdwJmr.png">
</div>
<div class="resource-card-content">
<span class="resource-card-title">写给大家看的设计书</span>
<span class="resource-card-description">作者: Robin Williams</span>
<span class="resource-card-description">出版社: 人民邮电出版社</span>
</div>
</a>
<a target="_blank" href="http://book.douban.com/subject/26102860/" class="resource-card">
<div class="resource-card-cover">
<img src="https://os.alipayobjects.com/rmsportal/txGrSvGFMTTrwjY.png">
</div>
<div class="resource-card-content">
<span class="resource-card-title">设计心理学 1</span>
<span class="resource-card-description">作者: 唐纳德•A•诺曼</span>
<span class="resource-card-description">出版社: 中信出版社</span>
</div>
</a>
<a target="_blank" href="http://book.douban.com/subject/26424688/" class="resource-card">
<div class="resource-card-cover">
<img src="https://os.alipayobjects.com/rmsportal/cZQyAARFxzaKEOG.png">
</div>
<div class="resource-card-content">
<span class="resource-card-title">设计心理学 3</span>
<span class="resource-card-description">作者: 唐纳德•A•诺曼</span>
<span class="resource-card-description">出版社: 中信出版社</span>
</div>
</a>
<a target="_blank" href="http://book.douban.com/subject/4886100/" class="resource-card">
<div class="resource-card-cover">
<img src="https://os.alipayobjects.com/rmsportal/moeFnnuXrputdag.png">
</div>
<div class="resource-card-content">
<span class="resource-card-title">Web 表单设计</span>
<span class="resource-card-description">作者: Luke Wroblewski</span>
<span class="resource-card-description">出版社: 清华大学出版社</span>
</div>
</a>
</div>

9
docs/spec/research-empty.en-US.md

@ -0,0 +1,9 @@
---
category: Design Patterns (Research)
type: Global Rules
order: 3
title: Empty Status
skip: true
---
设计模式 - 探索 - 全局规则 - 空状态

78
docs/spec/research-empty.zh-CN.md

@ -0,0 +1,78 @@
---
category: 设计模式 - 探索
type: 全局规则
order: 3
title: 空状态
---
任何内容区域(页面、区块、组件、单数据)没有内容/数据显示给用户时,就会出现空状态。
## 设计目标
- 空状态应给予提示,帮助让用户了解空状态原因,避免产生误解与迷失;
- 给予用户推荐操作提示,帮助用户摆脱空状态。
---
## 设计原则
<div class="design-inline-cards">
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*q5MRQ6TBR0EAAAAAAAAAAABkARQnAQ" />
<div>
<h4>明确</h4>
<p>通过使用清晰明了的语言、插画等形式告知用户空状态的具体原因。</p>
</div>
</div>
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*wOoaT6juZqwAAAAAAAAAAABkARQnAQ" />
<div>
<h4>提供邀请</h4>
<p>提供帮助文案、建议操作等解决方案,表明在下一个界面可以做什么,引导用户进行操作。</p>
</div>
</div>
</div>
### Do&Don’t
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*Bh_yRKPOByUAAAAAAAAAAABkARQnAQ" alt="正确示范" description="展示明确空状态提示。">
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*yiIXR4u8s2wAAAAAAAAAAABkARQnAQ" alt="错误示范" description="空状态没有任何提示。">
---
## 使用场景
### 新手引导
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*UyVCTaiJ3icAAAAAAAAAAABkARQnAQ">
一般来说,新用户希望空状态具有帮助说明和推荐操作。首次使用应用或功能场景的空状态非常有用,因为它向用户展示了该功能和流程,并且可以帮助用户快速上手。为了帮助首次使用新用户,空状态可以使用功能引导、帮助文档等方式填充原本为空的页面。
#### 使用引导变形
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*Pf8HSa477DQAAAAAAAAAAABkARQnAQ">
使用引导由状态提示、帮助引导、建议操作三个部分组成,设计时可根据业务流程选择模块来构成页面和变形。针对处于复杂流程中某一环的空状态页面,也可提供流程引导模块帮助用户全局理解操作流程,同时可提供文字按钮进行流程相关的快捷操作。
### 完成或清空
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*SIZBTJs3O4kAAAAAAAAAAABkARQnAQ">
这种空状态是用户自愿从功能上删除数据的情况。例如,客户完成了任务清单上的所有项目,阅读了所有通知。一般此类场景不需要进行操作引导,只需要用图形元素或提示信息进行空状态说明。
### 无数据
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*utf3Qr-9VssAAAAAAAAAAABkARQnAQ">
内容区域无数据的场景使用,由图形元素、提示信息、建议操作三类元素组合展示,根据使用场景决定是否提供建议操作。
---
## 扩展阅读
### 外部参考文章
- [Salesforce 空状态设计准则](https://www.lightningdesignsystem.com/guidelines/empty-state/#Message)
- [PREDIX 空状态设计准则](https://www.predix-ui.com/#/design/communication/empty-states)
- [Material Design 空状态设计准则](https://material.io/design/communication/empty-states.html#content)

7
docs/spec/research-exception.en-US.md

@ -0,0 +1,7 @@
---
category: Design Patterns (Research)
type: Template Document
order: 5
title: Exception Page
skip: true
---

130
docs/spec/research-exception.zh-CN.md

@ -0,0 +1,130 @@
---
category: 设计模式 - 探索
type: 模板文档
order: 5
title: 异常页
---
用于展示页面异常状态。
## 设计目标
解释发生了什么异常,为用户提供相应建议或操作,避免用户感到迷失和困惑。
---
## 设计原则
<div class="design-inline-cards">
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*te8yTbLcqrgAAAAAAAAAAABkARQnAQ" />
<div>
<h4>友好</h4>
<p>使用友好、清晰的语言来表达,不要使用难懂的术语,让用户产生困惑。</p>
</div>
</div>
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zHCcQqaRvmoAAAAAAAAAAABkARQnAQ" />
<div>
<h4>提供邀请</h4>
<p>引导用户进入下一个交互层次的提醒和暗示,以表明在下一个界面可以做什么。</p>
</div>
</div>
</div>
---
## 类型
### 异常页
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*OIo9TYjVhAEAAAAAAAAAAABkARQnAQ">
当页面出现异常时展示,其包含以下要素:
1.配图:为沉重的异常增添一点乐趣,缓解用户烦躁心理;
2.异常代码/问题:当异常有具体的 HTTP 错误代码时,可予以展示;
3.异常描述:简明扼要地描述异常原因,方便用户作对问题作反馈;
4.建议操作:协助用户处理异常,或把用户引导回正确的路径上。
#### 模板 - 404
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*tVUkTr052wUAAAAAAAAAAABkARQnAQ">
**什么时候用**
当用户请求访问的页面、项目、资源等未找到时可使用。
#### 模板 - 403
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*j5LCQabCiz8AAAAAAAAAAABkARQnAQ">
**什么时候用**
无权限,可能包括无应用权限或无数据权限,根据实际情况向用户反馈。
#### 模板 - 500
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*PRRMRY9cMPIAAAAAAAAAAABkARQnAQ">
**什么时候用**
当服务器出错,无法向用户提供服务时。
#### 模板 - 浏览器不兼容
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*bowLQ7DhaKsAAAAAAAAAAABkARQnAQ">
**什么时候用**
当浏览器不兼容导致用户无法打开网页的时候使用。
<br>
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*PpLRQb0Rc5gAAAAAAAAAAABkARQnAQ">
**设计建议**
当浏览器不兼容,对操作影响程度不同,当并不严重影响使用时,可使用全局提示,允许用户继续使用。
### 空状态
当没有内容/数据显示给用户时,展示空状态。空状态也属于一种特定的异常页,具体内容请前往查看[空状态](/docs/spec/research-empty)文档。
### 加载失败
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*NfSZSb3jGl8AAAAAAAAAAABkARQnAQ">
**什么时候用**
当页面因为网络等各种原因加载内容失败时展示,一般结合重试操作。
### 设计建议
页面的整体交互流程可能是由不同状态构成的,设计者在设计页面时不能只关注理想状态,应完整考虑各类突发场景,防止用户在使用时体验中断。
理想状态:所有页面模块正常展示的状态;
部分状态:部分模块不存在或部分内容为空状态,设计参考[空状态](/docs/spec/research-empty);
加载状态:用 Spin 或 Skeleton 反馈加载中状态;
错误状态:系统错误、无权限等;
空状态:内容完全为空的状态,建议使用引导类的[空状态](/docs/spec/research-empty)提示,如果是新用户参考使用新人引导页。
---
## 扩展阅读
### 会用到哪些模板文档
- [空状态](/docs/spec/research-empty)
### 外部参考文章
- [Avoid Being Embarrassed by Your Error Messages](https://www.uxmatters.com/mt/archives/2010/08/avoid-being-embarrassed-by-your-error-messages.php)
- [How to fix a bad user interface](https://www.scotthurff.com/posts/why-your-user-interface-is-awkward-youre-ignoring-the-ui-stack/#partial)

7
docs/spec/research-form.en-US.md

@ -0,0 +1,7 @@
---
category: Design Patterns (Research)
type: Template Document
order: 1
title: Form Page
skip: true
---

223
docs/spec/research-form.zh-CN.md

@ -0,0 +1,223 @@
---
category: 设计模式 - 探索
type: 模板文档
order: 1
title: 表单页
---
表单页是一种用于信息添加、录入的页面类型。用来确保用户按照要求录入信息提交给系统使用或引导用户进行应用设置。
## 设计目标
帮助用户明确当前页面任务,快速查找和定位修改目标,轻松准确地理解表单项含义及生效后果,同时简化填写流程,确保用户准确、轻松、快速地完成任务。
## 设计原则
<div class="design-inline-cards">
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*4IjJTbMSsmEAAAAAAAAAAABkARQnAQ" />
<div>
<h4>高效</h4>
<p>通过合理地信息组织形式和表单组价应用,使用户可以快速完成表单页任务。</p>
</div>
</div>
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*lEtuTZi2GvIAAAAAAAAAAABkARQnAQ" />
<div>
<h4>明确</h4>
<p>1. 快速定位重要信息和目标选项;</p>
<p>2. 标题、选项、提示等内容准确传达含义;</p>
<p>3. 让用户感知不同大小操作的前因后果,并及时响应相关反馈。</p>
</div>
</div>
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*R9PIRbGpFfYAAAAAAAAAAABkARQnAQ" />
<div>
<h4>安全感</h4>
<p>合理的操作后果保障机制,列如针对复杂表单提供分布或即时保存机制;针对不同场景任务提供返回、重置、取消、清空、撤销等后悔药和速效药功能。</p>
</div>
</div>
</div>
### Do&Don’t
在表单页中组织呈现各表单项时要注意简洁表达,高效准确,避免增加用户录入信息的成本。
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*k9DyRYLzjcoAAAAAAAAAAABkARQnAQ" alt="错误示范" />
一个表单页中针对同一种内容类型的表单项不要使用不同的组件或表现形式,会增加用户理解成本。
<br />
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*A0EBQ6eAkiwAAAAAAAAAAABkARQnAQ" alt="正确示范" />
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*V56PRpofMRUAAAAAAAAAAABkARQnAQ" alt="错误示范" />
表单项的标题、提示不要使用不易理解的词汇或过长,造成理解成本,如不可避免使用少见词汇,可使用帮助说明等元素辅助设计。
<br />
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*EC9uR6LiI0IAAAAAAAAAAABkARQnAQ" alt="错误示范" />
预填提示避免正确的废话,列如一个叫姓名的表单项输入提示是“请输入姓名”。
<br>
## 如何设计
表单类页面模板聚焦于提交一次表单的过程体验。按照任务的复杂度,提供四种解决问题的布局方式:
- 普通布局
- 任务拆解和编排
- 填写和预览
- 特定场景
### 普通布局
平铺所有需要填写的信息,适合内容项较少、内容项无法按照相关性分组的表单。
#### 模板 - 基础表单
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*c7b6TpKWl-cAAAAAAAAAAABkARQnAQ" />
**什么时候用**
当需要完成一个简单快速的任务,例如输入少量信息即可完成创建。
### 任务拆解和编排
将大型、复杂任务拆解为多个部分,并按照相关性分组,减轻用户输入负担。尽管每部分内容单独处理,但最终一起完成提交。适用于大型、复杂表单。通过适当的任务分割,可以降低用户出错率。
#### 模板 - 基础分步表单
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*E8wRRpLbdyoAAAAAAAAAAABkARQnAQ" />
**什么时候用**
将用户需要填写和确认的信息按照线性流程组织,利用步骤条告知用户完整流程和进度,常常在最后提交前让用户再次确认信息,并在流程结束给与明确的结果反馈。适用于具有明确的线性逻辑的任务。
#### 模板 - 分组表单
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*k6kGSLGZsT0AAAAAAAAAAABkARQnAQ" />
**什么时候用**
单次任务的表单页中需要填写内容众多,且不同内容之中存在一定可分类归纳性。
#### 模板 - 可编辑列表(开发中)
**什么时候用**
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*NLEeSLhLA3EAAAAAAAAAAABkARQnAQ" />
动态增减:建议条目表单数 ≤3 项,并且每个输入框不需要单独的标题使用。
<br />
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*PvoTSbqKywEAAAAAAAAAAABkARQnAQ"/>
可编辑表格:建议条目表单数 2 ~ 5 项 时使用,以使得每行内容可被完整呈现。
<br />
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*DWlCQazb-HQAAAAAAAAAAABkARQnAQ" />
折叠面板编辑:建议条目表单数在 6 ~ 8 项 时使用。
<br />
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*ttDGTLid8M4AAAAAAAAAAABkARQnAQ" />
抽屉编辑:建议条目表单表单数 >8 项 时使用。
<br />
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*p_wLTJEYOBgAAAAAAAAAAABkARQnAQ" />
规则树:应用于规则编辑场景。
适用于页面中需要添加一个或多个对象,且每个对象都需要添加或编辑多组数据的情况。
### 特定场景模板
#### 模板 - 设置
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*n9zkSKrDU8MAAAAAAAAAAABkARQnAQ" />
**什么时候用**
个人档案、应用配置等设置类页面,使用频率较低,一般用户操作后不会频繁修改。
**使用建议**
每个页面选择一种设置模式:
> - 即时生效模式:用户在修改选项即生效;
> - 提交生效模式:当设置项之间有关联关系,使用提交生效模式。
根据设置项数量确定是否需要分组:
> - 数量 <7 不建议分组
> - 数量 7~ 15 个建议分组;
> - 数量 >15 个建议使用页签分组。
#### [模板 - 登录](https://preview.pro.ant.design/user/login)
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*ba6DR5U23nAAAAAAAAAAAABkARQnAQ" />
Ant Design 标准登录模板
#### [模板 - 注册](https://preview.pro.ant.design/user/register)
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*6U_gQ6MbrSYAAAAAAAAAAABkARQnAQ" />
Ant Design 标准注册模板
## 设计建议
### 前期准备
- 表单页的核心由表单项组成,设计前建议先熟悉[表单基础规则](https://next.ant.design/components/form-cn/);
- 梳理用户当前信息录入任务中所涉及的信息类型,[并根据 Ant Design 数据录入规则](https://next.ant.design/docs/spec/data-entry-cn/) 确定所使用的组件。
### 布局方式
在单个表单页中需要根据内容量进行合理地布局,以兼顾页面展示和用户效率。表单页布局可由简到繁划分为 4 个梯度,每一级梯度都兼容前一种布局方式。
#### 基础布局
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*lacoSZduvVQAAAAAAAAAAABkARQnAQ" />
在一个区域内从上到下单列布局,引导用户纵向阅读,据[研究](https://www.uxmatters.com/mt/archives/2006/07/label-placement-in-forms.php)这是能够最高效完成任务的布局方式。
#### 弱分组
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*E7YuRo094e0AAAAAAAAAAABkARQnAQ" />
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*Nd_nQLmFQQwAAAAAAAAAAABkARQnAQ" alt="错误示范" description="为避免和弱分组布局的阅读顺序混淆,一个区域内禁用多列表单。" />
在空间有限时,较短宽度且具有相关性的表单项可多个组合在一行中,形成分组的暗示。
#### 区域内分组
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*eU8dRZUTEM8AAAAAAAAAAABkARQnAQ" />
当一个区域中内容较多且存在可分类归纳性时,可通过区分标题来进行区域内分组。
#### 卡片分组
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*DoKmSYGaYtYAAAAAAAAAAABkARQnAQ" />
关于使用何种布局方式的判断,和[详情页](https://next.ant.design/docs/spec/detail-page-cn#%E8%AE%BE%E8%AE%A1%E5%BB%BA%E8%AE%AE)类似,应从信息的复杂度和关联性两个维度去梳理。随后可选择相匹配的模板,进行页面快速搭建。
<br>
## 扩展阅读
### 会用到哪些模块或组件
- [表单](https://next.ant.design/components/form-cn/#header)
- [步骤条](https://next.ant.design/components/steps-cn/#header)
### 外部参考文章
- [Label Placement in Forms](https://www.uxmatters.com/mt/archives/2006/07/label-placement-in-forms.php)

7
docs/spec/research-list.en-US.md

@ -0,0 +1,7 @@
---
category: Design Patterns (Research)
type: Template Document
order: 3
title: List Page
skip: true
---

117
docs/spec/research-list.zh-CN.md

@ -0,0 +1,117 @@
---
category: 设计模式 - 探索
type: 模板文档
order: 3
title: 列表页
---
列表页可以查看和处理大量的条目,常有导航至详情的作用。用户可在列表页对条目进行筛选、对比、新增、分析、下钻至条目完整详情页等操作。
---
## 设计目标
帮助用户更高效的查看、处理、查找条目。
## 设计原则
<div class="design-inline-cards">
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*TZ7wT6tvulkAAAAAAAAAAABkARQnAQ" />
<div>
<h4>易扫读</h4>
<p>采用格式一致外观,突出有利于对象识别的关键信息。利用富交互分层展示信息以减少认知负荷。</p>
</div>
</div>
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*ngiJQaLQELEAAAAAAAAAAABkARQnAQ" />
<div>
<h4>可寻性</h4>
<p>列表以易于浏览的逻辑排序。提供合适的搜寻组件帮助用户快速查找信息。</p>
</div>
</div>
</div>
## 如何设计
### 基础布局
#### 单列布局
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*c0iNQIBusPMAAAAAAAAAAABkARQnAQ">
从上往下堆叠,数据过滤模块在最上方,过滤数据后,用户再由总体到具体的的浏览逻辑理解和分析。
#### 双栏布局
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*h8MsSr8UXCEAAAAAAAAAAABkARQnAQ">
将数据过滤模块放置在侧栏,当过滤条件过多,横向空间充裕时使用。
#### [模版 - 查询表格](https://preview.pro.ant.design/list/table-list)
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*uAGRTY5EMvIAAAAAAAAAAABkARQnAQ">
**什么时候使用**
每条条目需要都需要露出很多字段;用户在搜寻条目时有准确的查询范围时使用。
#### 模版 - 标准列表
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*3KMbRrbjvzkAAAAAAAAAAABkARQnAQ">
**什么时候使用**
提供每条条目的概览信息,点击列表可导航至条目详情。页面内常提供统计功能,供用户了解总体进展。可作为简易版的工作台使用。
#### [模板 - 卡片列表](https://preview.pro.ant.design/list/card-list)
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*coEVT7uElCUAAAAAAAAAAABkARQnAQ">
**什么时候使用**
用户无需以特定顺序浏览条目,将每个条目以富有吸引力的方式呈现。
#### 模版 - 搜索列表
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*yW4QQKNi_0QAAAAAAAAAAABkARQnAQ">
**什么时候使用**
以搜索为主寻找特定条目信息,通过关键词一次性在众多主题下的条目中搜寻结果。可对大量不同种类的内容进行搜索和筛选,满足对模糊目标的查找需求。
**涉及哪些操作**
筛选、搜索
#### 模版 - 成员管理
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*aJxDR6oP19gAAAAAAAAAAABkARQnAQ">
**什么时候使用**
成员管理是用于展示和管理某对象中所包含的成员的基本信息和权限信息的页面,管理操作通常包括添加成员、删除成员、成员角色与权限赋予等。
**涉及哪些操作**
筛选、删除等
## 设计建议
#### 批量操作
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*NvPKR5HZQ9MAAAAAAAAAAABkARQnAQ">
页级的批量操作影响整个页面,可布置于页底。
## 扩展阅读
#### 外部参考文章
- [Canvas 筛选器](https://canvas.hubspot.com/patterns/filters)
- [Canvas 搜索](https://canvas.hubspot.com/patterns/search)
- [Fiori 分析列表页](https://experience.sap.com/fiori-design-web/analytical-list-page/)
- [QuickBook 表格设计规则](https://designsystem.quickbooks.com/component/tables/)
- [文章:数据表格设计](https://medium.com/@taras.bakusevych/data-tables-design-3c705b106a64)
- [文章:Designing Tables for Reusability](https://uxdesign.cc/designing-tables-for-reusability-490a3760533)
- [文章:可供性与设计](http://www.woshipm.com/pd/1479.html)

9
docs/spec/research-message-and-feedback.en-US.md

@ -0,0 +1,9 @@
---
category: Design Patterns (Research)
type: Global Rules
order: 2
title: Message and Feedback
skip: true
---
设计模式 - 探索 - 全局规则 - 消息与反馈

124
docs/spec/research-message-and-feedback.zh-CN.md

@ -0,0 +1,124 @@
---
category: 设计模式 - 探索
type: 全局规则
order: 2
title: 消息与反馈
---
用于在必要时向用户反馈操作结果或传达消息。
## 设计目标
在不同事件下用户都能感知与操作场景和紧急程度匹配的结果反馈或消息提示,做到合理有效的信息传达。
## 反馈方式
在设计时需要考虑用户试图完成的任务以及需要引起注意的方式,采用何种反馈方式。反馈方式列举如下图:
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*SKfjS7vyRP4AAAAAAAAAAABkARQnAQ">
</div>
## 何时使用
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*vv37RaVAXhAAAAAAAAAAAABkARQnAQ">
</div>
### 成功
#### 留在原地
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*qQ8NTKMH-2IAAAAAAAAAAABkARQnAQ">
**对话框 Model**
在不跳转页面打断用户工作流程的前提下,告知用户重要的成功结果。
####
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*NPVGQr6f5-4AAAAAAAAAAABkARQnAQ">
**全局提示 Message**
在不希望在用户执行操作时中断用户前提下显示一条简短的成功消息。
#### 跳转
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*0EdyRa7WeUAAAAAAAAAAAABkARQnAQ">
**独占式 Inline Text & Illustration**
- 长流程步骤表单在最后告知用户成功结果;
- 需要展示较复杂的补充信息(例如配置信息详情)。
####
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*524fSKE97wYAAAAAAAAAAABkARQnAQ">
**全局提示 Message**
在不希望在用户执行操作时中断用户前提下显示一条简短的成功消息。
### 失败
#### 留在原地
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*S03WS5uHqDsAAAAAAAAAAABkARQnAQ">
**对话框 Model**
提醒用户完成当前工作流之外的重要操作(例如警告信息不安全)。
####
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*4sHLQowCs6IAAAAAAAAAAABkARQnAQ">
**警告提示 Alert**
提醒用户系统中需要立即引起注意的错误信息。
####
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*Qg51Sq2A_M4AAAAAAAAAAABkARQnAQ">
**表单校验提示**
- 用户输入的内容不符合字段或表单的要求;
- 用户跳过了必填字段;
- 系统检测到表单数据中的错误。
####
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*QeWqTIWqrWEAAAAAAAAAAABkARQnAQ">
**通知提醒框 Notification**
- 向用户告知重要的问题或失败状态,希望用户立马做出决策;
- 反馈后台进程失败&告警结果。
#### 跳转
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*7ES2TrY6UJgAAAAAAAAAAABkARQnAQ">
**独占式 Inline Text & Illustration**
- 长流程步骤表单最后出现第三方原因造成的失败结果(例如应用引擎创建失败);
- 需要展示失败详情。
### 后台操作
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*owL_SK1xmggAAAAAAAAAAABkARQnAQ">
**通知提醒框 Notification**
- 向用户告知重要的问题或失败状态,希望用户立马做出决策;
- 反馈后台进程结果。
####
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*IGpqRbPGZxQAAAAAAAAAAABkARQnAQ">
**通知中心**
向用户通知相关活动信息(例如用户需要审批的项目或者用户申请的审批进程)。

9
docs/spec/research-navigation.en-US.md

@ -0,0 +1,9 @@
---
category: Design Patterns (Research)
type: Global Rules
order: 1
title: Navigation
skip: true
---
设计模式 - 探索 - 全局规则 - 导航

285
docs/spec/research-navigation.zh-CN.md

@ -0,0 +1,285 @@
---
category: 设计模式 - 探索
type: 全局规则
order: 1
title: 导航
---
导航用来展示当前产品中,用户在哪儿,可以去哪儿。
## 设计目标
让用户明确知晓当前所处产品中的位置,并方便快捷地带用户到他想去的地方。
---
## 设计原则
<div class="design-inline-cards">
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*7BUOQYDiEr0AAAAAAAAAAABkARQnAQ" />
<div>
<h4>可循性</h4>
<p>用户可定位到他们想要的信息。</p>
</div>
</div>
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*NfLHQJfGmUQAAAAAAAAAAABkARQnAQ" />
<div>
<h4>高效</h4>
<p>1. 多接入点:对同一目的地提供多个链接;</p>
<p>2. 捷径:提供访问内容的捷径,如相关链接;</p>
<p>3. 逃生舱:点击 logo 回到首页重新启动信息搜寻。</p>
</div>
</div>
</div>
---
## 设计建议
### 信息架构
• 设计时应尽量保持浅平宽的信息架构层级;
• 从用户的使用路径考虑导航,而非仅基于层级结构;
• 常见的组织方式有:
1. 按主题,例如产品提供的服务或内容分类,好处是直接呈现站点的内容范围;
2. 按受众群体,例如管理员、运营、操作员;
3. 按任务,例如了解合作模式、联系合作专员、签约流程、合作联调、业务运营、客户服务。
### 导航路径
完善的导航应该允许用户沿多种路径移动:
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*Q9WMS64xs2gAAAAAAAAAAABkARQnAQ">
</div>
**A-平移**:同层级跳转
**B-下钻**:进入低层级的内容
**C-返回**:返向浏览历史或高层级内容
**D-联想导航**:根据相关性导航至内容
---
## 类型
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*MU2BQpS51mMAAAAAAAAAAABkARQnAQ">
正确理解和使用导航组件对产品全局体验至关重要。
我们将导航划分为以下 5 种类型:
1.全局导航
2.返回类导航
3.页内导航
4.下钻类导航
5.联想类导航
### 全局导航
全局导航体现网站的核心组织结构。
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*PgY8S6Mx3x8AAAAAAAAAAABkARQnAQ">
</div>
#### 侧边导航
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*fNW0Rak8sL8AAAAAAAAAAABkARQnAQ">
- 很多菜单时使用,建议菜单多于 6 项时使用;
- 可以承载多个层级,但建议 1-3 个层级;
- 企业级产品推荐使用侧栏导航,其可见性更好易于扫读,各菜单重要性受菜单排列顺序影响较小。
#### 顶部导航
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*MmmnTKl0hO8AAAAAAAAAAABkARQnAQ">
- 各菜单权重常常与排列顺序呈正相关,即排列顺序影响用户使用频次;
- 建议 2~7 项内容使用;
- 建议 1-2 个层级;超出 2 个层级时,建议采用弹出式导航。
#### 弹出式导航
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*8lgCQb8copwAAAAAAAAAAABkARQnAQ" alt="正确示范">
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*_k8wR4PoOSsAAAAAAAAAAABkARQnAQ" alt="错误示范">
用于拓展导航承载层级,适用于大型网站。
站点地图式导航可以让用户对整个网站的可用功能一目了然。
1. 不要让用户延着狭窄的悬停路径获取导航菜单;
2. 不要让用户逐层打开每层菜单去查找,低效又困难;
> 此建议仅针对导航类菜单,不适用于操作类菜单。
#### 实用工具
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*UXcoSYBXgOMAAAAAAAAAAABkARQnAQ">
通常放在网站的右上角,是一种习惯用法,用户习惯在这个位置找到这些内容。
内容通常包括:
• 全局搜索
• 通知中心
• 网站帮助
• 客服信息、购物车
• 收藏夹
• 登录工具
• 语言切换
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*DgCoRI0aFLcAAAAAAAAAAABkARQnAQ" alt="错误示范">
**不要将页面内的操作放到实用工具中。**
### 子站点导航
企业级产品常采用层级+数据库混合结构的信息架构,这种信息架构通常层级较深,为了实现用户感知层面的浅平宽,将较深几个层级组织为一个子站点,降低单个站点层级数量,减轻用户认知负担。
另一种子站点场景是,面对一些任务复杂,需要较大的工作空间,以子站点的方式沉浸式处理任务。最常见的是编辑器。子站点模式下,对全站导航功能需求低,通常只需提供一个返回上级或回到首页的出口。
> 此处的数据库是一种信息架构形式,各页面内容独立,但都遵循一致的形式/格式。
<img class="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*jYG0T7S-SjsAAAAAAAAAAABkARQnAQ">
#### 沉浸式导航
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*vABzS5JNgocAAAAAAAAAAABkARQnAQ">
用于处理较为复杂或需要较大工作空间的任务。
#### 多级站点导航
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*mXw5TIVLL-sAAAAAAAAAAABkARQnAQ">
- 菜单数量较多的子站点使用;
- 子站点设计上,应明显区别于全站导航,使得进入子站点需要成较大的过渡波动,提示用户进入了新的空间。
### 页内导航
信息架构中较低层级的内容导航可以使用页内导航,如果页面需要分享给他人,需在在 url 添加定位标记。
#### 页头
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*Ah4HQ6gPheQAAAAAAAAAAABkARQnAQ">
页头位于页内容上方,主要作用是申明页面主题、页内信息导航、页面级内容操作。
#### Tree 树型控件
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*PJ2fTKBEZIoAAAAAAAAAAABkARQnAQ">
页面内多层次的结构展示。
#### 锚点
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*d6eDQZy-6gkAAAAAAAAAAABkARQnAQ">
在各个页面分区之间跳转,当平铺呈现的内容过长时使用。
#### 回到顶部
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*-QkOT5KrcDwAAAAAAAAAAABkARQnAQ">
快速回到页面顶部。
#### 走马灯
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*gVZZQIz6yw4AAAAAAAAAAABkARQnAQ">
循环播放一系列内容。
### 下钻类导航
点击进入信息架构下层内容,默认站内跳转,站外新开标签页,典型场景为列表下钻至详情。
### 返回类导航
#### 面包屑
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*QcmiTLXUH1oAAAAAAAAAAABkARQnAQ">
反映当前页面在网站结构中的位置,在少于三个层级是无需展示,此时的全局导航能直接呈现位置。用户可通过面包屑返回上级页面。
#### 返回按钮
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*z1XdRrwsqgQAAAAAAAAAAABkARQnAQ">
**一般标题会和面包屑一起出现,有面包屑时标题默认不推荐使用返回按钮。**
页头中的返回按钮相当于一个短面包屑,用于返回上一层级页面。适用于子站点场景,该场景隐藏了全站导航,用户需要通过返回按钮回到上级页面。
### 联想类导航
#### 步骤条
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*jhNXQL5oRaMAAAAAAAAAAABkARQnAQ">
按照预先定义的顺序引导用户一步一步前后移动。
在一系列页面的每一页上都展示步骤条,并标记当前页面在这条线性路径上的位置。
适用于:
• 用户访问路径是线性的;
• 步骤条将复杂的任务分解为易于处理的小任务,减少用户出错,更快完成任务。
#### 上一篇下一篇
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*5Es3S4HJvrEAAAAAAAAAAABkARQnAQ">
协助我们移动到其他关系紧密的网页。
---
## 如何验证设计结果
验证导航系统的设计好坏可对其进行压力测试:像跳伞一样跳进网站里,验证导航系统的极限。
1)忽略首页,随机直达网站某一页面;
2)看用户是否能知道当前位置以及与网站其他部分的关系。在哪个网站的哪个部分?上层网页是什么?
3)是否知道这个网页会带你到哪里去?链接文字是否能说明去向?
---
## 扩展阅读
### 外部参考文章
- [阿里云-控制台导内容区导航系统](https://xconsole.aliyun-inc.com/spec/hxzewz)
- [Material Design Navigation](https://material.io/design/navigation/understanding-navigation.html#)
- [Predix Navigation](https://www.predix-ui.com/#/design/foundation/navigation)
- [Windows-UWP 应用的导航设计基础知识](https://docs.microsoft.com/zh-cn/windows/uwp/design/basics/navigation-basics)
- [When You Should Use a Breadcrumb Navigation?](https://uxmovement.com/navigation/when-you-should-use-a-breadcrumb-navigation/)
- 书籍:《web 信息架构》— 导航系统
- 书籍:《web 导航设计》

8
docs/spec/research-overview.en-US.md

@ -0,0 +1,8 @@
---
category: Design Patterns (Research)
order: 0
title: Overview
skip: true
---
设计模式-探索:概览

9
docs/spec/research-overview.zh-CN.md

@ -0,0 +1,9 @@
---
category: 设计模式 - 探索
order: 0
title: 概览
---
在探索频道中,将公开我们正在研究完善的设计模式和尚未定稿的内容,其中大部分内容可以使用现有的 antd 组件搭建。当然,也可能存在小部分新的组件还未被开发。开辟探索频道,初心是与用户一起完善 Ant Design,如果你正在使用这些内容,你的反馈可以帮助我们更快优化和迭代,并推动组件尽快进入开发状态。
<br/><br/>
[反馈地址](https://www.yuque.com/antdesign/topics) | [阿里内网反馈地址](https://yuque.antfin-inc.com/bigfish/topics)

7
docs/spec/research-result.en-US.md

@ -0,0 +1,7 @@
---
category: Design Patterns (Research)
type: Template Document
order: 4
title: Result Page
skip: true
---

120
docs/spec/research-result.zh-CN.md

@ -0,0 +1,120 @@
---
category: 设计模式 - 探索
type: 模板文档
order: 4
title: 结果页
---
结果页是用一个页面反馈操作结果,是反馈模式中最强的一种。
## 设何时使用
当完成一个流程操作后,需给与用户明确的结果反馈时,例如分步表单的最后一步。<br/> 当有大量的信息需要在结果页展示时。
## 设计目标
向用户传达任务完成结果,引导用户进行下一步操作,通过有效的反馈建立起用户对系统的信任。
## 设计原则
<div class="design-inline-cards">
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*HHLnR5RgpWQAAAAAAAAAAABkARQnAQ" />
<div>
<h4>慎重使用</h4>
<p>结果页是比较重的反馈方式,仅适用于吸引用户注意程度强、信息量较大、页面永久停留的场景中,其余场景不建议使用。</p>
</div>
</div>
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*hglURJfVdHoAAAAAAAAAAABkARQnAQ" />
<div>
<h4>即时结束</h4>
<p>当结果状态为成功时,可以默认提供几秒(建议 3-5秒)后自动跳转。</p>
</div>
</div>
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*tJC7RZviqzwAAAAAAAAAAABkARQnAQ" />
<div>
<h4>精简信息</h4>
<p>结果页信息建议为提交动作触发后的结果,例如校验建议在表单中完成。结果页信息需精简,仅展示结果相关内容,特殊场景可以增加补充信息。</p>
</div>
</div>
</div>
## 设计建议
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*98B4QKjg-QoAAAAAAAAAAABkARQnAQ" alt="正确示范">
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*EgnGQ4zImuMAAAAAAAAAAABkARQnAQ" alt="错误示范">
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*lVo2RKb6mL4AAAAAAAAAAABkARQnAQ" alt="正确示范">
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*4RFCTLatKrcAAAAAAAAAAABkARQnAQ" alt="错误示范">
标题构成建议为「对象+动作+结果/状态」或「动作+结果/状态」。
<br />
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*r7UFSLbqTdYAAAAAAAAAAABkARQnAQ" alt="正确示范">
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zXk0SI4qqYMAAAAAAAAAAABkARQnAQ" alt="错误示范">
操作引导建议不超过 2 项,过多操作会对用户选择造成困扰。
<br />
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*9gvmRq3RmnQAAAAAAAAAAABkARQnAQ" alt="正确示范">
轻量的反馈不建议使用结果页,可以使用全局提示、警告提示、通知提醒框等交互方式,详情参考反馈类设计指南。
<br />
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*JY1kR4qIR1wAAAAAAAAAAABkARQnAQ" alt="正确示范">
若结果状态为成功时,可在主按钮上告知用户几秒后自动跳转。
## 如何设计
### 基础布局
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*PQotS7GJC1gAAAAAAAAAAABkARQnAQ">
结果页可提供以下内容:
1. 结果反馈:明确告知用户提交结果;
2. 结果解释(可选):若需要对结果简要解释使用;
3. 建议操作:引导用户继续完成后续工作;
4. 补充信息(可选):在通知结果的同时,有补充信息需要反馈给用户;营销模块。
#### 模板 - 基础结果页
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*uXFNR4eef2oAAAAAAAAAAABkARQnAQ">
显示结果状态并引导用户进行下一步操作。
#### 模板 - 复杂结果页
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*SWabTZptxEcAAAAAAAAAAABkARQnAQ">
除结果状态和引导操作等基础信息外,同时展示相关推荐、流程进度、错误详情等信息。
#### 补充信息类型
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*QjpBRpyx5ecAAAAAAAAAAABkARQnAQ">
## 延伸阅读
### 会用到哪些全局规则
- [反馈](/docs/spec/research-message-and-feedback)
### 会用到哪些模块或组件
- [表单页](https://next.ant.design/components/form-cn/)
### 外部参考文章
- [Fiori 消息反馈类组件规则](https://experience.sap.com/fiori-design-web/message-box/)
- [阿里云结果页设计](https://xconsole.aliyun-inc.com/scenes/resultpage)
- [CANVAS 消息反馈类组件规则](https://canvas.hubspot.com/components/alerts-messaging)
- [PREDIX 通知提醒框和警告组件规则](https://www.predix-ui.com/#/design/communication/notifications)

7
docs/spec/research-workbench.en-US.md

@ -0,0 +1,7 @@
---
category: Design Patterns (Research)
type: Template Document
order: 2
title: Workbench
skip: true
---

98
docs/spec/research-workbench.zh-CN.md

@ -0,0 +1,98 @@
---
category: 设计模式 - 探索
type: 模板文档
order: 2
title: 工作台
---
工作台常被作为应用的主页,是一个为用户提供便利的交通枢纽。工作台提供常用信息入口,以中心辐射的方式导航至应用的各功能模块;呈现用户当前需要关注的信息,缩短获取关键信息的路径;同时允许用户在工作台直接操作一些高频任务。
---
## 设计目标
用户侧:提供处理和查看信息的捷径,并为用户提供必要的帮助;<br/>
产品侧:与用户更好地沟通,适当宣传产品的新动向等运营内容。
## 设计原则
<div class="design-inline-cards">
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*aFiGRbIvuH4AAAAAAAAAAABkARQnAQ" />
<div>
<h4>可寻性</h4>
<p>用户是否能定位到他们想要的信息。</p>
</div>
</div>
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*lTUuSKmd8WsAAAAAAAAAAABkARQnAQ" />
<div>
<h4>降低记忆负载</h4>
<p>理解用户再次访问的核心目标,为可能的目的地提供最短导航路径。</p>
</div>
</div>
## 如何设计
#### 模板 - 工作台
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*8s67TL62WEoAAAAAAAAAAABkARQnAQ">
**什么时候使用**
- 为用户再次访问缩短导航路径;
- 为用户提供常用导航入口。
**涉及哪些功能**
使用帮助;核心数据;快捷入口;待办清单;关注;运营模块。
**设计建议**
- 展示与日常工作相关模块,将总模块数量控制在 5-9 个;
- 尽量在首屏呈现最常使用的内容;
- 提供基于角色的差异化视图。
#### 模板 - 新手引导
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*LQBmQauTEAsAAAAAAAAAAABkARQnAQ">
**什么时候使用**
- 当新用户到达平台,尚未开始任何工作时,缩短新用户学习时长;
- 部分模块无内容时,请参见「空状态」指引。
**涉及哪些功能**
使用帮助;空状态引导
**设计建议**
- 向用户介绍平台用途,并引导用户开始工作;
- 如果需要用户管理复杂的对象,提供 Demo 预览入口;
### 设计建议
#### 选择合适的导航方式
这类页面一般会提供两类导航形式。<br/>
① 用户知道他想要使用的功能,需要利用导航获取。例如:
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*xlYoTIf8NpwAAAAAAAAAAABkARQnAQ">
</div>
② 发现类导航,用户须完成某任务,但不知道使用哪个功能来完成。例如:
<div>
<img src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*9nKdRJBAu8sAAAAAAAAAAABkARQnAQ">
</div>
#### 按照使用频次布置内容
<img class="preview-img no-padding" align="right" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*1tfiR5-xKUQAAAAAAAAAAABkARQnAQ">
用户在日常工作中最常使用的内容,按照使用频次将内容布置以下各区域。
#### 考虑异常状态
详见异常页
> 另,关于是否应该推荐用户个性化定制,这部分内容尚在探索中。

6
docs/spec/shadow.en-US.md

@ -0,0 +1,6 @@
---
category: Global Styles
order: 6
title: Shadow
skip: true
---

8
docs/spec/shadow.md

@ -1,8 +0,0 @@
---
category: 全局样式
order: 4
title:
zh-CN: 阴影
en-US: Shadow
skip: true
---

344
docs/spec/shadow.zh-CN.md

@ -0,0 +1,344 @@
---
category: 全局样式
order: 6
title: 阴影
---
阴影来源于现实生活的反映物体与物体之间距离的物理现象。在界面中,我们往往通过模拟元素的投影直截了当的来告诉用户,元素之间的高度距离与层次关系。
## 高度
阴影是由两个不同阶层的平面产生,且强度由两者之间的距离决定。所以物体的高度直接影响物体的阴影,对象离地面越远阴影越大,模糊值越高。我们将系统分为无、低、中、高四个 UI 层级,各自分布在不同的高度层级,阴影属性也有所不同。
<div>
<img class="preview-img no-padding" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*o-OFQK5hJP0AAAAAAAAAAABkARQnAQ" alt="高度">
</div>
**第 0 层**:物体紧贴地面,投影与物体完全重叠,在界面中不对此层定义阴影值。如:输入框等;
<div>
<img class="preview-img no-padding" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*li3zQbxRuOMAAAAAAAAAAABkARQnAQ" alt="高度">
</div>
**第 1 层**: 物体位于低层级,此时物体被操作(悬停、点击等)触发为悬浮状态,当操作完成或取消时,悬停状态反馈也跟随消失,物体回归到原有的层级中,如:卡片 hover 等;
<div>
<img class="preview-img no-padding" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*mXnoSI8MWuEAAAAAAAAAAABkARQnAQ" alt="高度">
</div>
**第 2 层**:物体位于中层级,此时物体与基准面的关系是展开并跟随,物体由地面上的元素展开产生,会跟随元素所在层级的移动而移动,如:下拉面板等;
<div>
<img class="preview-img no-padding" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*yNOwR6Gqy4MAAAAAAAAAAABkARQnAQ" alt="高度">
</div>
**第 3 层**:物体位于高层级,该物体的运动和其他层级没有关联,如:对话框等。
<div>
<img class="preview-img no-padding" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*4pFoR4gWL2oAAAAAAAAAAABkARQnAQ" alt="高度">
</div>
## 光源
阴影的方向是由光源与物体的相对位置所决定的。假定光源所处高度不变,光源与物体的距离和物体与阴影的距离成正比。光源越远,则阴影距离物体越远。阴影的方向在界面里通常使用 `X, Y` 坐标轴来表示。
<div>
<img class="preview-img no-padding" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*1oijTJh2HEIAAAAAAAAAAABkARQnAQ" alt="阴影值">
</div>
## 阴影值
综上可知。阴影由光照而产生。主要影响其值的是物体高度与光源位置:
1. 在不同高度上时,投射出的阴影颜色、模糊度、面积都有所区分。离地面越远的物体,产生的阴影颜色越淡、模糊度越高、面积越大;反之则颜色更深、模糊度越低、面积越小;
2. 而投影的方向主要由光源与物体的相对位置决定。在 Ant Design 中不同的阴影方向使用在不同的地方:
- 阴影向下:主要应用在组件内部或组件本身,是比较常规场景的用法
- 阴影向上:主要应用与底部导航或工具栏等
- 阴影向左:主要应用与右边导航栏、抽屉组件或固定表格栏
- 阴影向右:主要应用与左边导航栏、抽屉组件或固定表格栏
阴影是模拟的真实世界的反馈,Ant Design 为了更符合真实阴影,在 4.0 中采用了三层阴影的表达方式,让阴影更柔和,更符合真实状态
<div>
<img class="preview-img no-padding" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*1oijTJh2HEIAAAAAAAAAAABkARQnAQ" alt="阴影值">
</div>
### 常用阴影设计表
**第一层:**
<table>
<thead>
<tr>
<th>阴影类型</th>
<th>阴影颜色(rgba)</th>
<th>方向(X, Y)</th>
<th>模糊度(Blur)</th>
<th>扩展值(Spread)</th>
</tr>
</thead>
<tbody>
<tr>
<td rowSpan="3">@shadow-1-up</td>
<td>rgba(0, 0, 0, 0.16)</td>
<td>0px, -1px</td>
<td>2px</td>
<td>-2px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.12)</td>
<td>0px, -3px</td>
<td>6px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.09)</td>
<td>0px, -5px</td>
<td>12px</td>
<td>4px</td>
</tr>
<tr>
<td rowSpan="3">@shadow-1-down</td>
<td>rgba(0, 0, 0, 0.16)</td>
<td>0px, 1px</td>
<td>2px</td>
<td>-2px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.12)</td>
<td>0px, 3px</td>
<td>6px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.09)</td>
<td>0px, 5px</td>
<td>12px</td>
<td>4px</td>
</tr>
<tr>
<td rowSpan="3">@shadow-1-left</td>
<td>rgba(0, 0, 0, 0.16)</td>
<td>-1px, 0px</td>
<td>2px</td>
<td>-2px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.12)</td>
<td>-3px, 0px</td>
<td>6px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.09)</td>
<td>-5px, 0px</td>
<td>12px</td>
<td>4px</td>
</tr>
<tr>
<td rowSpan="3">@shadow-1-right</td>
<td>rgba(0, 0, 0, 0.16)</td>
<td>1px, 0px</td>
<td>2px</td>
<td>-2px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.12)</td>
<td>3px, 0px</td>
<td>6px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.09)</td>
<td>5px, 0px</td>
<td>12px</td>
<td>4px</td>
</tr>
</tbody>
</table>
**第二层:**
<table>
<thead>
<tr>
<th>阴影类型</th>
<th>阴影颜色(rgba)</th>
<th>方向(X, Y)</th>
<th>模糊度(Blur)</th>
<th>扩展值(Spread)</th>
</tr>
</thead>
<tbody>
<tr>
<td rowSpan="3">@shadow-2-up</td>
<td>rgba(0, 0, 0, 0.12)</td>
<td>0px, -3px</td>
<td>6px</td>
<td>-4px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.08)</td>
<td>0px, -6px</td>
<td>16px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.05)</td>
<td>0px, -9px</td>
<td>28px</td>
<td>8px</td>
</tr>
<tr>
<td rowSpan="3">@shadow-2-down</td>
<td>rgba(0, 0, 0, 0.12)</td>
<td>0px, 3px</td>
<td>6px</td>
<td>-4px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.08)</td>
<td>0px, 6px</td>
<td>16px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.05)</td>
<td>0px, 9px</td>
<td>28px</td>
<td>8px</td>
</tr>
<tr>
<td rowSpan="3">@shadow-2-left</td>
<td>rgba(0, 0, 0, 0.12)</td>
<td>-3px, 0px</td>
<td>6px</td>
<td>-4px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.08)</td>
<td>-6px, 0px</td>
<td>16px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.05)</td>
<td>-9px, 0px</td>
<td>28px</td>
<td>8px</td>
</tr>
<tr>
<td rowSpan="3">@shadow-2-right</td>
<td>rgba(0, 0, 0, 0.12)</td>
<td>3px, 0px</td>
<td>6px</td>
<td>-4px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.08)</td>
<td>6px, 0px</td>
<td>16px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.05)</td>
<td>9px, 0px</td>
<td>28px</td>
<td>8px</td>
</tr>
</tbody>
</table>
**第三层:**
<table>
<thead>
<tr>
<th>阴影类型</th>
<th>阴影颜色(rgba)</th>
<th>方向(X, Y)</th>
<th>模糊度(Blur)</th>
<th>扩展值(Spread)</th>
</tr>
</thead>
<tbody>
<tr>
<td rowSpan="3">@shadow-3-up</td>
<td>rgba(0, 0, 0, 0.08)</td>
<td>0px, -6px</td>
<td>16px</td>
<td>-8px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.05)</td>
<td>0px, -9px</td>
<td>28px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.03)</td>
<td>0px, -12px</td>
<td>48px</td>
<td>16px</td>
</tr>
<tr>
<td rowSpan="3">@shadow-3-down</td>
<td>rgba(0, 0, 0, 0.08)</td>
<td>0px, 6px</td>
<td>16px</td>
<td>-8px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.05)</td>
<td>0px, 9px</td>
<td>28px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.03)</td>
<td>0px, 12px</td>
<td>48px</td>
<td>16px</td>
</tr>
<tr>
<td rowSpan="3">@shadow-3-left</td>
<td>rgba(0, 0, 0, 0.08)</td>
<td>-6px, 0px</td>
<td>16px</td>
<td>-8px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.05)</td>
<td>-9px, 0px</td>
<td>28px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.03)</td>
<td>-12px, 0px</td>
<td>48px</td>
<td>16px</td>
</tr>
<tr>
<td rowSpan="3">@shadow-3-right</td>
<td>rgba(0, 0, 0, 0.08)</td>
<td>6px, 0px</td>
<td>16px</td>
<td>-8px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.05)</td>
<td>9px, 0px</td>
<td>28px</td>
<td>0px</td>
</tr>
<tr>
<td>rgba(0, 0, 0, 0.03)</td>
<td>12px, 0px</td>
<td>48px</td>
<td>16px</td>
</tr>
</tbody>
</table>

172
docs/spec/visual.zh-CN.md

@ -3,24 +3,170 @@ order: 3
title: 可视化
---
可视化语言是基于中台设计语言 Ant Design 衍生的一套具有数据可视化特性的设计指导原则,让数据表达更符合用户心理,帮助「设计者」孵化出更具业务特性的可视化解决方案以满足个性化设计需求,屏蔽不必要的设计差异和实现成本,从而解放「设计者」和前端的研发资源,实现全面提高数据图表的研发效率。
可视化语言是基于 Ant Design 衍生的一套具有数据可视化特性的设计指导原则,让数据表达更符合用户心理,以帮助『设计者』孵化出更具业务特性的数据可视化解决方案,屏蔽不必要的设计差异和实现成本,从而解放『设计者』和前端的生产力,实现数据图表的研发效能全面提高。
同时,这是一份动态更新的设计文档,你的阅读和互动正是我们不断前进的动力,[GitHub 反馈地址](https://github.com/antvis/site/issues)
同时,这是一份动态更新的设计文档,你的阅读和反馈正是我们不断前进的动力,[GitHub 反馈地址](https://github.com/antvis/site/issues)。
<br />
## 设计资源
# 前端实现
AntV 提供完善的设计原则 & 指引和设计资源文件(Sketch),此外还提供了一份完整的图表用法说明,来帮助用户快速理解图表并设计出高质量的可视化图表。
- [设计原则](https://antv.vision/zh/docs/specification/principles/basic)
- [设计资源](https://antv.vision/zh/docs/specification/resources)
- [图表用法](https://antv-2018.alipay.com/zh-cn/vis/chart/index.html)
## 前端实现
AntV 基于原生 JavaScipt 封装了一套 AntV 的组件库,其包含高交互基础图表库 G2Plot,专注解决流程与关系分析的图表库 G6,适于移动端应用的图表库 F2 等,也欢迎社区其他框架的实现版本。
[AntV](https://antv.vision/zh) 是基于原生 JavaScipt 封装的可视化组件库,包含高交互基础图表库 G2Plot,流程与关系分析的图表库 G6,专注解决地理空间数据可视分析的 L7,适用于移动端的高性能图表库 F2 ,欢迎社区贡献其他框架的实现版本。
- [G2 可视化引擎](https://g2.antv.vision/zh)
- [G2Plot 开箱即用的图表库](https://g2plot.antv.vision/zh) 🔥
- [G6 图可视化引擎](https://g6.antv.vision/zh)
- [F2 移动端可视化方案](https://f2.antv.vision/zh)
- [L7 地理空间数据可视分析引擎](https://l7.antv.vision/zh)
- [F2 移动端可视化方案](https://f2.antv.vision/zh)
<br />
# 如何设计
### 了解用户
用户是谁?他们要从可视化作品上获取什么信息?在企业级产品中,用户可能是公司高层、BI 分析师、运营、数据开发等不同角色,不一样的角色在使用可视化作品时,其目的以及使用路径会有所不同。建议在设计开始前对使用者进行充分剖析,以便完整地讲述你的数据故事,准确呈现你的数据见解。
<br />
### 设计原则
- 准确:从数据转化到可视表达时不歪曲,不误导,不遗漏,忠实反映数据里包含的信息;
- 有效:信息传达有重点,克制不冗余,避免信息过载,用最适量的数据-油墨比(Data-ink Ratio)表达对用户最有用的信息;
- 清晰:表现方式清楚易读,具条理性,可以帮助用户快速达成目标,在最少的时间内获取更多的信息;
- 美:对数据的完美表达,合理利用视觉元素进行艺术创作,不过度修饰,给用户优雅的体验。
<br />
## 图表用法
### 选择正确的图表类型
我们提供了完整的图表用法说明,帮助您更正确地选择图表类型。
#### 时间类
<img class="preview-img no-padding" align="right" description="代表类型:折线图、面积图等" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*z0ZSRabgdpQAAAAAAAAAAABkARQnAQ" />
通常用于表现数据在时间维度上的趋势和变化。
#### 比较类
<img class="preview-img no-padding" align="right" description="代表类型:柱状图、气泡图等" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*mvE4T6jti5QAAAAAAAAAAABkARQnAQ" />
使用图形的长度、宽度、位置、面积、角度和颜色来比较数值的大小,通常用于展示不同分类间的数值对比。
#### 分布类
<img class="preview-img no-padding" align="right" description="代表类型:散点图、箱形图等" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*_ft8Soe5p6EAAAAAAAAAAABkARQnAQ" />
通常用于展示连续数据上数值的分布情况。
#### 流程类
<img class="preview-img no-padding" align="right" description="代表类型:漏斗图等" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*kJj6Qo3-UFIAAAAAAAAAAABkARQnAQ" />
通常用于表示流程流转、流量关系。
#### 占比类
<img class="preview-img no-padding" align="right" description="代表类型:环图、饼图、百分比堆叠类型图表等" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*52XJRK9B0KUAAAAAAAAAAABkARQnAQ" />
显示同一维度上占比关系。
<br />
获取更多图表用法内容,请前往 [AntV 图表用法](https://antv-2018.alipay.com/zh-cn/vis/chart/index.html)
<br />
### 色板
<img class="preview-img no-padding" align="right" description="AntV 官方默认色板示例" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*58AFS77miwoAAAAAAAAAAABkARQnAQ" />
AntV 提供了一套默认的图表颜色,包括颜色的用法,
<br />
获取更多色板,请前往 [AntV - 设计语言 - 视觉](https://antv.vision/zh/docs/specification/principles/visual/)
<br />
### 组件使用建议
#### 标题与注释
标题是对图表的主题进行阐述的一段话;注释是表明数据来源,让图表看起来来源清晰、可靠。
#### 轴
<img class="preview-img no-padding" align="right" description="轴的元素" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*i4tXQZkMGrMAAAAAAAAAAABkARQnAQ" />
<img class="preview-img no-padding" align="right" description="轴的分类" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*-ycMQZ48GykAAAAAAAAAAABkARQnAQ" />
用来定义坐标系中数据在方向和值的映射关系。
#### 图例
<img class="preview-img no-padding" align="right" description="图例的元素" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*8oYwRJbGmhMAAAAAAAAAAABkARQnAQ" />
<img class="preview-img no-padding" align="right" description="图例的分类" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*sSGjRJGyrqQAAAAAAAAAAABkARQnAQ" />
用来解释图表区域中包含的所有视觉元素的含义。
#### 标签
<img class="preview-img no-padding" align="right" description="标签的分类" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*j2gNQ4E-wAoAAAAAAAAAAABkARQnAQ" />
对当前的一组数据进行的内容标注。
#### 提示信息
<img class="preview-img no-padding" align="right" description="提示信息的元素" src="https://gw.alipayobjects.com/zos/basement_prod/f9683e72-81a4-47cc-a208-6570187cce11.svg" />
指当鼠标悬停在图表上或者手指点按移动设备的某个数据点时,以交互提示信息的形式展示该点的数据,比如该点的值,数据单位等。
#### 图形
<img class="preview-img no-padding" align="right" description="图形的分类" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*itDLQb2fXpkAAAAAAAAAAABkARQnAQ" />
图形是统计图表的视觉通道在形状上映射的视觉展现,是图表的主体部分,其他图表组件的目的是帮助读者更好地理解数据在图形上的映射关系。
<br />
获取组件使用建议,请前往 [AntV - 设计语言 - 图表组件设计指引](https://antv.vision/zh/docs/specification/components/titlenotes)
<br />
### 图表布局适应
<img class="preview-img no-padding" align="right" description="图表响应式示意" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*0vfXTIlbSXwAAAAAAAAAAABkARQnAQ" />
数据可视化始终面对海量数据量与有限屏幕空间的冲突,如何解决不同端、不同屏幕尺寸下内容的适配问题,在有限的空间内帮助用户更快地理解信息和更快地分析洞察,是我们一直致力研究的问题。
<img class="preview-img no-padding" align="right" description="设计思路" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*WsO3T5klNMIAAAAAAAAAAABkARQnAQ" />
在 Ant Design 的可视化体系中,我们发展出一套适用于全量图表的布局适应规则,从整体图表、图表内原子组件梳理了适用于所有图表的布局适应体系。以右侧动图为例,图中横轴的轴标签跟随具体尺寸发生了旋转。更多内容即将发布,敬请期待。
<br />
### 交互
<div style="text-align:center;">
<img alt="Background" src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*QXtKSIMgaOUAAAAAAAAAAABkARQnAQ" />
</div>
区别于传统数据报表相对静态的表现形式,交互式图表并不停留在信息展示层面。用户通过与图不断产生交互,从数据中获取更深层次的分析和信息。
在数据可视化中,我们根据用户的意识层次及每层次对应的目标,将交互动作拆解成“数据获取、信息加工、知识流转”三层。其匹配“概览第一,聚焦过滤,再按需查看详情”的可视化信息检索箴言。亦符合人类寻求信息的基本逻辑:先大体,再局部,然后聚焦兴趣点进行探索,这是一个由表及里的过程。
更多交互式图表内容请前往 [ AntV -- 设计语言 -- 交互](https://antv.vision/zh/docs/specification/principles/interact)
# 设计资源
- 最新的图表资产已登陆 「AntDesign 官网 -- 资源 -- AntDesign Chart 资源包」
- 也可以访问 [Kitchen](https://kitchen.alipay.com/)官网下载 Sketch 插件,除了可以直接使用源文件之外,还可以使用 Kitchen「📈图表生成器」,用保真数据动态生成图表。
<br />

86
docs/spec/work-with-us.en-US.md

@ -1,86 +0,0 @@
---
order: 3
category: Other
title: Work with Us
---
我们(蚂蚁金服体验技术部)是一支兼具设计视角和工程视角的团队,服务蚂蚁金服上百个中后台系统,主打产品 Ant Design 服务全球近 100 万设计师和工程师,是西湖区学院路西侧最具影响力的设计语言。欢迎来这里和我们一起打造优雅高效的人机设计/研发体系。
## UI/UE 设计师
```__react
const emails = [
'momo.zxy#alipay.com',
'lindong.lld#alipay.com',
];
ReactDOM.render(
<p>作品和简历请投递:{emails[parseInt(Math.random() * emails.length, 10)]}</p>
, mountNode)
```
> 注明简历来自 ant.design 官网
- 岗位级别:P6/P7
- 岗位地点:杭州
- 岗位要求:
- 至少 2-3 年的工作经验,扎实设计功底;
- 抽象能力强,善于透过表象找本质;
- 沟通能力佳,善于自我管理;
- 有企业级设计实战经验,加分;
- 有良好的英文能力和国际视眼,加分;
- 深度了解 SAP、Salesforce、Google 等设计体系,加分。
- 爱 🐱。
- 岗位职责:
- 参与金融云、数据服务、人工智能以及金融核心等业务领域的设计工作;
- 参与 Ant Design 的打磨,将其建设成全球卓越的设计体系。
## UI/UX Designer
Please submit your work and resume: lindong.lld@alipay.com
- Post level: P6 / P7
- Position/Location: Hangzhou
- Job requirements:
- At least 2-3 years working experience, solid design skills;
- Strong abstract ability, good at finding essence through appearance;
- Good communication skills and good at self-management;
- Have practical experience in enterprise-level design, extra points;
- Have good English skills and international vision, extra points;
- In-depth understanding of design systems such as SAP, Salesforce, Google, and more points.
- Job Responsibilities:
- Participate in the design of financial cloud, data services, artificial intelligence and financial core business areas;
- Participate in the polishing of Ant Design and build it into a global outstanding design system.
## 前端工程师
简历请投递:afc163+antd@gmail.com
> 注明简历来自 ant.design 官网
- 岗位级别:P6/P7/P8
- 岗位地点:杭州
- 岗位要求:
- 在 React 技术栈持续耕耘,情有独钟。
- 热爱开源。
- 坚持和善于用技术和工具解决其他问题。
- 丰富的中后台前端研发经验。
- 爱 🐱。
- 岗位职责:
- 负责 Ant Design 前端基础设施研发。
- 负责中后台设计/前端工具体系建设。
##Front-end Engineer
Please submit your resume: afc163+antd@gmail.com
- Post level: P6 / P7 / P8
- Position: Hangzhou
- Job requirements:
- Continue to work on the React technology stack and love it.
- Love open source.
- Persist and be good at using technology and tools to solve other problems.
- Rich experience in mid- and back-end front-end R & D.
- Job Responsibilities:
- Responsible for Ant Design front-end infrastructure research and development.
- Responsible for mid-back design / front-end tool system construction.

65
docs/spec/work-with-us.zh-CN.md

@ -1,65 +0,0 @@
---
order: 3
category: 其他
title: 加入我们
---
我们(蚂蚁金服体验技术部)是一支兼具设计视角和工程视角的团队,服务蚂蚁金服上百个中后台系统,主打产品 Ant Design 服务全球 100 万设计师和工程师,是西湖区学院路西侧最具影响力的设计语言。欢迎来这里和我们一起打造优雅高效的人机设计/研发体系。
## UI/UE 设计师
简历和作品集请投递:lindong.lld#alipay.com
> 注明简历来自 ant.design 官网
- 岗位级别:P6/P7/P8
- 岗位地点:杭州
- 岗位要求:
- 至少 3-5 年的工作经验,扎实设计功底;
- 抽象能力强,善于透过表象找本质;
- 沟通能力佳,善于自我管理;
- 有企业级设计实战经验,加分;
- 有数据驱动的增长设计实践,加分;
- 深度理解 SAP、Salesforce、Google 等设计体系,能提出自己独到见解并落实到实践中,加加加分。
- 岗位职责:
- 参与[蚂蚁金融科技](https://tech.antfin.com/)、[区块链](https://tech.antfin.com/blockchain)、人工智能等企业级产品的设计工作;
- 参与[语雀](https://www.yuque.com/)、[云凤蝶](https://www.yunfengdie.com/)等创新产品的设计工作;
- 参与 Ant Design 的打磨,将其建设成全球卓越的设计体系。
- 参与 AntV 的打磨,将其建设成全球一流的数据可视化体系。
- One More Thing ❤️ :
- 你们总是为世界带去美好,但总是忘却你们也需要美好。我们正在努力打造 [🍳 Kitchen:一款为设计师提效的 Sketch 工具集](https://kitchen.alipay.com/)、[语雀画板](https://yuque.com/) 等专属设计师的产品,让设计真正变成财富。期待志同道合的你,一道给设计行业带来「微小而美好的改变」。
## 前端工程师
简历请投递:afc163+antd@gmail.com
> 注明简历来自 ant.design 官网
- 岗位级别:P6/P7/P8
- 岗位地点:杭州
- 岗位要求:
- 在 React 技术栈持续耕耘,情有独钟。
- 热爱开源。
- 坚持和善于用技术和工具解决其他问题。
- 丰富的中后台前端研发经验。
- 爱 🐱。
- 岗位职责:
- 负责 Ant Design 前端基础设施研发。
- 负责中后台设计/前端工具体系建设。
## ADI(Artificial Design Intelligence) 工程师
简历和作品集请投递:lindong.lld#alipay.com
> 注明简历来自 ant.design 官网
- 岗位级别:P7/P8
- 岗位地点:杭州
- 岗位要求:
- 有良好的工程师背景,善于学习和使用各类工具、框架解决研发问题;
- 对人工智能应用在设计行业,有坚定的信心和意愿;
- 已经有相关实践工作,优先考虑。
- 岗位职责:
- 负责 Ant Design 工具体系和智能设计的研发,并配合团队成员进行商业化实践,把设计做成业务;
- 组建和培养有梯度的研发团队。

6
site/bisheng.config.js

@ -36,6 +36,7 @@ module.exports = {
docs: './docs',
changelog: ['CHANGELOG.zh-CN.md', 'CHANGELOG.en-US.md'],
'components/form/v3': ['components/form/v3.zh-CN.md', 'components/form/v3.en-US.md'],
'docs/resources': ['./docs/resources.zh-CN.md', './docs/resources.en-US.md'],
},
theme: './site/theme',
htmlTemplate: './site/theme/static/template.html',
@ -46,8 +47,8 @@ module.exports = {
'Global Styles': 1,
设计模式: 2,
'Design Patterns': 2,
其他: 6,
Other: 6,
'设计模式 - 探索': 3,
'Design Patterns (Research)': 3,
Components: 100,
组件: 100,
},
@ -85,6 +86,7 @@ module.exports = {
'0.12.x': 'http://012x.ant.design',
'1.x': 'http://1x.ant.design',
'2.x': 'http://2x.ant.design',
'3.x': 'http://3x.ant.design',
},
},
filePathMapper(filePath) {

4
site/theme/en-US.js

@ -4,11 +4,11 @@ module.exports = {
'app.theme.switch.dark': 'Switch default mode',
'app.theme.switch.default': 'Switch dark mode',
'app.header.search': 'Search...',
'app.header.menu.home': 'Home',
'app.header.menu.documentation': 'Docs',
'app.header.menu.components': 'Components',
'app.header.menu.spec': 'Design',
'app.header.menu.resource': 'Resources',
'app.header.menu.more': 'More',
'app.header.menu.mobile': 'Mobile',
'app.header.menu.pro.v4': 'Ant Design Pro v4',
'app.header.menu.ecosystem': 'Ecosystem',
@ -50,6 +50,8 @@ module.exports = {
'app.home.design-patterns': 'Design patterns',
'app.home.more': 'Learn More',
'app.home.play-video': 'Play video',
'app.home.qr': '4.0 is out',
'app.home.qr.desc': '4.0 is out',
'app.home.getting-started': 'Getting Started',
'app.home.design-language': 'Design Language',
'app.home.product-antv-slogan': 'A new generation of data visualization solution',

9
site/theme/index.js

@ -2,6 +2,7 @@ const path = require('path');
const homeTmpl = './template/Home/index';
const contentTmpl = './template/Content/index';
const resourcesTmpl = './template/Resources/index';
const appShellTmpl = './template/AppShell';
function pickerGenerator(module) {
@ -92,6 +93,14 @@ module.exports = {
path: 'docs/spec/:children',
component: contentTmpl,
},
{
path: 'docs/resources',
component: resourcesTmpl,
},
{
path: 'docs/resources-cn',
component: resourcesTmpl,
},
],
},
};

3
site/theme/static/common.less

@ -203,7 +203,6 @@ a {
}
& &-avatar {
background-color: #fff;
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
box-shadow: @shadow-2;
}
}

258
site/theme/static/header.less

@ -1,40 +1,13 @@
@import '../../../components/style/themes/default.less';
@header-height: 64px;
@menu-item-border: 2px;
#header {
position: relative;
z-index: 10;
max-width: 100%;
background: @component-background;
box-shadow: 0 2px 8px rgba(240, 241, 242, 65);
&.home-nav-bottom {
background: rgba(255, 255, 255, 0.9);
border-bottom-color: #ebedee;
.search {
border-left-color: #ebedee;
}
a {
color: @site-text-color;
}
}
.header-link {
color: @site-text-color;
}
.ant-menu-item-active .header-link {
color: @primary-color;
}
// ===================== Home Page =====================
&.home-header {
position: absolute;
top: 0;
right: 0;
left: 0;
max-width: 1200px;
max-width: 1280px;
margin-right: auto;
margin-left: auto;
background: transparent;
@ -42,10 +15,10 @@
#logo {
padding-right: 16px;
padding-left: 0;
padding-left: 40px;
.page-wrapper-rtl & {
padding-right: 0;
padding-right: 40px;
padding-left: 16px;
}
}
@ -53,235 +26,10 @@
.ant-menu {
background: transparent;
}
.header-lang-button,
.header-direction-button {
margin-right: 0;
}
}
}
#logo {
float: left;
height: @header-height;
padding-left: 40px;
overflow: hidden;
color: @site-heading-color;
font-size: 18px;
font-family: Avenir, @font-family, sans-serif;
line-height: @header-height;
white-space: nowrap;
text-decoration: none;
.ant-row-rtl & {
float: right;
padding-right: 40px;
padding-left: 0;
}
img {
position: relative;
top: -1.5px;
height: 32px;
margin-right: 16px;
.ant-row-rtl & {
margin-right: 0;
margin-left: 16px;
}
}
}
#search-box {
float: left;
height: 22px;
margin: 22px auto 0;
padding-left: 16px;
line-height: 22px;
border-left: 1px solid @site-border-color-split;
.ant-row-rtl & {
float: right;
padding-right: 16px;
padding-left: 0;
border-right: 1px solid @site-border-color-split;
border-left: none;
}
}
#search-box .anticon {
position: relative;
top: 0.5px;
color: #ced4d9;
}
#search-box input {
width: 200px;
margin-top: -5px;
font-size: 14px;
background: transparent;
border: 0;
box-shadow: none;
&::placeholder {
color: #a3b1bf;
}
}
.header-lang-button,
.version,
.header-direction-button {
float: right;
margin-top: 20px;
margin-left: 16px;
#header .ant-row-rtl & {
float: left;
margin-right: 16px;
margin-left: 0;
}
}
.header-lang-button,
.header-direction-button {
margin-right: 40px;
color: @text-color;
border-color: @border-color-base;
#header .ant-row-rtl & {
margin-right: 16px;
margin-left: 16px;
}
}
.header-lang-button {
margin-right: 0;
#header .ant-row-rtl & {
margin-right: 16px;
margin-left: 0;
}
}
// Adjust github button style
.github-btn {
float: right;
height: auto;
margin: 20px 0 0 16px;
#header .ant-row-rtl & {
float: left;
.gh-count {
display: none !important;
}
}
.gh-btn {
height: auto;
padding: 1px 4px;
background: transparent;
border: 0;
.gh-ico {
width: 20px;
height: 20px;
margin: 0;
}
.gh-text {
display: none;
}
}
.gh-count {
height: auto;
padding: 4px 8px;
font-weight: normal;
background: #fff;
&:hover {
color: @primary-color;
}
}
}
#nav {
float: right;
font-size: 14px;
font-family: Avenir, @font-family, sans-serif;
border: 0;
.ant-row-rtl & {
float: left;
}
&.ant-menu-horizontal {
border-bottom: none;
& > .ant-menu-item,
& > .ant-menu-submenu {
min-width: 72px;
height: @header-height;
line-height: @header-height - @menu-item-border - 2px;
border-top: @menu-item-border solid transparent;
&:hover {
border-top: @menu-item-border solid @primary-color;
border-bottom: @menu-item-border solid transparent;
}
}
& > .ant-menu-submenu-open {
border-top: @menu-item-border solid @primary-color;
border-bottom: @menu-item-border solid transparent;
}
& > .ant-menu-item-selected {
border-top: @menu-item-border solid @primary-color;
border-bottom: @menu-item-border solid transparent;
a {
color: @primary-color;
}
}
}
& > .ant-menu-item,
& > .ant-menu-submenu {
text-align: center;
}
}
.component-select {
&.ant-select-dropdown {
font-size: 14px;
border: 0;
border-radius: 0;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.25);
}
.ant-select-dropdown-menu {
max-height: 200px;
}
.ant-select-dropdown-menu-item {
border-radius: 0 !important;
}
.ant-component-decs {
position: absolute;
right: 16px;
color: #aaa;
font-size: 12px;
.ant-row-rtl & {
right: auto;
left: 16px;
}
}
}
@media (max-width: @screen-sm-min) {
.github-btn {
display: none;
}
#header.home-header {
.ant-row {
.ant-col {

1
site/theme/static/index.less

@ -6,7 +6,6 @@
@import './home';
@import './page-nav';
@import './markdown';
@import './resource';
@import './design-doc';
@import './preview-img';
@import './toc';

82
site/theme/static/resource.less

@ -1,82 +0,0 @@
.resource-cards {
display: flex;
flex-flow: wrap;
width: 100%;
}
.resource-card {
position: relative;
display: flex;
width: ~'calc(50% - 24px)';
min-width: 400px;
max-width: 500px;
height: 130px;
margin: 24px 24px 0 0;
overflow: hidden;
color: #777;
font-size: 12px;
border: 1px solid @border-color-base;
border-radius: @border-radius-base;
transition: all 0.3s ease;
}
.resource-card:hover {
border-color: transparent;
box-shadow: 0 3px 8px #d3ddeb;
}
.resource-card:hover .resource-card-title {
color: @primary-color;
}
.resource-card.disabled {
opacity: 0.45;
pointer-events: none;
}
.resource-card-cover,
.resource-card-icon {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 130px;
}
.resource-card-cover img {
width: 68px;
}
.resource-card-content {
display: flex;
flex-flow: column;
justify-content: center;
}
.resource-card-title {
display: block;
margin-bottom: 6px;
overflow: hidden;
color: @site-text-color;
font-size: 16px;
line-height: 1.2;
white-space: nowrap;
text-overflow: ellipsis;
}
.resource-card-hot-badge {
margin-left: 2px;
padding: 0 3px;
color: #fff;
font-size: 12px;
line-height: 20px;
vertical-align: top;
background: #f50;
border-radius: 2px;
}
.resource-card-description {
display: block;
padding-right: 16px;
color: #697b8c;
}

65
site/theme/static/responsive.less

@ -11,23 +11,6 @@
cursor: pointer;
}
@media only screen and (max-width: @screen-xl) {
#search-box {
display: none;
}
#logo {
padding: 0 40px;
}
.banner-wrapper .banner-title-wrapper {
h1 {
font-size: 36px;
}
p {
font-size: 16px;
}
}
}
@media only screen and (max-width: @screen-lg) {
.main-container {
padding-right: 48px;
@ -45,16 +28,6 @@
}
@media only screen and (max-width: 767.99px) {
#header {
text-align: center;
#logo {
float: initial;
padding-right: 0;
}
}
#search-box {
display: none;
}
.preview-image-boxes {
float: none;
width: 100%;
@ -75,44 +48,6 @@
margin: 29px auto 16px;
}
.popover-menu {
width: 300px;
div.version {
margin: 16px auto;
}
.ant-popover-inner {
overflow: hidden;
&-content {
padding: 0;
.ant-select {
display: block;
width: 60%;
}
.ant-btn {
margin: 16px 8% 0 8px;
}
}
}
#nav a.header-link {
color: #333;
}
}
ul#nav,
ul#nav li {
width: 100%;
font-size: 14px;
}
ul#nav li {
padding: 0 !important;
line-height: 40px;
border: 0;
a {
color: #333;
}
}
.toc {
display: none;
}

75
site/theme/template/Content/Article.jsx → site/theme/template/Content/Article.tsx

@ -6,8 +6,36 @@ import { Timeline, Alert, Affix } from 'antd';
import EditButton from './EditButton';
import { getMetaDescription } from '../utils';
class Article extends React.Component {
shouldComponentUpdate(nextProps) {
interface LocaleString {
[locale: string]: string;
}
export interface ArticleProps {
titleRegionClassName?: string;
location: {
pathname: string;
};
content: {
meta: {
toc?: boolean;
timeline?: boolean;
title: string | LocaleString;
subtitle?: string;
filename?: string;
};
description?: any[];
toc: string[];
content: any[];
api?: any;
};
intl: { locale: string };
utils: {
toReactComponent: (content: any[]) => React.ReactElement;
};
}
class Article extends React.Component<ArticleProps> {
shouldComponentUpdate(nextProps: ArticleProps) {
const { location } = this.props;
const { location: nextLocation } = nextProps;
@ -17,11 +45,12 @@ class Article extends React.Component {
return true;
}
onResourceClick = e => {
onResourceClick: React.MouseEventHandler<HTMLAnchorElement> = event => {
const { target } = (event as unknown) as { target: HTMLAnchorElement };
if (!window.gtag) {
return;
}
const cardNode = e.target.closest('.resource-card');
const cardNode = target.closest('.resource-card') as HTMLAnchorElement;
if (cardNode) {
window.gtag('event', 'resource', {
event_category: 'Download',
@ -30,23 +59,23 @@ class Article extends React.Component {
}
if (
window.location.href.indexOf('docs/react/recommendation') > 0 &&
e.target.matches('.markdown > table td > a[href]')
target.matches('.markdown > table td > a[href]')
) {
window.gtag('event', 'recommendation', {
event_category: 'Click',
event_label: e.target.href,
event_label: target.href,
});
}
};
getArticle(article) {
getArticle(article: React.ReactElement) {
const { content } = this.props;
const { meta } = content;
if (!meta.timeline) {
return article;
}
const timelineItems = [];
let temp = [];
let temp: React.ReactNode[] = [];
let i = 1;
Children.forEach(article.props.children, child => {
if (child.type === 'h2' && temp.length > 0) {
@ -66,6 +95,7 @@ class Article extends React.Component {
render() {
const {
titleRegionClassName,
content,
intl: { locale },
utils,
@ -73,7 +103,7 @@ class Article extends React.Component {
const { meta, description } = content;
const { title, subtitle, filename } = meta;
const isNotTranslated = locale === 'en-US' && typeof title === 'object';
const helmetTitle = `${title[locale] || title} - Ant Design`;
const helmetTitle = `${(title as LocaleString)[locale] || title} - Ant Design`;
const helmetDesc = getMetaDescription(description);
const contentChild = getMetaDescription(getChildren(content.content));
const metaDesc = helmetDesc || contentChild;
@ -99,16 +129,21 @@ class Article extends React.Component {
}
/>
)}
<h1>
{title[locale] || title}
{!subtitle || locale === 'en-US' ? null : <span className="subtitle">{subtitle}</span>}
<EditButton title={<FormattedMessage id="app.content.edit-page" />} filename={filename} />
</h1>
{!description
? null
: utils.toReactComponent(
['section', { className: 'markdown' }].concat(getChildren(description)),
)}
<div className={titleRegionClassName}>
<h1>
{(title as LocaleString)[locale] || title}
{!subtitle || locale === 'en-US' ? null : <span className="subtitle">{subtitle}</span>}
<EditButton
title={<FormattedMessage id="app.content.edit-page" />}
filename={filename}
/>
</h1>
{!description
? null
: utils.toReactComponent(
['section', { className: 'markdown' }].concat(getChildren(description)),
)}
</div>
{!content.toc || content.toc.length <= 1 || meta.toc === false ? null : (
<Affix className="toc-affix" offsetTop={16}>
{utils.toReactComponent(['ul', { className: 'toc' }].concat(getChildren(content.toc)))}
@ -132,4 +167,4 @@ class Article extends React.Component {
}
}
export default injectIntl(Article);
export default (injectIntl(Article as any) as any) as React.ComponentClass<ArticleProps>;

7
site/theme/template/Content/EditButton.jsx → site/theme/template/Content/EditButton.tsx

@ -4,7 +4,12 @@ import { EditOutlined } from '@ant-design/icons';
const branchUrl = 'https://github.com/ant-design/ant-design/edit/master/';
export default function EditButton({ title, filename }) {
export interface EditButtonProps {
title: React.ReactNode;
filename?: string;
}
export default function EditButton({ title, filename }: EditButtonProps) {
return (
<Tooltip title={title}>
<a

221
site/theme/template/Content/MainContent.jsx

@ -13,6 +13,7 @@ import { DarkIcon, DefaultIcon } from './ThemeIcon';
import Article from './Article';
import PrevAndNext from './PrevAndNext';
import Footer from '../Layout/Footer';
import SiteContext from '../Layout/SiteContext';
import ComponentDoc from './ComponentDoc';
import * as utils from '../utils';
@ -59,7 +60,6 @@ const getSideBarOpenKeys = nextProps => {
class MainContent extends Component {
static contextTypes = {
isMobile: PropTypes.bool.isRequired,
theme: PropTypes.oneOf(['default', 'dark']),
setTheme: PropTypes.func,
setIframeTheme: PropTypes.func,
@ -286,113 +286,122 @@ class MainContent extends Component {
};
render() {
const { isMobile, theme, setIframeTheme } = this.context;
const { openKeys } = this.state;
const {
localizedPageData,
demos,
intl: { formatMessage },
} = this.props;
const { meta } = localizedPageData;
const activeMenuItem = this.getActiveMenuItem();
const menuItems = this.getMenuItems();
const menuItemsForFooterNav = this.getMenuItems({
before: <LeftOutlined className="footer-nav-icon-before" />,
after: <RightOutlined className="footer-nav-icon-after" />,
});
const { prev, next } = this.getFooterNav(menuItemsForFooterNav, activeMenuItem);
const mainContainerClass = classNames('main-container', {
'main-container-component': !!demos,
});
const menuChild = (
<Menu
inlineIndent={30}
className="aside-container menu-site"
mode="inline"
openKeys={openKeys}
selectedKeys={[activeMenuItem]}
onOpenChange={this.handleMenuOpenChange}
>
{menuItems}
</Menu>
);
const componentPage = /^\/?components/.test(this.props.location.pathname);
return (
<div className="main-wrapper">
<Row>
{isMobile ? (
<MobileMenu key="Mobile-menu" wrapperClassName="drawer-wrapper">
{menuChild}
</MobileMenu>
) : (
<Col xxl={4} xl={5} lg={6} md={6} sm={24} xs={24} className="main-menu">
<Affix>
<section className="main-menu-inner">{menuChild}</section>
</Affix>
</Col>
)}
<Col xxl={20} xl={19} lg={18} md={18} sm={24} xs={24}>
<section className={mainContainerClass}>
{demos ? (
<ComponentDoc
{...this.props}
doc={localizedPageData}
demos={demos}
theme={theme}
setIframeTheme={setIframeTheme}
/>
) : (
<Article {...this.props} content={localizedPageData} />
)}
<ContributorsList
className="contributors-list"
fileName={meta.filename}
renderItem={(item, loading) =>
loading ? (
<Avatar style={{ opacity: 0.3 }} />
) : (
<Tooltip
title={`${formatMessage({ id: 'app.content.contributors' })}: ${
item.username
}`}
key={item.username}
>
<a
href={`https://github.com/${item.username}`}
target="_blank"
rel="noopener noreferrer"
<SiteContext.Consumer>
{({ isMobile }) => {
const { theme, setIframeTheme } = this.context;
const { openKeys } = this.state;
const {
localizedPageData,
demos,
intl: { formatMessage },
} = this.props;
const { meta } = localizedPageData;
const activeMenuItem = this.getActiveMenuItem();
const menuItems = this.getMenuItems();
const menuItemsForFooterNav = this.getMenuItems({
before: <LeftOutlined className="footer-nav-icon-before" />,
after: <RightOutlined className="footer-nav-icon-after" />,
});
const { prev, next } = this.getFooterNav(menuItemsForFooterNav, activeMenuItem);
const mainContainerClass = classNames('main-container', {
'main-container-component': !!demos,
});
const menuChild = (
<Menu
inlineIndent={30}
className="aside-container menu-site"
mode="inline"
openKeys={openKeys}
selectedKeys={[activeMenuItem]}
onOpenChange={this.handleMenuOpenChange}
>
{menuItems}
</Menu>
);
const componentPage = /^\/?components/.test(this.props.location.pathname);
return (
<div className="main-wrapper">
<Row>
{isMobile ? (
<MobileMenu key="Mobile-menu" wrapperClassName="drawer-wrapper">
{menuChild}
</MobileMenu>
) : (
<Col xxl={4} xl={5} lg={6} md={6} sm={24} xs={24} className="main-menu">
<Affix>
<section className="main-menu-inner">{menuChild}</section>
</Affix>
</Col>
)}
<Col xxl={20} xl={19} lg={18} md={18} sm={24} xs={24}>
<section className={mainContainerClass}>
{demos ? (
<ComponentDoc
{...this.props}
doc={localizedPageData}
demos={demos}
theme={theme}
setIframeTheme={setIframeTheme}
/>
) : (
<Article {...this.props} content={localizedPageData} />
)}
<ContributorsList
className="contributors-list"
fileName={meta.filename}
renderItem={(item, loading) =>
loading ? (
<Avatar style={{ opacity: 0.3 }} />
) : (
<Tooltip
title={`${formatMessage({ id: 'app.content.contributors' })}: ${
item.username
}`}
key={item.username}
>
<a
href={`https://github.com/${item.username}`}
target="_blank"
rel="noopener noreferrer"
>
<Avatar src={item.url}>{item.username}</Avatar>
</a>
</Tooltip>
)
}
repo="ant-design"
owner="ant-design"
/>
</section>
{componentPage && (
<div className="fixed-widgets">
<Tooltip
getPopupContainer={node => node.parentNode}
title={formatMessage({ id: `app.theme.switch.${theme}` })}
overlayClassName="fixed-widgets-tooltip"
>
<Avatar src={item.url}>{item.username}</Avatar>
</a>
</Tooltip>
)
}
repo="ant-design"
owner="ant-design"
/>
</section>
{componentPage && (
<div className="fixed-widgets">
<Tooltip
getPopupContainer={node => node.parentNode}
title={formatMessage({ id: `app.theme.switch.${theme}` })}
overlayClassName="fixed-widgets-tooltip"
>
<Avatar
className={classNames('fixed-widgets-avatar', `fixed-widgets-avatar-${theme}`)}
size={44}
onClick={this.changeTheme}
icon={theme === 'dark' ? <DarkIcon /> : <DefaultIcon />}
/>
</Tooltip>
</div>
)}
<PrevAndNext prev={prev} next={next} />
<Footer />
</Col>
</Row>
</div>
<Avatar
className={classNames(
'fixed-widgets-avatar',
`fixed-widgets-avatar-${theme}`,
)}
size={44}
onClick={this.changeTheme}
icon={theme === 'dark' ? <DarkIcon /> : <DefaultIcon />}
/>
</Tooltip>
</div>
)}
<PrevAndNext prev={prev} next={next} />
<Footer />
</Col>
</Row>
</div>
);
}}
</SiteContext.Consumer>
);
}
}

24
site/theme/template/Home/Banner/Background.tsx

@ -2,8 +2,8 @@ import * as React from 'react';
import Hitu from '@ant-design/hitu';
import './Background.less';
const RANDOM_OFFSET = 20;
const TOTAL_FRAMES = 500;
const RANDOM_OFFSET = 50;
const TOTAL_FRAMES = 600;
function randomFrames(x: number, y: number): any[] {
const common = { x, y, cubic: Hitu.CUBIC_EASE_IN_OUT };
@ -63,7 +63,7 @@ const Circle2 = () => (
</filter>
<linearGradient id="banner-circle-fill-2" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style={{ stopColor: '#FAFCFE' }} />
<stop offset="100%" style={{ stopColor: '#F9FCFE' }} />
<stop offset="50%" style={{ stopColor: '#F3F9FC' }} />
</linearGradient>
</defs>
<circle
@ -87,8 +87,8 @@ const React1 = () => (
<feDropShadow dx="10" dy="10" stdDeviation="10" floodColor="rgba(0,0,0,0.05)" />
</filter>
<linearGradient id="banner-rect-fill-1" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style={{ stopColor: '#F8FBFF' }} />
<stop offset="100%" style={{ stopColor: '#F9FCFF' }} />
<stop offset="25%" style={{ stopColor: '#F8FCFF' }} />
<stop offset="100%" style={{ stopColor: '#F8FBFF' }} />
</linearGradient>
</defs>
<rect
@ -105,21 +105,21 @@ React1.width = (ReactSize1 + ShadowSize) * 2;
React1.height = (ReactSize1 + ShadowSize) * 2;
// ================================== Diamond 1 ===================================
const DiamondSize1 = 180;
const DiamondSize1 = 400;
const Diamond1 = () => {
const start = ShadowSize;
const center = ShadowSize + DiamondSize1;
const end = ShadowSize + DiamondSize1 * 2;
return (
<svg>
<svg width={center * 2} height={center * 2}>
<defs>
<filter id="banner-diamond-shadow-1">
<feDropShadow dx="10" dy="10" stdDeviation="10" floodColor="rgba(0,0,0,0.05)" />
</filter>
<linearGradient id="banner-diamond-fill-1" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style={{ stopColor: '#F8FBFF' }} />
<stop offset="100%" style={{ stopColor: '#F9FCFF' }} />
<stop offset="60%" style={{ stopColor: '#FCFDFF' }} />
<stop offset="100%" style={{ stopColor: '#FCFDFE' }} />
</linearGradient>
</defs>
@ -138,13 +138,13 @@ export default function Background() {
const [circleFrames, setCircleFrames] = React.useState<any[]>(randomFrames(550, 200));
const [circle2Frames, setCircle2Frames] = React.useState<any[]>(randomFrames(0, 448));
const [reactFrames, setReactFrames] = React.useState<any[]>(randomFrames(1400, 300));
const [diamondFrames, setDiamondFrames] = React.useState<any[]>(randomFrames(1100, -20));
const [diamondFrames, setDiamondFrames] = React.useState<any[]>(randomFrames(1100, -230));
return (
<div className="home-banner-background">
<img
alt="background"
src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*_fCZRqKuJBgAAAAAAAAAAABkARQnAQ"
src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*kJM2Q6uPXCAAAAAAAAAAAABkARQnAQ"
/>
<Hitu
width={1440}
@ -155,7 +155,7 @@ export default function Background() {
setCircleFrames(randomFrames(550, 200));
setCircle2Frames(randomFrames(0, 448));
setReactFrames(randomFrames(1400, 300));
setDiamondFrames(randomFrames(1100, -20));
setDiamondFrames(randomFrames(1100, -230));
}
}}
shapes={[

35
site/theme/template/Home/Banner/index.less

@ -6,8 +6,10 @@
position: relative;
height: 512px;
overflow: hidden;
background: radial-gradient(rgba(255, 255, 255, 0.5), rgba(235, 245, 255, 0.58)),
linear-gradient(150deg, #fbfcfd, #f8fcff);
// background: radial-gradient(rgba(255, 255, 255, 0.5), rgba(235, 245, 255, 0.58)),
// linear-gradient(150deg, #fbfcfd, #f8fcff);
background: url(https://gw.alipayobjects.com/zos/basement_prod/a8cf2dfe-ff6a-4a2e-ab73-f72dced0df99.svg);
background-size: cover;
&-holder {
position: relative;
@ -32,6 +34,18 @@
color: @home-color;
}
.banner-qr {
margin: 8px auto 0;
color: @home-color;
font-weight: normal;
text-align: center;
.anticon {
display: inline-block;
margin-right: 8px;
}
}
&-operations {
margin-top: 72px;
white-space: nowrap;
@ -65,6 +79,23 @@
}
}
.banner-qr-code {
.ant-popover-inner-content {
padding: 12px 12px;
}
img {
width: 136px;
height: 136px;
}
p {
margin: 8px 0 0 0;
color: #314659;
text-align: center;
}
}
@media (min-width: @screen-sm-min) {
.home-banner {
height: 448px;

39
site/theme/template/Home/Banner/index.tsx

@ -1,18 +1,51 @@
import * as React from 'react';
import { Button } from 'antd';
import { Button, Popover } from 'antd';
import { Link } from 'bisheng/router';
import { FormattedMessage, useIntl } from 'react-intl';
import { PlayCircleFilled } from '@ant-design/icons';
import { PlayCircleFilled, MobileFilled } from '@ant-design/icons';
import Background from './Background';
import { getLocalizedPathname } from '../../utils';
import Logo from './Logo';
import './index.less';
import SiteContext from '../../Layout/SiteContext';
export default function Banner() {
const { isMobile } = React.useContext(SiteContext);
const { locale } = useIntl();
const isZhCN = locale === 'zh-CN';
let qrNode: React.ReactElement | null = null;
if (isMobile) {
qrNode = (
<a href="http://antd4.antfin.com/">
<MobileFilled /> <FormattedMessage id="app.home.qr" />
</a>
);
} else {
qrNode = (
<Popover
placement="bottom"
overlayClassName="banner-qr-code"
content={
<div>
<img
alt="qr"
src="https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*eafgRK7InNMAAAAAAAAAAABkARQnAQ"
/>
<p>
<FormattedMessage id="app.home.qr.desc" />
</p>
</div>
}
>
<a>
<MobileFilled /> <FormattedMessage id="app.home.qr" />
</a>
</Popover>
);
}
return (
<div className="home-banner">
<Background />
@ -30,6 +63,8 @@ export default function Banner() {
<PlayCircleFilled /> <FormattedMessage id="app.home.play-video" />
</a>
{isZhCN && <div className="banner-qr">{qrNode}</div>}
<div className="home-banner-content-operations">
<Link to={getLocalizedPathname('/docs/react/introduce', isZhCN)}>
<Button type="primary" shape="round">

3
site/theme/template/Home/DesignPage/index.less

@ -74,8 +74,7 @@
.design-mini-panel {
&:hover {
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
box-shadow: @shadow-2;
}
.ant-card-meta-title {

3
site/theme/template/Home/MorePage.less

@ -2,8 +2,7 @@
.more-card {
&:hover {
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
box-shadow: @shadow-2;
}
.ant-card-cover {

11
site/theme/template/Home/index.less

@ -15,7 +15,7 @@
}
.home-block-content {
margin: 88px 24px 124px;
margin: 88px 40px 124px;
h2.ant-typography {
margin-bottom: 56px;
@ -59,3 +59,12 @@
}
}
}
@media only screen and (max-width: 767.99px) {
.home-container {
.home-block-content {
margin-right: 24px;
margin-left: 24px;
}
}
}

343
site/theme/template/Layout/Header.jsx

@ -1,343 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import GitHubButton from 'react-github-button';
import { Link } from 'bisheng/router';
import { FormattedMessage, injectIntl } from 'react-intl';
import classNames from 'classnames';
import { SearchOutlined, MenuOutlined } from '@ant-design/icons';
import { Select, Menu, Row, Col, Popover, Input, Button } from 'antd';
import * as utils from '../utils';
import { version as antdVersion } from '../../../../package.json';
const { Option } = Select;
let docsearch;
if (typeof window !== 'undefined') {
docsearch = require('docsearch.js'); // eslint-disable-line
}
function initDocSearch(locale) {
if (!docsearch) {
return;
}
const lang = locale === 'zh-CN' ? 'cn' : 'en';
docsearch({
apiKey: '60ac2c1a7d26ab713757e4a081e133d0',
indexName: 'ant_design',
inputSelector: '#search-box input',
algoliaOptions: { facetFilters: [`tags:${lang}`] },
transformData(hits) {
hits.forEach(hit => {
hit.url = hit.url.replace('ant.design', window.location.host); // eslint-disable-line
hit.url = hit.url.replace('https:', window.location.protocol); // eslint-disable-line
});
return hits;
},
debug: false, // Set debug to true if you want to inspect the dropdown
});
}
class Header extends React.Component {
static contextTypes = {
router: PropTypes.object.isRequired,
isMobile: PropTypes.bool.isRequired,
theme: PropTypes.oneOf(['default', 'dark']),
direction: PropTypes.string,
};
state = {
menuVisible: false,
};
componentDidMount() {
const { intl } = this.props;
const { router } = this.context;
router.listen(this.handleHideMenu);
const { searchInput } = this;
document.addEventListener('keyup', event => {
if (event.keyCode === 83 && event.target === document.body) {
searchInput.focus();
}
});
initDocSearch(intl.locale);
}
handleShowMenu = () => {
this.setState({
menuVisible: true,
});
};
handleHideMenu = () => {
this.setState({
menuVisible: false,
});
};
handleDirectionChange = () => {
const { changeDirection } = this.props;
const { direction } = this.context;
if (direction !== 'rtl') {
changeDirection('rtl');
} else {
changeDirection('ltr');
}
};
getNextDirectionText = () => {
const { direction } = this.context;
if (direction !== 'rtl') {
return 'RTL';
}
return 'LTR';
};
onMenuVisibleChange = visible => {
this.setState({
menuVisible: visible,
});
};
handleVersionChange = url => {
const currentUrl = window.location.href;
const currentPathname = window.location.pathname;
window.location.href = currentUrl
.replace(window.location.origin, url)
.replace(currentPathname, utils.getLocalizedPathname(currentPathname));
};
handleLangChange = () => {
const {
location: { pathname },
} = this.props;
const currentProtocol = `${window.location.protocol}//`;
const currentHref = window.location.href.substr(currentProtocol.length);
if (utils.isLocalStorageNameSupported()) {
localStorage.setItem('locale', utils.isZhCN(pathname) ? 'en-US' : 'zh-CN');
}
window.location.href =
currentProtocol +
currentHref.replace(
window.location.pathname,
utils.getLocalizedPathname(pathname, !utils.isZhCN(pathname)),
);
};
render() {
const { menuVisible } = this.state;
const { isMobile } = this.context;
const menuMode = isMobile ? 'inline' : 'horizontal';
const {
location,
themeConfig,
intl: { locale },
} = this.props;
const docVersions = { ...themeConfig.docVersions, [antdVersion]: antdVersion };
const versionOptions = Object.keys(docVersions).map(version => (
<Option value={docVersions[version]} key={version}>
{version}
</Option>
));
const pathname = location.pathname.replace(/(^\/|\/$)/g, '');
const module = pathname
.split('/')
.slice(0, -1)
.join('/');
let activeMenuItem = module || 'home';
if (location.pathname === 'changelog' || location.pathname === 'changelog-cn') {
activeMenuItem = 'docs/react';
}
const isHome = ['', 'index', 'index-cn'].includes(pathname);
const isZhCN = locale === 'zh-CN';
const headerClassName = classNames({
clearfix: true,
'home-header': isHome,
});
const menu = [
isHome ? (
<GitHubButton key="github" type="stargazers" namespace="ant-design" repo="ant-design" />
) : null,
<Button
size="small"
onClick={this.handleDirectionChange}
className="header-direction-button"
key="direction-button"
>
{this.getNextDirectionText()}
</Button>,
<Button
size="small"
onClick={this.handleLangChange}
className="header-lang-button"
key="lang-button"
>
<FormattedMessage id="app.header.lang" />
</Button>,
<Select
key="version"
className="version"
size="small"
dropdownMatchSelectWidth={false}
defaultValue={antdVersion}
onChange={this.handleVersionChange}
getPopupContainer={trigger => trigger.parentNode}
>
{versionOptions}
</Select>,
<Menu
className="menu-site"
mode={menuMode}
selectedKeys={[activeMenuItem]}
id="nav"
key="nav"
>
{isHome ? null : (
<Menu.Item key="home" className="hide-in-home-page">
<Link to={utils.getLocalizedPathname('/', isZhCN)}>
<FormattedMessage id="app.header.menu.home" />
</Link>
</Menu.Item>
)}
<Menu.Item key="docs/spec">
<Link to={utils.getLocalizedPathname('/docs/spec/introduce', isZhCN)}>
<FormattedMessage id="app.header.menu.spec" />
</Link>
</Menu.Item>
<Menu.Item key="docs/react">
<Link to={utils.getLocalizedPathname('/docs/react/introduce', isZhCN)}>
<FormattedMessage id="app.header.menu.documentation" />
</Link>
</Menu.Item>
<Menu.Item key="components">
<Link to={utils.getLocalizedPathname('/components/button/', isZhCN)}>
<FormattedMessage id="app.header.menu.components" />
</Link>
</Menu.Item>
<Menu.SubMenu
key="ecosystem"
className="hide-in-home-page"
title={<FormattedMessage id="app.header.menu.ecosystem" />}
>
<Menu.Item key="pro">
<a
href="http://pro.ant.design"
className="header-link"
target="_blank"
rel="noopener noreferrer"
>
<FormattedMessage id="app.header.menu.pro.v4" />
</a>
</Menu.Item>
<Menu.Item key="ng">
<a
href="http://ng.ant.design"
className="header-link"
target="_blank"
rel="noopener noreferrer"
>
Ant Design of Angular
</a>
</Menu.Item>
<Menu.Item key="vue">
<a
href="http://vue.ant.design"
className="header-link"
target="_blank"
rel="noopener noreferrer"
>
Ant Design of Vue
</a>
</Menu.Item>
{isZhCN ? (
<Menu.Item key="course" className="hide-in-home-page">
<a
href="https://www.yuque.com/ant-design/course"
className="header-link"
target="_blank"
rel="noopener noreferrer"
>
Ant Design 实战教程
</a>
</Menu.Item>
) : null}
</Menu.SubMenu>
</Menu>,
];
const colProps = isHome
? [{ flex: 'none' }, { flex: 'auto' }]
: [
{
xxl: 4,
xl: 5,
lg: 5,
md: 5,
sm: 24,
xs: 24,
},
{
xxl: 20,
xl: 19,
lg: 19,
md: 19,
sm: 0,
xs: 0,
},
];
const searchPlaceholder = locale === 'zh-CN' ? '在 ant.design 中搜索' : 'Search in ant.design';
return (
<header id="header" className={headerClassName}>
{isMobile && (
<Popover
overlayClassName="popover-menu"
placement="bottomRight"
content={menu}
trigger="click"
visible={menuVisible}
arrowPointAtCenter
onVisibleChange={this.onMenuVisibleChange}
>
<MenuOutlined className="nav-phone-icon" onClick={this.handleShowMenu} />
</Popover>
)}
<Row>
<Col {...colProps[0]}>
<h1>
<Link to={utils.getLocalizedPathname('/', isZhCN)} id="logo">
<img
alt="logo"
src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
/>
Ant Design
</Link>
</h1>
</Col>
<Col {...colProps[1]}>
<div id="search-box">
<SearchOutlined />
<Input
ref={ref => {
this.searchInput = ref;
}}
placeholder={searchPlaceholder}
/>
</div>
{!isMobile && menu}
</Col>
</Row>
</header>
);
}
}
export default injectIntl(Header);

50
site/theme/template/Layout/Header/Github.less

@ -0,0 +1,50 @@
@import '../../../static/theme.less';
@import '../../../../../components/style/themes/default.less';
#github-btn {
display: flex;
flex-flow: nowrap;
height: auto;
.gh-btn {
height: auto;
padding: 1px 4px;
background: transparent;
border: 0;
.gh-ico {
width: 20px;
height: 20px;
margin: 0;
}
.gh-text {
display: none;
}
}
.gh-count {
height: auto;
padding: 4px 8px;
font-weight: normal;
background: #fff;
&:hover {
color: @primary-color;
}
}
&.responsive-mode {
.gh-count {
display: none !important;
}
}
}
.ant-row-rtl {
#github-btn {
.gh-count {
display: none !important;
}
}
}

23
site/theme/template/Layout/Header/Github.tsx

@ -0,0 +1,23 @@
import * as React from 'react';
import classNames from 'classnames';
import GitHubButton from 'react-github-button';
import './Github.less';
export interface GithubProps {
responsive: null | 'narrow' | 'crowded';
}
export default ({ responsive }: GithubProps) => {
return (
<GitHubButton
id="github-btn"
className={classNames({
'responsive-mode': responsive,
[`responsive-${responsive}`]: responsive,
})}
type="stargazers"
namespace="ant-design"
repo="ant-design"
/>
);
};

40
site/theme/template/Layout/Header/Logo.less

@ -0,0 +1,40 @@
@import '../../../static/theme.less';
@import '../../../../../components/style/themes/default.less';
@import './index.less';
#logo {
height: @header-height;
padding-left: 40px;
overflow: hidden;
color: @site-heading-color;
font-size: 18px;
font-family: Avenir, @font-family, sans-serif;
line-height: @header-height;
white-space: nowrap;
text-decoration: none;
.ant-row-rtl & {
float: right;
padding-right: 40px;
padding-left: 0;
}
img {
position: relative;
top: -1.5px;
height: 32px;
margin-right: 16px;
.ant-row-rtl & {
margin-right: 0;
margin-left: 16px;
}
}
}
@media only screen and (max-width: @mobile-max-width) {
#logo {
padding-right: 0;
padding-left: 0;
}
}

15
site/theme/template/Layout/Header/Logo.tsx

@ -0,0 +1,15 @@
import * as React from 'react';
import { Link } from 'bisheng/router';
import * as utils from '../../utils';
import { SharedProps } from './interface';
import './Logo.less';
export default ({ isZhCN }: SharedProps) => (
<h1>
<Link to={utils.getLocalizedPathname('/', isZhCN)} id="logo">
<img alt="logo" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" />
Ant Design
</Link>
</h1>
);

67
site/theme/template/Layout/Header/More.tsx

@ -0,0 +1,67 @@
import * as React from 'react';
import { Dropdown, Menu, Button } from 'antd';
import { FormattedMessage } from 'react-intl';
import { DownOutlined } from '@ant-design/icons';
import { SharedProps } from './interface';
export function getEcosystemGroup({ isZhCN }: SharedProps): React.ReactElement {
return (
<Menu.ItemGroup key="ecosystem" title={<FormattedMessage id="app.header.menu.ecosystem" />}>
<Menu.Item key="pro">
<a
href="http://pro.ant.design"
className="header-link"
target="_blank"
rel="noopener noreferrer"
>
<FormattedMessage id="app.header.menu.pro.v4" />
</a>
</Menu.Item>
<Menu.Item key="ng">
<a
href="http://ng.ant.design"
className="header-link"
target="_blank"
rel="noopener noreferrer"
>
Ant Design of Angular
</a>
</Menu.Item>
<Menu.Item key="vue">
<a
href="http://vue.ant.design"
className="header-link"
target="_blank"
rel="noopener noreferrer"
>
Ant Design of Vue
</a>
</Menu.Item>
{isZhCN ? (
<Menu.Item key="course" className="hide-in-home-page">
<a
href="https://www.yuque.com/ant-design/course"
className="header-link"
target="_blank"
rel="noopener noreferrer"
>
Ant Design
</a>
</Menu.Item>
) : null}
</Menu.ItemGroup>
);
}
export default (props: SharedProps) => {
const menu = <Menu>{getEcosystemGroup(props)}</Menu>;
return (
<Dropdown overlay={menu} placement="bottomRight">
<Button size="small" className="header-button">
<FormattedMessage id="app.header.menu.more" />
<DownOutlined />
</Button>
</Dropdown>
);
};

86
site/theme/template/Layout/Header/Navigation.less

@ -0,0 +1,86 @@
@import '../../../static/theme.less';
@import '../../../../../components/style/themes/default.less';
@import './index.less';
#nav {
height: 100%;
font-size: 14px;
font-family: Avenir, @font-family, sans-serif;
border: 0;
&.ant-menu-horizontal {
border-bottom: none;
& > .ant-menu-item,
& > .ant-menu-submenu {
min-width: 72px;
height: @header-height;
line-height: @header-height - @menu-item-border - 2px;
border-top: @menu-item-border solid transparent;
&:hover {
border-top: @menu-item-border solid @primary-color;
border-bottom: @menu-item-border solid transparent;
}
}
& .ant-menu-submenu-title .anticon {
margin: 0;
}
& > .ant-menu-submenu-open {
border-top: @menu-item-border solid @primary-color;
border-bottom: @menu-item-border solid transparent;
}
& > .ant-menu-item-selected {
border-top: @menu-item-border solid @primary-color;
border-bottom: @menu-item-border solid transparent;
a {
color: @primary-color;
}
}
}
& > .ant-menu-item,
& > .ant-menu-submenu {
text-align: center;
}
}
.header-link {
color: @site-text-color;
}
.ant-menu-item-active .header-link {
color: @primary-color;
}
// Popover menu is only used for mobile
.popover-menu {
width: 300px;
.ant-popover-inner-content {
padding: 0;
#nav {
.ant-menu-item,
.ant-menu-submenu {
text-align: left;
}
.ant-menu-item-group-title {
padding-left: 24px;
}
.ant-menu-item-group-list {
padding: 0 16px;
}
.ant-menu-item,
a {
color: #333;
}
}
}
}

102
site/theme/template/Layout/Header/Navigation.tsx

@ -0,0 +1,102 @@
import * as React from 'react';
import classNames from 'classnames';
import { FormattedMessage } from 'react-intl';
import { Link } from 'bisheng/router';
import { UnorderedListOutlined } from '@ant-design/icons';
import { Menu } from 'antd';
import { getEcosystemGroup } from './More';
import * as utils from '../../utils';
import { SharedProps } from './interface';
import './Navigation.less';
export interface NavigationProps extends SharedProps {
isMobile: boolean;
pathname: string;
responsive: null | 'narrow' | 'crowded';
location: { pathname: string };
directionText: string;
onLangChange: () => void;
onDirectionChange: () => void;
}
export default ({
isZhCN,
isMobile,
pathname,
responsive,
location,
directionText,
onLangChange,
onDirectionChange,
}: NavigationProps) => {
const menuMode = isMobile ? 'inline' : 'horizontal';
const module = pathname
.split('/')
.slice(0, -1)
.join('/');
let activeMenuItem = module || 'home';
if (location.pathname === 'changelog' || location.pathname === 'changelog-cn') {
activeMenuItem = 'docs/react';
} else if (location.pathname === 'docs/resources' || location.pathname === 'docs/resources-cn') {
activeMenuItem = 'docs/resources';
}
let additional: React.ReactNode = null;
const additionalItems = [
<Menu.Item key="github">
<a href="https://github.com/ant-design/ant-design" target="_blank" rel="noopener noreferrer">
Github
</a>
</Menu.Item>,
<Menu.Item key="switch-lang" onClick={onLangChange}>
<FormattedMessage id="app.header.lang" />
</Menu.Item>,
<Menu.Item key="switch-direction" onClick={onDirectionChange}>
{directionText}
</Menu.Item>,
getEcosystemGroup({ isZhCN }),
];
if (isMobile) {
additional = additionalItems;
} else if (responsive === 'crowded') {
additional = (
<Menu.SubMenu key="additional" title={<UnorderedListOutlined />}>
{additionalItems}
</Menu.SubMenu>
);
}
return (
<Menu
className={classNames('menu-site')}
mode={menuMode}
selectedKeys={[activeMenuItem]}
id="nav"
>
<Menu.Item key="docs/spec">
<Link to={utils.getLocalizedPathname('/docs/spec/introduce', isZhCN)}>
<FormattedMessage id="app.header.menu.spec" />
</Link>
</Menu.Item>
<Menu.Item key="docs/react">
<Link to={utils.getLocalizedPathname('/docs/react/introduce', isZhCN)}>
<FormattedMessage id="app.header.menu.documentation" />
</Link>
</Menu.Item>
<Menu.Item key="components">
<Link to={utils.getLocalizedPathname('/components/button/', isZhCN)}>
<FormattedMessage id="app.header.menu.components" />
</Link>
</Menu.Item>
<Menu.Item key="docs/resources">
<Link to={utils.getLocalizedPathname('/docs/resources', isZhCN)}>
<FormattedMessage id="app.header.menu.resource" />
</Link>
</Menu.Item>
{additional}
</Menu>
);
};

133
site/theme/template/Layout/Header/SearchBox.less

@ -0,0 +1,133 @@
@import '../../../static/theme.less';
@import '../../../../../components/style/themes/default.less';
@import './index.less';
@search-icon-color: #ced4d9;
#search-box {
position: relative;
display: flex;
flex: auto !important;
align-items: center;
height: 22px;
margin: 0 auto 0 0 !important;
padding-left: 16px;
line-height: 22px;
white-space: nowrap;
border-left: 1px solid @site-border-color-split;
transition: width 0.5s;
.ant-row-rtl & {
margin: 0 0 0 auto !important;
padding-right: 16px;
padding-left: 0;
border-right: 1px solid @site-border-color-split;
border-left: none;
}
> * {
flex: auto;
}
.anticon {
position: absolute;
top: 50%;
z-index: 1;
flex: none;
color: @search-icon-color;
transform: translateY(-50%);
pointer-events: none;
}
input {
width: 100%;
max-width: 200px;
padding-left: 20px;
font-size: 14px;
background: transparent;
border: 0;
box-shadow: none;
&::placeholder {
color: #a3b1bf;
}
}
// ================ Narrow ================
&.narrow-mode {
flex: none !important;
width: 30px;
&:hover {
.anticon {
color: #a3b1bf;
}
}
.anticon {
right: 0;
left: auto;
.ant-row-rtl & {
right: auto;
left: 0;
}
}
input {
max-width: none;
padding-right: 20px;
padding-left: 11px;
cursor: pointer;
.ant-row-rtl & {
padding-right: 11px;
padding-left: 20px;
}
}
&.focused {
width: 500px;
.anticon {
color: @search-icon-color;
}
input {
cursor: text;
}
}
}
}
.component-select {
&.ant-select-dropdown {
font-size: 14px;
border: 0;
border-radius: 0;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.25);
}
.ant-select-dropdown-menu {
max-height: 200px;
}
.ant-select-dropdown-menu-item {
border-radius: 0 !important;
}
.ant-component-decs {
position: absolute;
right: 16px;
color: #aaa;
font-size: 12px;
.ant-row-rtl & {
right: auto;
left: 16px;
}
}
}
@media only screen and (max-width: @mobile-max-width) {
#search-box {
display: none;
}
}

56
site/theme/template/Layout/Header/SearchBox.tsx

@ -0,0 +1,56 @@
import * as React from 'react';
import { Input } from 'antd';
import classNames from 'classnames';
import { SearchOutlined } from '@ant-design/icons';
import { SharedProps } from './interface';
import './SearchBox.less';
export interface SearchBoxProps extends SharedProps {
onTriggerFocus?: (focus: boolean) => void;
responsive: null | 'narrow' | 'crowded';
}
export default ({ isZhCN, responsive, onTriggerFocus }: SearchBoxProps) => {
const inputRef = React.useRef<any>(null);
const [focused, setFocused] = React.useState(false);
const searchPlaceholder = isZhCN ? '在 ant.design 中搜索' : 'Search in ant.design';
function triggerFocus(focus: boolean) {
setFocused(focus);
onTriggerFocus?.(focus);
}
React.useEffect(() => {
document.addEventListener('keyup', event => {
if (event.keyCode === 83 && event.target === document.body) {
inputRef.current.focus();
}
});
}, []);
return (
<div
id="search-box"
className={classNames({
'narrow-mode': responsive,
focused,
})}
onClick={() => {
inputRef.current.focus();
}}
>
<SearchOutlined />
<Input
ref={inputRef}
placeholder={searchPlaceholder}
onFocus={() => {
triggerFocus(true);
}}
onBlur={() => {
triggerFocus(false);
}}
/>
</div>
);
};

54
site/theme/template/Layout/Header/index.less

@ -0,0 +1,54 @@
@import '../../../static/theme.less';
@import '../../../../../components/style/themes/default.less';
@header-height: 64px;
@menu-item-border: 2px;
@mobile-max-width: 767.99px;
#header {
position: relative;
z-index: 10;
max-width: 100%;
background: @component-background;
box-shadow: 0 2px 8px rgba(240, 241, 242, 65);
.menu-row {
display: flex;
align-items: center;
margin: 0;
> * {
flex: none;
margin: 0 16px 0 0;
&:last-child {
margin-right: 40px;
}
}
}
// Adjust github button style
.ant-row-rtl {
.menu-row {
> * {
&:last-child {
margin-right: 16px;
margin-left: 40px;
}
}
}
}
// Buttons
.header-button {
color: @text-color;
border-color: @border-color-base;
}
}
@media only screen and (max-width: @mobile-max-width) {
#header {
text-align: center;
}
}

318
site/theme/template/Layout/Header/index.tsx

@ -0,0 +1,318 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, injectIntl } from 'react-intl';
import classNames from 'classnames';
import { UnorderedListOutlined } from '@ant-design/icons';
import { Select, Row, Col, Popover, Button } from 'antd';
import * as utils from '../../utils';
import { version as antdVersion } from '../../../../../package.json';
import Logo from './Logo';
import SearchBox from './SearchBox';
import More from './More';
import Navigation from './Navigation';
import Github from './Github';
import SiteContext from '../SiteContext';
import './index.less';
const RESPONSIVE_XS = 1120;
const RESPONSIVE_SM = 1200;
const { Option } = Select;
let docsearch: any;
if (typeof window !== 'undefined') {
docsearch = require('docsearch.js'); // eslint-disable-line
}
function initDocSearch(locale: string) {
if (!docsearch) {
return;
}
const lang = locale === 'zh-CN' ? 'cn' : 'en';
docsearch({
apiKey: '60ac2c1a7d26ab713757e4a081e133d0',
indexName: 'ant_design',
inputSelector: '#search-box input',
algoliaOptions: { facetFilters: [`tags:${lang}`] },
transformData(hits: { url: string }[]) {
hits.forEach(hit => {
hit.url = hit.url.replace('ant.design', window.location.host); // eslint-disable-line
hit.url = hit.url.replace('https:', window.location.protocol); // eslint-disable-line
});
return hits;
},
debug: false, // Set debug to true if you want to inspect the dropdown
});
}
export interface HeaderProps {
intl: {
locale: string;
};
location: { pathname: string };
themeConfig: { docVersions: Record<string, string> };
changeDirection: (direction: string) => void;
}
interface HeaderState {
menuVisible: boolean;
windowWidth: number;
searching: boolean;
}
class Header extends React.Component<HeaderProps, HeaderState> {
static contextTypes = {
router: PropTypes.object.isRequired,
theme: PropTypes.oneOf(['default', 'dark']),
direction: PropTypes.string,
};
state = {
menuVisible: false,
windowWidth: 1400,
searching: false,
};
componentDidMount() {
const { intl } = this.props;
const { router } = this.context;
router.listen(this.handleHideMenu);
initDocSearch(intl.locale);
window.addEventListener('resize', this.onWindowResize);
this.onWindowResize();
}
componentWillUnmount() {
window.removeEventListener('resize', this.onWindowResize);
}
onWindowResize = () => {
this.setState({
windowWidth: window.innerWidth,
});
};
onTriggerSearching = (searching: boolean) => {
this.setState({ searching });
};
handleShowMenu = () => {
this.setState({
menuVisible: true,
});
};
handleHideMenu = () => {
this.setState({
menuVisible: false,
});
};
onDirectionChange = () => {
const { changeDirection } = this.props;
const { direction } = this.context;
if (direction !== 'rtl') {
changeDirection('rtl');
} else {
changeDirection('ltr');
}
};
getNextDirectionText = () => {
const { direction } = this.context;
if (direction !== 'rtl') {
return 'RTL';
}
return 'LTR';
};
onMenuVisibleChange = (visible: boolean) => {
this.setState({
menuVisible: visible,
});
};
handleVersionChange = (url: string) => {
const currentUrl = window.location.href;
const currentPathname = window.location.pathname;
window.location.href = currentUrl
.replace(window.location.origin, url)
.replace(currentPathname, utils.getLocalizedPathname(currentPathname));
};
onLangChange = () => {
const {
location: { pathname },
} = this.props;
const currentProtocol = `${window.location.protocol}//`;
const currentHref = window.location.href.substr(currentProtocol.length);
if (utils.isLocalStorageNameSupported()) {
localStorage.setItem('locale', utils.isZhCN(pathname) ? 'en-US' : 'zh-CN');
}
window.location.href =
currentProtocol +
currentHref.replace(
window.location.pathname,
utils.getLocalizedPathname(pathname, !utils.isZhCN(pathname)),
);
};
render() {
return (
<SiteContext.Consumer>
{({ isMobile }) => {
const { menuVisible, windowWidth, searching } = this.state;
const {
location,
themeConfig,
intl: { locale },
} = this.props;
const docVersions = { ...themeConfig.docVersions, [antdVersion]: antdVersion };
const versionOptions = Object.keys(docVersions).map(version => (
<Option value={docVersions[version]} key={version}>
{version}
</Option>
));
const pathname = location.pathname.replace(/(^\/|\/$)/g, '');
const isHome = ['', 'index', 'index-cn'].includes(pathname);
const isZhCN = locale === 'zh-CN';
let responsive: null | 'narrow' | 'crowded' = null;
if (windowWidth < RESPONSIVE_XS) {
responsive = 'crowded';
} else if (windowWidth < RESPONSIVE_SM) {
responsive = 'narrow';
}
const headerClassName = classNames({
clearfix: true,
'home-header': isHome,
});
const sharedProps = {
isZhCN,
};
const searchBox = (
<SearchBox
key="search"
{...sharedProps}
responsive={responsive}
onTriggerFocus={this.onTriggerSearching}
/>
);
const navigationNode = (
<Navigation
key="nav"
{...sharedProps}
location={location}
responsive={responsive}
isMobile={isMobile}
pathname={pathname}
directionText={this.getNextDirectionText()}
onLangChange={this.onLangChange}
onDirectionChange={this.onDirectionChange}
/>
);
let menu: (React.ReactElement | null)[] = [
navigationNode,
<Select
key="version"
className="version"
size="small"
defaultValue={antdVersion}
onChange={this.handleVersionChange}
getPopupContainer={trigger => trigger.parentNode}
>
{versionOptions}
</Select>,
<Button
size="small"
onClick={this.onLangChange}
className="header-button header-lang-button"
key="lang-button"
>
<FormattedMessage id="app.header.lang" />
</Button>,
<Button
size="small"
onClick={this.onDirectionChange}
className="header-button header-direction-button"
key="direction-button"
>
{this.getNextDirectionText()}
</Button>,
<More key="more" {...sharedProps} />,
<Github key="github" responsive={responsive} />,
];
if (windowWidth < RESPONSIVE_XS) {
menu = searching ? [] : [navigationNode];
} else if (windowWidth < RESPONSIVE_SM) {
menu = searching ? [] : menu;
}
const colProps = isHome
? [{ flex: 'none' }, { flex: 'auto' }]
: [
{
xxl: 4,
xl: 5,
lg: 6,
md: 6,
sm: 24,
xs: 24,
},
{
xxl: 20,
xl: 19,
lg: 18,
md: 18,
sm: 0,
xs: 0,
},
];
return (
<header id="header" className={headerClassName}>
{isMobile && (
<Popover
overlayClassName="popover-menu"
placement="bottomRight"
content={menu}
trigger="click"
visible={menuVisible}
arrowPointAtCenter
onVisibleChange={this.onMenuVisibleChange}
>
<UnorderedListOutlined className="nav-phone-icon" onClick={this.handleShowMenu} />
</Popover>
)}
<Row style={{ flexFlow: 'nowrap' }}>
<Col {...colProps[0]}>
<Logo {...sharedProps} />
</Col>
<Col {...colProps[1]} className="menu-row">
{searchBox}
{!isMobile && menu}
</Col>
</Row>
</header>
);
}}
</SiteContext.Consumer>
);
}
}
export default injectIntl(Header as any);

3
site/theme/template/Layout/Header/interface.tsx

@ -0,0 +1,3 @@
export interface SharedProps {
isZhCN: boolean;
}

11
site/theme/template/Layout/SiteContext.tsx

@ -0,0 +1,11 @@
import * as React from 'react';
export interface SiteContextProps {
isMobile: boolean;
}
const SiteContext = React.createContext<SiteContextProps>({
isMobile: false,
});
export default SiteContext;

94
site/theme/template/Layout/index.jsx

@ -1,7 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { enquireScreen } from 'enquire-js';
import { IntlProvider } from 'react-intl';
import { presetPalettes, presetDarkPalettes } from '@ant-design/colors';
import themeSwitcher from 'theme-switcher';
@ -14,6 +13,7 @@ import setupLogRocketReact from 'logrocket-react';
// eslint-disable-next-line import/no-unresolved
import zhCN from 'antd/es/locale/zh_CN';
import Header from './Header';
import SiteContext from './SiteContext';
import enLocale from '../../en-US';
import cnLocale from '../../zh-CN';
import * as utils from '../utils';
@ -51,10 +51,7 @@ if (typeof window !== 'undefined') {
}
}
let isMobile = false;
enquireScreen(b => {
isMobile = b;
});
const RESPONSIVE_MOBILE = 768;
const SITE_THEME_STORE_KEY = 'site-theme';
// for dark.css timestamp to remove cache
@ -73,7 +70,6 @@ export default class Layout extends React.Component {
};
static childContextTypes = {
isMobile: PropTypes.bool,
theme: PropTypes.oneOf(['default', 'dark']),
setTheme: PropTypes.func,
direction: PropTypes.string,
@ -87,7 +83,6 @@ export default class Layout extends React.Component {
this.state = {
appLocale,
isMobile,
theme:
typeof localStorage !== 'undefined'
? localStorage.getItem(SITE_THEME_STORE_KEY) || 'default'
@ -101,8 +96,8 @@ export default class Layout extends React.Component {
}
getChildContext() {
const { isMobile: mobile, theme, setTheme, direction, setIframeTheme } = this.state;
return { isMobile: mobile, theme, setTheme, direction, setIframeTheme };
const { theme, setTheme, direction, setIframeTheme } = this.state;
return { theme, setTheme, direction, setIframeTheme };
}
componentDidMount() {
@ -134,17 +129,25 @@ export default class Layout extends React.Component {
}, 0);
}
enquireScreen(b => {
this.setState({
isMobile: !!b,
});
});
this.updateMobileMode();
window.addEventListener('resize', this.updateMobileMode);
}
componentWillUnmount() {
clearTimeout(this.timer);
window.removeEventListener('resize', this.updateMobileMode);
}
updateMobileMode = () => {
const { isMobile } = this.state;
const newIsMobile = window.innerWidth < RESPONSIVE_MOBILE;
if (isMobile !== newIsMobile) {
this.setState({
isMobile: newIsMobile,
});
}
};
setIframeTheme = (iframeNode, theme) => {
iframeNode.contentWindow.postMessage(
JSON.stringify({
@ -192,7 +195,7 @@ export default class Layout extends React.Component {
render() {
const { children, helmetContext = {}, ...restProps } = this.props;
const { appLocale, direction } = this.state;
const { appLocale, direction, isMobile } = this.state;
const title =
appLocale.locale === 'zh-CN'
? 'Ant Design - 一套企业级 UI 设计语言和 React 组件库'
@ -206,32 +209,41 @@ export default class Layout extends React.Component {
pageWrapperClass += ' page-wrapper-rtl';
}
return (
<HelmetProvider context={helmetContext}>
<Helmet encodeSpecialCharacters={false}>
<html lang={appLocale.locale === 'zh-CN' ? 'zh' : 'en'} data-direction={direction} />
<title>{title}</title>
<link
rel="apple-touch-icon-precomposed"
sizes="144x144"
href="https://gw.alipayobjects.com/zos/antfincdn/UmVnt3t4T0/antd.png"
/>
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<meta property="og:type" content="website" />
<meta
property="og:image"
content="https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png"
/>
</Helmet>
<IntlProvider locale={appLocale.locale} messages={appLocale.messages} defaultLocale="en-US">
<ConfigProvider locale={appLocale.locale === 'zh-CN' ? zhCN : null} direction={direction}>
<div className={pageWrapperClass}>
<Header {...restProps} changeDirection={this.changeDirection} />
{children}
</div>
</ConfigProvider>
</IntlProvider>
</HelmetProvider>
<SiteContext.Provider value={{ isMobile }}>
<HelmetProvider context={helmetContext}>
<Helmet encodeSpecialCharacters={false}>
<html lang={appLocale.locale === 'zh-CN' ? 'zh' : 'en'} data-direction={direction} />
<title>{title}</title>
<link
rel="apple-touch-icon-precomposed"
sizes="144x144"
href="https://gw.alipayobjects.com/zos/antfincdn/UmVnt3t4T0/antd.png"
/>
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<meta property="og:type" content="website" />
<meta
property="og:image"
content="https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png"
/>
</Helmet>
<IntlProvider
locale={appLocale.locale}
messages={appLocale.messages}
defaultLocale="en-US"
>
<ConfigProvider
locale={appLocale.locale === 'zh-CN' ? zhCN : null}
direction={direction}
>
<div className={pageWrapperClass}>
<Header {...restProps} changeDirection={this.changeDirection} />
{children}
</div>
</ConfigProvider>
</IntlProvider>
</HelmetProvider>
</SiteContext.Provider>
);
}
}

35
site/theme/template/Resources/AffixTabs.less

@ -0,0 +1,35 @@
@import '../../../../components/style/themes/default.less';
@import './index.less';
.resource-affix-tabs {
position: fixed;
top: 0;
right: 0;
left: 0;
z-index: 11;
padding: 0 @resource-padding;
background: #fff;
box-shadow: @shadow-2;
transform: translateY(-100%);
opacity: 0;
transition: opacity 0.3s, transform 0.3s;
&-fixed {
transform: translateY(0);
opacity: 1;
}
.ant-tabs {
max-width: 1208px;
margin: 0 auto;
.ant-tabs-bar {
margin: 0;
border-bottom-color: transparent;
.ant-tabs-tab {
padding: 21px 0;
}
}
}
}

79
site/theme/template/Resources/AffixTabs.tsx

@ -0,0 +1,79 @@
import * as React from 'react';
import classNames from 'classnames';
import throttle from 'lodash/throttle';
import { Tabs } from 'antd';
import scrollTo from '../../../../components/_util/scrollTo';
import './AffixTabs.less';
const VIEW_BALANCE = 32;
const { TabPane } = Tabs;
export default () => {
const containerRef = React.useRef<HTMLDivElement>(null);
const idsRef = React.useRef<string[]>([]);
const [, forceUpdate] = React.useState<{}>({});
const [fixedId, setFixedId] = React.useState<string | null>(null);
React.useEffect(() => {
idsRef.current = Array.from(document.querySelectorAll('h2[id]')).map(({ id }) => id);
forceUpdate({});
}, []);
const onSyncAffix = React.useMemo(() => {
function doSync() {
const scrollY = window.scrollY;
const containerHeight = containerRef.current!.offsetHeight;
for (let i = idsRef.current.length - 1; i >= 0; i -= 1) {
const id = idsRef.current[i];
const current = document.getElementById(id)!;
const offsetTop = current.offsetTop - containerHeight - VIEW_BALANCE;
if (offsetTop <= scrollY) {
setFixedId(id);
return;
}
}
setFixedId(null);
}
return throttle(doSync);
}, []);
React.useEffect(() => {
window.addEventListener('scroll', onSyncAffix);
window.addEventListener('resize', onSyncAffix);
onSyncAffix();
return () => {
window.removeEventListener('scroll', onSyncAffix);
window.removeEventListener('resize', onSyncAffix);
};
}, []);
return (
<div
className={classNames('resource-affix-tabs', {
'resource-affix-tabs-fixed': fixedId,
})}
ref={containerRef}
>
<Tabs
activeKey={fixedId || undefined}
onChange={key => {
const newTop =
document.getElementById(key)!.offsetTop -
containerRef.current!.offsetHeight -
VIEW_BALANCE;
scrollTo(newTop);
}}
>
{idsRef.current.map(id => (
<TabPane key={id} tab={id.replace(/-/g, ' ')} />
))}
</Tabs>
</div>
);
};

137
site/theme/template/Resources/index.less

@ -0,0 +1,137 @@
@import '../../../../components/style/themes/default.less';
@ArticleMaxWidth: 1208px;
@resource-padding: 40px;
@resource-padding-xs: 24px;
#resources-page {
article {
padding: 0 @resource-padding;
// Title
.title-region {
margin: 0 -@resource-padding;
padding: 0 @resource-padding;
overflow: hidden;
background: url(https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*y_r7RogIG1wAAAAAAAAAAABkARQnAQ);
background-size: cover;
h1 {
max-width: @ArticleMaxWidth;
margin: 56px auto 16px;
font-size: 38px;
line-height: 46px;
}
.markdown {
max-width: @ArticleMaxWidth;
margin: 0 auto 56px;
font-weight: 200;
font-size: 16px;
line-height: 24px;
}
}
// Content
> .markdown {
max-width: @ArticleMaxWidth;
margin: 0 auto;
> p {
margin-bottom: 56px;
}
}
h2 {
margin-top: 124px;
color: #314659;
font-weight: lighter;
font-size: 30px;
line-height: 38px;
&:first-child {
margin-top: 88px;
}
}
h3 {
margin-top: 56px;
font-weight: 400;
font-size: 24px;
line-height: 32px;
}
p {
color: #697b8c;
}
}
.resource-cards {
.resource-card {
display: flex;
flex-direction: column;
height: 100%;
color: inherit;
list-style: none;
border: 1px solid #e6e6e6;
border-radius: 2px;
cursor: pointer;
transition: box-shadow 0.3s;
&:hover {
box-shadow: @shadow-2;
}
.resource-card-image {
width: calc(100% + 2px);
max-width: none;
height: 184px;
margin: -1px -1px 0 -1px;
object-fit: cover;
}
.resource-card-title {
margin: 16px 20px 8px 20px;
color: #0d1a26;
font-size: 20px;
line-height: 28px;
}
.resource-card-description {
margin: 0 20px 20px 20px;
color: #697b8c;
font-size: 14px;
line-height: 22px;
}
}
}
footer {
margin-top: 176px;
.rc-footer-container {
max-width: @ArticleMaxWidth;
margin: 0 auto;
padding-right: 0;
padding-left: 0;
}
}
}
@media only screen and (max-width: 767.99px) {
#resources-page {
article {
padding: 0 @resource-padding-xs;
// Title
.title-region {
margin: 0 -@resource-padding-xs;
padding: 0 @resource-padding-xs;
}
}
.ant-col {
padding-top: 16px !important;
padding-bottom: 16px !important;
}
}
}

152
site/theme/template/Resources/index.tsx

@ -0,0 +1,152 @@
import * as React from 'react';
import collect from 'bisheng/collect';
import { useIntl } from 'react-intl';
import Article from '../Content/Article';
import Footer from '../Layout/Footer';
import * as utils from '../utils';
import './index.less';
import AffixTabs from './AffixTabs';
interface PageData {
meta: {
order?: number;
title: string;
filename: string;
};
content: ContentUnit[];
toc: any[];
}
interface PagesData {
'docs/resources': {
docs: {
resources: {
[locale: string]: () => Promise<PageData>;
};
};
};
}
interface ResourcesProps {
location: {
pathname: string;
};
data: PagesData;
localizedPageData: PageData;
utils: {
toReactComponent: (content: any[]) => React.ReactElement;
get: (data: PagesData, path: string[]) => any;
};
}
type ContentUnit = string | Record<string, any> | ContentUnit[];
function getUnitString(unit: ContentUnit[]): string {
if (!unit) return '';
const last = unit[unit.length - 1];
return Array.isArray(last) ? getUnitString(last) : (last as string);
}
function toList([, ...items]: ContentUnit[]): ContentUnit[] {
return [
'div',
{ className: 'ant-row resource-cards', style: 'margin: -12px -12px 0 -12px' },
...items.map(([, title, [, image, description, link]]: any) => {
let titleStr = getUnitString(title);
const imageStr = getUnitString(image);
const descStr = getUnitString(description);
const linkStr = getUnitString(link);
let coverColor: string | null = null;
const titleMatch = titleStr.match(/(.*)(#[\dA-Fa-f]{6})/);
if (titleMatch) {
titleStr = titleMatch[1].trim();
coverColor = titleMatch[2];
}
return [
'div',
{
className: 'ant-col ant-col-xs-24 ant-col-sm-12 ant-col-md-8 ant-col-lg-6 gutter-row',
style: 'padding: 12px;',
},
[
'a',
{ className: 'resource-card', target: '_blank', href: linkStr },
[
'img',
{
className: 'resource-card-image',
src: imageStr,
alt: titleStr,
style: coverColor
? {
backgroundColor: coverColor,
objectFit: 'contain',
}
: {},
},
],
['p', { className: 'resource-card-title' }, titleStr],
['p', { className: 'resource-card-description' }, descStr],
],
];
}),
];
}
function injectCards(content: ContentUnit[]): ContentUnit[] {
const newContent: ContentUnit[] = [];
for (let i = 0; i < content.length; i += 1) {
const unit = content[i];
if (Array.isArray(unit) && (unit[1] as any).class === 'next-block-use-cards') {
newContent.push(toList(content[i + 1] as any));
i += 1;
} else {
newContent.push(unit);
}
}
return newContent;
}
const Resources = (props: ResourcesProps) => {
const { localizedPageData } = props;
const { locale } = useIntl();
const content = React.useMemo(() => injectCards(localizedPageData.content), [
localizedPageData.content,
]);
return (
<div id="resources-page">
<AffixTabs />
<Article
{...props}
content={{
...localizedPageData,
content,
}}
intl={{ locale }}
titleRegionClassName="title-region"
/>
<Footer />
</div>
);
};
export default collect(async (nextProps: ResourcesProps) => {
const { pathname } = nextProps.location;
const pageDataPath = pathname.replace('-cn', '').split('/');
const pageData = nextProps.utils.get(nextProps.data, pageDataPath);
const locale = utils.isZhCN(pathname) ? 'zh-CN' : 'en-US';
const pageDataPromise = pageData[locale]();
return { localizedPageData: await pageDataPromise };
})(Resources);

4
site/theme/template/utils.tsx

@ -114,7 +114,7 @@ export function isZhCN(pathname: string) {
return /-cn\/?$/.test(pathname);
}
export function getLocalizedPathname(path: string, zhCN: boolean) {
export function getLocalizedPathname(path: string, zhCN?: boolean) {
const pathname = path.startsWith('/') ? path : `/${path}`;
if (!zhCN) {
// to enUS
@ -175,7 +175,7 @@ export function loadScript(src: string) {
});
}
export function getMetaDescription(jml: any[]) {
export function getMetaDescription(jml?: any[] | null) {
const COMMON_TAGS = ['h1', 'h2', 'h3', 'p', 'img', 'a', 'code', 'strong'];
if (!Array.isArray(jml)) {
return '';

4
site/theme/zh-CN.js

@ -4,11 +4,11 @@ module.exports = {
'app.theme.switch.dark': '切换浅色模式',
'app.theme.switch.default': '切换暗黑模式',
'app.header.search': '全文本搜索...',
'app.header.menu.home': '首页',
'app.header.menu.documentation': '文档',
'app.header.menu.components': '组件',
'app.header.menu.spec': '设计',
'app.header.menu.resource': '资源',
'app.header.menu.more': '更多',
'app.header.menu.mobile': '移动版',
'app.header.menu.pro.v4': 'Ant Design Pro v4',
'app.header.menu.ecosystem': '生态',
@ -49,6 +49,8 @@ module.exports = {
'app.home.design-patterns': '设计模式',
'app.home.more': '更多内容',
'app.home.play-video': '播放视频',
'app.home.qr': '4.0 正式版发布',
'app.home.qr.desc': '扫描上方二维码查看',
'app.home.getting-started': '开始使用',
'app.home.design-language': '设计语言',
'app.home.product-antv-slogan': '全新一代数据可视化解决方案',

6
typings/custom-typings.d.ts

@ -8,8 +8,14 @@ declare module '*.svg' {
export default src;
}
declare module 'bisheng/collect';
declare module 'bisheng/router';
declare module 'react-github-button';
declare module 'jsonml.js/*';
declare module 'rc-pagination/*';
declare module 'omit.js';

Loading…
Cancel
Save