├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── FUNDING.yml ├── .gitignore ├── .stylelintrc ├── CNAME ├── LICENSE ├── README-zh_CN.md ├── README.md ├── docs ├── cases.md ├── download.md ├── edit │ ├── edit-block.md │ └── video.md ├── guide │ ├── banner.md │ ├── content.md │ ├── examples.md │ ├── header-footer.md │ ├── layout.md │ └── type.md ├── introduce.md └── use │ ├── create-react-app.en-US.md │ ├── create-react-app.zh-CN.md │ ├── dumi.md │ ├── dva-cli.md │ ├── getting-started.md │ ├── pro-1-x.md │ ├── pro.md │ └── umi.md ├── documentation.md ├── index.text ├── package.json ├── prettier ├── install-service-worker.js ├── lib │ ├── index.js │ ├── parser-babylon.js │ ├── parser-flow.js │ ├── parser-glimmer.js │ ├── parser-graphql.js │ ├── parser-markdown.js │ ├── parser-parse5.js │ ├── parser-postcss.js │ ├── parser-typescript.js │ ├── parser-vue.js │ └── sw-toolbox.js ├── service-worker.js └── worker.js ├── renovate.json ├── site ├── bisheng.common.config.js ├── bisheng.edit.config.js ├── bisheng.index.config.js ├── bisheng.templates.config.js ├── edit │ ├── en-US.js │ ├── index.js │ ├── static │ │ ├── banner-slide.less │ │ ├── common.less │ │ ├── content.less │ │ ├── custom.less │ │ ├── edit-influence.less │ │ ├── edit-list │ │ │ ├── box-model.less │ │ │ ├── child.less │ │ │ ├── collapse.less │ │ │ ├── common.less │ │ │ ├── custom.less │ │ │ ├── editor-bg-image.less │ │ │ ├── editor-color.less │ │ │ ├── editor-font.less │ │ │ ├── editor-gradient.less │ │ │ └── index.less │ │ ├── edit-stage.less │ │ ├── index.html │ │ ├── index.less │ │ ├── login-controller.less │ │ ├── nav-controller.less │ │ ├── other-view.less │ │ ├── side-menu.less │ │ ├── sort.less │ │ └── style.js │ ├── template │ │ ├── NotFound.jsx │ │ ├── component.config.js │ │ ├── components │ │ │ ├── EditInfluence.jsx │ │ │ ├── EditListController.jsx │ │ │ ├── EditStageController.jsx │ │ │ ├── Iframe.jsx │ │ │ ├── ListComponents │ │ │ │ ├── CheckboxGroup.jsx │ │ │ │ ├── ChildComp.jsx │ │ │ │ ├── EditorComp.jsx │ │ │ │ ├── EditorOther.jsx │ │ │ │ ├── InputGroup.jsx │ │ │ │ └── PropsComp.jsx │ │ │ ├── MediumEditor.jsx │ │ │ ├── NavController │ │ │ │ ├── HistoryButton.jsx │ │ │ │ ├── NewFileButton.jsx │ │ │ │ ├── PublishModal.jsx │ │ │ │ └── index.jsx │ │ │ ├── SideMenu.jsx │ │ │ ├── StateComponents │ │ │ │ ├── ButtonViewComponent │ │ │ │ │ ├── ContentEditView.jsx │ │ │ │ │ ├── ContentEditViewItem.jsx │ │ │ │ │ ├── ContentWrapper.jsx │ │ │ │ │ ├── IconComp.jsx │ │ │ │ │ ├── ImageComp.jsx │ │ │ │ │ ├── LinkComp.jsx │ │ │ │ │ ├── MenuComp.jsx │ │ │ │ │ ├── MenuEditView.jsx │ │ │ │ │ ├── TextyComp.jsx │ │ │ │ │ └── VideoComp.jsx │ │ │ │ ├── EditButtonView.jsx │ │ │ │ ├── ListSort.jsx │ │ │ │ └── SwitchSlideView.jsx │ │ │ └── saveJsZip.jsx │ │ ├── index.jsx │ │ ├── layout.jsx │ │ ├── template.config.js │ │ └── utils.jsx │ └── zh-CN.js ├── shared │ ├── constants.js │ ├── defaultTemplate.js │ ├── leancloud.js │ ├── localStorage.js │ ├── redux │ │ ├── actionTypes.js │ │ ├── actions.js │ │ ├── index.js │ │ ├── reducers │ │ │ ├── currentEditData.js │ │ │ ├── historyEdit.js │ │ │ ├── index.js │ │ │ ├── mediaStateSelect.js │ │ │ ├── templateData.js │ │ │ └── userIsLogin.js │ │ └── saga.js │ ├── url.js │ └── utils.js ├── templates │ ├── index.js │ ├── static │ │ ├── bottom-func-bar.less │ │ ├── common.less │ │ ├── content.less │ │ ├── custom.less │ │ ├── index.html │ │ ├── index.less │ │ ├── lessToString.jsx │ │ └── point.less │ └── template │ │ ├── BottomBar.jsx │ │ ├── NotFound.jsx │ │ ├── element │ │ ├── Banner0 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Banner1 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Banner2 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Banner3 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Banner4 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Banner5 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content0 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content1 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content10 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content11 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content12 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content13 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content2 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content3 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content4 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content5 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content6 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content7 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content8 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Content9 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Feature6 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Feature7 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Feature8 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Footer0 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Footer1 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Footer2 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Nav0 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Nav1 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Nav2 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Nav3 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Pricing0 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Pricing1 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Pricing2 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Teams0 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Teams1 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Teams2 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ ├── Teams3 │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── template.config.js │ │ └── template.config.js │ │ ├── index.jsx │ │ ├── layout.jsx │ │ ├── other │ │ ├── Point.jsx │ │ └── otherToString.jsx │ │ └── utils.jsx ├── theme │ ├── en-US.js │ ├── index.js │ ├── static │ │ ├── antd.less │ │ ├── common.less │ │ ├── default.less │ │ ├── footer.less │ │ ├── header.less │ │ ├── home │ │ │ ├── banner.less │ │ │ ├── index.less │ │ │ ├── page1.less │ │ │ ├── page2.less │ │ │ ├── page3.less │ │ │ ├── page4.less │ │ │ └── responsive.less │ │ ├── index.less │ │ ├── page │ │ │ ├── highlight.less │ │ │ ├── index.less │ │ │ ├── markdown.less │ │ │ ├── page-nav.less │ │ │ ├── responsive.less │ │ │ └── toc.less │ │ ├── preview-img.less │ │ ├── responsive.less │ │ ├── style.js │ │ └── template.html │ ├── template │ │ ├── Content │ │ │ ├── Article.jsx │ │ │ ├── EditButton.jsx │ │ │ ├── MainContent.jsx │ │ │ └── index.jsx │ │ ├── Home │ │ │ ├── Banner.jsx │ │ │ ├── Page1.jsx │ │ │ ├── Page2.jsx │ │ │ ├── Page3.jsx │ │ │ ├── Page4.jsx │ │ │ ├── component │ │ │ │ ├── ImageLoadComp.jsx │ │ │ │ ├── Templates.jsx │ │ │ │ ├── WaterfallLayout.jsx │ │ │ │ └── data.json │ │ │ ├── index.jsx │ │ │ └── utils.jsx │ │ ├── Layout │ │ │ ├── Footer.jsx │ │ │ ├── Header.jsx │ │ │ ├── Layout.jsx │ │ │ ├── PhoneNav.jsx │ │ │ └── index.jsx │ │ ├── NotFound.jsx │ │ ├── Other │ │ │ ├── Cases.jsx │ │ │ ├── Download.jsx │ │ │ ├── cases.less │ │ │ └── download.less │ │ └── utils.jsx │ └── zh-CN.js └── utils.jsx └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | _site 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: ant-design-landing 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | custom: # Replace with a single custom sponsorship URL 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | .ipr 4 | .iws 5 | *~ 6 | ~* 7 | *.diff 8 | *.patch 9 | *.bak 10 | .DS_Store 11 | Thumbs.db 12 | .project 13 | .*proj 14 | .svn/ 15 | *.swp 16 | *.swo 17 | *.pyc 18 | *.pyo 19 | node_modules 20 | dist 21 | psd 22 | old 23 | _site 24 | .vscode -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "rules": { 4 | "comment-empty-line-before": null, 5 | "declaration-empty-line-before": null, 6 | "function-comma-newline-after": null, 7 | "function-name-case": null, 8 | "function-parentheses-newline-inside": null, 9 | "function-max-empty-lines": null, 10 | "function-whitespace-after": null, 11 | "indentation": null, 12 | "number-leading-zero": null, 13 | "number-no-trailing-zeros": null, 14 | "rule-empty-line-before": null, 15 | "selector-combinator-space-after": null, 16 | "selector-list-comma-newline-after": null, 17 | "selector-pseudo-element-colon-notation": null, 18 | "unit-no-unknown": null, 19 | "value-list-max-empty-lines": null, 20 | "no-descending-specificity": null 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | landing.ant.design -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT LICENSE 2 | 3 | Copyright (c) 2015-present Alipay.com, https://www.alipay.com/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README-zh_CN.md: -------------------------------------------------------------------------------- 1 | <p align="center"> 2 | <a href="http://landing.ant.design"> 3 | <img width="150px" height="150px" src="https://gw.alipayobjects.com/zos/rmsportal/hSYPdZJwZeXAgfkktcEu.svg"/> 4 | </a> 5 | </p> 6 | <h1 align="center">Ant Design Landing</h1> 7 | <div align="center">Ant Design 的 Landing Page 模板与设计指引</div> 8 | 9 | <div align="center"> 10 | 此网站的内容是从 <a href="https://motion.ant.design">Ant Motion</a> 模板区块中分离出来. 11 | </div> 12 | 13 | <div align="center"><a href="./README.md">English</a> | 简体中文</div> 14 | 15 | ## 什么是Landing? 16 | 17 | Landing 是运用 Ant Motion 动效组件来搭建完成的页面模板,拥有丰富的各类首页模板,下载模板代码包,即可快速使用,也可使用首页编辑器,快速搭建一个属于你的专属首页。 18 | 19 | ## 三大特性 20 | 21 | - [设计指引](https://landing.ant.design/docs/introduce) 22 | - [源文件下载](https://landing.ant.design/docs/download) 23 | - [响应式布局](https://landing.ant.design/docs/guide/layout) 24 | 25 | 26 | ## 丰富的模板 27 | 28 | 拥有丰富的各类首页模板提供下载。 29 | 30 | [](http://landing.ant.design) 31 | 32 | ## 丰富的模块 33 | 34 | 多样的模块,可灵活又快速的配置出你想要的首页模板。 35 | 36 | 37 | <div style="max-width: 600px"> 38 | <img src="https://user-images.githubusercontent.com/6802825/47980280-ec459480-e101-11e8-8a94-1ada4ff61faa.jpg" width="100%"> 39 | </div> 40 | 41 | [进入编辑 😀](https://landing.ant.design/edit) 42 | 43 | ## 脚手架里的示例 44 | 45 | [生成首页在 dva-cli 里运行的例子](https://github.com/ant-motion/ant-motion-dva-cli-example) 46 | 47 | [生成首页在 umi 里运行的例子](https://github.com/ant-motion/landing-umi-example) 48 | 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | <p align="center"> 2 | <a href="http://landing.ant.design"> 3 | <img width="150px" height="150px" src="https://gw.alipayobjects.com/zos/rmsportal/hSYPdZJwZeXAgfkktcEu.svg"/> 4 | </a> 5 | </p> 6 | <h1 align="center">Ant Design Landing</h1> 7 | 8 | <div align="center"> 9 | 10 | Landing Pages of Ant Design System 11 | 12 | [](https://david-dm.org/ant-design/ant-design-landing) 13 | [](https://david-dm.org/ant-design/ant-design-landing?type=dev) 14 | 15 | </div> 16 | 17 | <div align="center">English | <a href="./README-zh_CN.md">简体中文</a></div> 18 | 19 | ## What is Landing? 20 | 21 | Landing is a template built by Ant Motion's motion components. It has a rich homepage template, downloads the template code package, and can be used quickly. You can also use the editor to quickly build your own dedicated page. 22 | 23 | <div align="center"> 24 | <a href="https://landing.ant.design/edit">Go Editing 📝</a> 25 | </div> 26 | 27 | ## Features 28 | 29 | - [Specifications](https://landing.ant.design/docs/introduce) 30 | - [Download](https://landing.ant.design/docs/download) 31 | - [Responsive](https://landing.ant.design/docs/guide/layout) 32 | 33 | ## Templates 34 | 35 | Has a wealth of various page templates to provide downloads. 36 | 37 | [](http://landing.ant.design) 38 | 39 | ## Modules 40 | 41 | Diverse modules, you can quickly and flexibly configure the page template you want. 42 | 43 | <div style="max-width: 600px"> 44 | <img src="https://user-images.githubusercontent.com/6802825/47980280-ec459480-e101-11e8-8a94-1ada4ff61faa.jpg" width="100%"> 45 | </div> 46 | 47 | ## Example in scaffolding 48 | 49 | - [dva-cli-example](https://github.com/ant-motion/ant-motion-dva-cli-example) 50 | - [umi-example](https://github.com/ant-motion/landing-umi-example) 51 | -------------------------------------------------------------------------------- /docs/cases.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | title: 4 | zh-CN: 实践案例 5 | en-US: Case 6 | --- 7 | 8 | 目前在外部也有许多产品实践,如果你的页面想在这里展现,[欢迎留言](https://github.com/ant-design/ant-motion/issues/30)。 9 | 10 | ```__react 11 | const casesData = [ 12 | { title: '蚂蚁科技官网', content: '蚂蚁金融科技,数字金融新原力', url: 'https://tech.antfin.com/', img: 'https://gw.alipayobjects.com/zos/rmsportal/vHQCWlZGnFSYiPOnbluw.jpg' }, 13 | { title: 'Ant Design官网', content: '服务于企业级产品的设计体系。', url: 'https://ant.design/', img: 'https://gw.alipayobjects.com/zos/rmsportal/yYQUqTuAxwHzSgGEGqkE.jpg' }, 14 | { title: '闪蝶', content: '提供专业的云上建站服务,满足不同行业的个性化需求', url: 'https://morpho.alipay.com/domain-intro', img: 'https://gw.alipayobjects.com/mdn/rms_ae7ad9/afts/img/A*YHa3S5yO6EsAAAAAAAAAAABkARQnAQ' }, 15 | { title: '智能物料设计平台', content: '花更少的时间做更专业的物料', url: 'https://chitu.alipay.com/', img: 'https://gw.alipayobjects.com/zos/rmsportal/aBwXHHpGMhIrnhUPUYVW.jpg' }, 16 | ]; 17 | 18 | import React from 'react'; 19 | import Demo from '../site/theme/template/Other/Cases'; 20 | ReactDOM.render(<Demo data={casesData}/>, mountNode); 21 | ``` -------------------------------------------------------------------------------- /docs/download.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 4 3 | title: 4 | zh-CN: 设计资源 5 | en-US: Download Sketch 6 | --- 7 | 8 | 这里提供以 Ant Design 设计规范完成的相关设计资源,更多设计资源正在整理和完善中。 9 | 10 | ```__react 11 | const downloadData = [ 12 | { title: '基础模板', content: '百搭型产品 Landing 模板,拼搭自已的专属产品 Landing Page', name: 'basic', url: 'https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Landing.Template.sketch', img: 'https://gw.alipayobjects.com/mdn/rms_ae7ad9/afts/img/A*an5vQIKuBLgAAAAAAAAAAABkARQnAQ' }, 13 | { title: 'Ant Design Home 3.0', content: 'Ant Design 首页的源文件', name: 'antd', url: 'https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.home-3.0.sketch', img: 'https://gw.alipayobjects.com/zos/rmsportal/JhuPtNExKmpFjYKxBSZg.jpg' }, 14 | { title: 'Ant Design Landing', content: 'Ant Design Landing 首页的源文件', name: 'landing', url: 'https://github.com/ant-design/ant-design/releases/download/resource/Ant.Design.Landings.home.noImg.sketch', img: 'https://gw.alipayobjects.com/mdn/rms_ae7ad9/afts/img/A*Ke86RZXx9SkAAAAAAAAAAABjARQnAQ' }, 15 | ]; 16 | 17 | import React from 'react'; 18 | import Demo from '../site/theme/template/Other/Download'; 19 | ReactDOM.render(<Demo data={downloadData}/>, mountNode); 20 | ``` -------------------------------------------------------------------------------- /docs/edit/video.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | category: 4 | zh-CN: 编辑器教程 5 | en-US: Edit-help 6 | title: 7 | zh-CN: 视频教程 8 | en-US: Video help 9 | --- 10 | 11 | ```__react 12 | import React from 'react'; 13 | function Demo(){ 14 | return ( 15 | <div style={{ padding: '16px', background: '#f2f4f5', }}> 16 | <video controls width="100%" style={{ display: 'block' }} src="https://gw.alipayobjects.com/os/rmsportal/SarwPFyWpqKjipcHkZFI.mp4" /> 17 | </div> 18 | ) 19 | } 20 | ReactDOM.render(<Demo />, mountNode); 21 | ``` -------------------------------------------------------------------------------- /docs/guide/banner.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | category: 4 | zh-CN: 设计指引 5 | en-US: Guide 6 | title: 7 | zh-CN: Banner 首屏 8 | en-US: Banner 9 | --- 10 | 11 | Banner 是整个展示页面最重要的组成部分之一,一般介绍产品的名称和简介,并且体现整体产品的风格走向。 12 | 13 | 高度为 750px 为例: Banner 一屏的设计尺寸为 1200\*750px,半屏的设计尺寸为 1200\*375px(多用于技术类的产品),主要由单屏和多屏滚动两种类型: 14 | 15 | ## 单屏布局一 16 | 17 | <img class="preview-img" align="right" alt="单屏布局一" description="" src="https://gw.alipayobjects.com/zos/rmsportal/doqiWMyWYcCPFBMrXJLn.jpg"> 18 | 19 | 1)全屏背景图; 20 | 21 | 2)标题、文案和按钮与页面居中对齐; 22 | 23 | ## 单屏布局二 24 | 25 | <img class="preview-img" align="right" alt="单屏布局二" description="" src="https://gw.alipayobjects.com/zos/rmsportal/JOxMWSQxCWoKakcYZWcI.jpg"> 26 | 27 | 1)主图在页面左侧,标题、文案和按钮在页面右侧; 28 | 29 | 2)建议文案和button部分左对齐; 30 | 31 | ## 单屏布局三 32 | 33 | <img class="preview-img" align="right" alt="单屏布局三" description="" src="https://gw.alipayobjects.com/zos/rmsportal/ZGjSLLsUrJFbFVrUxaft.jpg"> 34 | 35 | 1)主图在页面右侧,标题、文案和按钮在页面左侧; 36 | 37 | 2)建议文案和button部分左对齐; 38 | 39 | ## 单屏布局四 40 | 41 | <img class="preview-img" align="right" alt="单屏布局四" description="" src="https://gw.alipayobjects.com/zos/rmsportal/YEneEHFzGvSNtGSFJALF.jpg"> 42 | 43 | 1)主图在页面下方; 44 | 45 | 2)标题、文案和button与页面居中对齐; 46 | 47 | ## 多屏滚动类 48 | 49 | <img class="preview-img" align="right" alt="多屏滚动类" description="" src="https://gw.alipayobjects.com/zos/rmsportal/rtlntsHdPmorumOLIHVY.jpg"> 50 | 51 | 1)多屏Headers组合,底部有走马灯滚动轮播; 52 | 53 | 2)建议滚动屏不超过5个; 54 | 55 | 56 | ## 半屏类型 57 | 58 | <img class="preview-img" align="right" alt="半屏类型" description="" src="https://gw.alipayobjects.com/zos/rmsportal/ItuPxLqTgqgEhMaxexvp.jpg"> 59 | 60 | 1)半屏的设计尺寸为1200*375px; 61 | 62 | 2)排版方式和类别与整屏的相同(在此列举其中一种); -------------------------------------------------------------------------------- /docs/guide/content.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 4 3 | category: 4 | zh-CN: 设计指引 5 | en-US: Guide 6 | title: 7 | zh-CN: 内容区块 8 | en-US: Content 9 | --- 10 | 11 | 内容页一般用来介绍产品的功能、特性以及相关信息。展示型页面中可选择添加内容页(或多个内容页组合),也可以选择不添加。 12 | 每一屏的最小设计尺寸为 1200*375px,可以自由灵活的选择多种模板进行拼接。 13 | 14 | > 我们将分点阐述、合作伙伴/客户、价格表、团队展示、联系我们等合称为内容区块。 15 | 16 | 17 | ## 全屏式 18 | 19 | <img class="preview-img" align="right" alt="全屏式" description="" src="https://gw.alipayobjects.com/zos/rmsportal/gixQJkEyeexiuExLyvFW.jpg"> 20 | 21 | 1)全屏背景图; 22 | 23 | 2)标题、文案和按钮与页面居中对齐; 24 | 25 | ## 两栏式1 26 | 27 | <img class="preview-img" align="right" alt="两栏式1" description="" src="https://gw.alipayobjects.com/zos/rmsportal/YNEYwjpXrQAXfTFjVoBE.png"> 28 | 29 | 1)主介绍图在页面左侧,标题文案在页面右侧; 30 | 31 | 2)标题和文案内容左对齐 32 | 33 | ## 两栏式2 34 | 35 | <img class="preview-img" align="right" alt="两栏式2" description="" src="https://gw.alipayobjects.com/zos/rmsportal/pKbGyGLZKkyKlIDylGLL.png"> 36 | 37 | 1)主介绍图在页面右侧,标题文案在页面左侧; 38 | 39 | 2)标题和文案内容左对齐; 40 | 41 | ## 单行多栏式 42 | 43 | <img class="preview-img" align="right" alt="单行多栏式" description="" src="https://gw.alipayobjects.com/zos/rmsportal/zwHaRpBbcrtKJmRCBBho.png"> 44 | 45 | 1)内容区块按栅格均分; 46 | 47 | 2)一行可放置3~4个并列区块(建议不超过4个); 48 | 49 | ## 双行多栏式1 50 | 51 | <img class="preview-img" align="right" alt="双行多栏式1" description="" src="https://gw.alipayobjects.com/zos/rmsportal/AaQRpekusPmFNjxigIwJ.png"> 52 | 53 | 1)内容区块按栅格均分; 54 | 55 | 2)一行可放置2~3个并列区块(建议不超过3个); 56 | 57 | ## 双行多栏式2 58 | 59 | <img class="preview-img" align="right" alt="双行多栏式2" description="" src="https://gw.alipayobjects.com/zos/rmsportal/ViVQULPluvShAolReqME.png"> 60 | 61 | 1)内容区块按栅格均分; 62 | 63 | 2)一行可放置3~5个并列内容区(建议不超过5个); 64 | 65 | 66 | ## 半屏设计模板 67 | 68 | <img class="preview-img" align="right" alt="半屏设计模板" description="" src="https://gw.alipayobjects.com/zos/rmsportal/yWBvgWQNtuTBDjcalEJe.png"> 69 | 70 | 1)半屏的设计尺寸为 1200*375px; 71 | 72 | 2)排版方式和类别与整屏的相同(再次列举其中两种)); 73 | 74 | <img class="preview-img" align="right" alt="半屏设计模板" description="" src="https://gw.alipayobjects.com/zos/rmsportal/NKvJFXcmOrGkIMSJHZJk.png"> -------------------------------------------------------------------------------- /docs/guide/examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 5 3 | category: 4 | zh-CN: 设计指引 5 | en-US: Guide 6 | title: 7 | zh-CN: 组合示例 8 | en-US: Examples 9 | --- 10 | 11 | ## 示例 12 | 13 | 我们将以上模板整合出三个模板,以供参考: 14 | 15 | <div class="examples-wrapper"> 16 | <div class="examples-img"> 17 | <img width="100%" src="https://gw.alipayobjects.com/zos/rmsportal/aniQEcLzAFArUbkPYkyQ.png"> 18 | <p>示例1</p> 19 | </div> 20 | <div class="examples-img"> 21 | <img width="100%" src="https://gw.alipayobjects.com/zos/rmsportal/HCsgacmIIXZqvicZJDDZ.png"> 22 | <p>示例2</p> 23 | </div> 24 | <div class="examples-img"> 25 | <img width="100%" src="https://gw.alipayobjects.com/zos/rmsportal/ZrFKiApOqmIjSuYsHrpr.png"> 26 | <p>示例3</p> 27 | </div> 28 | </div> 29 | 30 | <style> 31 | .examples-wrapper{ 32 | width: calc(100% + 48px); 33 | margin-left: -24px; 34 | } 35 | .examples-img { 36 | width: 33%; 37 | display: inline-block; 38 | padding: 0 24px; 39 | vertical-align: top; 40 | } 41 | .examples-img p { 42 | text-align: center; 43 | margin: auto; 44 | } 45 | @media only screen and (max-width: 767.99px) { 46 | .examples-wrapper{ 47 | width: 100%; 48 | margin: auto; 49 | } 50 | .examples-img { 51 | width: 100%; 52 | padding: 0; 53 | margin-bottom: 16px; 54 | } 55 | } 56 | </style> -------------------------------------------------------------------------------- /docs/guide/header-footer.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | category: 4 | zh-CN: 设计指引 5 | en-US: Guide 6 | title: 7 | zh-CN: 页头与页尾 8 | en-US: Header and Footer 9 | --- 10 | 11 | 页头承载的是品牌信息与整个网站的结构信息,明确的告知我们网站里最主要的几块内容。 12 | 13 | 页尾则是一个网站的落款,提供的相关的产品信息、友情链接与版权信息。 14 | 15 | ## 顶部页头导航 16 | 17 | 顶部导航高度为 64px, 主要展示 logo、基本导航内容、用户相关信息。 我们提供了三种示例供调选: 18 | 19 | ### 基本型页头导航 20 | 21 | <img class="preview-img" align="right" alt="基本型页头导航" description="" src="https://gw.alipayobjects.com/zos/rmsportal/mbmfZSnXKIPOUBhfQQIs.png"> 22 | 23 | 由 logo 与基本导航内容组成。 24 | 25 | ### 用户信息页头导航 26 | 27 | <img class="preview-img" align="right" alt="用户信息页头导航" description="" src="https://gw.alipayobjects.com/zos/rmsportal/joIcEcNcOorilRaACobU.png"> 28 | 29 | 如果有登录信息或其它信息需要在导航展现时,我们可以在导航基本内容右侧添加其它信息。 30 | 31 | ### 单 logo 页头 32 | 33 | <img class="preview-img" align="right" alt="单 logo 页头" description="" src="https://gw.alipayobjects.com/zos/rmsportal/arCBcBBCQEgsEGSCsKfs.png"> 34 | 35 | 如果不需要导航时,我们建议将背景设为透明,将 logo 融入首屏里。此处只展示类型。 36 | 37 | ## 页脚 38 | 39 | Footer(页脚)作为展示页中也非常重要的一部分,在页面的最底部,包含的信息内容为:实用导航,语言选择,社交链接,帮助和支持,版权和隐私声明等。 40 | 41 | ### 单版权信息 42 | 43 | <img class="preview-img" align="right" alt="单版权信息" description="" src="https://gw.alipayobjects.com/zos/rmsportal/SMzRpciAJCazFxVEazLO.png"> 44 | 45 | 页尾不需要任何信息内容时。 46 | 47 | ### 内容较少 48 | 49 | <img class="preview-img" align="right" alt="内容较少" description="" src="https://gw.alipayobjects.com/zos/rmsportal/pjXwqSImebEPYqQrXnBH.png"> 50 | 51 | 页尾内容比较少时。 52 | 53 | 54 | ### 内容较多 55 | 56 | <img class="preview-img" align="right" alt="内容较多" description="" src="https://gw.alipayobjects.com/zos/rmsportal/YyhadUOedrCfjGRCmfqP.png"> 57 | 58 | 页尾内容比较多时。 -------------------------------------------------------------------------------- /docs/guide/layout.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | category: 4 | zh-CN: 设计指引 5 | en-US: Guide 6 | title: 7 | zh-CN: 布局 8 | en-US: Layout 9 | --- 10 | 11 | Ant Design 目前提供了两套布局方案: [Layout](https://ant.design/components/layout-cn/) 和 [Grid](https://ant.design/components/grid-cn/), 同样 Landing 的整体布局也是以 8 的倍数来计算。我们以页面宽度来做整体布局,提供以下两种类型: 12 | 13 | --- 14 | 15 | ## 百分比类型 16 | 17 | <img class="preview-img" align="right" alt="100% 类型示例" description="两边的距离为 4%" src="https://gw.alipayobjects.com/zos/rmsportal/krTDyBweacvtOdScbhVq.jpg"> 18 | 19 | 100% 类型,内容的宽度为 92%, 左右边距为 4%; 20 | 21 | 需要注意: 在 banner 使用百分比类型布局后,导航必需也使用百分比类型; 22 | 23 | 24 | --- 25 | 26 | ## 像素类型 27 | 28 | <img class="preview-img" align="right" alt="像素类型示例" description="两边的距离为 24px" src="https://gw.alipayobjects.com/zos/rmsportal/bWJWBtBklmyOlISZyOFi.jpg"> 29 | 30 | 以 1152px 为最大宽度为例,为在响应式方面保证更好的预览效果,我们在最大宽度外面增加了 24px 的边距, 避免屏幕尺寸在低于 1152px 的时候内容贴边, 于是需要将内容区域的最大宽度改为 1200px,再增加 24px 的内边距 `padding: 0 24px`。 31 | -------------------------------------------------------------------------------- /docs/guide/type.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | category: 4 | zh-CN: 设计指引 5 | en-US: Guide 6 | title: 7 | zh-CN: 类型 8 | en-US: Type 9 | --- 10 | 11 | 展示类页面(Display Page)一般是指当用户进入某个网站时浏览到的第一个页面,也可以当作着陆页(Landing Page)来吸引用户的注意。在此,我们归纳整理了几种最常见的展示类模板,可以用于灵活的搭配组合。 12 | 13 | 我们对 Landing Page 做了以下两种类型: 14 | 15 | --- 16 | 17 | ## 分步浏览 18 | 19 | <img class="preview-img" align="right" alt="分步浏览示例" description="包含:USP (产品 logo,名称,slogan ),CTA(登录/注册栏,行动按钮),导航,分点阐述,客户展示,页尾。" src="https://gw.alipayobjects.com/zos/rmsportal/VVtazyoxkkGjvjySprqS.png"> 20 | 21 | 分步浏览展示产品的主要信息,通过精彩的视觉,动效,使用户增加产品认知,提升使用兴趣,提供试用机制,进而达到转化目的 22 | 适用产品范围较广。 23 | 24 | 规范: 25 | 26 | 1. 分点阐述:数量不宜过多,建议3-5条。 27 | 28 | 2. CTA:此为转化的重要环节,一定要做的显著,且随时随地都可触达且明确告知用户付出与收获。 29 | 30 | 3. 客户证言:用真实信息,建议有真实个人或公司照片。如非有名客户,建议具体说明帮他解决的问题和使用体验。 31 | 32 | --- 33 | 34 | ## 邀请注册 35 | 36 | <img class="preview-img" align="right" alt="邀请注册示例" description="USP (产品 logo,名称,slogan ),媒体展示,CTA(登录/注册栏),导航,页尾。。" src="https://gw.alipayobjects.com/zos/rmsportal/QAdOyxYZJCCQFazUXhus.jpg"> 37 | 38 | 一屏之内展示出产品卖点或价值主张,突出显示 CTA。主要目的在于快速留住游客,是指直接转化为使用者。 39 | 40 | 常用于功能较为单一,属于社交型、服务型等需要获取用户信息,建立用户联系的产品。 41 | 42 | 规范: 43 | 44 | 1. USP:一句话阐述核心竞争力,字体较大,不宜过长,力求简单好记。 45 | 46 | 2. 媒体展示:与 USP 内容相关。如用视频,长度建议1~3分钟。 47 | 48 | 3. CTA 登录/注册:尽量优化注册流程,或提供第三方社交账号登录。 49 | 50 | 4. 不建议在注册前就为用户提供较多的价值和内容。 -------------------------------------------------------------------------------- /docs/introduce.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 介绍 5 | en-US: Introduce 6 | --- 7 | 8 | 9 | 10 | <div class="file-logo"> 11 | <div class="ant-logo"> 12 | <img src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" height="100%"/> 13 | </div> 14 | <span>+</span> 15 | <div class="landing-logo"> 16 | <img src="https://gw.alipayobjects.com/zos/rmsportal/SVDdpZEbAlWBFuRGIIIL.svg" height="100%"> 17 | </div> 18 | </div> 19 | 20 | Ant Design Landing 是针对产品首页的解决方案,我们秉承 [Ant Design](https://ant.design) 的 [设计价值观](https://ant.design/docs/spec/introduce-cn),延用 [Ant Design](https://ant.design) 的 [设计原则](http://ant.design/docs/spec/proximity-cn),可以快速搭建出你想要的首页,进一步提升你的工作效率。随着『设计者』的不断反馈,我们将持续迭代,逐步沉淀和总结出更多首页模块的代码实现,阐述首页(Landing page)的最佳实践,也十分期待你的参与和共建。 21 | 22 | ## 作用 23 | 24 | - 激发用户的探索兴趣,继续深入访问。 25 | - 引导用户直接购买产品或服务。 26 | - 用户通过提供个人信息或注册来交换一些试用与服务。 27 | - 让用户分享、评论或产生其它一些互动。 28 | 29 | ## 构成元素 30 | 31 | - 全局导航 32 | - 首屏阐述 Banner: 33 | > - USP(unique selling proposition) 产品卖点或价值主张: 产品 logo,名称,slogan, 媒体展示(背景,图片,视频)。 34 | > - CTA(Call-To-Action): 行动按钮,登录/ 注册。 35 | - 分点阐述: 36 | > - 产品特色/优势。 37 | > - 使用方法 + 核心功能 + 解决方案 38 | - 合作伙伴/客户: 成功案例,客户展示,客户证言。 39 | - 价格表 40 | - 团队展示 41 | - 联系我们 42 | - 全局页脚 43 | 44 | ### 动效 45 | 46 | 延用 [Ant Motion](https://motion.ant.design) 动画组件与规范,提供基本的动画组件与 banner 切换效果,以 `scroll-anim` 组件为基本动画框架,随滚动来完成页面的进出场效果。 47 | 48 | - [单元素动效执行组件](https://motion.ant.design/components/tween-one) 49 | - [样式进出场组件](https://motion.ant.design/components/animate) 50 | - [队列进出场组件](https://motion.ant.design/components/queue-anim) 51 | - [文字动效组件](https://motion.ant.design/components/texty) 52 | - [随滚动执行效果组件](https://motion.ant.design/components/scroll-anim) 53 | - [Banner 切换效果组件](https://motion.ant.design/components/banner-anim) 54 | 55 | ## 设计资源 56 | 57 | 我们提供完善的设计规范、最佳实践和设计资源文件 Sketch,来帮助业务快速设计出高质量的产品原型。 58 | 59 | 60 | ## 谁在使用 61 | 62 | 目前 Ant Design 旗下产品全部使用 Landing 搭建,如果你和你的组织使用了这个产品,欢迎到 Ant Design Landing Users 留言。 63 | 64 | 65 | ### For 设计者 66 | 67 | 如果你是产品或设计师,你可以找到相关模板或各模块的 Sketch 设计资源,大幅度提升设计效率和沟通效率。 68 | 69 | ### For 开发者 70 | 71 | 如果你是工程师,只需将你下载的以『Home』为名的文件包替换掉你的项目里的首页即可,具体介绍请查看 [使用文档](/docs/use/getting-started)。 72 | 73 | 74 | ## 如何贡献 75 | 76 | 我们欢迎任何形式的贡献,有任何建议或意见,请给我们 [提问]()。 77 | -------------------------------------------------------------------------------- /docs/use/dumi.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | category: 4 | zh-CN: 使用教程 5 | en-US: Tutorial 6 | title: 7 | zh-CN: dumi 里使用 8 | en-US: Use in dumi 9 | --- 10 | 11 | [dumi](https://d.umijs.org/) 基于 [Umi](https://umijs.org/)、为组件开发场景而生的文档工具 12 | 13 | 使用 demo 地址请查看 [dumi-example](https://github.com/ant-motion/landing-dumi-example); 14 | 15 | ## 文件路径 16 | 17 | 我们首先初始化一个站点模式的组件库开发脚手架, 如果没装安 dumi 的,请先查看 dumi 的[轻松上手](https://d.umijs.org/#%E8%BD%BB%E6%9D%BE%E4%B8%8A%E6%89%8B) 18 | ``` 19 | $ npx @umijs/create-dumi-lib --site 20 | ``` 21 | 安装完后,再将 Home 复制到 docs 里,我们的文件目录为: 22 | 23 | ``` 24 | │── docs 25 | + │── Home 26 | | └── index.md 27 | │── src 28 | │ │── Foo 29 | │ │── index.ts 30 | │ └── ... 31 | │── package.json 32 | │── ... 33 | ``` 34 | 35 | ## 安装依赖 36 | 37 | 安装 dumi 里的依赖: `npm install`; 38 | 39 | 我们组件的依赖详细参考[开始使用里的安装依赖](docs/use/getting-started#安装依赖); 40 | 41 | ## 修改首页 42 | 43 | 更改 index.md, 删掉全部内容,增加 gapless: true, 再在下面添加 code, 最后的 index.md 如下: 44 | 45 | ``` 46 | --- 47 | gapless: true 48 | --- 49 | 50 | <code src="./Home/index.jsx" inline /> 51 | ``` 52 | ## 删除 Home 里的 md 文件 53 | 54 | 将 documentation.md 从文件包里删除; 55 | 56 | ## 完成 57 | 58 | 完成以上步骤之后,我们再启动 `npm start` 即可查看在 landing 上下载的模板。 59 | -------------------------------------------------------------------------------- /docs/use/dva-cli.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | category: 4 | zh-CN: 使用教程 5 | en-US: Tutorial 6 | title: 7 | zh-CN: dva-cli 里使用 8 | en-US: Use in dva 9 | --- 10 | [dva](https://github.com/dvajs/dva) 脚手架为 ant design 提供的基于 redux、redux-saga 和 react-router 比较完善的轻量级前端框架,具体教程[请查看](https://github.com/sorrycc/blog/issues/18)。 11 | 12 | 如何使用 demo 地址请查看 [dva-cli-example](https://github.com/ant-motion/ant-motion-dva-cli-example); 13 | 14 | 基本配置请查看 [开始使用](docs/use/getting-started); 15 | 16 | ## 文件路径 17 | 18 | [dva-cli](https://github.com/dvajs/dva-cli) 脚手架的文件目录为 `src/routes`, 首先我们需要将下载的 Home 文件包直接复制到 routes 文件夹下。 19 | 20 | ## 修改路由 21 | 22 | 复制完成后,我们需要将主页入口修改成以上复制的文件目录。 23 | 24 | ```jsx 25 | import IndexPage from './routes/Home'; 26 | ``` 27 | 28 | ## CSS Modules 29 | 30 | dva 默认使用了 `css-modules`,同样我们提供了两套解决方案。 31 | 32 | ### 关闭 css-modules 33 | 34 | 如果你当前项目为新项目,且对 `css-modules` 并不是太了解,可以选择关闭 `css-modules`,只需要在 `.roadhogrc` 文件里加上 `"disableCSSModules": true` 即可。 35 | ```json 36 | { 37 | "entry": "src/index.js", 38 | + "disableCSSModules": true, // 加在此处 39 | "env": { 40 | "development": { 41 | "extraBabelPlugins": [ 42 | "dva-hmr", 43 | "transform-runtime" 44 | ] 45 | }, 46 | "production": { 47 | "extraBabelPlugins": [ 48 | "transform-runtime" 49 | ] 50 | } 51 | }, 52 | } 53 | ``` 54 | 55 | ### 使用 global 56 | 57 | 使用 `css-modules` 的 `global`, 在 `index.less` 里添加 `:global`, 将样式不作转换, `global` 具体使用[请查看开始使用](/docs/use/getting-started#样式)。 58 | 59 | 60 | ## 按需加载 61 | 62 | dva 里使用 `babel-plugin-import` 我们只需要 `.roadhogrc` 文件里添加 `["import", { "libraryName": "antd", "style": true }]` 即可。 63 | 64 | ```json 65 | 66 | { 67 | "entry": "src/index.js", 68 | "env": { 69 | "development": { 70 | "extraBabelPlugins": [ 71 | "dva-hmr", 72 | "transform-runtime", 73 | ["import", { "libraryName": "antd", "style": true }] 74 | ] 75 | }, 76 | "production": { 77 | "extraBabelPlugins": [ 78 | "transform-runtime", 79 | ["import", { "libraryName": "antd", "style": true }] 80 | ] 81 | } 82 | }, 83 | } 84 | ``` 85 | 86 | ## 完成 87 | 88 | 完成以上频骤之后,我们再启动 `npm start` 即可查看在 landing 上下载的模板。 -------------------------------------------------------------------------------- /docs/use/pro.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 4 3 | category: 4 | zh-CN: 使用教程 5 | en-US: Tutorial 6 | title: 7 | zh-CN: pro 里使用 8 | en-US: Use in pro 9 | --- 10 | 11 | [Ant Design pro](https://pro.ant.design) 是 Ant Design 推出的一个开箱即用的中台前端/设计解决方案。 12 | 13 | ## 文件路径 14 | 15 | [Ant Design pro v2.x](https://pro.ant.design) 使用的为 umi 脚手架,文件目录同样为 `src/pages`, 首先我们需要将下载的 Home 文件包直接复制到 `pages` 文件夹下。 16 | 17 | ## 修改路由 18 | 19 | 文件目录: `config/router.config.js`; 20 | 21 | 修改 `dashboard` 的路由, 增加 `Home` 路由; 22 | 23 | ```js 24 | export default [ 25 | + { path: '/', component: './Home' }, // 增加 Home 路由 26 | // user 27 | { 28 | path: '/user', 29 | ... 30 | }, 31 | // app 32 | { 33 | - path: '/', 34 | + path: '/dashboard', // 更改 dashboard 路由; 35 | component: '../layouts/BasicLayout', 36 | Routes: ['src/pages/Authorized'], 37 | authority: ['admin', 'user'], 38 | ... 39 | }, 40 | ]; 41 | ``` 42 | 43 | ## 安装依赖 44 | 45 | 详细参考[开始使用里的安装依赖](docs/use/getting-started#安装依赖); 46 | 47 | ## CSS Modules 48 | 49 | 多方案请查看 [umi 里使用的 css module](/docs/use/umi#CSS-Modules); 50 | 51 | 这里推荐使用 css-module 的 global; 52 | 53 | antMotionStyle.less 如下 54 | 55 | ``` 56 | :global { 57 | @import './common.less'; 58 | @import './custom.less'; 59 | @import './content.less'; 60 | @import './nav0.less'; 61 | @import './banner0.less'; 62 | ... 63 | } 64 | ``` 65 | 66 | ## 暂时先删除换肤插件 67 | 68 | 由于换肤插件需要重新 build 全部的 less, 暂时不支持 landing 的 less,所以我们先暂时删除换肤插件。 69 | 70 | 文件目录:`config/config.js`; 71 | 72 | 删除 `webpackPlugin` 相关的代码: 73 | ```jsx 74 | // https://umijs.org/config/ 75 | import os from 'os'; 76 | import pageRoutes from './router.config'; 77 | - import webpackPlugin from './plugin.config'; 78 | import defaultSettings from '../src/defaultSettings'; 79 | 80 | ... 81 | 82 | export default { 83 | // add for transfer to umi 84 | ... 85 | manifest: { 86 | basePath: '/', 87 | }, 88 | 89 | - chainWebpack: webpackPlugin, 90 | }; 91 | 92 | ``` -------------------------------------------------------------------------------- /documentation.md: -------------------------------------------------------------------------------- 1 | # 如何使用: 2 | 3 | - umi 里如何使用[请查看](https://landing.ant.design/docs/use/umi)。 4 | - 其它脚手架使用[请查看](https://landing.ant.design/docs/use/getting-started)。 5 | -------------------------------------------------------------------------------- /index.text: -------------------------------------------------------------------------------- 1 | /* eslint no-undef: 0 */ 2 | /* eslint arrow-parens: 0 */ 3 | import React from 'react'; 4 | import { enquireScreen } from 'enquire-js'; 5 | &scrollAnim& 6 | &import& 7 | &dataSource& 8 | import './less/antMotionStyle.less'; 9 | 10 | let isMobile; 11 | enquireScreen((b) => { 12 | isMobile = b; 13 | }); 14 | 15 | const { location = {} } = typeof window !== 'undefined' ? window : {}; 16 | 17 | export default class Home extends React.Component { 18 | constructor(props) { 19 | super(props); 20 | this.state = { 21 | isMobile, 22 | show: !location.port,// 如果不是 dva 2.0 请删除 23 | }; 24 | } 25 | 26 | componentDidMount() { 27 | &scrollScreen-pragma& 28 | // 适配手机屏幕; 29 | enquireScreen((b) => { 30 | this.setState({ isMobile: !!b }); 31 | }); 32 | // dva 2.0 样式在组件渲染之后动态加载,导致滚动组件不生效;线上不影响; 33 | /* 如果不是 dva 2.0 请删除 start */ 34 | if (location.port) { 35 | // 样式 build 时间在 200-300ms 之间; 36 | setTimeout(() => { 37 | this.setState({ 38 | show: true, 39 | }); 40 | &scrollScreen& 41 | }, 500); 42 | } 43 | /* 如果不是 dva 2.0 请删除 end */ 44 | } 45 | 46 | render() { 47 | &children& 48 | return ( 49 | <div className="templates-wrapper" ref={(d) => { this.dom = d; }}> 50 | {/* 如果不是 dva 2.0 替换成 {children} start */} 51 | {this.state.show && children} 52 | {/* 如果不是 dva 2.0 替换成 {children} end */} 53 | </div> 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /prettier/install-service-worker.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* eslint-env browser */ 4 | 5 | if ('serviceWorker' in navigator) { 6 | navigator.serviceWorker.register('/service-worker.js', { 7 | scope: '/edit/', 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /prettier/service-worker.js: -------------------------------------------------------------------------------- 1 | /* eslint-env serviceworker */ 2 | /* global toolbox */ 3 | 4 | 5 | importScripts('lib/sw-toolbox.js'); 6 | 7 | toolbox.precache([ 8 | // Scripts 9 | 'lib/index.js', 10 | 'lib/parser-babylon.js', 11 | 'lib/parser-postcss.js', 12 | 'lib/parser-flow.js', 13 | 'lib/parser-glimmer.js', 14 | 'lib/parser-graphql.js', 15 | 'lib/sw-toolbox.js', 16 | ]); 17 | 18 | // Default to hit the cache only if there's a network error 19 | toolbox.router.default = toolbox.networkFirst; 20 | 21 | // For scripts, stylesheets and images, we can use the "fastest" strategy 22 | // This means you need to reload twice to get new changes 23 | toolbox.router.get(/\.(js|css|png|svg)$/, toolbox.fastest); 24 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /site/bisheng.edit.config.js: -------------------------------------------------------------------------------- 1 | const commonConfig = require('./bisheng.common.config'); 2 | 3 | module.exports = { source: {}, 4 | output: './_site/edit', 5 | root: '/edit/', 6 | entryName: 'edit', 7 | theme: './site/edit', 8 | htmlTemplate: './site/edit/static/index.html', 9 | port: 7112, 10 | themeConfig: { 11 | }, 12 | ...commonConfig }; 13 | -------------------------------------------------------------------------------- /site/bisheng.index.config.js: -------------------------------------------------------------------------------- 1 | const commonConfig = require('./bisheng.common.config'); 2 | 3 | module.exports = { port: 7111, 4 | root: '/', 5 | source: { 6 | docs: './docs', 7 | }, 8 | theme: './site/theme', 9 | htmlTemplate: './site/theme/static/template.html', 10 | themeConfig: { 11 | root: '/', 12 | categoryOrder: { 13 | 介绍: 0, 14 | 设计指引: 1, 15 | 编辑器教程: 2, 16 | 使用教程: 3, 17 | 实践案例: 4, 18 | 设计资源: 5, 19 | Introduce: 0, 20 | Guide: 1, 21 | 'Edit-help': 2, 22 | Tutorial: 3, 23 | }, 24 | }, 25 | ...commonConfig }; 26 | -------------------------------------------------------------------------------- /site/bisheng.templates.config.js: -------------------------------------------------------------------------------- 1 | const commonConfig = require('./bisheng.common.config'); 2 | 3 | module.exports = { source: {}, 4 | output: './_site/templates', 5 | root: '/templates/', 6 | entryName: 'templates', 7 | theme: './site/templates', 8 | htmlTemplate: './site/templates/static/index.html', 9 | port: 7113, 10 | themeConfig: { 11 | }, 12 | ...commonConfig }; 13 | -------------------------------------------------------------------------------- /site/edit/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | routes: 3 | { 4 | path: '/', 5 | component: './template/index', 6 | childRoutes: [ 7 | { 8 | path: 'index-cn', 9 | component: './template/index', 10 | }, 11 | ], 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /site/edit/static/banner-slide.less: -------------------------------------------------------------------------------- 1 | .banner-slide { 2 | background: fade(@primary-color, 55); 3 | border-radius: 4px 4px 0 0; 4 | overflow: hidden; 5 | display: inline-block; 6 | padding: 4px 8px 0; 7 | &-wrapper { 8 | position: absolute; 9 | bottom: 0; 10 | display: flex; 11 | width: 100%; 12 | justify-content: center; 13 | cursor: auto; 14 | opacity: 0; 15 | } 16 | .ant-pagination { 17 | display: inline-block; 18 | margin-right: 8px; 19 | } 20 | & .ant-pagination.mini .ant-pagination-item-link { 21 | border-radius: 100%; 22 | background: @primary-color; 23 | color: @edit-text-color; 24 | &:hover, 25 | &:focus { 26 | background: #597ef7; 27 | } 28 | &:active { 29 | background: #1d39c4; 30 | } 31 | } 32 | .ant-pagination-disabled a { 33 | background: rgb(218, 218, 218) !important; 34 | color: rgba(0, 0, 0, 0.25) !important; 35 | } 36 | .ant-pagination .ant-pagination-simple-pager { 37 | color: @edit-text-color; 38 | margin: 0 8px; 39 | input { 40 | background: transparent; 41 | padding: 0; 42 | margin: 0; 43 | &:hover { 44 | border-color: @edit-text-color; 45 | } 46 | } 47 | .ant-pagination-slash { 48 | margin: 0 5px; 49 | } 50 | } 51 | .ant-btn { 52 | vertical-align: top; 53 | } 54 | } 55 | 56 | .manage-wrapper { 57 | width: 300px; 58 | .ant-popover-inner-content { 59 | padding: 12px 0; 60 | position: relative; 61 | } 62 | .manage-button { 63 | text-align: center; 64 | margin: 16px 0; 65 | } 66 | } 67 | 68 | .list-drag-selected { 69 | box-shadow: 0 6px 10px rgba(0, 0, 0, 0.25); 70 | transform: scale(1.1) !important; 71 | } 72 | -------------------------------------------------------------------------------- /site/edit/static/common.less: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | background: #fff; 4 | color: @edit-text-color; 5 | } 6 | 7 | body, 8 | div, 9 | dl, 10 | dt, 11 | dd, 12 | ul, 13 | ol, 14 | li, 15 | h1, 16 | h2, 17 | h3, 18 | h4, 19 | h5, 20 | h6 { 21 | margin: 0; 22 | padding: 0; 23 | } 24 | 25 | .gu-mirror { 26 | position: fixed !important; 27 | margin: 0 !important; 28 | z-index: 9999 !important; 29 | opacity: 0.8; 30 | background: fade(@primary-color, 70); 31 | pointer-events: none; 32 | 33 | >div, 34 | >p { 35 | display: none; 36 | } 37 | 38 | >.img { 39 | display: block; 40 | } 41 | 42 | &.img-wrapper { 43 | background: none; 44 | } 45 | } 46 | 47 | .gu-hide { 48 | display: none !important; 49 | } 50 | 51 | .gu-unselectable { 52 | -webkit-user-select: none !important; 53 | -moz-user-select: none !important; 54 | -ms-user-select: none !important; 55 | user-select: none !important; 56 | } 57 | 58 | .gu-transit { 59 | background: fade(@primary-color, 35); 60 | 61 | >p { 62 | display: none; 63 | } 64 | } 65 | 66 | .placeholder { 67 | background: @primary-color; 68 | text-align: center; 69 | color: @edit-text-color; 70 | font-size: 12px; 71 | line-height: 32px; 72 | position: absolute; 73 | width: 100%; 74 | } 75 | 76 | .modal-form { 77 | .ant-form-item { 78 | margin-bottom: 0; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /site/edit/static/content.less: -------------------------------------------------------------------------------- 1 | .edit { 2 | &-content-wrapper { 3 | height: ~"calc(100% - 64px)"; 4 | position: relative; 5 | } 6 | &-stage-wrapper { 7 | display: inline-block; 8 | width: ~"calc(100% - 40px)"; 9 | height: 100%; 10 | position: absolute; 11 | margin-left: 40px; 12 | left: 0; 13 | top: 0; 14 | .edit-preview { 15 | width: 100%; 16 | height: ~"calc(100% - 16px)"; 17 | max-height: 100%; 18 | border: 0; 19 | overflow: hidden; 20 | display: block; 21 | margin: auto; 22 | position: absolute; 23 | left: 0; 24 | right: 0; 25 | top: 16px; 26 | bottom: 0; 27 | transition: width .15s @ease-in-out, max-height .15s @ease-in-out, top .15s @ease-in-out; 28 | &.mobile { 29 | box-shadow: 0 0 0 1px #000; 30 | } 31 | } 32 | .mobile { 33 | width: 375px; 34 | max-height: 667px; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /site/edit/static/custom.less: -------------------------------------------------------------------------------- 1 | @edit-text-color: #fff; 2 | @edit-list-text-color: fade(#fff, 55); 3 | 4 | @edit-bg-color: #262626; 5 | @edit-line-color: #000; 6 | 7 | @edit-mouse-catcher-hover: #666; 8 | 9 | @edit-login-text-color: #314659; 10 | -------------------------------------------------------------------------------- /site/edit/static/edit-influence.less: -------------------------------------------------------------------------------- 1 | .edit-influence { 2 | height: 16px; 3 | background: black; 4 | >div { 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | height: 100%; 9 | } 10 | .ant-select { 11 | line-height: 16px; 12 | color: @edit-text-color; 13 | &.ant-select-single:not(.ant-select-customize-input) .ant-select-selector { 14 | background: transparent; 15 | border: none; 16 | border-radius: 0; 17 | &:focus { 18 | box-shadow: none; 19 | } 20 | &--single { 21 | height: 16px; 22 | } 23 | &__rendered { 24 | line-height: 16px; 25 | } 26 | &-selected-value { 27 | padding-right: 16px; 28 | span { 29 | font-size: 12px; 30 | } 31 | } 32 | } 33 | &-arrow { 34 | color: fade(@edit-text-color, 55); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /site/edit/static/edit-list/box-model.less: -------------------------------------------------------------------------------- 1 | .@{editorList} { 2 | .ant-collapse { 3 | .box-model-wrapper { 4 | width: 145px; 5 | height: 60px; 6 | margin: 20px auto; 7 | border: 1px solid @edit-list-text-color; 8 | } 9 | .box-model { 10 | position: relative; 11 | height: 100%; 12 | .top, 13 | .right, 14 | .bottom, 15 | .left, 16 | .center, 17 | .top-left, 18 | .top-right, 19 | .bottom-right, 20 | .bottom-left { 21 | position: absolute; 22 | margin: auto; 23 | width: 56px; 24 | height: 22px; 25 | .ant-select-selection { 26 | background: @bgColor; 27 | .ant-input, 28 | .ant-select-selection__placeholder { 29 | text-align: center; 30 | } 31 | } 32 | } 33 | .top { 34 | top: -11px; 35 | left: 0; 36 | right: 0; 37 | .editor-color-picker { 38 | left: -85px; 39 | } 40 | } 41 | .right { 42 | right: -28px; 43 | top: 0; 44 | bottom: 0; 45 | .editor-color-picker { 46 | right: -13px; 47 | left: auto; 48 | } 49 | } 50 | .bottom { 51 | bottom: -11px; 52 | left: 0; 53 | right: 0; 54 | } 55 | .left { 56 | left: -28px; 57 | top: 0; 58 | bottom: 0; 59 | } 60 | .center { 61 | top: 0; 62 | right: 0; 63 | bottom: 0; 64 | left: 0; 65 | } 66 | .top-left { 67 | top: -11px; 68 | left: -28px; 69 | } 70 | .top-right { 71 | top: -11px; 72 | right: -28px; 73 | } 74 | .bottom-left { 75 | bottom: -11px; 76 | left: -28px; 77 | } 78 | .bottom-right { 79 | bottom: -11px; 80 | right: -28px; 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /site/edit/static/edit-list/child.less: -------------------------------------------------------------------------------- 1 | .child-wrapper { 2 | .sort-manage { 3 | height: 32px; 4 | display: flex; 5 | align-items: center; 6 | transition: background .45s @ease-in-out, box-shadow .45s @ease-in-out, transform .45s @ease-in-out; 7 | &:hover { 8 | background: @heiColor; 9 | } 10 | &-delete { 11 | width: 32px; 12 | .ant-btn { 13 | background: transparent; 14 | height: 32px; 15 | width: 32px; 16 | line-height: 32px; 17 | color: rgba(255, 255, 255, 0.55); 18 | border: none; 19 | } 20 | } 21 | &-icon { 22 | width: 32px; 23 | } 24 | &-name { 25 | width: ~"calc(100% - 64px)"; 26 | } 27 | } 28 | .add-type { 29 | border-top: 1px solid @heiColor; 30 | padding-top: 8px; 31 | display: flex; 32 | align-items: center; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /site/edit/static/edit-list/custom.less: -------------------------------------------------------------------------------- 1 | @edit-list-text-color: fade(@edit-text-color, 55); 2 | @edit-list-text-color-hover: @edit-text-color; 3 | @input-line-color: @edit-list-text-color; 4 | @input-line-color-hover: @edit-list-text-color-hover; 5 | 6 | @heiColor: #121212; 7 | @huiColor: #121212; 8 | @bgColor: #262626; 9 | 10 | @editorList: edit-list-tab; 11 | -------------------------------------------------------------------------------- /site/edit/static/edit-list/editor-bg-image.less: -------------------------------------------------------------------------------- 1 | @import "custom"; 2 | 3 | @bgImage: editor-bg-image; 4 | 5 | .@{bgImage} { 6 | &-wrapper { 7 | border-top: 1px solid @heiColor; 8 | padding-top: 8px; 9 | 10 | .add-button { 11 | font-size: 14px !important; 12 | } 13 | } 14 | 15 | &-list { 16 | display: grid; 17 | grid-template-columns: 24px 24px auto 24px; 18 | grid-template-rows: 32px; 19 | gap: 0 4px; 20 | align-items: center; 21 | line-height: 32px; 22 | height: 32px; 23 | 24 | transition: background .3s @ease-in-out; 25 | 26 | &-preview { 27 | grid-column-start: 2; 28 | background-size: cover; 29 | background-position: center; 30 | background-clip: content-box; 31 | width: 24px; 32 | height: 24px; 33 | border: 1px solid fade(#fff, 15); 34 | } 35 | 36 | &-bar { 37 | grid-column-start: 1; 38 | text-align: center; 39 | outline: none; 40 | } 41 | 42 | &-name { 43 | grid-column-start: 3; 44 | text-overflow: ellipsis; 45 | overflow: hidden; 46 | white-space: nowrap; 47 | user-select: none; 48 | color: rgba(255, 255, 255, 0.55); 49 | &:hover { 50 | color: rgba(255, 255, 255, 0.85); 51 | } 52 | } 53 | 54 | &-delete { 55 | grid-column-start: 4; 56 | text-align: center; 57 | cursor: pointer; 58 | } 59 | 60 | &:hover, 61 | &:active { 62 | background-color: fade(@heiColor, 70); 63 | } 64 | } 65 | &-pop { 66 | width: 248px; 67 | padding: 16px; 68 | &-type { 69 | padding-bottom: 8px; 70 | border-bottom: 1px solid @bgColor; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /site/edit/static/edit-list/editor-color.less: -------------------------------------------------------------------------------- 1 | @color: editor-color; 2 | .@{color} { 3 | width: 100%; 4 | height: 22px; 5 | border-radius: 4px; 6 | cursor: pointer; 7 | overflow: hidden; 8 | display: block; 9 | transition: box-shadow .3s, border .3s; 10 | border: 1px solid #a4a7a8; 11 | 12 | i { 13 | width: 100%; 14 | height: 100%; 15 | display: block; 16 | position: relative; 17 | &:after { 18 | content: ''; 19 | display: block; 20 | position: absolute; 21 | width: 0; 22 | height: 0; 23 | border-bottom: 4px solid white; 24 | border-left: 4px solid transparent; 25 | right: 1px; 26 | bottom: 1px; 27 | } 28 | } 29 | &.active { 30 | border-color: @input-line-color-hover; 31 | box-shadow: 0 0 4px @input-line-color-hover; 32 | } 33 | &-wrapper { 34 | &:hover { 35 | .color-close { 36 | opacity: 1; 37 | } 38 | } 39 | .color-close { 40 | position: absolute; 41 | line-height: 12px; 42 | text-align: center; 43 | width: 12px; 44 | height: 12px; 45 | top: -5px; 46 | left: -5px; 47 | border-radius: 100%; 48 | background: #f00; 49 | color: @edit-text-color; 50 | opacity: 0; 51 | cursor: pointer; 52 | transition: opacity .3s @ease-out; 53 | .anticon-close { 54 | font-size: 12px; 55 | transform: scale(.8); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /site/edit/static/edit-list/editor-font.less: -------------------------------------------------------------------------------- 1 | @font: editor-font; 2 | .@{editorList} { 3 | .@{font} { 4 | &-align { 5 | .left, 6 | .center, 7 | .right, 8 | .justify { 9 | width: 16px; 10 | margin: auto; 11 | &:after, 12 | &:before { 13 | background: @edit-list-text-color; 14 | box-shadow: 0 6px 0 @edit-list-text-color; 15 | content: ''; 16 | display: block; 17 | margin: auto; 18 | height: 1px; 19 | } 20 | &:before { 21 | margin-top: 5px; 22 | } 23 | &:after { 24 | margin-top: 2px; 25 | } 26 | } 27 | .left, 28 | .center, 29 | .right { 30 | &:after { 31 | width: 13px; 32 | } 33 | &:before { 34 | width: 100%; 35 | } 36 | } 37 | .left { 38 | &:after { 39 | margin-left: 0; 40 | } 41 | } 42 | .right { 43 | &:after { 44 | margin-right: 0; 45 | } 46 | } 47 | .justify { 48 | &:after, 49 | &:before { 50 | width: 100%; 51 | } 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /site/edit/static/edit-list/editor-gradient.less: -------------------------------------------------------------------------------- 1 | @import "custom"; 2 | @gradient: editor-gradient; 3 | 4 | .@{gradient} { 5 | padding-bottom: 1px; 6 | border-bottom: 1px solid @bgColor; 7 | margin-bottom: 8px; 8 | 9 | &-bar { 10 | height: 16px; 11 | border: 1px solid @bgColor; 12 | cursor: crosshair; 13 | position: relative; 14 | background-repeat: no-repeat; 15 | margin: 16px 0; 16 | 17 | &-item { 18 | position: relative; 19 | height: 100%; 20 | margin-right: 8px; 21 | } 22 | } 23 | 24 | &-point { 25 | box-shadow: @bgColor 0 0 0 1px; 26 | height: 100%; 27 | width: 8px; 28 | position: absolute; 29 | cursor: ew-resize; 30 | transition: shadow .3s; 31 | border-radius: 2px; 32 | background: #eee; 33 | 34 | &.active { 35 | box-shadow: @edit-list-text-color-hover 0 0 0 2px, @bgColor 0 0 0 3px, @bgColor 0 0 0 1px inset; 36 | } 37 | } 38 | 39 | &-repeat { 40 | color: @edit-list-text-color; 41 | 42 | .ant-checkbox +span { 43 | color: @edit-list-text-color; 44 | } 45 | } 46 | 47 | &-color { 48 | .ant-row { 49 | margin-bottom: 0 !important; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /site/edit/static/edit-list/index.less: -------------------------------------------------------------------------------- 1 | 2 | @import "common"; 3 | @import "editor-color"; 4 | @import "collapse"; 5 | @import "editor-font"; 6 | @import "editor-bg-image"; 7 | @import "editor-gradient"; 8 | @import "box-model"; 9 | @import "child"; 10 | 11 | .edit-right-view { 12 | .edit-list-tab { 13 | height: 100%; 14 | text-align: left; 15 | .tab-scroll { 16 | overflow: auto; 17 | height: 100%; 18 | position: relative; 19 | } 20 | &s { 21 | height: 100%; 22 | &.ant-tabs:not(.ant-tabs-vertical) > .ant-tabs-content > .ant-tabs-tabpane-inactive { 23 | height: 100%; 24 | } 25 | .ant-tabs { 26 | &-bar { 27 | height: 64px; 28 | border-color: @edit-line-color; 29 | } 30 | &-content { 31 | height: ~"calc(100% - 80px)"; 32 | } 33 | &-ink-bar { 34 | display: none !important; 35 | } 36 | &-tab { 37 | margin-right: 0; 38 | border-right: 1px solid @edit-line-color; 39 | padding: 0 24px; 40 | line-height: 64px; 41 | font-size: 16px; 42 | color: fade(@edit-text-color, 60); 43 | height: 65px; 44 | transition: color 0.3s @ease-in-out, background .3s @ease-in-out; 45 | &-active { 46 | color: @edit-text-color; 47 | background: @edit-bg-color; 48 | } 49 | &:hover { 50 | color: @edit-text-color; 51 | } 52 | .anticon { 53 | margin: 0; 54 | } 55 | } 56 | } 57 | } 58 | .props-explain { 59 | color: @edit-text-color; 60 | padding: 0 16px; 61 | font-size: 12px; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /site/edit/static/index.less: -------------------------------------------------------------------------------- 1 | // @import '~antd/lib/style/v2-compatible-reset.less'; 2 | @import "~antd/lib/style/themes/default.less"; 3 | @import '~antd/lib/tag/style/index.css'; 4 | @import '~antd/lib/slider/style/index.css'; 5 | @import './common'; 6 | @import './custom'; 7 | @import './login-controller'; 8 | @import './edit-list/index'; 9 | @import './content'; 10 | @import './edit-influence'; 11 | @import './nav-controller'; 12 | @import './side-menu'; 13 | @import './edit-stage'; 14 | @import './banner-slide'; 15 | @import './other-view.less'; 16 | @import './sort.less'; 17 | @import '../../templates/static/point'; 18 | 19 | .edit { 20 | &-wrapper { 21 | width: 100%; 22 | position: relative; 23 | height: 100vh; 24 | background: @edit-bg-color; 25 | overflow: hidden; 26 | /** { 27 | -webkit-user-select: none; 28 | -moz-user-select: none; 29 | -ms-user-select: none; 30 | user-select: none; 31 | } */ 32 | > div { 33 | height: 100%; 34 | float: left; 35 | } 36 | } 37 | &-left-view { 38 | width: ~"calc(100% - 288px)"; 39 | } 40 | &-right-view { 41 | width: 288px; 42 | border-left: 1px solid @edit-line-color; 43 | } 44 | } 45 | p { 46 | margin: 0; 47 | } 48 | -------------------------------------------------------------------------------- /site/edit/static/login-controller.less: -------------------------------------------------------------------------------- 1 | .login-controller { 2 | background: @edit-bg-color; 3 | width: 100%; 4 | height: 100vh; 5 | position: absolute; 6 | top: 0; 7 | left: 0; 8 | color: @edit-login-text-color; 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | .login-view { 13 | width: 360px; 14 | padding: 24px; 15 | background: #fff; 16 | border-radius: 4px; 17 | box-shadow: 0 0 16px rgba(0, 0, 0, 0.35); 18 | .header { 19 | font-size: 46px; 20 | margin: 0 auto 32px; 21 | width: 60px; 22 | height: 60px; 23 | line-height: 60px; 24 | border-radius: 100%; 25 | color: @edit-login-text-color; 26 | background: @primary-color; 27 | text-align: center; 28 | display: flex; 29 | align-items: center; 30 | justify-content: center; 31 | } 32 | p { 33 | margin-bottom: 16px; 34 | } 35 | &.password-no { 36 | animation: antSwingIn .5s linear; 37 | } 38 | } 39 | } 40 | 41 | @keyframes antSwingIn { 42 | 0%, 43 | 100% { 44 | transform: translateX(0); 45 | } 46 | 20% { 47 | transform: translateX(-10px); 48 | } 49 | 40% { 50 | transform: translateX(10px); 51 | } 52 | 60% { 53 | transform: translateX(-5px); 54 | } 55 | 80% { 56 | transform: translateX(5px); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /site/edit/static/other-view.less: -------------------------------------------------------------------------------- 1 | .other { 2 | .ant-radio-button-wrapper { 3 | vertical-align: top; 4 | .point-radio-wrapper { 5 | width: 100%; 6 | height: 100%; 7 | display: flex; 8 | align-items: center; 9 | justify-content: center; 10 | .point { 11 | background: rgba(255, 255, 255, 0.3); 12 | border-color: transparent; 13 | transition: background .3s @ease-out, border .3s @ease-out; 14 | &-stroke { 15 | background: transparent; 16 | border-color: rgba(255, 255, 255, 0.3); 17 | } 18 | } 19 | } 20 | } 21 | .ant-radio-button-wrapper-checked { 22 | .point-radio-wrapper .point { 23 | background: rgba(255, 255, 255, 0.9); 24 | border-color: transparent; 25 | &-stroke { 26 | background: transparent; 27 | border-color: rgba(255, 255, 255, 0.9); 28 | } 29 | } 30 | } 31 | &-demo { 32 | overflow: hidden; 33 | border: 1px solid rgba(255, 255, 255, 0.3); 34 | border-radius: 4px; 35 | video, 36 | img { 37 | display: block; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /site/edit/static/sort.less: -------------------------------------------------------------------------------- 1 | .sort-manage { 2 | height: 48px; 3 | display: flex; 4 | align-items: center; 5 | transition: background .45s @ease-in-out, box-shadow .45s @ease-in-out, transform .45s @ease-in-out; 6 | &:hover { 7 | background: #e6f7ff; 8 | } 9 | &-list { 10 | position: relative; 11 | } 12 | &-icon { 13 | width: 48px; 14 | text-align: center; 15 | cursor: pointer; 16 | &[disabled] { 17 | color: rgba(0, 0, 0, 0.25) !important; 18 | pointer-events: none; 19 | } 20 | } 21 | &-delete { 22 | text-align: center; 23 | width: 48px; 24 | } 25 | &-name { 26 | width: ~"calc(100% - 80px)"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /site/edit/static/style.js: -------------------------------------------------------------------------------- 1 | import 'rc-drawer/assets/index.css'; 2 | import 'antd/lib/auto-complete/style/index.css'; 3 | import 'medium-editor/dist/css/medium-editor.css'; 4 | import 'medium-editor/dist/css/themes/default.css'; 5 | // import 'rc-editor-list/assets/index.css'; 6 | import 'codemirror/lib/codemirror.css'; 7 | import 'codemirror/theme/ambiance.css'; 8 | import 'codemirror/addon/hint/show-hint.css'; 9 | import './index.less'; 10 | -------------------------------------------------------------------------------- /site/edit/template/NotFound.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function NotFound(props) { 4 | return ( 5 | <div id="page-404" className={props.className}> 6 | <section> 7 | <h1>404</h1> 8 | <p> 9 | 你要找的页面不存在 10 | {' '} 11 | <a href="/">返回首页</a> 12 | </p> 13 | </section> 14 | <style 15 | dangerouslySetInnerHTML={{ 16 | __html: '#page-404{ height: calc(100% - 199px);}', 17 | }} 18 | /> 19 | </div> 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /site/edit/template/components/EditInfluence.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Select } from 'antd'; 3 | import { LaptopOutlined, MobileOutlined } from '@ant-design/icons'; 4 | import * as actions from '../../../shared/redux/actions'; 5 | 6 | const Option = Select.Option; 7 | 8 | class EditInfluence extends React.Component { 9 | onChange = (v) => { 10 | const { dispatch } = this.props; 11 | dispatch(actions.setCurrentMediaData(v)); 12 | } 13 | 14 | render() { 15 | const { mediaStateSelect } = this.props; 16 | return ( 17 | <div className="edit-influence"> 18 | <div className={mediaStateSelect}> 19 | <Select defaultValue={mediaStateSelect} size="small" onChange={this.onChange}> 20 | <Option value="Desktop"> 21 | <LaptopOutlined style={{ fontSize: '12px' }} /> 22 | <span style={{ marginLeft: 4 }}> 23 | Desktop 24 | </span> 25 | </Option> 26 | <Option value="Mobile"> 27 | <MobileOutlined style={{ fontSize: '12px' }} /> 28 | <span style={{ marginLeft: 4 }}> 29 | Mobile 30 | </span> 31 | </Option> 32 | </Select> 33 | </div> 34 | </div> 35 | ); 36 | } 37 | } 38 | 39 | export default EditInfluence; 40 | -------------------------------------------------------------------------------- /site/edit/template/components/ListComponents/CheckboxGroup.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Checkbox, Row, Col } from 'antd'; 3 | import { FormattedMessage } from 'react-intl'; 4 | 5 | const AntCheckboxGroup = Checkbox.Group; 6 | 7 | export default class CheckboxGroup extends React.PureComponent { 8 | onCheckAllChange = (e) => { 9 | const { children } = this.props; 10 | const checked = e.target.checked; 11 | this.props.onChange(checked ? children.map((item) => item.key) : []); 12 | } 13 | 14 | render() { 15 | const { children, value } = this.props; 16 | const checkAll = value.length === children.length; 17 | const indeterminate = !!value.length && (value.length < children.length); 18 | return ( 19 | <div> 20 | <div> 21 | <Checkbox 22 | indeterminate={indeterminate} 23 | checked={checkAll} 24 | onChange={this.onCheckAllChange} 25 | > 26 | <FormattedMessage id="app.common.all" /> 27 | </Checkbox> 28 | </div> 29 | <div> 30 | <AntCheckboxGroup value={value} onChange={this.props.onChange}> 31 | <Row> 32 | {children.map((item) => ( 33 | <Col key={item.key} span={12}><Checkbox value={item.key}>{item.name}</Checkbox></Col> 34 | ))} 35 | </Row> 36 | </AntCheckboxGroup> 37 | </div> 38 | </div> 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /site/edit/template/components/ListComponents/InputGroup.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input, InputNumber } from 'antd'; 3 | 4 | const AntInputGroup = Input.Group; 5 | 6 | export default class InputGroup extends React.PureComponent { 7 | onInputChange = (v, key) => { 8 | const { value } = this.props; 9 | const i = key === 'start' ? 0 : 1; 10 | const newValue = Array.isArray(value) ? value : [value, value]; 11 | newValue[i] = v; 12 | this.props.onChange(newValue); 13 | } 14 | 15 | render() { 16 | const { value } = this.props; 17 | const newValue = Array.isArray(value) ? value : [value, value]; 18 | return ( 19 | <div> 20 | <AntInputGroup compact> 21 | <InputNumber 22 | {...this.props} 23 | size="small" 24 | value={newValue[0]} 25 | style={{ width: '50%' }} 26 | onChange={(v) => { this.onInputChange(v, 'start'); }} 27 | /> 28 | <InputNumber 29 | {...this.props} 30 | size="small" 31 | value={newValue[1] || newValue[0]} 32 | style={{ width: '50%' }} 33 | onChange={(v) => { this.onInputChange(v, 'end'); }} 34 | /> 35 | </AntInputGroup> 36 | </div> 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /site/edit/template/components/MediumEditor.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import MediumEditor from 'medium-editor'; 3 | 4 | import { tagRep } from '../../../utils'; 5 | 6 | const noop = () => { }; 7 | export default class Editor extends React.Component { 8 | medium = null; 9 | 10 | state = { 11 | text: '', 12 | }; 13 | 14 | constructor(props) { 15 | super(props); 16 | this.state = { 17 | text: props.text, 18 | }; 19 | } 20 | 21 | componentDidMount() { 22 | const { options } = this.props; 23 | const { text } = this.state; 24 | this.dom.innerHTML = text; 25 | this.medium = new MediumEditor(this.dom, { 26 | // paste: { cleanPastedHTML: true }, 27 | placeholder: { 28 | text: '请输入...', 29 | }, 30 | anchor: { 31 | placeholderText: 'Paste or type a having (http) link.', 32 | targetCheckbox: true, 33 | targetCheckboxText: 'Open in new window', 34 | }, 35 | ...options, 36 | }); 37 | this.addChange(); 38 | } 39 | 40 | addChange = () => { 41 | const { textToString } = this.props; 42 | this.medium.subscribe('editableInput', (e, b) => { 43 | if (b.innerHTML.match(tagRep)) { 44 | this.setState({ 45 | text: b.innerHTML, 46 | }, () => { 47 | (this.props.onChange || noop)(b); 48 | }); 49 | } 50 | }); 51 | this.medium.subscribe('blur', (e, b) => { 52 | e.stopPropagation(); 53 | if (b.innerHTML.match(tagRep) && e.type === 'click') { 54 | (this.props.onBlur || noop)(textToString ? b.innerText : `<span>${b.innerHTML}</span>`); 55 | } 56 | }); 57 | } 58 | 59 | /* componentWillReceiveProps(nextProps) { 60 | if (nextProps.text !== this.state.text) { 61 | this.setState({ 62 | text: nextProps.text, 63 | }, () => { 64 | this.medium.destroy(); 65 | this.dom.innerHTML = nextProps.text; 66 | this.medium.setup(); 67 | this.addChange(); 68 | }); 69 | } 70 | } */ 71 | 72 | componentWillUnmount() { 73 | this.medium.destroy(); 74 | } 75 | 76 | render() { 77 | const { options, onChange, onBlur, text, children, textToString, ...props } = this.props; 78 | return ( 79 | <div 80 | ref={(c) => { this.dom = c; }} 81 | {...props} 82 | /> 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /site/edit/template/components/StateComponents/ButtonViewComponent/ContentEditView.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | 4 | import { getIdsAndCurrentData } from '../../../utils'; 5 | import { mapStateToProps } from '../../../../../shared/utils'; 6 | 7 | import ContentEditViewItem from './ContentEditViewItem'; 8 | 9 | function ContentEditView({ currentEditData, templateData }) { 10 | const { currentEditTemplateData } = getIdsAndCurrentData(currentEditData, templateData, 'Content'); 11 | if (!currentEditTemplateData.children) { 12 | return null; 13 | } 14 | 15 | return ( 16 | <div> 17 | <div style={{ marginTop: 16, textAlign: 'center' }}> 18 | {Object.keys(currentEditTemplateData.children).map((key) => (<ContentEditViewItem key={key} id={key} />))} 19 | </div> 20 | </div> 21 | ); 22 | } 23 | 24 | export default connect(mapStateToProps)(ContentEditView); 25 | -------------------------------------------------------------------------------- /site/edit/template/components/StateComponents/ButtonViewComponent/ContentEditViewItem.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input, Row, Col } from 'antd'; 3 | import { connect } from 'react-redux'; 4 | 5 | import { getIdsAndCurrentData } from '../../../utils'; 6 | import { mapStateToProps } from '../../../../../shared/utils'; 7 | import * as actions from '../../../../../shared/redux/actions'; 8 | 9 | function ContentEditViewItem({ id, currentEditData, templateData, dispatch }) { 10 | const { ids, currentEditTemplateData } = getIdsAndCurrentData(currentEditData, templateData, 'Content'); 11 | 12 | const item = currentEditTemplateData.children[id]; 13 | 14 | const onBlur = React.useCallback((e) => { 15 | currentEditTemplateData.children[id].children = e.target.value; 16 | dispatch(actions.changeChild({ templateData, currentData: currentEditTemplateData, ids })); 17 | }, [dispatch, templateData, ids, currentEditTemplateData, id]); 18 | 19 | return ( 20 | <Row style={{ marginBottom: 16, textAlign: 'right' }}> 21 | <Col span={6} style={{ paddingRight: 8, lineHeight: '32px' }}>{item.name}</Col> 22 | <Col span={18}> 23 | <Input 24 | defaultValue={item.children} 25 | onBlur={onBlur} 26 | /> 27 | </Col> 28 | </Row> 29 | ); 30 | } 31 | 32 | export default connect(mapStateToProps)(ContentEditViewItem); 33 | -------------------------------------------------------------------------------- /site/edit/template/components/StateComponents/ButtonViewComponent/ContentWrapper.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Modal } from 'antd'; 3 | import { 4 | FormOutlined, 5 | } from '@ant-design/icons'; 6 | import { FormattedMessage } from 'react-intl'; 7 | import ContentEditView from './ContentEditView'; 8 | 9 | export default class ContentWrapper extends React.Component { 10 | state = { 11 | editContentShow: false, 12 | }; 13 | 14 | onOpenModal = () => { 15 | this.setState({ 16 | editContentShow: !this.state.editContentShow, 17 | }); 18 | } 19 | 20 | render() { 21 | return ( 22 | <div> 23 | <Button type="primary" size="small" onClick={this.onOpenModal}> 24 | <FormOutlined /> 25 | </Button> 26 | <Modal 27 | title={<FormattedMessage id="app.common.edit.content" />} 28 | visible={this.state.editContentShow} 29 | onCancel={this.onOpenModal} 30 | footer={null} 31 | width={400} 32 | > 33 | <ContentEditView {...this.props} /> 34 | </Modal> 35 | </div> 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /site/edit/template/components/StateComponents/ButtonViewComponent/IconComp.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Popover, Input } from 'antd'; 3 | import { FormattedMessage } from 'react-intl'; 4 | 5 | export default class IconComp extends React.Component { 6 | onIconChange = (e) => { 7 | this.props.setTemplateConfigData(e.target.value); 8 | } 9 | 10 | render() { 11 | const { editText } = this.props; 12 | const popContent = ( 13 | <div> 14 | <p style={{ marginBottom: 8 }}> 15 | <FormattedMessage id="app.state.icon.only-use" /> 16 | <a href="https://ant.design/components/icon-cn/" target="_blank"> 17 | {' '} 18 | ant design Icon 19 | {' '} 20 | </a> 21 | </p> 22 | <Input 23 | style={{ width: 250 }} 24 | onBlur={this.onIconChange} 25 | defaultValue={editText} 26 | placeholder={<FormattedMessage id="app.state.icon.paste" />} 27 | /> 28 | </div> 29 | ); 30 | return ( 31 | <Popover 32 | placement="bottomRight" 33 | title={<FormattedMessage id="app.state.icon.header" />} 34 | content={popContent} 35 | trigger="click" 36 | > 37 | <Button type="primary" size="small" onClick={this.props.closeEditText}> 38 | Icon 39 | </Button> 40 | </Popover> 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /site/edit/template/components/StateComponents/ButtonViewComponent/ImageComp.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Popover, Input } from 'antd'; 3 | import { 4 | PictureOutlined, 5 | } from '@ant-design/icons'; 6 | import { FormattedMessage } from 'react-intl'; 7 | 8 | export default class ImageComp extends React.Component { 9 | onImageBtnChange = (e) => { 10 | const value = e.target.value; 11 | if (value !== this.props.editText) { 12 | this.props.setTemplateConfigData(value); 13 | } 14 | } 15 | 16 | render() { 17 | const { editText } = this.props; 18 | return ( 19 | <Popover 20 | placement="bottomRight" 21 | title={<FormattedMessage id="app.state.image.header" />} 22 | content={( 23 | <Input 24 | style={{ width: 250 }} 25 | onBlur={this.onImageBtnChange} 26 | defaultValue={editText} 27 | placeholder={<FormattedMessage id="app.state.image.placeholder" />} 28 | /> 29 | )} 30 | trigger="click" 31 | > 32 | <Button type="primary" size="small" onClick={this.props.closeEditText}> 33 | <PictureOutlined /> 34 | </Button> 35 | </Popover> 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /site/edit/template/components/StateComponents/ButtonViewComponent/MenuComp.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Modal } from 'antd'; 3 | import { BarsOutlined } from '@ant-design/icons'; 4 | import { FormattedMessage } from 'react-intl'; 5 | import MenuEditView from './MenuEditView'; 6 | 7 | export default class ImageComp extends React.Component { 8 | state = { 9 | editMenuShow: false, 10 | } 11 | 12 | switchEditMenuFunc = () => { 13 | this.setState({ 14 | editMenuShow: !this.state.editMenuShow, 15 | }); 16 | } 17 | 18 | render() { 19 | const { editData } = this.props; 20 | if (typeof editData.children !== 'string') { 21 | return null; 22 | } 23 | return ( 24 | <div> 25 | <Button type="primary" size="small" onClick={this.switchEditMenuFunc}> 26 | <BarsOutlined /> 27 | </Button> 28 | <Modal 29 | title={<FormattedMessage id="app.state.menu.header" />} 30 | visible={this.state.editMenuShow} 31 | onCancel={this.switchEditMenuFunc} 32 | footer={null} 33 | width={400} 34 | > 35 | <MenuEditView {...this.props} /> 36 | </Modal> 37 | </div> 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /site/edit/template/components/StateComponents/ButtonViewComponent/TextyComp.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Popover, Input } from 'antd'; 3 | import { FormattedMessage } from 'react-intl'; 4 | 5 | export default class TextyComp extends React.Component { 6 | onImageBtnChange = (e) => { 7 | const value = e.target.value; 8 | this.props.setTemplateConfigData(value); 9 | } 10 | 11 | render() { 12 | const { editText } = this.props; 13 | return ( 14 | <Popover 15 | placement="bottomRight" 16 | title={<FormattedMessage id="app.state.texty.header" />} 17 | content={( 18 | <Input 19 | style={{ width: 250 }} 20 | onBlur={this.onImageBtnChange} 21 | defaultValue={editText || ''} 22 | placeholder={<FormattedMessage id="app.state.texty.header" />} 23 | /> 24 | )} 25 | trigger="click" 26 | > 27 | <Button type="primary" size="small" onClick={this.props.closeEditText}> 28 | Ty 29 | </Button> 30 | </Popover> 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /site/edit/template/components/StateComponents/ButtonViewComponent/VideoComp.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Popover, Input, Row, Col } from 'antd'; 3 | import { 4 | VideoCameraOutlined, 5 | } from '@ant-design/icons'; 6 | import { FormattedMessage } from 'react-intl'; 7 | import { isImg } from '../../../../../utils'; 8 | 9 | export default class VideoComp extends React.Component { 10 | onVideoChange = (e, data, key) => { 11 | data[key] = e.target.value; 12 | this.props.setTemplateConfigData(data); 13 | } 14 | 15 | render() { 16 | const { editText } = this.props; 17 | const popContent = ( 18 | <div style={{ width: 350, lineHeight: '32px' }}> 19 | <Row> 20 | <Col span={8} style={{ textAlign: 'right', paddingRight: 8 }}> 21 | <FormattedMessage id="app.state.video.placeholder" /> 22 | </Col> 23 | <Col span={16}> 24 | <Input 25 | onBlur={(e) => { this.onVideoChange(e, editText, 'video'); }} 26 | defaultValue={editText.video} 27 | placeholder={<FormattedMessage id="app.state.video.placeholder" />} 28 | /> 29 | </Col> 30 | </Row> 31 | <Row style={{ marginTop: 16 }}> 32 | <Col span={8} style={{ textAlign: 'right', paddingRight: 8 }}> 33 | <FormattedMessage id="app.state.video.preview" /> 34 | </Col> 35 | <Col span={16}> 36 | <Input 37 | onBlur={(e) => { this.onVideoChange(e, editText, 'image'); }} 38 | defaultValue={editText.image && editText.image.match(isImg) ? editText.image : ''} 39 | placeholder={<FormattedMessage id="app.state.video.preview" />} 40 | /> 41 | </Col> 42 | </Row> 43 | </div> 44 | ); 45 | return ( 46 | <Popover 47 | placement="bottomRight" 48 | title={<FormattedMessage id="app.state.video.header" />} 49 | content={popContent} 50 | trigger="click" 51 | > 52 | <Button type="primary" size="small"> 53 | <VideoCameraOutlined /> 54 | </Button> 55 | </Popover> 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /site/edit/template/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import { IntlProvider } from 'react-intl'; 4 | import { ConfigProvider } from 'antd'; 5 | import zhCN from 'antd/es/locale/zh_CN'; 6 | 7 | import enLocale from '../en-US'; 8 | import cnLocale from '../zh-CN'; 9 | 10 | import Layout from './layout'; 11 | 12 | import store from '../../shared/redux'; 13 | import { isZhCN } from '../../theme/template/utils'; 14 | import '../static/style'; 15 | 16 | class Edit extends React.Component { 17 | constructor(props) { 18 | super(props); 19 | const { pathname } = props.location; 20 | const appLocale = isZhCN(pathname) ? cnLocale : enLocale; 21 | 22 | this.state = { 23 | appLocale, 24 | }; 25 | } 26 | 27 | render() { 28 | const { appLocale } = this.state; 29 | return ( 30 | <Provider store={store}> 31 | <IntlProvider locale={appLocale.locale} messages={appLocale.messages}> 32 | <ConfigProvider locale={appLocale.locale === 'zh-CN' ? zhCN : null}> 33 | <Layout {...this.props} /> 34 | </ConfigProvider> 35 | </IntlProvider> 36 | </Provider> 37 | ); 38 | } 39 | } 40 | 41 | export default Edit; 42 | -------------------------------------------------------------------------------- /site/edit/template/utils.jsx: -------------------------------------------------------------------------------- 1 | import { mergeEditDataToDefault, getDataSourceValue } from '../../utils'; 2 | import tempData from '../../templates/template/element/template.config'; 3 | 4 | // import { createLogger } from 'redux-logger'; 5 | const worker = new Worker('./worker.js'); 6 | 7 | export function formatCode({ code, cb, parser = 'babylon', key }) { 8 | const options = { 9 | useTabs: false, 10 | tabWidth: 2, 11 | printWidth: 80, 12 | singleQuote: true, 13 | trailingComma: 'es5', 14 | bracketSpacing: true, 15 | parser, 16 | arrowParens: 'always', 17 | semi: true, 18 | }; 19 | worker.onmessage = (message) => { 20 | cb(message.data.formatted, message.data.key); 21 | }; 22 | worker.postMessage({ 23 | text: code, 24 | key, 25 | options, 26 | }); 27 | } 28 | 29 | /* export function hasErrors(fieldsError) { 30 | return Object.keys(fieldsError).some((field) => fieldsError[field] && fieldsError[field][0] !== 'password error' 31 | ); 32 | } */ 33 | 34 | export const getCurrentDom = (pos, data) => { 35 | const t = data.map((item) => { 36 | const rect = item.rect; 37 | if (pos.x >= rect.x && pos.y >= rect.y 38 | && pos.x <= rect.x + rect.width && pos.y <= rect.y + rect.height) { 39 | return { 40 | ...item, 41 | rect, 42 | }; 43 | } 44 | return null; 45 | }).filter((item) => item); 46 | return t[t.length - 1]; 47 | }; 48 | 49 | export const getIdsAndCurrentData = (currentEditData, templateData, key) => { 50 | const { id } = currentEditData; 51 | const ids = id.split('-'); 52 | ids[1] = key; 53 | const cid = ids[0].split('_')[0]; 54 | const tempDataSource = tempData[cid]; 55 | const newTemplateDataSource = mergeEditDataToDefault(templateData.data.config[ids[0]], 56 | tempDataSource); 57 | const currentEditTemplateData = getDataSourceValue(key, newTemplateDataSource); 58 | return { ids, currentEditTemplateData }; 59 | }; 60 | -------------------------------------------------------------------------------- /site/shared/constants.js: -------------------------------------------------------------------------------- 1 | export const DEFAULT_USER_NAME = 'antd-landing-user-name'; 2 | 3 | // leancloud 4 | export const DEFAULT_FILE_NAME = 'Edit'; 5 | export const DEFAULT_USER_AV_NAME = 'EditUser'; 6 | 7 | export const DEFAULT_TEMPLATE_DATA = { 8 | template: [ 9 | 'Nav0_0', 'Banner0_0', 'Content0_0', 10 | 'Content1_0', 'Content3_0', 'Footer0_0', 11 | ], 12 | config: {}, 13 | style: [], 14 | other: {}, 15 | page: {}, 16 | }; 17 | -------------------------------------------------------------------------------- /site/shared/leancloud.js: -------------------------------------------------------------------------------- 1 | import AV from 'leancloud-storage'; 2 | 3 | export const appId = 'ogaJShC9qJERt8LqGO80z2pO-gzGzoHsz'; 4 | export const appKey = '8e5H5xBF86hI9vItQI1pt4kP'; 5 | 6 | AV.init({ 7 | appId, 8 | appKey, 9 | // serverURLs: 'https://avoscloud.com', 10 | serverURLs: 'https://ogajshc9.lc-cn-n1-shared.com', 11 | }); 12 | 13 | export default AV; 14 | -------------------------------------------------------------------------------- /site/shared/localStorage.js: -------------------------------------------------------------------------------- 1 | import store from 'store'; 2 | 3 | /** 4 | * Auth 5 | */ 6 | 7 | export function getUserAuthState(userId) { 8 | return !!store.get(`antd-landing-login-${userId}`); 9 | } 10 | 11 | export function setUserAuthState(userId, state) { 12 | store.set(`antd-landing-login-${userId}`, state); 13 | } 14 | 15 | /** 16 | * User 17 | */ 18 | 19 | export function getUserTemplateIds(userId) { 20 | const value = store.get(userId, []); 21 | return typeof value === 'string' ? value.split(',').filter((c) => c) : value; 22 | } 23 | 24 | export function unshiftToUserTemplateIds(userId, tid) { 25 | const ids = getUserTemplateIds(userId); 26 | store.set(userId, [tid, ...ids]); 27 | } 28 | 29 | export function removeUserTemplateIds(userId) { 30 | store.remove(userId); 31 | } 32 | 33 | export function removeUserTemplate(userId, tid) { 34 | const ids = getUserTemplateIds(userId); 35 | store.set(userId, ids.filter((id) => id !== tid)); 36 | } 37 | 38 | /** 39 | * Template 40 | */ 41 | 42 | export function getTemplate(tid) { 43 | return store.get(tid, undefined); 44 | } 45 | 46 | export function saveTemplate(template) { 47 | store.set(template.id, template); 48 | } 49 | 50 | export function removeTemplate(tid) { 51 | store.remove(tid); 52 | } 53 | -------------------------------------------------------------------------------- /site/shared/redux/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const GET_USER_DATA = '[landing] GET_USER_DATA'; 2 | export const CREATE_NEW_TEMPLATE = '[landing] CREATE_NEW_TEMPLATE'; 3 | export const SET_TEMPLATE_DATA = '[landing] SET_TEMPLATE_DATA'; 4 | export const CHANGE_CHILD = '[landing] CHANGE_CHILD'; 5 | export const SET_USER_AND_TEMPLATE_DATA = '[landing] SET_USER_AND_TEMPLATE_DATA'; 6 | export const UPDATE_HISTORY = '[landing] UPDATE_HISTORY'; 7 | 8 | export const POST_TYPE = { 9 | POST_DEFAULT: '[landing] default', 10 | POST_SET: '[landing] set', 11 | POST_SUCCESS: '[landing] success', 12 | POST_ERROR: '[landing] error', 13 | SET_TEMPLATE: '[landing] setTemplate', 14 | SET_EDIT: '[landing] setEdit', 15 | SET_MEDIA: '[landing] setMedia', 16 | SET_USER: '[landing] setUser', 17 | SET_HISTORY_NUM: '[landing] setHistoryNum', 18 | UPDATE_HISTORY_RE_NUM: '[landing] updateHistoryReNum', 19 | SAVE_HISTORY: '[landing] saveHistory', 20 | SET_USERTEMPLATE: '[landing] setUserTemplate', 21 | }; 22 | -------------------------------------------------------------------------------- /site/shared/redux/actions.js: -------------------------------------------------------------------------------- 1 | import { GET_USER_DATA, CREATE_NEW_TEMPLATE, SET_TEMPLATE_DATA, CHANGE_CHILD, POST_TYPE, SET_USER_AND_TEMPLATE_DATA } from './actionTypes'; 2 | 3 | export const getUserData = (data) => ({ 4 | type: GET_USER_DATA, 5 | data, 6 | }); 7 | 8 | export const createNewTemplate = (data) => ({ 9 | type: CREATE_NEW_TEMPLATE, 10 | data, 11 | }); 12 | 13 | export const setTemplateData = (data) => ({ 14 | type: SET_TEMPLATE_DATA, 15 | data, 16 | }); 17 | 18 | export const changeChild = (data) => ({ 19 | type: CHANGE_CHILD, 20 | data, 21 | }); 22 | 23 | export const setUserAndTemplateData = (data) => ({ 24 | type: SET_USER_AND_TEMPLATE_DATA, 25 | data, 26 | }); 27 | 28 | // 编辑 props 29 | export const setCurrentData = (data) => { 30 | return { 31 | type: POST_TYPE.SET_EDIT, 32 | data, 33 | }; 34 | }; 35 | 36 | // 编辑 media 状态 37 | export const setCurrentMediaData = (data) => { 38 | return { 39 | type: POST_TYPE.SET_MEDIA, 40 | data, 41 | }; 42 | }; 43 | 44 | export const setUserData = (data) => { 45 | return { 46 | type: POST_TYPE.SET_USER, 47 | data, 48 | }; 49 | }; 50 | 51 | // 记录 history 步数; 52 | export const setCurrentHistoryNum = (data) => { 53 | return { 54 | type: POST_TYPE.SET_HISTORY_NUM, 55 | data, 56 | }; 57 | }; 58 | // 删除之前,保存当前的 59 | export const updateHistoryReNum = (data) => { 60 | return { 61 | type: POST_TYPE.UPDATE_HISTORY_RE_NUM, 62 | data, 63 | }; 64 | }; 65 | -------------------------------------------------------------------------------- /site/shared/redux/index.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import createSagaMiddleware from 'redux-saga'; 3 | import rootReducer from './reducers'; 4 | import rootSaga from './saga'; 5 | 6 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; 7 | const sagaMiddleware = createSagaMiddleware(); 8 | 9 | const store = createStore( 10 | rootReducer, 11 | composeEnhancers( 12 | applyMiddleware(sagaMiddleware), 13 | ), 14 | ); 15 | 16 | sagaMiddleware.run(rootSaga); 17 | 18 | export default store; 19 | -------------------------------------------------------------------------------- /site/shared/redux/reducers/currentEditData.js: -------------------------------------------------------------------------------- 1 | import { POST_TYPE } from '../actionTypes'; 2 | 3 | export default function currentEditData(state, action) { 4 | switch (action.type) { 5 | case POST_TYPE.SET_EDIT: 6 | return action.data || null; 7 | case POST_TYPE.SET_MEDIA: 8 | return null; 9 | default: 10 | return state || null; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /site/shared/redux/reducers/historyEdit.js: -------------------------------------------------------------------------------- 1 | import { POST_TYPE } from '../actionTypes'; 2 | 3 | export default function historyEdit(state, action) { 4 | switch (action.type) { 5 | case POST_TYPE.SET_HISTORY_NUM: 6 | return { 7 | ...state, 8 | num: action.data, 9 | }; 10 | case POST_TYPE.UPDATE_HISTORY_RE_NUM: 11 | return { 12 | num: 0, 13 | history: (state.num 14 | ? [action.data, ...state.history.filter((c, i) => i >= state.num && c)] 15 | : [action.data, ...state.history]).filter((c, i) => i < 30 && c), // 只记录30步 16 | }; 17 | default: 18 | return state || { 19 | num: 0, 20 | history: [], 21 | }; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /site/shared/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import templateData from './templateData'; 3 | import currentEditData from './currentEditData'; 4 | import mediaStateSelect from './mediaStateSelect'; 5 | import userIsLogin from './userIsLogin'; 6 | import historyEdit from './historyEdit'; 7 | 8 | const reducer = combineReducers({ 9 | templateData, 10 | currentEditData, 11 | mediaStateSelect, 12 | userIsLogin, 13 | historyEdit, 14 | }); 15 | 16 | export default reducer; 17 | -------------------------------------------------------------------------------- /site/shared/redux/reducers/mediaStateSelect.js: -------------------------------------------------------------------------------- 1 | import { POST_TYPE } from '../actionTypes'; 2 | 3 | export default function mediaStateSelect(state, action) { 4 | switch (action.type) { 5 | case POST_TYPE.SET_MEDIA: 6 | return action.data || 'Desktop'; 7 | default: 8 | return state || 'Desktop'; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /site/shared/redux/reducers/templateData.js: -------------------------------------------------------------------------------- 1 | import { POST_TYPE } from '../actionTypes'; 2 | 3 | const TEMPLATE_TYPE = { 4 | DEFAULT: 'default', 5 | SET: 'set', 6 | SUCCESS: 'success', 7 | ERROR: 'error', 8 | }; 9 | 10 | function resolveTemplateType(actionType) { 11 | switch (actionType) { 12 | case POST_TYPE.POST_SET: 13 | return TEMPLATE_TYPE.SET; 14 | case POST_TYPE.POST_SUCCESS: 15 | return TEMPLATE_TYPE.SUCCESS; 16 | case POST_TYPE.POST_ERROR: 17 | return TEMPLATE_TYPE.ERROR; 18 | default: 19 | return TEMPLATE_TYPE.DEFAULT; 20 | } 21 | } 22 | 23 | export default function templateData(state, action) { 24 | switch (action.type) { 25 | case POST_TYPE.POST_SUCCESS: 26 | case POST_TYPE.POST_SET: 27 | case POST_TYPE.POST_ERROR: 28 | return { 29 | type: resolveTemplateType(action.type), 30 | uid: action.templateData.id, 31 | data: action.templateData ? { ...action.templateData.attributes } : null, 32 | }; 33 | case POST_TYPE.SET_USERTEMPLATE: 34 | return { 35 | ...action.data.templateData, 36 | }; 37 | case POST_TYPE.SET_TEMPLATE: 38 | return { 39 | type: state.type, 40 | uid: state.uid, 41 | data: action.data, 42 | }; 43 | case POST_TYPE.SET_EDIT: 44 | case POST_TYPE.SET_MEDIA: 45 | case POST_TYPE.SET_USER: 46 | return state || null; 47 | default: 48 | return state || { 49 | type: resolveTemplateType(action.type), 50 | data: null, 51 | }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /site/shared/redux/reducers/userIsLogin.js: -------------------------------------------------------------------------------- 1 | import { POST_TYPE } from '../actionTypes'; 2 | 3 | export default function userIsLogin(state, action) { 4 | switch (action.type) { 5 | case POST_TYPE.SET_USER: 6 | return action.data || false; 7 | case POST_TYPE.SET_USERTEMPLATE: 8 | return action.data.userIsLogin || false; 9 | case POST_TYPE.POST_SUCCESS: 10 | return action.userIsLogin || false; 11 | default: 12 | return state || false; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /site/shared/url.js: -------------------------------------------------------------------------------- 1 | import qs from 'query-string'; 2 | 3 | // get url query object / specific query value 4 | export function get(name) { 5 | const queryString = ((window && window.location.hash) || '').replace('#', ''); 6 | const query = qs.parse(queryString); 7 | return name ? query[name] : query; 8 | } 9 | 10 | // update url query string 11 | export function update(name, value) { 12 | if (typeof window === 'undefined') { 13 | return ''; 14 | } 15 | 16 | const urlData = get(); 17 | urlData[name] = value; 18 | 19 | window.location.hash = `#${qs.stringify(urlData)}`; 20 | } 21 | -------------------------------------------------------------------------------- /site/templates/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | routes: [ 3 | { path: '/', component: './template/index' }, 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /site/templates/static/bottom-func-bar.less: -------------------------------------------------------------------------------- 1 | @bottomBar: bottom-func-bar; 2 | .@{bottomBar} { 3 | position: fixed; 4 | bottom: 0; 5 | height: 32px; 6 | line-height: 32px; 7 | left: 4%; 8 | text-align: center; 9 | box-shadow: 0 -2px 6px fade(#000, 15); 10 | transform: translateY(0%); 11 | transition: transform .3s @ease-in-out; 12 | ul { 13 | display: inline-block; 14 | border-radius: 4px 4px 0 0; 15 | overflow: hidden; 16 | background: @bottom-bar-bg-color; 17 | li { 18 | cursor: pointer; 19 | display: inline-block; 20 | width: 120px; 21 | border-right: 1px solid @bottom-bar-line-color; 22 | color: @template-text-color; 23 | .anticon { 24 | margin-right: 8px; 25 | } 26 | &:last-child { 27 | border-right: none; 28 | } 29 | } 30 | } 31 | .bar-icon { 32 | background: @bottom-bar-bg-color; 33 | position: absolute; 34 | top: -12px; 35 | width: 32px; 36 | height: 13px; 37 | margin: auto; 38 | left: 0; 39 | right: 0; 40 | border-radius: 4px 4px 0 0; 41 | box-shadow: 0 -2px 6px fade(#000, 15); 42 | cursor: pointer; 43 | .arrow { 44 | display: inline-block; 45 | position: absolute; 46 | top: 50%; 47 | left: ~"calc(50% - 2.8px)"; 48 | svg { 49 | display: none; 50 | } 51 | &:after, 52 | &:before { 53 | content: ''; 54 | display: block; 55 | position: absolute; 56 | width: 6px; 57 | height: 2px; 58 | background: #fff; 59 | transition: transform .3s @ease-in-out; 60 | } 61 | &:after { 62 | transform: rotate(45deg) translateX(-2px); 63 | } 64 | &:before { 65 | transform: rotate(-45deg) translateX(2px); 66 | } 67 | transition: transform .3s @ease-in-out; 68 | } 69 | } 70 | &.close { 71 | transform: translateY(100%); 72 | .arrow { 73 | transform: translateY(-3px); 74 | &:after { 75 | transform: rotate(-45deg) translateX(-2px); 76 | } 77 | &:before { 78 | transform: rotate(45deg) translateX(2px); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /site/templates/static/common.less: -------------------------------------------------------------------------------- 1 | 2 | // @import "~antd/lib/style/v2-compatible-reset.less"; 3 | 4 | body { 5 | word-wrap: break-word; 6 | } 7 | 8 | body, 9 | div, 10 | dl, 11 | dt, 12 | dd, 13 | ul, 14 | ol, 15 | li, 16 | h1, 17 | h2, 18 | h3, 19 | h4, 20 | h5, 21 | h6 { 22 | margin: 0; 23 | padding: 0; 24 | } 25 | 26 | /* .content-wrapper > .tween-one-leaving, 27 | .queue-anim-leaving { 28 | // position: absolute !important; 29 | // width: 100%; 30 | } */ 31 | 32 | .video { 33 | max-width: 800px; 34 | } 35 | 36 | #react-content { 37 | min-height: 100%; 38 | } 39 | .home-page-wrapper p { 40 | padding: 0; 41 | margin: 0; 42 | } 43 | -------------------------------------------------------------------------------- /site/templates/static/content.less: -------------------------------------------------------------------------------- 1 | @homepage: home-page; 2 | .@{homepage}-wrapper { 3 | width: 100%; 4 | position: relative; 5 | overflow: hidden; 6 | .@{homepage} { 7 | height: 100%; 8 | max-width: 1200px; 9 | position: relative; 10 | margin: auto; 11 | will-change: transform; 12 | } 13 | .title-wrapper > h1, > h1 { 14 | font-size: 32px; 15 | color: @text-color; 16 | margin-bottom: 16px; 17 | } 18 | .title-wrapper { 19 | margin: 0 auto 64px; 20 | text-align: center; 21 | } 22 | } 23 | 24 | .@{homepage} { 25 | padding: 128px 24px; 26 | } 27 | 28 | @media screen and (max-width: 767px) { 29 | .@{homepage}-wrapper { 30 | .@{homepage} { 31 | padding: 56px 24px; 32 | >h1 { 33 | font-size: 24px; 34 | margin: 0 auto 32px; 35 | &.title-h1 { 36 | margin-bottom: 8px; 37 | } 38 | } 39 | >p { 40 | margin-bottom: 32px; 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /site/templates/static/custom.less: -------------------------------------------------------------------------------- 1 | @import "~antd/lib/style/themes/default.less"; 2 | 3 | @line-color: #e9e9e9; 4 | 5 | @shadow-color: rgba(0, 0, 0, 0.15); 6 | 7 | @bottom-bar-bg-color: #262626; 8 | @bottom-bar-line-color: #000; 9 | 10 | @template-bg-color: #001529; 11 | @template-bg-color-light: #ececec; 12 | @template-nav-bg-color: #001529; 13 | @template-text-color: #ccc; 14 | @template-text-title-color: #bcbcbc; 15 | @template-text-color-light: #fff; 16 | @template-footer-text-color: #999; 17 | 18 | @animate-duration: .45s; 19 | 20 | /* 详细页图片或框框的样式; 21 | */ 22 | .page-shadow() { 23 | box-shadow: 0 5px 8px @shadow-color; 24 | } 25 | 26 | .page-pro() { 27 | border-radius: 6px; 28 | border: 1px solid @line-color; 29 | transform: translateY(0); 30 | transition: transform .3s @ease-out, box-shadow .3s @ease-out; 31 | &:hover { 32 | .page-shadow(); 33 | transform: translateY(-5px); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /site/templates/static/index.less: -------------------------------------------------------------------------------- 1 | @import './common.less'; 2 | @import './custom.less'; 3 | @import './point.less'; 4 | @import './content.less'; 5 | @import './bottom-func-bar.less'; 6 | 7 | .is-edit { 8 | * { 9 | pointer-events: none; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /site/templates/static/lessToString.jsx: -------------------------------------------------------------------------------- 1 | /* eslin import/no-webpack-loader-syntax:[0] */ 2 | import point from '!raw-loader!./point.less'; 3 | import common from '!raw-loader!./common.less'; 4 | import custom from '!raw-loader!./custom.less'; 5 | import content from '!raw-loader!./content.less'; 6 | 7 | export default { 8 | common, 9 | custom, 10 | point, 11 | content, 12 | }; 13 | -------------------------------------------------------------------------------- /site/templates/static/point.less: -------------------------------------------------------------------------------- 1 | @import './custom.less'; 2 | @point: point; 3 | .@{point} { 4 | float: left; 5 | width: 8px; 6 | height: 8px; 7 | opacity: .5; 8 | cursor: pointer; 9 | pointer-events: auto; 10 | transition: opacity .3s @ease-out, background .3s @ease-out; 11 | margin: 6px auto; 12 | background: @primary-color; 13 | border-radius: 100%; 14 | &.active { 15 | opacity: 1; 16 | background: @primary-color; 17 | } 18 | &-wrapper { 19 | position: fixed; 20 | z-index: 9998; 21 | top: 0; 22 | right: 16px; 23 | width: 10px; 24 | display: flex; 25 | height: 100%; 26 | align-items: center; 27 | pointer-events: none; 28 | } 29 | &-left { 30 | left: 16px; 31 | } 32 | &-rect { 33 | border-radius: 0; 34 | } 35 | &-prismatic { 36 | border-radius: 0; 37 | transform: rotate(45deg); 38 | } 39 | &-stroke { 40 | border: 2px solid @primary-color; 41 | background: transparent; 42 | } 43 | &-small { 44 | width: 6px; 45 | &.point { 46 | height: 6px; 47 | } 48 | } 49 | &-large { 50 | width: 10px; 51 | &.point { 52 | height: 10px; 53 | } 54 | } 55 | } 56 | 57 | @media screen and (max-width: 767px) { 58 | .@{point}-wrapper { 59 | display: none; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /site/templates/template/BottomBar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Popconfirm } from 'antd'; 3 | import Icon, { 4 | HomeOutlined, 5 | } from '@ant-design/icons'; 6 | import { getNewHref, RemoveLocalStorage } from '../../utils'; 7 | import { getURLData } from '../../theme/template/utils'; 8 | 9 | export default class BottomBar extends React.Component { 10 | state = { 11 | close: false, 12 | } 13 | 14 | onRemoveLocalStorage = () => { 15 | const uid = getURLData('uid'); 16 | localStorage.removeItem(uid); 17 | location.reload(); 18 | }; 19 | 20 | onClose = () => { 21 | const { close } = this.state; 22 | this.setState({ 23 | close: !close, 24 | }); 25 | } 26 | 27 | render() { 28 | const { close } = this.state; 29 | return ( 30 | <div className={`bottom-func-bar${close ? ' close' : ''}`}> 31 | <div className="bar-icon" onClick={this.onClose}> 32 | <i className="arrow" /> 33 | </div> 34 | <ul> 35 | <li 36 | onClick={() => { 37 | location.href = getNewHref('7111', null, true); 38 | }} 39 | > 40 | <HomeOutlined /> 41 | 返回首页 42 | </li> 43 | {/* <li 44 | onClick={() => { 45 | location.href = `${getNewHref('7112', null, true)}${location.hash}`; 46 | }} 47 | > 48 | <EditOutlined /> 49 | 返回编辑 50 | </li> */} 51 | <li> 52 | <Popconfirm 53 | title="清除当前缓存,重新从服务器读取最后保存的数据;如有编辑,请先保存。" 54 | onConfirm={this.onRemoveLocalStorage} 55 | okText="确定" 56 | cancelText="取消" 57 | overlayStyle={{ width: 320 }} 58 | > 59 | <Icon component={() => RemoveLocalStorage('14')} /> 60 | 清除缓存 61 | </Popconfirm> 62 | </li> 63 | </ul> 64 | </div> 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /site/templates/template/NotFound.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function NotFound(props) { 4 | return ( 5 | <div id="page-404" className={props.className}> 6 | <section> 7 | <h1> 8 | 404 9 | </h1> 10 | <p> 11 | 你要找的页面不存在 12 | {' '} 13 | <a href="/"> 14 | 返回首页 15 | </a> 16 | </p> 17 | </section> 18 | <style 19 | dangerouslySetInnerHTML={{ 20 | __html: '#page-404{ height: calc(100% - 199px);}', 21 | }} 22 | /> 23 | </div> 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /site/templates/template/element/Banner0/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @banner0: banner0; 3 | .@{banner0} { 4 | // 如果在第一屏且导航位置为 relative, 一屏为 height: calc(~"100vh - 64px"); 5 | width: 100%; 6 | height: 100vh; 7 | position: relative; 8 | text-align: center; 9 | border-color: #666; 10 | background-image: url("https://zos.alipayobjects.com/rmsportal/gGlUMYGEIvjDOOw.jpg"); 11 | background-size: cover; 12 | background-attachment: fixed; 13 | background-position: center; 14 | & &-text-wrapper { 15 | display: inline-block; 16 | position: absolute; 17 | top: 20%; 18 | margin: auto; 19 | left: 0; 20 | right: 0; 21 | font-size: 14px; 22 | color: @template-text-color-light; 23 | width: 550px; 24 | >.queue-anim-leaving { 25 | position: relative !important; 26 | } 27 | } 28 | & &-title { 29 | width: 350px; 30 | left: 30px; 31 | min-height: 60px; 32 | margin: auto; 33 | display: inline-block; 34 | font-size: 40px; 35 | position: relative; 36 | } 37 | & &-content { 38 | margin-bottom: 20px; 39 | word-wrap: break-word; 40 | min-height: 24px; 41 | } 42 | & &-button { 43 | border: 1px solid #fff; 44 | color: #fff; 45 | background: transparent; 46 | box-shadow: 0 0 0 transparent; 47 | font-size: 16px; 48 | height: 40px; 49 | transition: background .45s @ease-out, box-shadow .45s @ease-out; 50 | &:hover { 51 | color: #fff; 52 | border-color: #fff; 53 | background: rgba(255, 255, 255, 0.1); 54 | box-shadow: 0 0 10px rgba(50, 250, 255, 0.75); 55 | } 56 | &:focus { 57 | color: #fff; 58 | border-color: #fff; 59 | } 60 | &.queue-anim-leaving { 61 | width: auto; 62 | } 63 | } 64 | & &-icon { 65 | bottom: 20px; 66 | font-size: 24px; 67 | position: absolute; 68 | left: 50%; 69 | margin-left: -12px; 70 | color: @template-text-color-light; 71 | } 72 | } 73 | 74 | @media screen and (max-width: 767px) { 75 | .@{banner0} { 76 | background-attachment: inherit; 77 | & &-text-wrapper { 78 | width: 90%; 79 | } 80 | & &-title { 81 | width: 90%; 82 | left: 0; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /site/templates/template/element/Banner0/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | wrapper: { 12 | className: 'banner0', 13 | }, 14 | textWrapper: { 15 | className: 'banner0-text-wrapper', 16 | }, 17 | title: { 18 | className: 'banner0-title', 19 | children: 'https://zos.alipayobjects.com/rmsportal/HqnZZjBjWRbjyMr.png', 20 | }, 21 | content: { 22 | className: 'banner0-content', 23 | children: '一个高效的页面动画解决方案', 24 | }, 25 | button: { 26 | className: 'banner0-button', 27 | children: 'Learn More', 28 | }, 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /site/templates/template/element/Banner2/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | wrapper: { 12 | className: 'banner2', 13 | }, 14 | BannerAnim: { 15 | children: [ 16 | { 17 | name: 'elem0', 18 | BannerElement: { 19 | className: 'banner-user-elem', 20 | }, 21 | page: { 22 | className: 'home-page banner2-page', 23 | }, 24 | textWrapper: { 25 | className: 'banner2-text-wrapper', 26 | }, 27 | bg: { 28 | className: 'bg bg0', 29 | }, 30 | title: { 31 | className: 'banner2-title', 32 | children: 'Ant Motion', 33 | }, 34 | content: { 35 | className: 'banner2-content', 36 | children: '一个高效的页面动画解决方案', 37 | }, 38 | button: { 39 | className: 'banner2-button', 40 | children: 'Learn More', 41 | }, 42 | }, 43 | ], 44 | }, 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /site/templates/template/element/Banner3/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button } from 'antd'; 3 | import QueueAnim from 'rc-queue-anim'; 4 | import Texty from 'rc-texty'; 5 | import 'rc-texty/assets/index.css'; 6 | /* replace-start */ 7 | import './index.less'; 8 | /* replace-end */ 9 | class Banner extends React.PureComponent { 10 | render() { 11 | const { ...currentProps } = this.props; 12 | const { dataSource } = currentProps; 13 | delete currentProps.dataSource; 14 | delete currentProps.isMobile; 15 | const children = dataSource.textWrapper.children.map((item) => { 16 | const { name, texty, ...$item } = item; 17 | if (name.match('button')) { 18 | return ( 19 | <Button 20 | type="primary" 21 | key={name} 22 | {...$item} 23 | /* replace-start */ 24 | data-edit="link,text" 25 | /* replace-end */ 26 | > 27 | {/* replace-start-value = item.children */ 28 | React.createElement('span', { dangerouslySetInnerHTML: { __html: item.children } }) 29 | /* replace-end-value */} 30 | </Button> 31 | ); 32 | } 33 | /* replace-start */ 34 | if (texty) { 35 | $item['data-edit'] = 'texty'; 36 | } 37 | /* replace-end */ 38 | return ( 39 | <div 40 | key={name} 41 | {...$item} 42 | > 43 | { 44 | texty 45 | ? ( 46 | <Texty type="mask-bottom"> 47 | {item.children} 48 | </Texty> 49 | ) 50 | : ( 51 | /* replace-start-value = item.children */ 52 | React.createElement('span', { dangerouslySetInnerHTML: { __html: item.children } }) 53 | /* replace-end-value */ 54 | ) 55 | } 56 | </div> 57 | ); 58 | }); 59 | return ( 60 | <div 61 | {...currentProps} 62 | {...dataSource.wrapper} 63 | > 64 | <QueueAnim 65 | key="QueueAnim" 66 | type={['bottom', 'top']} 67 | delay={200} 68 | {...dataSource.textWrapper} 69 | > 70 | {children} 71 | </QueueAnim> 72 | </div> 73 | ); 74 | } 75 | } 76 | export default Banner; 77 | -------------------------------------------------------------------------------- /site/templates/template/element/Banner3/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | wrapper: { 12 | className: 'banner3', 13 | }, 14 | textWrapper: { 15 | className: 'banner3-text-wrapper', 16 | children: [ 17 | { name: 'nameEn', className: 'banner3-name-en', children: 'Seeking Experience & Engineering Conference' }, 18 | { name: 'slogan', className: 'banner3-slogan', children: '首届蚂蚁金服体验科技大会', texty: true }, 19 | { name: 'name', className: 'banner3-name', children: '探索极致用户体验与最佳工程实践探索' }, 20 | { name: 'button', className: 'banner3-button', children: '立即报名' }, 21 | { name: 'time', className: 'banner3-time', children: '2018.01.06 / 中国·杭州' }, 22 | ], 23 | }, 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /site/templates/template/element/Banner4/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import QueueAnim from 'rc-queue-anim'; 3 | import TweenOne from 'rc-tween-one'; 4 | /* replace-start-value = import { getChildrenToRender } from './utils'; */ 5 | import { getChildrenToRender } from '../../utils'; 6 | /* replace-end-value */ 7 | /* replace-start */ 8 | import './index.less'; 9 | /* replace-end */ 10 | class Banner4 extends React.PureComponent { 11 | render() { 12 | const { ...tagProps } = this.props; 13 | const { dataSource } = tagProps; 14 | delete tagProps.dataSource; 15 | delete tagProps.isMobile; 16 | const animType = { 17 | queue: 'bottom', 18 | one: { 19 | y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad', 20 | }, 21 | }; 22 | return ( 23 | <div 24 | {...tagProps} 25 | {...dataSource.wrapper} 26 | > 27 | <div 28 | {...dataSource.page} 29 | > 30 | <QueueAnim 31 | key="text" 32 | type={animType.queue} 33 | leaveReverse 34 | ease={['easeOutQuad', 'easeInQuad']} 35 | {...dataSource.childWrapper} 36 | componentProps={{ md: dataSource.childWrapper.md, xs: dataSource.childWrapper.xs }} 37 | /* replace-start */ 38 | data-edit="childWrapper" 39 | /* replace-end */ 40 | > 41 | { 42 | dataSource.childWrapper.children.map(getChildrenToRender) 43 | } 44 | </QueueAnim> 45 | <TweenOne 46 | animation={animType.one} 47 | key="title" 48 | {...dataSource.image} 49 | > 50 | <img src={dataSource.image.children} width="100%" alt="img" /> 51 | </TweenOne> 52 | </div> 53 | </div> 54 | ); 55 | } 56 | } 57 | export default Banner4; 58 | -------------------------------------------------------------------------------- /site/templates/template/element/Banner4/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @banner4: banner4; 3 | 4 | .@{banner4} { 5 | // 如果在第一屏且导航位置为 relative, 一屏为 height: calc(~"100vh - 64px"); 6 | width: 100%; 7 | height: 100vh; 8 | position: relative; 9 | text-align: center; 10 | background: #4b5564; 11 | overflow: hidden; 12 | 13 | & &-page { 14 | padding: 1px 0 0; 15 | } 16 | 17 | &-title-wrapper { 18 | margin-top: 64px; 19 | } 20 | 21 | &-title { 22 | color: #fff; 23 | font-size: 48px; 24 | line-height: 1.5; 25 | } 26 | 27 | &-content { 28 | font-size: 14px; 29 | line-height: 20px; 30 | color: #fff; 31 | margin: 8px auto 16px; 32 | } 33 | 34 | &-image, &-image-mobile { 35 | width: 80%; 36 | max-height: 60%; 37 | overflow: hidden; 38 | margin: auto; 39 | position: absolute; 40 | bottom: 0; 41 | left: 0; 42 | right: 0; 43 | } 44 | } 45 | 46 | @media screen and (max-width: 767px) { 47 | .@{banner4} { 48 | height: 500px; 49 | & &-page.home-page { 50 | padding-top: 1px; 51 | padding-bottom: 0; 52 | } 53 | 54 | &-title-wrapper { 55 | margin-top: 96px; 56 | } 57 | &-title { 58 | font-size: 3em; 59 | } 60 | &-image { 61 | width: 100%; 62 | padding: 0 24px; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /site/templates/template/element/Banner4/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | wrapper: { 12 | className: 'home-page-wrapper banner4', 13 | }, 14 | page: { 15 | className: 'home-page banner4-page', 16 | }, 17 | childWrapper: { 18 | className: 'banner4-title-wrapper', 19 | children: [ 20 | { 21 | name: 'title', 22 | children: 'Ant Design Pro', 23 | className: 'banner4-title', 24 | }, 25 | { 26 | name: 'content', 27 | className: 'banner4-content', 28 | children: '开箱即用的中台前端/设计解决方案', 29 | }, 30 | { 31 | name: 'button', 32 | children: { 33 | href: '#', 34 | type: 'primary', 35 | children: '开始使用', 36 | }, 37 | }, 38 | ], 39 | }, 40 | image: { 41 | className: 'banner4-image', 42 | children: 'https://gw.alipayobjects.com/mdn/rms/afts/img/A*k3InRLiZDk4AAAAAAAAAAABjARQnAQ', 43 | }, 44 | }, 45 | }; 46 | -------------------------------------------------------------------------------- /site/templates/template/element/Banner5/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import QueueAnim from 'rc-queue-anim'; 3 | import TweenOne from 'rc-tween-one'; 4 | /* replace-start-value = import { getChildrenToRender } from './utils'; */ 5 | import { getChildrenToRender } from '../../utils'; 6 | /* replace-end-value */ 7 | /* replace-start */ 8 | import './index.less'; 9 | /* replace-end */ 10 | class Banner5 extends React.PureComponent { 11 | render() { 12 | const { ...tagProps } = this.props; 13 | const { dataSource } = tagProps; 14 | delete tagProps.dataSource; 15 | delete tagProps.isMobile; 16 | const animType = { 17 | queue: 'bottom', 18 | one: { 19 | y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad', 20 | }, 21 | }; 22 | return ( 23 | <div 24 | {...tagProps} 25 | {...dataSource.wrapper} 26 | > 27 | <div 28 | {...dataSource.page} 29 | > 30 | <QueueAnim 31 | key="text" 32 | type={animType.queue} 33 | leaveReverse 34 | ease={['easeOutQuad', 'easeInQuad']} 35 | {...dataSource.childWrapper} 36 | componentProps={{ md: dataSource.childWrapper.md, xs: dataSource.childWrapper.xs }} 37 | /* replace-start */ 38 | data-edit="childWrapper" 39 | /* replace-end */ 40 | > 41 | { 42 | dataSource.childWrapper.children.map(getChildrenToRender) 43 | } 44 | </QueueAnim> 45 | <TweenOne 46 | animation={animType.one} 47 | key="title" 48 | {...dataSource.image} 49 | > 50 | <img src={dataSource.image.children} width="100%" alt="img" /> 51 | </TweenOne> 52 | </div> 53 | </div> 54 | ); 55 | } 56 | } 57 | export default Banner5; 58 | -------------------------------------------------------------------------------- /site/templates/template/element/Banner5/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | wrapper: { 12 | className: 'home-page-wrapper banner5', 13 | }, 14 | page: { 15 | className: 'home-page banner5-page', 16 | }, 17 | childWrapper: { 18 | className: 'banner5-title-wrapper', 19 | children: [ 20 | { 21 | name: 'title', 22 | children: '产品名', 23 | className: 'banner5-title', 24 | }, 25 | { 26 | name: 'explain', 27 | className: 'banner5-explain', 28 | children: '产品标语介绍', 29 | }, 30 | { 31 | name: 'content', 32 | className: 'banner5-content', 33 | children: '产品的详细说明,如是什么东西之类的文字', 34 | }, 35 | { 36 | name: 'button', 37 | className: 'banner5-button-wrapper', 38 | children: { 39 | href: '#', 40 | className: 'banner5-button', 41 | type: 'primary', 42 | children: '开始使用', 43 | }, 44 | }, 45 | ], 46 | }, 47 | image: { 48 | className: 'banner5-image', 49 | children: 'https://gw.alipayobjects.com/mdn/rms_ae7ad9/afts/img/A*-wAhRYnWQscAAAAAAAAAAABkARQnAQ', 50 | }, 51 | }, 52 | }; 53 | -------------------------------------------------------------------------------- /site/templates/template/element/Content0/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import QueueAnim from 'rc-queue-anim'; 3 | import { Row, Col } from 'antd'; 4 | import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; 5 | /* replace-start-value = import { getChildrenToRender } from './utils'; */ 6 | import { getChildrenToRender } from '../../utils'; 7 | /* replace-end-value */ 8 | /* replace-start */ 9 | import './index.less'; 10 | /* replace-end */ 11 | 12 | class Content extends React.PureComponent { 13 | render() { 14 | const { dataSource, isMobile, ...props } = this.props; 15 | const { wrapper, titleWrapper, page, OverPack: overPackData, childWrapper } = dataSource; 16 | return ( 17 | <div 18 | {...props} 19 | {...wrapper} 20 | > 21 | <div {...page}> 22 | <div 23 | {...titleWrapper} 24 | /* replace-start */ 25 | data-edit="titleWrapper" 26 | /* replace-end */ 27 | > 28 | { 29 | titleWrapper.children.map(getChildrenToRender) 30 | } 31 | </div> 32 | <OverPack {...overPackData}> 33 | <QueueAnim 34 | type="bottom" 35 | key="block" 36 | leaveReverse 37 | component={Row} 38 | componentProps={childWrapper} 39 | /* replace-start */ 40 | data-edit="Row" 41 | /* replace-end */ 42 | > 43 | {childWrapper.children.map((block, i) => { 44 | const { children: item, ...blockProps } = block; 45 | return ( 46 | <Col 47 | key={i.toString()} 48 | {...blockProps} 49 | /* replace-start */ 50 | data-edit="Col" 51 | /* replace-end */ 52 | > 53 | <div 54 | {...item} 55 | /* replace-start */ 56 | data-edit="childWrapper" 57 | /* replace-end */ 58 | > 59 | {item.children.map(getChildrenToRender)} 60 | </div> 61 | </Col> 62 | ); 63 | })} 64 | </QueueAnim> 65 | </OverPack> 66 | </div> 67 | </div> 68 | ); 69 | } 70 | } 71 | 72 | export default Content; 73 | -------------------------------------------------------------------------------- /site/templates/template/element/Content0/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content0: content0; 3 | 4 | .@{content0}-wrapper { 5 | min-height: 446px; 6 | overflow: hidden; 7 | 8 | .@{content0} { 9 | height: 100%; 10 | padding: 64px 24px; 11 | 12 | >.title-wrapper { 13 | margin: 0 auto 48px; 14 | } 15 | 16 | &-block { 17 | padding: 0 4%; 18 | display: inline-block; 19 | text-align: center; 20 | min-height: 200px; 21 | margin-bottom: 24px; 22 | img { 23 | width: 100%; 24 | } 25 | 26 | &-wrapper { 27 | position: relative; 28 | height: 100%; 29 | top: 25%; 30 | padding: 20px 0; 31 | } 32 | 33 | &.queue-anim-leaving { 34 | position: relative !important; 35 | } 36 | 37 | &-icon { 38 | width: 100px; 39 | height: 100px; 40 | margin: auto; 41 | } 42 | 43 | &-title { 44 | line-height: 32px; 45 | margin: 10px auto; 46 | font-size: 24px; 47 | } 48 | } 49 | } 50 | } 51 | 52 | @media screen and (max-width: 767px) { 53 | .@{content0}-wrapper { 54 | min-height: 880px; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /site/templates/template/element/Content1/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content1: content1; 3 | .@{content1}-wrapper { 4 | height: 360px; 5 | .@{content1} { 6 | height: 100%; 7 | padding: 0 24px; 8 | &-img { 9 | height: 100%; 10 | transform-origin: top; 11 | padding: 0 32px; 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | span { 16 | display: block; 17 | width: 250px; 18 | img { 19 | display: block; 20 | } 21 | } 22 | } 23 | &-text { 24 | padding: 0 32px; 25 | height: 100%; 26 | .@{content1}-content, 27 | .@{content1}-title { 28 | position: relative !important; 29 | } 30 | .@{content1}-title { 31 | font-size: 32px; 32 | font-weight: normal; 33 | color: #404040; 34 | margin-top: 120px; 35 | } 36 | .content { 37 | margin-top: 20px; 38 | } 39 | } 40 | } 41 | } 42 | 43 | @media screen and (max-width: 767px) { 44 | .@{content1}-wrapper { 45 | height: 600px; 46 | .@{content1} { 47 | &-img { 48 | height: 200px; 49 | padding: 0; 50 | text-align: center; 51 | margin-top: 64px; 52 | span { 53 | display: inline-block; 54 | width: 180px; 55 | height: 200px; 56 | line-height: 200px; 57 | margin: auto; 58 | } 59 | } 60 | &-text { 61 | height: auto; 62 | margin-bottom: 20px; 63 | text-align: center; 64 | padding: 0; 65 | .@{content1}-content, 66 | .@{content1}-title { 67 | width: 100%; 68 | top: auto; 69 | } 70 | .@{content1}-title { 71 | margin: 32px auto 16px; 72 | font-size: 24px; 73 | } 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /site/templates/template/element/Content1/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | wrapper: { 12 | className: 'home-page-wrapper content1-wrapper', 13 | }, 14 | OverPack: { 15 | className: 'home-page content1', 16 | playScale: 0.3, 17 | }, 18 | imgWrapper: { 19 | className: 'content1-img', 20 | md: 10, 21 | xs: 24, 22 | }, 23 | img: { 24 | children: 'https://zos.alipayobjects.com/rmsportal/nLzbeGQLPyBJoli.png', 25 | }, 26 | textWrapper: { 27 | className: 'content1-text', 28 | md: 14, 29 | xs: 24, 30 | }, 31 | title: { 32 | className: 'content1-title', 33 | children: '企业资源管理', 34 | }, 35 | content: { 36 | className: 'content1-content', 37 | children: '云资源集中编排、弹性伸缩、持续发布和部署,高可用及容灾。' 38 | + '云资源集中编排、弹性伸缩、持续发布和部署,高可用及容灾。' 39 | + '云资源集中编排、弹性伸缩、持续发布和部署,高可用及容灾。', 40 | }, 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /site/templates/template/element/Content10/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import QueueAnim from 'rc-queue-anim'; 3 | /* replace-start */ 4 | import './index.less'; 5 | /* replace-end */ 6 | 7 | class Content10 extends React.PureComponent { 8 | constructor(props) { 9 | super(props); 10 | this.state = { 11 | showInfo: props.isMobile, 12 | }; 13 | } 14 | 15 | onClick = () => { 16 | window.open(this.props.dataSource.Content.children.url.children); 17 | } 18 | 19 | markerEnter = () => { 20 | this.setState({ 21 | showInfo: true, 22 | }); 23 | } 24 | 25 | markerLeave = () => { 26 | this.setState({ 27 | showInfo: false, 28 | }); 29 | } 30 | 31 | render() { 32 | const { ...props } = this.props; 33 | const { dataSource } = props; 34 | delete props.dataSource; 35 | delete props.isMobile; 36 | return ( 37 | <div 38 | {...props} 39 | {...dataSource.wrapper} 40 | 41 | > 42 | <div 43 | {...dataSource.Content} 44 | onMouseEnter={this.markerEnter} 45 | onMouseLeave={this.markerLeave} 46 | onClick={this.onClick} 47 | onTouchEnd={this.onClick} 48 | /* replace-start */ 49 | data-edit="Content" 50 | /* replace-end */ 51 | > 52 | <div 53 | {...dataSource.Content.children.icon} 54 | /* replace-start */ 55 | data-edit="Content,image" 56 | /* replace-end */ 57 | > 58 | <img src={dataSource.Content.children.icon.children} alt="img" /> 59 | </div> 60 | <div 61 | {...dataSource.Content.children.iconShadow} 62 | /* replace-start */ 63 | data-edit="Content,image" 64 | /* replace-end */ 65 | > 66 | <img src={dataSource.Content.children.iconShadow.children} alt="img" /> 67 | </div> 68 | </div> 69 | <QueueAnim type="scale"> 70 | {this.state.showInfo && ( 71 | <div className="map-tip" key="map"> 72 | <h2>{dataSource.Content.children.title.children}</h2> 73 | <p>{dataSource.Content.children.content.children}</p> 74 | </div> 75 | )} 76 | </QueueAnim> 77 | </div> 78 | ); 79 | } 80 | } 81 | 82 | export default Content10; 83 | -------------------------------------------------------------------------------- /site/templates/template/element/Content10/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content10: content10; 3 | .@{content10}-wrapper { 4 | height: 480px; 5 | background: url(https://gw.alipayobjects.com/os/s/prod/seeconf/c66ebea962cdf544926ca5a472dea5ea.jpg) no-repeat 50%; 6 | background-size: cover; 7 | position: relative; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | .icon-wrapper { 12 | text-align: center; 13 | position: relative; 14 | cursor: pointer; 15 | img { 16 | display: block; 17 | } 18 | } 19 | .icon { 20 | position: relative; 21 | z-index: 1; 22 | animation: BeatAnim 2s ease-in-out infinite; 23 | } 24 | .icon-shadow { 25 | display: inline-block; 26 | position: relative; 27 | top: -12px; 28 | z-index: 0; 29 | animation: ScaleAnim 2s ease-in-out infinite; 30 | transform-origin: 50%; 31 | } 32 | .map-tip { 33 | position: absolute; 34 | width: 330px; 35 | background: #fff; 36 | padding: 16px; 37 | border-radius: 4px; 38 | box-shadow: 0 2px 8px rgba(13, 26, 38, 0.12); 39 | left: 50%; 40 | top: 50%; 41 | margin-left: 30px; 42 | margin-top: -60px; 43 | font-size: 14px; 44 | z-index: 10; 45 | transform-origin: 0 50%; 46 | text-align: left; 47 | h2 { 48 | font-size: 16px; 49 | color: #0d1a26; 50 | margin-bottom: 8px; 51 | } 52 | } 53 | } 54 | 55 | @media screen and (max-width: 767px) { 56 | .@{content10}-wrapper { 57 | padding-bottom: 0; 58 | } 59 | } 60 | 61 | @keyframes BeatAnim { 62 | 0%, 63 | 25%, 64 | 35%, 65 | 45% { 66 | transform: translateY(0); 67 | } 68 | 15% { 69 | transform: translateY(-30px); 70 | } 71 | 30% { 72 | transform: translateY(-15px); 73 | } 74 | 40% { 75 | transform: translateY(-7px); 76 | } 77 | } 78 | 79 | @keyframes ScaleAnim { 80 | 0%, 81 | 25%, 82 | 35%, 83 | 45% { 84 | transform: scale(1); 85 | } 86 | 15% { 87 | transform: scale(0.5); 88 | } 89 | 30% { 90 | transform: scale(0.7); 91 | } 92 | 40% { 93 | transform: scale(0.9); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /site/templates/template/element/Content10/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | import less from '!raw-loader!./index.less'; 3 | import templateStr from '!raw-loader!./index'; 4 | 5 | export default { 6 | component, 7 | templateStr, 8 | less, 9 | dataSource: { 10 | wrapper: { 11 | className: 'home-page-wrapper content10-wrapper', 12 | }, 13 | Content: { 14 | className: 'icon-wrapper', 15 | children: { 16 | icon: { 17 | className: 'icon', 18 | children: 'https://gw.alipayobjects.com/zos/rmsportal/zIUVomgdcKEKcnnQdOzw.svg', 19 | name: '主要图标', 20 | }, 21 | iconShadow: { 22 | className: 'icon-shadow', 23 | children: 'https://gw.alipayobjects.com/zos/rmsportal/WIePwurYppfVvDNASZRN.svg', 24 | name: '图标影阴', 25 | }, 26 | url: { 27 | children: 'https://gaode.com/place/B0FFH3KPBX', 28 | name: '跳转地址', 29 | }, 30 | title: { 31 | children: '大会地址', 32 | name: '弹框标题', 33 | }, 34 | content: { 35 | children: '蚂蚁 Z 空间 浙江省杭州市西湖区西溪路556号', 36 | name: '弹框内容', 37 | }, 38 | }, 39 | }, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /site/templates/template/element/Content11/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; 3 | import QueueAnim from 'rc-queue-anim'; 4 | import TweenOne from 'rc-tween-one'; 5 | import { Button } from 'antd'; 6 | /* replace-start-value = import { getChildrenToRender } from './utils'; */ 7 | import { getChildrenToRender } from '../../utils'; 8 | /* replace-end-value */ 9 | /* replace-start */ 10 | import './index.less'; 11 | /* replace-end */ 12 | 13 | class Content11 extends React.PureComponent { 14 | render() { 15 | const { ...props } = this.props; 16 | const { dataSource } = props; 17 | delete props.dataSource; 18 | delete props.isMobile; 19 | return ( 20 | <OverPack 21 | {...props} 22 | {...dataSource.OverPack} 23 | > 24 | <QueueAnim 25 | type="bottom" 26 | leaveReverse 27 | key="page" 28 | delay={[0, 100]} 29 | {...dataSource.titleWrapper} 30 | /* replace-start */ 31 | data-edit="titleWrapper" 32 | /* replace-end */ 33 | > 34 | { 35 | dataSource.titleWrapper.children.map(getChildrenToRender) 36 | } 37 | </QueueAnim> 38 | <TweenOne 39 | key="button" 40 | style={{ textAlign: 'center' }} 41 | {...dataSource.button} 42 | animation={{ y: 30, opacity: 0, type: 'from', delay: 300 }} 43 | > 44 | <Button 45 | {...dataSource.button.children.a} 46 | /* replace-start */ 47 | data-edit="link,text" 48 | /* replace-end */ 49 | > 50 | 51 | { 52 | /* replace-start-value = dataSource.button.children.a.children */ 53 | React.createElement('span', { dangerouslySetInnerHTML: { __html: dataSource.button.children.a.children } }) 54 | /* replace-end-value */ 55 | } 56 | </Button> 57 | </TweenOne> 58 | </OverPack> 59 | ); 60 | } 61 | } 62 | 63 | export default Content11; 64 | -------------------------------------------------------------------------------- /site/templates/template/element/Content11/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content11: content11; 3 | .@{content11}-wrapper { 4 | height: 480px; 5 | background: url("https://gw.alipayobjects.com/zos/rmsportal/ZsWYzLOItgeaWDSsXdZd.svg") no-repeat bottom; 6 | background-size: cover; 7 | background-size: 100%; 8 | margin: 0 auto; 9 | overflow: hidden; 10 | padding-top: 96px; 11 | &.home-page-wrapper { 12 | .title-wrapper { 13 | margin-bottom: 32px; 14 | } 15 | } 16 | .button { 17 | box-shadow: 0 8px 16px #0554b7; 18 | background: linear-gradient(to right, #05cbff, #1e5aff) !important; 19 | height: 42px; 20 | line-height: 42px; 21 | font-size: 14px; 22 | border: 0; 23 | border-radius: 21px; 24 | color: #fff; 25 | width: 128px; 26 | padding: 0 15px; 27 | display: inline-block; 28 | transition: transform .3s, box-shadow .3s; 29 | &:hover { 30 | transform: translateY(-4px); 31 | box-shadow: 0 12px 20px #0554b7; 32 | } 33 | &:active { 34 | transform: translateY(4px); 35 | box-shadow: 0 4px 8px #0554b7; 36 | } 37 | } 38 | .title-content { 39 | line-height: 32px; 40 | } 41 | } 42 | 43 | @media screen and (max-width: 767px) { 44 | .@{content11}-wrapper { 45 | padding-bottom: 0; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /site/templates/template/element/Content11/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | import less from '!raw-loader!./index.less'; 3 | import templateStr from '!raw-loader!./index'; 4 | 5 | export default { 6 | component, 7 | templateStr, 8 | less, 9 | dataSource: { 10 | OverPack: { 11 | className: 'home-page-wrapper content11-wrapper', 12 | playScale: 0.3, 13 | }, 14 | titleWrapper: { 15 | className: 'title-wrapper', 16 | children: [ 17 | { 18 | name: 'image', 19 | children: 'https://gw.alipayobjects.com/zos/rmsportal/PiqyziYmvbgAudYfhuBr.svg', 20 | className: 'title-image', 21 | }, 22 | { 23 | name: 'title', 24 | children: '丰富的特色展台', 25 | className: 'title-h1', 26 | }, 27 | { 28 | name: 'content', 29 | children: '特色展台包括 Ant Design 、AntV、AntG、Egg 等明星产品,更有产品专家', 30 | className: 'title-content', 31 | }, 32 | { 33 | name: 'content2', 34 | children: '现场问诊,为你答疑解难', 35 | className: 'title-content', 36 | }, 37 | ], 38 | }, 39 | button: { 40 | className: '', 41 | children: { 42 | a: { 43 | className: 'button', 44 | href: '#', 45 | children: '立即报名', 46 | }, 47 | }, 48 | }, 49 | }, 50 | }; 51 | -------------------------------------------------------------------------------- /site/templates/template/element/Content12/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content12: content12; 3 | .@{content12}-wrapper { 4 | background-color: #fafafa; 5 | min-height: 470px; 6 | .@{content12} { 7 | padding: 64px 24px; 8 | >p { 9 | text-align: center; 10 | } 11 | } 12 | .img-wrapper { 13 | margin: 0 auto; 14 | left: 0; 15 | right: 0; 16 | .block { 17 | margin-bottom: 40px; 18 | .block-content { 19 | display: flex; 20 | border-radius: 4px; 21 | text-align: center; 22 | position: relative; 23 | overflow: hidden; 24 | border: none; 25 | height: 64px; 26 | align-items: center; 27 | transition: box-shadow .3s @ease-out, transform .3s @ease-out; 28 | & > span { 29 | width: 100%; 30 | display: block; 31 | } 32 | } 33 | } 34 | } 35 | } 36 | 37 | @media screen and (max-width: 767px) { 38 | .@{content12}-wrapper { 39 | overflow: hidden; 40 | .@{content12} { 41 | ul { 42 | li { 43 | display: block; 44 | width: 100%; 45 | padding: 2%; 46 | span { 47 | height: 168px; 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /site/templates/template/element/Content13/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; 3 | import QueueAnim from 'rc-queue-anim'; 4 | /* replace-start-value = import { getChildrenToRender } from './utils'; */ 5 | import { getChildrenToRender } from '../../utils'; 6 | /* replace-end-value */ 7 | /* replace-start */ 8 | import './index.less'; 9 | /* replace-end */ 10 | 11 | class Content13 extends React.PureComponent { 12 | render() { 13 | const { ...props } = this.props; 14 | const { dataSource } = props; 15 | delete props.dataSource; 16 | delete props.isMobile; 17 | return ( 18 | <OverPack 19 | {...props} 20 | {...dataSource.OverPack} 21 | > 22 | <QueueAnim 23 | type="bottom" 24 | leaveReverse 25 | key="page" 26 | delay={[0, 100]} 27 | {...dataSource.titleWrapper} 28 | /* replace-start */ 29 | data-edit="titleWrapper" 30 | /* replace-end */ 31 | > 32 | { 33 | dataSource.titleWrapper.children.map(getChildrenToRender) 34 | } 35 | </QueueAnim> 36 | </OverPack> 37 | ); 38 | } 39 | } 40 | 41 | export default Content13; 42 | -------------------------------------------------------------------------------- /site/templates/template/element/Content13/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content13: content13; 3 | .@{content13}-wrapper { 4 | min-height: 380px; 5 | background: url("https://gw.alipayobjects.com/zos/rmsportal/ZsWYzLOItgeaWDSsXdZd.svg") no-repeat bottom; 6 | background-size: cover; 7 | background-size: 100%; 8 | margin: 0 auto; 9 | overflow: hidden; 10 | padding: 96px 0; 11 | &.home-page-wrapper { 12 | .title-wrapper { 13 | margin-bottom: 32px; 14 | } 15 | } 16 | .title-content { 17 | line-height: 32px; 18 | } 19 | } 20 | 21 | @media screen and (max-width: 767px) { 22 | .@{content13}-wrapper { 23 | padding-bottom: 0; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /site/templates/template/element/Content13/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | OverPack: { 12 | className: 'home-page-wrapper content13-wrapper', 13 | playScale: 0.3, 14 | }, 15 | titleWrapper: { 16 | className: 'title-wrapper', 17 | children: [ 18 | { 19 | name: 'image', 20 | children: 'https://gw.alipayobjects.com/zos/rmsportal/PiqyziYmvbgAudYfhuBr.svg', 21 | className: 'title-image', 22 | }, 23 | { 24 | name: 'title', 25 | children: '丰富的特色展台', 26 | className: 'title-h1', 27 | }, 28 | { 29 | name: 'content', 30 | children: '特色展台包括 Ant Design 、AntV、AntG、Egg 等明星产品,更有产品专家', 31 | className: 'title-content', 32 | }, 33 | { 34 | name: 'content2', 35 | children: '现场问诊,为你答疑解难', 36 | className: 'title-content', 37 | }, 38 | ], 39 | }, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /site/templates/template/element/Content2/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content2: content2; 3 | .@{content2}-wrapper { 4 | height: 360px; 5 | .@{content2} { 6 | height: 100%; 7 | padding: 0 24px; 8 | &-img { 9 | height: 100%; 10 | transform-origin: top; 11 | padding: 0 32px; 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | span { 16 | display: block; 17 | width: 250px; 18 | img { 19 | display: block; 20 | } 21 | } 22 | } 23 | &-text { 24 | padding: 0 32px; 25 | height: 100%; 26 | .@{content2}-content, 27 | .@{content2}-title { 28 | position: relative !important; 29 | } 30 | .@{content2}-title { 31 | font-size: 32px; 32 | font-weight: normal; 33 | color: #404040; 34 | margin-top: 120px; 35 | } 36 | .@{content2}-content { 37 | margin-top: 20px; 38 | } 39 | } 40 | } 41 | } 42 | 43 | @media screen and (max-width: 767px) { 44 | .@{content2}-wrapper { 45 | height: 600px; 46 | .@{content2} { 47 | &-img { 48 | height: 200px; 49 | padding: 0; 50 | text-align: center; 51 | margin-top: 64px; 52 | span { 53 | display: inline-block; 54 | width: 180px; 55 | height: 200px; 56 | line-height: 200px; 57 | margin: auto; 58 | } 59 | } 60 | &-text { 61 | height: auto; 62 | margin-bottom: 20px; 63 | text-align: center; 64 | padding: 0; 65 | .@{content2}-content, 66 | .@{content2}-title { 67 | width: 100%; 68 | top: auto; 69 | } 70 | .@{content2}-title { 71 | margin: 32px auto 16px; 72 | font-size: 24px; 73 | } 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /site/templates/template/element/Content2/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | less, 9 | templateStr, 10 | dataSource: { 11 | wrapper: { 12 | className: 'home-page-wrapper content2-wrapper', 13 | }, 14 | OverPack: { 15 | className: 'home-page content2', 16 | playScale: 0.3, 17 | }, 18 | imgWrapper: { 19 | className: 'content2-img', 20 | md: 10, 21 | xs: 24, 22 | }, 23 | img: { 24 | children: 'https://zos.alipayobjects.com/rmsportal/tvQTfCupGUFKSfQ.png', 25 | }, 26 | textWrapper: { 27 | className: 'content2-text', 28 | md: 14, 29 | xs: 24, 30 | }, 31 | title: { 32 | className: 'content2-title', 33 | children: '分布式中间件', 34 | }, 35 | content: { 36 | className: 'content2-content', 37 | children: '金融级联机交易处理中间件,大规模分布式计算机,数万笔/秒级并发能力,严格保证交易数据统一性。' 38 | + '金融级联机交易处理中间件,大规模分布式计算机,数万笔/秒级并发能力,严格保证交易数据统一性。', 39 | }, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /site/templates/template/element/Content3/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content3: content3; 3 | .@{content3}-wrapper { 4 | min-height: 764px; 5 | .@{content3} { 6 | height: 100%; 7 | overflow: hidden; 8 | & .title-content { 9 | text-align: center; 10 | } 11 | &-block-wrapper { 12 | position: relative; 13 | .@{content3}-block { 14 | display: inline-block; 15 | padding: 48px 24px; 16 | vertical-align: top; 17 | .@{content3}-icon { 18 | display: inline-block; 19 | width: 15%; 20 | vertical-align: top; 21 | } 22 | .@{content3}-text { 23 | width: 85%; 24 | display: inline-block; 25 | padding-left: 8%; 26 | } 27 | &.clear-both { 28 | clear: both; 29 | } 30 | } 31 | } 32 | } 33 | } 34 | 35 | @media screen and (max-width: 767px) { 36 | .@{content3}-wrapper { 37 | min-height: 1080px; 38 | .@{content3} { 39 | &-block-wrapper { 40 | margin: 20px auto; 41 | height: auto; 42 | .@{content3}-block { 43 | .@{content3}-title { 44 | font-size: 20px; 45 | } 46 | &.queue-anim-leaving { 47 | position: relative !important; 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /site/templates/template/element/Content4/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TweenOne from 'rc-tween-one'; 3 | import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; 4 | import VideoPlay from 'react-sublime-video'; 5 | /* replace-start-value = import { getChildrenToRender } from './utils'; */ 6 | import { getChildrenToRender } from '../../utils'; 7 | /* replace-end-value */ 8 | /* replace-start */ 9 | import './index.less'; 10 | /* replace-end */ 11 | 12 | function Content4(props) { 13 | const { ...tagProps } = props; 14 | const { dataSource, isMobile } = tagProps; 15 | delete tagProps.dataSource; 16 | delete tagProps.isMobile; 17 | const animation = { 18 | y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad', 19 | }; 20 | const videoChildren = dataSource.video.children.video; 21 | const videoNameArray = videoChildren.split('.'); 22 | const type = videoNameArray[videoNameArray.length - 1]; 23 | return ( 24 | <div 25 | {...tagProps} 26 | {...dataSource.wrapper} 27 | > 28 | <div 29 | {...dataSource.page} 30 | > 31 | <div 32 | key="title" 33 | {...dataSource.titleWrapper} 34 | /* replace-start */ 35 | data-edit="titleWrapper" 36 | /* replace-end */ 37 | > 38 | { 39 | dataSource.titleWrapper.children.map(getChildrenToRender) 40 | } 41 | </div> 42 | <OverPack {...dataSource.OverPack}> 43 | <TweenOne 44 | key="video" 45 | animation={{ ...animation, delay: 300 }} 46 | {...dataSource.video} 47 | /* replace-start */ 48 | data-edit="video" 49 | /* replace-end */ 50 | > 51 | {isMobile 52 | ? ( 53 | <video width="100%" loop controls poster={dataSource.video.children.image}> 54 | <source src={videoChildren} type={`video/${type}`} /> 55 | <track kind="captions" /> 56 | </video> 57 | ) 58 | : ( 59 | <VideoPlay loop width="100%" poster={dataSource.video.children.image}> 60 | <source src={videoChildren} type={`video/${type}`} /> 61 | </VideoPlay> 62 | )} 63 | </TweenOne> 64 | </OverPack> 65 | </div> 66 | </div> 67 | ); 68 | } 69 | 70 | export default Content4; 71 | -------------------------------------------------------------------------------- /site/templates/template/element/Content4/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content4: content4; 3 | .@{content4}-wrapper { 4 | min-height: 720px; 5 | background: #fafafa; 6 | .@{content4} { 7 | height: 100%; 8 | overflow: hidden; 9 | &-video { 10 | border-radius: 4px; 11 | overflow: hidden; 12 | max-width: 800px; 13 | margin: auto; 14 | background: #fff; 15 | box-shadow: 0 4px 8px rgba(0, 0, 0, .15); 16 | video { 17 | display: block; 18 | margin: auto; 19 | } 20 | } 21 | } 22 | } 23 | 24 | @media screen and (max-width: 767px) { 25 | .@{content4}-wrapper { 26 | min-height: 350px; 27 | .@{content4} { 28 | overflow: hidden; 29 | width: 90%; 30 | margin: auto; 31 | &-video { 32 | top: 15%; 33 | background: url("https://zos.alipayobjects.com/rmsportal/HZgzhugQZkqUwBVeNyfz.jpg") no-repeat center; 34 | background-size: cover; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /site/templates/template/element/Content4/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | wrapper: { 12 | className: 'home-page-wrapper content4-wrapper', 13 | }, 14 | page: { 15 | className: 'home-page content4', 16 | }, 17 | OverPack: { 18 | playScale: 0.3, 19 | className: '', 20 | }, 21 | titleWrapper: { 22 | className: 'title-wrapper', 23 | children: [ 24 | { 25 | name: 'title', 26 | children: '蚂蚁金融云提供专业的服务', 27 | className: 'title-h1', 28 | }, 29 | { 30 | name: 'content', 31 | className: 'title-content content4-title-content', 32 | children: '科技想象力,金融创造力', 33 | }, 34 | ], 35 | }, 36 | video: { 37 | className: 'content4-video', 38 | 39 | children: { 40 | video: 'https://os.alipayobjects.com/rmsportal/EejaUGsyExkXyXr.mp4', 41 | image: 'https://zos.alipayobjects.com/rmsportal/HZgzhugQZkqUwBVeNyfz.jpg', 42 | }, 43 | }, 44 | }, 45 | }; 46 | -------------------------------------------------------------------------------- /site/templates/template/element/Content5/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content5: content5; 3 | .@{content5}-wrapper { 4 | background-color: #fafafa; 5 | min-height: 720px; 6 | .@{content5} { 7 | >p { 8 | text-align: center; 9 | } 10 | &-img-wrapper { 11 | margin: 0 auto; 12 | left: 0; 13 | right: 0; 14 | .block { 15 | margin-bottom: 24px; 16 | .content5-block-content { 17 | display: block; 18 | background: #fff; 19 | border-radius: 4px; 20 | padding: 10px; 21 | text-align: center; 22 | position: relative; 23 | overflow: hidden; 24 | .page-pro(); 25 | border: none; 26 | color: @text-color; 27 | transition: box-shadow .3s @ease-out, transform .3s @ease-out; 28 | & > span { 29 | width: 100%; 30 | height: 160px; 31 | display: block; 32 | background: @line-color; 33 | padding: 5%; 34 | } 35 | & p { 36 | width: 100%; 37 | line-height: 30px; 38 | } 39 | &:hover { 40 | & p { 41 | bottom: 0; 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | 50 | @media screen and (max-width: 767px) { 51 | .@{content5}-wrapper { 52 | height: 2000px; 53 | overflow: hidden; 54 | .@{content5} { 55 | ul { 56 | li { 57 | display: block; 58 | width: 100%; 59 | padding: 2%; 60 | span { 61 | height: 168px; 62 | } 63 | p { 64 | position: relative; 65 | bottom: 0; 66 | } 67 | } 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /site/templates/template/element/Content6/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content6: content6; 3 | .@{content6}-wrapper { 4 | min-height: 720px; 5 | .@{content6} { 6 | height: 100%; 7 | display: flex; 8 | align-items: center; 9 | 10 | &-text { 11 | min-height: 424px; 12 | >*.queue-anim-leaving { 13 | position: relative !important; 14 | } 15 | .title-h1 { 16 | position: relative; 17 | margin: 0 0 16px; 18 | text-align: left; 19 | font-size: 2em; 20 | } 21 | .title-content { 22 | position: relative; 23 | margin-bottom: 64px; 24 | text-align: left; 25 | } 26 | ul { 27 | position: relative; 28 | display: inline-block; 29 | li { 30 | margin-bottom: 24px; 31 | .@{content6}-icon { 32 | display: inline-block; 33 | width: 30px; 34 | height: 30px; 35 | position: absolute; 36 | } 37 | .@{content6}-title, 38 | .@{content6}-content { 39 | margin-left: 45px; 40 | } 41 | .@{content6}-title { 42 | font-size: 14px; 43 | margin-bottom: 10px; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .@{content6}-wrapper { 53 | height: 860px; 54 | overflow: hidden; 55 | .@{content6} { 56 | display: block; 57 | &-img, 58 | &-text { 59 | display: block; 60 | width: 100%; 61 | } 62 | &-text { 63 | >h1, 64 | >p { 65 | text-align: center; 66 | } 67 | > h1 { 68 | margin: 56px auto 16px; 69 | } 70 | p { 71 | margin-bottom: 32px; 72 | } 73 | } 74 | &-img { 75 | margin-top: 20px; 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /site/templates/template/element/Content7/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content7: content7; 3 | .@{content7}-wrapper { 4 | min-height: 720px; 5 | .@{content7} { 6 | >h1, 7 | >p { 8 | text-align: center; 9 | } 10 | &-tag { 11 | & i { 12 | width: 12px; 13 | height: 14px; 14 | display: inline-block; 15 | vertical-align: middle; 16 | margin-right: 5px; 17 | } 18 | &-name { 19 | display: inline-block; 20 | } 21 | } 22 | .ant-tabs-bar { 23 | text-align: center; 24 | } 25 | .ant-tabs { 26 | .ant-tabs-nav { 27 | float: none; 28 | text-align: center; 29 | } 30 | } 31 | &-tabs-wrapper { 32 | position: relative; 33 | margin-top: 24px; 34 | } 35 | &-content { 36 | display: flex; 37 | align-items: center; 38 | } 39 | &-text { 40 | padding: 24px 48px; 41 | } 42 | &-img { 43 | padding: 24px 48px; 44 | } 45 | .ant-tabs-tabpane { 46 | margin-top: 40px; 47 | } 48 | } 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .@{content7}-wrapper { 53 | min-height: 980px; 54 | overflow: hidden; 55 | .@{content7} { 56 | max-width: 100%; 57 | &-content { 58 | display: block; 59 | } 60 | &-text, 61 | &-img { 62 | text-align: left; 63 | padding: 0; 64 | } 65 | &-img { 66 | margin-top: 32px; 67 | } 68 | .ant-tabs-bar { 69 | width: auto; 70 | .ant-tabs-nav { 71 | float: left; 72 | } 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /site/templates/template/element/Content8/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @content8: content8; 3 | .@{content8}-wrapper { 4 | &.home-page-wrapper { 5 | overflow: initial; 6 | width: ~"calc(100% - 112px)"; 7 | min-height: 878px; 8 | margin: auto; 9 | border-radius: 4px; 10 | box-shadow: 0 32px 32px rgba(34, 94, 222, 0.08); 11 | background: #fff; 12 | & .home-page { 13 | margin-top: -220px; 14 | padding: 64px 24px; 15 | overflow: hidden; 16 | } 17 | } 18 | .content-wrapper { 19 | margin-top: 72px; 20 | .@{content8}-block-wrapper { 21 | margin-bottom: 60px; 22 | } 23 | .@{content8}-block { 24 | width: 100%; 25 | max-width: 192px; 26 | margin: auto; 27 | } 28 | .@{content8}-img { 29 | border-radius: 8px; 30 | overflow: hidden; 31 | width: 100%; 32 | img { 33 | width: 100%; 34 | display: block; 35 | &[src=""] { 36 | background: linear-gradient(to top right, #d6defc, #fff); 37 | padding-bottom: 100%; 38 | } 39 | } 40 | } 41 | .@{content8}-title { 42 | font-size: 20px; 43 | color: #0d1a26; 44 | font-weight: 400; 45 | margin: 24px auto 8px; 46 | text-align: center; 47 | white-space: nowrap; 48 | } 49 | .@{content8}-content { 50 | text-align: center; 51 | white-space: nowrap; 52 | font-size: 14px; 53 | color: #697b8c; 54 | } 55 | } 56 | } 57 | 58 | @media screen and (max-width: 767px) { 59 | .@{content8}-wrapper.home-page-wrapper { 60 | padding-bottom: 0; 61 | box-shadow: none; 62 | width: 100%; 63 | .@{content8} { 64 | &.home-page { 65 | margin: auto; 66 | padding-bottom: 0; 67 | } 68 | } 69 | .content-wrapper { 70 | .@{content8}-block { 71 | max-width: 240px; 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /site/templates/template/element/Feature7/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; 3 | import QueueAnim from 'rc-queue-anim'; 4 | import { Row, Col } from 'antd'; 5 | 6 | /* replace-start-value = import { getChildrenToRender } from './utils'; */ 7 | import { getChildrenToRender } from '../../utils'; 8 | /* replace-end-value */ 9 | /* replace-start */ 10 | import './index.less'; 11 | /* replace-end */ 12 | 13 | function Feature7(props) { 14 | const { dataSource, isMobile, ...tagProps } = props; 15 | const { blockWrapper, titleWrapper } = dataSource; 16 | const childrenToRender = blockWrapper.children.map((item, i) => ( 17 | <Col 18 | {...item} 19 | key={i.toString()} 20 | /* replace-start */ 21 | data-edit="Col" 22 | /* replace-end */ 23 | > 24 | <a 25 | {...item.children} 26 | /* replace-start */ 27 | data-edit="linkA" 28 | /* replace-end */ 29 | > 30 | {item.children.children.map(getChildrenToRender)} 31 | </a> 32 | </Col> 33 | )); 34 | return ( 35 | <div 36 | {...tagProps} 37 | {...dataSource.wrapper} 38 | > 39 | <div {...dataSource.page}> 40 | <div 41 | {...dataSource.titleWrapper} 42 | /* replace-start */ 43 | data-edit="titleWrapper" 44 | /* replace-end */ 45 | > 46 | {titleWrapper.children.map(getChildrenToRender)} 47 | </div> 48 | <OverPack {...dataSource.OverPack}> 49 | <QueueAnim 50 | key="queue" 51 | type="bottom" 52 | leaveReverse 53 | interval={50} 54 | component={Row} 55 | {...blockWrapper} 56 | /* replace-start */ 57 | data-edit="Row" 58 | /* replace-end */ 59 | > 60 | {childrenToRender} 61 | </QueueAnim> 62 | </OverPack> 63 | </div> 64 | </div> 65 | ); 66 | } 67 | 68 | export default Feature7; 69 | -------------------------------------------------------------------------------- /site/templates/template/element/Feature7/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @feature7: feature7; 3 | 4 | .@{feature7} { 5 | &-wrapper { 6 | min-height: 564px; 7 | margin: 0 auto; 8 | overflow: hidden; 9 | background-color: #f7f9fc; 10 | 11 | &.home-page-wrapper { 12 | .home-page { 13 | padding: 64px 24px; 14 | } 15 | } 16 | } 17 | 18 | &-title { 19 | 20 | &-wrapper { 21 | text-align: center; 22 | margin-bottom: 40px; 23 | } 24 | 25 | &-h1 { 26 | font-size: 32px; 27 | color: @text-color; 28 | } 29 | 30 | &-content { 31 | margin-top: 16px; 32 | } 33 | } 34 | 35 | &-block { 36 | margin-top: 28px; 37 | 38 | &-group { 39 | display: block; 40 | padding: 28px 24px; 41 | box-shadow: 0 2px 16px fade(#000, 8); 42 | background-image: url('https://gw.alipayobjects.com/mdn/rms_ae7ad9/afts/img/A*fMOFSpRXMxsAAAAAAAAAAABkARQnAQ'); 43 | background-repeat: no-repeat; 44 | background-position: 100% 100%; 45 | transition: box-shadow @animate-duration @ease-in-out, transform @animate-duration @ease-in-out; 46 | 47 | &:hover { 48 | transform: translateY(-5px); 49 | box-shadow: 0 6px 16px fade(#000, 12); 50 | } 51 | } 52 | 53 | &-image { 54 | float: left; 55 | width: 24px; 56 | } 57 | 58 | &-title { 59 | font-size: 14px; 60 | float: left; 61 | margin-left: 8px; 62 | margin-bottom: 16px; 63 | color: @text-color; 64 | } 65 | 66 | &-content { 67 | clear: both; 68 | color: fade(@text-color, 75); 69 | } 70 | } 71 | } 72 | 73 | @media screen and (max-width: 767px) { 74 | .@{feature7}-wrapper { 75 | min-height: 1540px; 76 | &.home-page-wrapper { 77 | .home-page { 78 | padding: 56px 24px; 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /site/templates/template/element/Footer0/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TweenOne from 'rc-tween-one'; 3 | import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; 4 | /* replace-start */ 5 | import './index.less'; 6 | /* replace-end */ 7 | 8 | class Footer extends React.PureComponent { 9 | render() { 10 | const { ...props } = this.props; 11 | const { dataSource } = props; 12 | delete props.dataSource; 13 | delete props.isMobile; 14 | return ( 15 | <div {...props} {...dataSource.wrapper}> 16 | <OverPack 17 | {...dataSource.OverPack} 18 | > 19 | <TweenOne 20 | animation={{ y: '+=30', opacity: 0, type: 'from' }} 21 | key="footer" 22 | {...dataSource.copyright} 23 | > 24 | { 25 | /* replace-start-value = dataSource.copyright.children */ 26 | React.createElement('span', { dangerouslySetInnerHTML: { __html: dataSource.copyright.children } }) 27 | /* replace-end-value */ 28 | } 29 | </TweenOne> 30 | </OverPack> 31 | </div> 32 | ); 33 | } 34 | } 35 | 36 | export default Footer; 37 | -------------------------------------------------------------------------------- /site/templates/template/element/Footer0/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | .footer0-wrapper { 3 | background-color: @template-bg-color; 4 | height: 80px; 5 | overflow: hidden; 6 | .footer0 { 7 | height: 100%; 8 | padding: 0 24px; 9 | line-height: 80px; 10 | text-align: center; 11 | color: @template-footer-text-color; 12 | position: relative; 13 | } 14 | } 15 | 16 | @media screen and (max-width: 767px) { 17 | .footer0-wrapper { 18 | .footer0 { 19 | font-size: 12px; 20 | &.home-page { 21 | padding: 0; 22 | } 23 | >div { 24 | width: 90%; 25 | margin: auto; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /site/templates/template/element/Footer0/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | wrapper: { 12 | className: 'home-page-wrapper footer0-wrapper', 13 | }, 14 | OverPack: { 15 | className: 'home-page footer0', 16 | playScale: 0.05, 17 | }, 18 | copyright: { 19 | className: 'copyright', 20 | children: '<span>©2018 <a href="https://motion.ant.design">Ant Motion</a> All Rights Reserved</span>', 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /site/templates/template/element/Footer1/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | .footer1-wrapper { 3 | background: @template-bg-color; 4 | overflow: hidden; 5 | position: relative; 6 | min-height: 360px; 7 | color: @template-footer-text-color; 8 | .footer1 { 9 | .home-page { 10 | padding: 64px 24px 80px; 11 | } 12 | } 13 | .block { 14 | padding: 0 32px; 15 | .logo { 16 | max-width: 180px; 17 | } 18 | .slogan { 19 | font-size: 12px; 20 | margin-top: -20px; 21 | } 22 | >h2 { 23 | margin-bottom: 24px; 24 | color: @template-text-color; 25 | } 26 | a { 27 | color: @template-footer-text-color; 28 | margin-bottom: 12px; 29 | float: left; 30 | clear: both; 31 | &:hover { 32 | color: @primary-color; 33 | } 34 | } 35 | } 36 | .copyright-wrapper { 37 | width: 100%; 38 | border-top: 1px solid fade(@line-color, 10); 39 | .home-page { 40 | padding: 0 24px; 41 | overflow: hidden; 42 | } 43 | .copyright { 44 | height: 80px; 45 | text-align: center; 46 | line-height: 80px; 47 | } 48 | } 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .footer1 { 53 | min-height: 550px; 54 | &-wrapper { 55 | .footer1 { 56 | .home-page { 57 | padding: 64px 24px 32px; 58 | } 59 | } 60 | } 61 | .logo { 62 | margin: 0 auto 24px; 63 | } 64 | .block { 65 | text-align: center; 66 | margin-bottom: 32px; 67 | padding: 0; 68 | } 69 | >ul { 70 | width: 90%; 71 | margin: 20px auto 0; 72 | padding: 10px 0; 73 | >li { 74 | width: 100%; 75 | h2 { 76 | margin-bottom: 10px; 77 | } 78 | li { 79 | display: inline-block; 80 | margin-right: 10px; 81 | } 82 | } 83 | } 84 | .copyright { 85 | &-wrapper { 86 | .home-page { 87 | padding: 0; 88 | .copyright { 89 | font-size: 12px; 90 | } 91 | } 92 | } 93 | 94 | span { 95 | width: 90%; 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /site/templates/template/element/Footer2/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TweenOne from 'rc-tween-one'; 3 | import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; 4 | /* replace-start-value = import { isImg } from './utils'; */ 5 | import { isImg } from '../../../../utils'; 6 | /* replace-end-value */ 7 | /* replace-start */ 8 | import './index.less'; 9 | /* replace-end */ 10 | 11 | class Footer2 extends React.PureComponent { 12 | render() { 13 | const { ...props } = this.props; 14 | const { dataSource } = props; 15 | delete props.dataSource; 16 | delete props.isMobile; 17 | return ( 18 | <div {...props} {...dataSource.wrapper}> 19 | <OverPack 20 | {...dataSource.OverPack} 21 | > 22 | <TweenOne {...dataSource.links}> 23 | {dataSource.links.children.map((item, i) => { 24 | return ( 25 | <a 26 | key={i.toString()} 27 | {...item} 28 | /* replace-start */ 29 | data-edit="link,image" 30 | /* replace-end */ 31 | > 32 | <img src={item.children} height="100%" alt="img" /> 33 | </a> 34 | ); 35 | })} 36 | </TweenOne> 37 | <TweenOne 38 | animation={{ x: '+=30', opacity: 0, type: 'from' }} 39 | key="copyright" 40 | {...dataSource.copyright} 41 | /* replace-start */ 42 | data-edit="textAndImage" 43 | /* replace-end */ 44 | > 45 | { 46 | dataSource.copyright.children.map((item, i) => ( 47 | React.createElement(item.name.indexOf('title') === 0 ? 'h1' : 'div', { key: i.toString(), ...item }, ( 48 | typeof item.children === 'string' && item.children.match(isImg) 49 | ? React.createElement('img', { src: item.children, alt: 'img' }) 50 | : /* replace-start-value = item.children */React.createElement('span', { dangerouslySetInnerHTML: { __html: item.children } }) 51 | /* replace-end-value */ 52 | )) 53 | )) 54 | } 55 | </TweenOne> 56 | </OverPack> 57 | </div> 58 | ); 59 | } 60 | } 61 | 62 | export default Footer2; 63 | -------------------------------------------------------------------------------- /site/templates/template/element/Footer2/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | .footer2-wrapper { 3 | background-color: #0d1a26; 4 | height: 80px; 5 | overflow: hidden; 6 | .footer2 { 7 | height: 100%; 8 | padding: 0 24px; 9 | line-height: 80px; 10 | text-align: center; 11 | color: @template-footer-text-color; 12 | position: relative; 13 | } 14 | .copyright { 15 | float: right; 16 | >* { 17 | display: inline-block; 18 | } 19 | &-logo { 20 | width: 16px; 21 | margin-right: 8px; 22 | img { 23 | width: 100%; 24 | } 25 | } 26 | &-line { 27 | padding: 0 12px; 28 | margin: 0 12px; 29 | } 30 | } 31 | .links { 32 | float: left; 33 | display: flex; 34 | align-items: center; 35 | height: 100%; 36 | a { 37 | height: 21px; 38 | display: inline-block; 39 | margin-right: 32px; 40 | img { 41 | display: block; 42 | } 43 | } 44 | } 45 | } 46 | 47 | @media screen and (max-width: 767px) { 48 | .footer2-wrapper { 49 | .footer2 { 50 | font-size: 12px; 51 | &.home-page { 52 | padding: 0; 53 | } 54 | >div { 55 | width: 90%; 56 | margin: auto; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /site/templates/template/element/Nav1/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | wrapper: { 12 | className: 'header1 home-page-wrapper', 13 | }, 14 | page: { 15 | className: 'home-page', 16 | }, 17 | logo: { 18 | className: 'header1-logo', 19 | children: 'https://os.alipayobjects.com/rmsportal/mlcYmsRilwraoAe.svg', 20 | }, 21 | Menu: { 22 | className: 'header1-menu', 23 | children: [ 24 | { 25 | name: 'item0', 26 | a: { 27 | children: '导航一', 28 | href: '', 29 | }, 30 | }, 31 | { 32 | name: 'item1', 33 | a: { 34 | children: '导航二', 35 | href: '', 36 | }, 37 | }, 38 | { 39 | name: 'item2', 40 | a: { 41 | children: '导航三', 42 | href: '', 43 | }, 44 | }, 45 | { 46 | name: 'item3', 47 | a: { 48 | children: '导航四', 49 | href: '', 50 | }, 51 | }, 52 | ], 53 | }, 54 | mobileMenu: { 55 | className: 'header1-mobile-menu', 56 | }, 57 | help: { 58 | className: 'help', 59 | children: '帮助', 60 | }, 61 | user: { 62 | }, 63 | }, 64 | }; 65 | -------------------------------------------------------------------------------- /site/templates/template/element/Nav2/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | isScrollLink: true, 12 | wrapper: { 13 | className: 'header2 home-page-wrapper', 14 | }, 15 | page: { 16 | className: 'home-page', 17 | }, 18 | logo: { 19 | className: 'header2-logo', 20 | children: 'https://os.alipayobjects.com/rmsportal/mlcYmsRilwraoAe.svg', 21 | }, 22 | LinkMenu: { 23 | className: 'header2-menu', 24 | children: [ 25 | { 26 | name: 'linkNav', 27 | to: '当前页面 ID 地址,参考如上', 28 | children: '导航名称', 29 | className: 'menu-item', 30 | }, 31 | ], 32 | }, 33 | mobileMenu: { 34 | className: 'header2-mobile-menu', 35 | }, 36 | }, 37 | }; 38 | -------------------------------------------------------------------------------- /site/templates/template/element/Pricing0/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @pricing0: pricing0; 3 | .@{pricing0}-wrapper { 4 | .@{pricing0} { 5 | min-height: 370px; 6 | padding: 0 24px; 7 | display: flex; 8 | align-items: flex-end; 9 | &-img-wrapper { 10 | height: 100%; 11 | transform-origin: top; 12 | padding: 0 32px; 13 | .@{pricing0}-img { 14 | display: block; 15 | width: 100%; 16 | max-width: 560px; 17 | img { 18 | display: block; 19 | } 20 | } 21 | } 22 | &-text-wrapper { 23 | min-height: 320px; 24 | padding: 0 40px; 25 | max-width: 560px; 26 | margin-bottom: 32px; 27 | .@{pricing0}-content, 28 | .@{pricing0}-title { 29 | position: relative !important; 30 | } 31 | .@{pricing0}-title { 32 | font-size: 24px; 33 | font-weight: normal; 34 | color: #404040; 35 | margin: 72px auto 16px; 36 | } 37 | .@{pricing0}-content { 38 | font-size: 12px; 39 | color: #666; 40 | line-height: 1.5; 41 | } 42 | .@{pricing0}-pricing { 43 | font-size: 36px; 44 | color: #404040; 45 | margin: 32px 0 24px; 46 | } 47 | } 48 | } 49 | } 50 | 51 | @media screen and (max-width: 767px) { 52 | .@{pricing0}-wrapper { 53 | min-height: 720px; 54 | .@{pricing0} { 55 | display: block; 56 | &-img-wrapper { 57 | padding: 0; 58 | text-align: center; 59 | margin-top: 24px; 60 | .@{pricing0}-img { 61 | display: inline-block; 62 | width: 80%; 63 | margin: auto; 64 | } 65 | } 66 | &-text-wrapper { 67 | height: auto; 68 | text-align: center; 69 | padding: 0; 70 | max-width: 100%; 71 | .@{pricing0}-content, 72 | .@{pricing0}-title { 73 | width: 100%; 74 | top: auto; 75 | } 76 | .@{pricing0}-title { 77 | margin: 32px auto 16px; 78 | font-size: 24px; 79 | } 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /site/templates/template/element/Pricing0/template.config.js: -------------------------------------------------------------------------------- 1 | import component from './index'; 2 | 3 | import less from '!raw-loader!./index.less'; 4 | import templateStr from '!raw-loader!./index'; 5 | 6 | export default { 7 | component, 8 | templateStr, 9 | less, 10 | dataSource: { 11 | wrapper: { 12 | className: 'home-page-wrapper pricing0-wrapper', 13 | 14 | }, 15 | OverPack: { 16 | playScale: 0.3, 17 | className: 'home-page pricing0', 18 | }, 19 | imgWrapper: { 20 | className: 'pricing0-img-wrapper', 21 | md: 12, 22 | xs: 24, 23 | }, 24 | img: { 25 | className: 'pricing0-img', 26 | name: 'image', 27 | children: 'https://gw.alipayobjects.com/mdn/rms_ae7ad9/afts/img/A*OnyWT4Nsxy0AAAAAAAAAAABjARQnAQ', 28 | }, 29 | childWrapper: { 30 | className: 'pricing0-text-wrapper', 31 | md: 12, 32 | xs: 24, 33 | children: [ 34 | { 35 | name: 'title', 36 | children: 'OceanBase 服务器', 37 | className: 'pricing0-title', 38 | }, 39 | { 40 | name: 'content', 41 | children: `云资源集中编排、弹性伸缩、持续发布和部署,高可用及容灾。按金融企业安全要求打造的完整云上安全体系,全方位保障金融应用及数据安全。<br/> 42 | 500-5Gbps,10 GB-50TB(含),1TB流量包,国内按峰值。 43 | `, 44 | className: 'pricing0-content', 45 | }, 46 | { 47 | name: 'pricing', 48 | children: '¥2,200', 49 | className: 'pricing0-pricing', 50 | }, 51 | { 52 | name: 'button', 53 | children: { 54 | icon: 'shopping-cart', 55 | href: '#', 56 | type: 'primary', 57 | children: '立即购买', 58 | }, 59 | }, 60 | ], 61 | }, 62 | }, 63 | }; 64 | -------------------------------------------------------------------------------- /site/templates/template/element/Pricing1/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @pricing1: pricing1; 3 | .@{pricing1}-wrapper { 4 | min-height: 760px; 5 | .@{pricing1} { 6 | >p { 7 | text-align: center; 8 | } 9 | &-content-wrapper { 10 | min-height: 400px; 11 | } 12 | &-block-box { 13 | width: 260px; 14 | border-radius: 4px; 15 | background: #eef0f3; 16 | text-align: center; 17 | color: #666; 18 | min-height: 400px; 19 | margin: auto; 20 | border: 1px solid transparent; 21 | .page-pro(); 22 | &.active { 23 | border-color: @primary-color; 24 | background: #fff; 25 | .@{pricing1} { 26 | &-top-wrapper { 27 | background: @primary-color; 28 | } 29 | &-name, 30 | &-money, 31 | &-button { 32 | color: #fff; 33 | } 34 | &-button { 35 | background: @primary-color; 36 | } 37 | } 38 | } 39 | } 40 | &-block { 41 | margin-bottom: 24px; 42 | } 43 | &-top-wrapper { 44 | width: 100%; 45 | padding: 16px 24px; 46 | } 47 | &-name { 48 | font-size: 14px; 49 | } 50 | &-money { 51 | font-family: 'Helvetica Neue', sans-serif; 52 | font-size: 32px; 53 | color: #666; 54 | } 55 | &-content { 56 | font-size: 12px; 57 | line-height: 2; 58 | font-weight: 300; 59 | margin: 32px 24px 48px; 60 | } 61 | &-line { 62 | display: block; 63 | height: 1px; 64 | background: #d9d9d9; 65 | margin: 0 24px; 66 | } 67 | &-button-wrapper { 68 | margin: 18px 24px; 69 | } 70 | &-button { 71 | padding: 0 24px; 72 | } 73 | } 74 | &.home-page-wrapper { 75 | .@{pricing1}-title-wrapper { 76 | margin-bottom: 64px; 77 | text-align: center; 78 | } 79 | } 80 | } 81 | 82 | @media screen and (max-width: 767px) { 83 | .@{pricing1}-wrapper { 84 | padding-bottom: 0; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /site/templates/template/element/Pricing2/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @pricing2: pricing2; 3 | 4 | .@{pricing2}-wrapper { 5 | min-height: 760px; 6 | 7 | .@{pricing2} { 8 | >p { 9 | text-align: center; 10 | } 11 | 12 | &-content-wrapper { 13 | min-height: 400px; 14 | } 15 | 16 | &-table-name-block { 17 | text-align: center; 18 | color: #666; 19 | width: 100%; 20 | } 21 | 22 | &-table-name { 23 | font-size: 24px; 24 | } 25 | 26 | &-table-money { 27 | font-size: 16px; 28 | margin: 8px 0 16px; 29 | } 30 | 31 | &-table-content { 32 | text-align: center; 33 | color: #666; 34 | 35 | &-name { 36 | color: #666; 37 | text-align: center; 38 | } 39 | } 40 | } 41 | 42 | &.home-page-wrapper { 43 | .@{pricing2}-title-wrapper { 44 | margin-bottom: 64px; 45 | text-align: center; 46 | } 47 | } 48 | } 49 | 50 | @media screen and (max-width: 767px) { 51 | .@{pricing2} { 52 | &-wrapper { 53 | padding-bottom: 0; 54 | } 55 | 56 | &-table { 57 | margin-bottom: 24px; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /site/templates/template/element/Teams0/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @teams0: teams0; 3 | 4 | .@{teams0}-wrapper { 5 | height: 430px; 6 | .@{teams0} { 7 | padding: 64px 24px; 8 | display: flex; 9 | align-items: flex-end; 10 | .banner-anim { 11 | width: 100%; 12 | height: 100%; 13 | } 14 | .banner-anim-thumb { 15 | span { 16 | background: #e9e9e9; 17 | box-shadow: none; 18 | &.active { 19 | background: @primary-color; 20 | } 21 | } 22 | } 23 | & .queue-anim-leaving { 24 | position: relative !important; 25 | } 26 | 27 | &-banner-user-elem { 28 | height: 100%; 29 | color: #fff; 30 | position: relative; 31 | overflow: hidden; 32 | } 33 | &-image { 34 | width: 120px; 35 | height: 120px; 36 | border-radius: 100%; 37 | overflow: hidden; 38 | margin: auto; 39 | display: flex; 40 | justify-content: center; 41 | align-items: center; 42 | margin-bottom: 24px; 43 | img { 44 | height: 100%; 45 | } 46 | } 47 | &-content { 48 | font-size: 12px; 49 | color: #919191; 50 | text-align: center; 51 | width: 80%; 52 | margin: 8px auto; 53 | } 54 | &-h1 { 55 | font-size: 24px; 56 | text-align: center; 57 | width: 80%; 58 | margin: 24px auto 0; 59 | } 60 | } 61 | } 62 | 63 | @media screen and (max-width: 767px) { 64 | .@{teams0}-wrapper { 65 | min-height: 480px; 66 | 67 | .@{teams0} { 68 | display: block; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /site/templates/template/element/Teams1/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import QueueAnim from 'rc-queue-anim'; 3 | import { Row, Col } from 'antd'; 4 | import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; 5 | /* replace-start-value = import { getChildrenToRender, isImg } from './utils'; */ 6 | import { getChildrenToRender } from '../../utils'; 7 | /* replace-end-value */ 8 | /* replace-start */ 9 | import './index.less'; 10 | /* replace-end */ 11 | 12 | class Teams1 extends React.PureComponent { 13 | getBlockChildren = (data) => data.map((item, i) => { 14 | const { titleWrapper, ...$item } = item; 15 | return ( 16 | <Col 17 | key={i.toString()} 18 | {...$item} 19 | /* replace-start */ 20 | data-edit="Col, titleWrapper" 21 | /* replace-end */ 22 | > 23 | {titleWrapper.children.map(getChildrenToRender)} 24 | </Col> 25 | ); 26 | }); 27 | 28 | render() { 29 | const { ...props } = this.props; 30 | const { dataSource } = props; 31 | delete props.dataSource; 32 | delete props.isMobile; 33 | const listChildren = this.getBlockChildren(dataSource.block.children); 34 | return ( 35 | <div 36 | {...props} 37 | {...dataSource.wrapper} 38 | > 39 | <div {...dataSource.page}> 40 | <div 41 | {...dataSource.titleWrapper} 42 | /* replace-start */ 43 | data-edit="titleWrapper" 44 | /* replace-end */ 45 | > 46 | { 47 | dataSource.titleWrapper.children.map(getChildrenToRender) 48 | } 49 | </div> 50 | <OverPack {...dataSource.OverPack}> 51 | <QueueAnim 52 | type="bottom" 53 | key="block" 54 | leaveReverse 55 | {...dataSource.block} 56 | component={Row} 57 | /* replace-start */ 58 | data-edit="Row" 59 | /* replace-end */ 60 | > 61 | {listChildren} 62 | </QueueAnim> 63 | </OverPack> 64 | </div> 65 | </div> 66 | ); 67 | } 68 | } 69 | 70 | export default Teams1; 71 | -------------------------------------------------------------------------------- /site/templates/template/element/Teams1/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @teams1: teams1; 3 | .@{teams1}-wrapper { 4 | min-height: 446px; 5 | overflow: hidden; 6 | .@{teams1} { 7 | overflow: hidden; 8 | height: 100%; 9 | padding: 64px 24px; 10 | > .title-wrapper { 11 | margin: 0 auto 48px; 12 | } 13 | .block-wrapper { 14 | position: relative; 15 | height: 100%; 16 | overflow: hidden; 17 | padding: 20px 0; 18 | .block { 19 | display: inline-block; 20 | text-align: center; 21 | margin-bottom: 48px; 22 | &.queue-anim-leaving { 23 | position: relative !important; 24 | } 25 | } 26 | } 27 | &-image, &-title, &-job, &-content { 28 | width: 200px; 29 | margin: auto; 30 | line-height: 1.5; 31 | } 32 | &-image { 33 | color: #404040; 34 | img { 35 | width: 100%; 36 | } 37 | } 38 | &-title { 39 | font-size: 24px; 40 | margin: 24px auto 8px; 41 | } 42 | &-job { 43 | margin: 8px auto; 44 | } 45 | &-job, &-content { 46 | font-size: 12px; 47 | color: #919191; 48 | } 49 | } 50 | } 51 | 52 | @media screen and (max-width: 767px) { 53 | .@{teams1}-wrapper { 54 | min-height: 1440px; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /site/templates/template/element/Teams2/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../static/custom.less'; 2 | @teams2: teams2; 3 | 4 | .@{teams2}-wrapper { 5 | min-height: 446px; 6 | overflow: hidden; 7 | 8 | .@{teams2} { 9 | overflow: hidden; 10 | height: 100%; 11 | padding: 64px 24px; 12 | 13 | >.title-wrapper { 14 | margin: 0 auto 48px; 15 | } 16 | 17 | .block-wrapper { 18 | position: relative; 19 | height: 100%; 20 | overflow: hidden; 21 | padding: 20px 0; 22 | min-height: 456px; 23 | 24 | .block { 25 | margin-bottom: 48px; 26 | vertical-align: text-top; 27 | 28 | &.queue-anim-leaving { 29 | position: relative !important; 30 | } 31 | } 32 | } 33 | 34 | &-image { 35 | color: #404040; 36 | width: 100%; 37 | 38 | img { 39 | width: 100%; 40 | } 41 | } 42 | 43 | &-textWrapper { 44 | padding-left: 16px; 45 | } 46 | 47 | &-title { 48 | font-size: 18px; 49 | margin-bottom: 2px; 50 | } 51 | 52 | &-job { 53 | margin-bottom: 4px; 54 | } 55 | 56 | &-job, 57 | &-content { 58 | font-size: 12px; 59 | color: #919191; 60 | } 61 | } 62 | } 63 | 64 | @media screen and (max-width: 767px) { 65 | .@{teams2}-wrapper { 66 | min-height: 1440px; 67 | 68 | .@{teams2}.home-page { 69 | padding-bottom: 0; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /site/templates/template/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Provider } from 'react-redux'; 3 | 4 | import Layout from './layout'; 5 | import store from '../../shared/redux'; 6 | import '../static/index.less'; 7 | 8 | function Index() { 9 | return ( 10 | <Provider store={store}> 11 | <Layout /> 12 | </Provider> 13 | ); 14 | } 15 | 16 | export default Index; 17 | -------------------------------------------------------------------------------- /site/templates/template/other/Point.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Link from 'rc-scroll-anim/lib/ScrollLink'; 3 | 4 | export default function Point(props) { 5 | const { data, size, position, type, stroke } = props; 6 | const children = data.map((item) => { 7 | if (item.match('nav') || item.match('footer')) { 8 | return null; 9 | } 10 | const className = `point ${type} ${stroke} ${size}`.trim(); 11 | return ( 12 | <Link 13 | key={item} 14 | className={className} 15 | to={item} 16 | toHash={false} 17 | /> 18 | ); 19 | }).filter((item) => item); 20 | const wrapperClass = `point-wrapper ${position} ${size}`.trim(); 21 | return ( 22 | <div 23 | className={wrapperClass} 24 | > 25 | <div> 26 | {children} 27 | </div> 28 | </div> 29 | ); 30 | } 31 | 32 | Point.defaultProps = { 33 | size: '', 34 | position: '', 35 | type: '', 36 | stroke: '', 37 | }; 38 | -------------------------------------------------------------------------------- /site/templates/template/other/otherToString.jsx: -------------------------------------------------------------------------------- 1 | import index from '!raw-loader!../../../../index.text'; 2 | import documentation from '!raw-loader!../../../../documentation.md'; 3 | import point from '!raw-loader!./Point.jsx'; 4 | 5 | export default { 6 | index, 7 | documentation, 8 | point: point.replace('../static/point.less', './less/point.less'), 9 | }; 10 | -------------------------------------------------------------------------------- /site/theme/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const homeTmpl = './template/Home/index'; 4 | const contentTmpl = './template/Content/index'; 5 | 6 | function pickerGenerator(module) { 7 | const tester = new RegExp(`^docs/${module || ''}`); 8 | return (markdownData) => { 9 | const { filename } = markdownData.meta; 10 | if (tester.test(filename) && !/\/demo$/.test(path.dirname(filename))) { 11 | return { 12 | meta: markdownData.meta, 13 | }; 14 | } 15 | return null; 16 | }; 17 | } 18 | 19 | module.exports = { 20 | lazyLoad(nodePath, nodeValue) { 21 | if (typeof nodeValue === 'string') { 22 | return true; 23 | } 24 | return nodePath.endsWith('/demo'); 25 | }, 26 | pick: { 27 | docs: pickerGenerator(), 28 | 'docs/guide': pickerGenerator(), 29 | 'docs/use': pickerGenerator(), 30 | 'docs/edit': pickerGenerator(), 31 | }, 32 | plugins: [ 33 | 'bisheng-plugin-description', 34 | 'bisheng-plugin-toc?maxDepth=2&keepElem', 35 | 'bisheng-plugin-antd', 36 | 'bisheng-plugin-react?lang=__react', 37 | ], 38 | routes: { 39 | path: '/', 40 | component: './template/Layout/index', 41 | indexRoute: { component: homeTmpl }, 42 | childRoutes: [ 43 | { 44 | path: 'index-cn', 45 | component: homeTmpl, 46 | }, 47 | { 48 | path: '/docs/:children', 49 | component: contentTmpl, 50 | }, 51 | { 52 | path: '/docs/:file/:children', 53 | component: contentTmpl, 54 | }, 55 | ], 56 | }, 57 | }; 58 | -------------------------------------------------------------------------------- /site/theme/static/antd.less: -------------------------------------------------------------------------------- 1 | // @import "~antd/lib/style/v2-compatible-reset.less"; 2 | @import "~antd/lib/style/themes/default.less"; 3 | @import "~antd/lib/style/mixins/motion.less"; 4 | -------------------------------------------------------------------------------- /site/theme/static/common.less: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | } 5 | 6 | body, 7 | div, 8 | dl, 9 | dt, 10 | dd, 11 | ul, 12 | ol, 13 | li, 14 | h1, 15 | h2, 16 | h3, 17 | h4, 18 | h5, 19 | h6 { 20 | margin: 0; 21 | padding: 0; 22 | } 23 | 24 | body { 25 | font-family: @font-family; 26 | overflow-x: hidden; 27 | -webkit-font-smoothing: antialiased; 28 | } 29 | 30 | a:focus { 31 | text-decoration: none; 32 | } 33 | 34 | #nprogress .bar { 35 | background: #fff; 36 | } 37 | 38 | #nprogress .spinner-icon { 39 | border-top-color: #fff; 40 | border-left-color: #fff; 41 | } 42 | .header-placeholder { 43 | background: @primary-color; 44 | width: 100%; 45 | height: 64px; 46 | position: absolute; 47 | top: 0; 48 | left: 0; 49 | } 50 | 51 | .page-wrapper { 52 | background: #fff; 53 | .page { 54 | margin: auto; 55 | max-width: 100%; 56 | transition: padding .45s @ease-out, max-width .45s @ease-out; 57 | padding: 0 20px; 58 | } 59 | } 60 | .drawer-content { 61 | padding: 40px 0; 62 | } 63 | 64 | .landing-move-motion(@className, @keyframeName) { 65 | .make-motion(@className, @keyframeName, .45s); 66 | .@{className}-enter, 67 | .@{className}-appear { 68 | opacity: 0; 69 | animation-timing-function: @ease-out; 70 | will-change: transform; 71 | } 72 | .@{className}-leave { 73 | animation-timing-function: @ease-out; 74 | position: absolute !important; 75 | top: 0; 76 | left: 0; 77 | width: 100%; 78 | z-index: 1; 79 | will-change: transform; 80 | } 81 | } 82 | 83 | .landing-move-motion(landing-move, landingMove); 84 | 85 | @keyframes landingMoveIn { 86 | 0% { 87 | transform: translateY(30px); 88 | opacity: 0; 89 | } 90 | 100% { 91 | transform: translateY(0%); 92 | opacity: 1; 93 | } 94 | } 95 | 96 | @keyframes landingMoveOut { 97 | 0% { 98 | transform: translateY(0); 99 | opacity: 1; 100 | } 101 | 100% { 102 | transform: translateY(-30px); 103 | opacity: 0; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /site/theme/static/default.less: -------------------------------------------------------------------------------- 1 | // 导航上划线 2 | @menu-item-border: 2px; 3 | 4 | /* 首页按钮投影色 */ 5 | @home-button-shadow-color: darken(@primary-color, 20%); 6 | 7 | .mouseHover(@color, @x: 0, @y: 4px, @blur: 12px) { 8 | transform: translateY(0); 9 | box-shadow: 0 0 0 fade(@color, 0); 10 | transition: box-shadow .3s @ease-out, transform .3s @ease-out; 11 | &:hover { 12 | transform: translateY(-4px); 13 | box-shadow: @x @y @blur fade(@color, 55); 14 | } 15 | } 16 | 17 | @site-heading-color: #0d1a26; 18 | @site-text-color: #314659; 19 | @site-text-color-secondary: #697b8c; 20 | @site-border-color-split: #ebedf0; 21 | @site-home-line: #ebedf0; 22 | -------------------------------------------------------------------------------- /site/theme/static/footer.less: -------------------------------------------------------------------------------- 1 | @padding-space: 144px; 2 | footer { 3 | clear: both; 4 | font-size: 14px; 5 | background-color: #000; 6 | position: relative; 7 | z-index: 100; 8 | color: rgba(255, 255, 255, 0.65); 9 | box-shadow: 0 1000px 0 1000px #fff; 10 | .ant-row { 11 | text-align: center; 12 | .footer-center { 13 | display: inline-block; 14 | text-align: left; 15 | > h2 { 16 | font-size: 16px; 17 | margin: 0 auto 24px; 18 | font-weight: 500; 19 | position: relative; 20 | > .title-icon { 21 | width: 27px; 22 | margin-right: 16px; 23 | } 24 | > .anticon { 25 | font-size: 16px; 26 | position: absolute; 27 | left: -22px; 28 | top: 3px; 29 | color: #aaa; 30 | } 31 | } 32 | > div { 33 | margin: 12px 0; 34 | } 35 | } 36 | } 37 | .footer-wrap { 38 | position: relative; 39 | padding: 86px @padding-space 93px @padding-space; 40 | border-bottom: 1px solid rgba(255, 255, 255, 0.25); 41 | } 42 | .bottom-bar { 43 | text-align: center; 44 | padding: 16px 0; 45 | margin: 0; 46 | line-height: 32px; 47 | overflow: hidden; 48 | font-family: Avenir, @font-family, sans-serif; 49 | font-size: 16px; 50 | a { 51 | color: rgba(255, 255, 255, 0.65); 52 | margin-left: 4px; 53 | &:hover { 54 | color: #fff; 55 | } 56 | } 57 | .translate-button { 58 | text-align: left; 59 | } 60 | .heart { 61 | color: #f73f51; 62 | font-size: 22px; 63 | } 64 | } 65 | a { 66 | color: rgba(255, 255, 255, 0.9); 67 | } 68 | h2 { 69 | color: rgba(255, 255, 255, 1); 70 | & > span { 71 | color: rgba(255, 255, 255, 1); 72 | } 73 | } 74 | } 75 | 76 | .home { 77 | footer { 78 | .footer-wrap { 79 | width: 100%; 80 | padding: 0; 81 | } 82 | .bottom-bar { 83 | margin: auto; 84 | max-width: 1200px; 85 | padding: 16px 24px; 86 | border-top: none; 87 | } 88 | .footer-wrap .ant-row { 89 | width: 100%; 90 | max-width: 1200px; 91 | padding: 86px 24px 93px; 92 | margin: auto; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /site/theme/static/header.less: -------------------------------------------------------------------------------- 1 | .header { 2 | height: 64px; 3 | line-height: 64px; 4 | background: @primary-color; 5 | box-shadow: 0 4px 12px rgba(138, 166, 195, .45); 6 | transition: box-shadow .45s @ease-out; 7 | position: relative; 8 | z-index: 999; 9 | .logo { 10 | display: flex; 11 | align-items: center; 12 | color: #fff; 13 | font-size: 16px; 14 | font-family: "SF UI Display", "Helvetica Neue For Number", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif; 15 | text-decoration: none; 16 | img { 17 | width: 28px; 18 | height: 28px; 19 | margin-right: 8px; 20 | } 21 | } 22 | .menu { 23 | display: flex; 24 | align-items: center; 25 | justify-content: flex-end; 26 | .ant-menu-horizontal { 27 | color: #fff; 28 | background: transparent; 29 | border-bottom: none; 30 | transition: none; 31 | height: 64px; 32 | >.ant-menu-item { 33 | line-height: 60px; 34 | height: 62px; 35 | border-top: @menu-item-border solid transparent; 36 | box-sizing: content-box; 37 | border-bottom: none; 38 | &:hover, 39 | &.ant-menu-item-selected { 40 | border-top-color: #fff; 41 | } 42 | } 43 | a { 44 | color: #fff; 45 | } 46 | } 47 | .gitbtn { 48 | display: inline-block; 49 | border: 1px solid #fff; 50 | border-radius: 28px; 51 | height: 28px; 52 | line-height: 28px; 53 | color: #fff; 54 | padding: 0 16px; 55 | margin-left: 20px; 56 | box-sizing: content-box; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /site/theme/static/home/banner.less: -------------------------------------------------------------------------------- 1 | .banner { 2 | background: @primary-color; 3 | color: #fff; 4 | position: relative; 5 | height: 682px; 6 | .banner-anim-elem { 7 | height: 100%; 8 | display: flex !important; 9 | justify-content: center; 10 | align-items: center; 11 | text-align: center; 12 | .text-wrapper { 13 | .logo-wrapper { 14 | width: 160px; 15 | height: 160px; 16 | margin: auto; 17 | position: relative; 18 | img { 19 | width: 100%; 20 | height: 100%; 21 | } 22 | i { 23 | background: #fff; 24 | position: absolute; 25 | transform-origin: top left; 26 | } 27 | .vertical { 28 | height: 264px; 29 | width: 1px; 30 | top: -52px; 31 | } 32 | .horizontal { 33 | width: 264px; 34 | height: 1px; 35 | left: -52px; 36 | } 37 | .left { 38 | left: 31px; 39 | } 40 | .right { 41 | left: 55px; 42 | } 43 | .top { 44 | top: 130px; 45 | } 46 | .bottom { 47 | bottom: 4px; 48 | } 49 | } 50 | .introduce { 51 | font-size: 16px; 52 | line-height: 32px; 53 | font-weight: 400; 54 | max-width: 557px; 55 | margin: 80px auto 64px; 56 | } 57 | .button-wrapper { 58 | .btn-temp { 59 | background: #fff; 60 | color: @primary-color; 61 | } 62 | .btn-editor { 63 | border: 1px solid #fff; 64 | color: #fff; 65 | margin-left: 24px; 66 | transition: box-shadow .3s @ease-out, transform .3s @ease-out, color .3s @ease-out, border .3s @ease-out, background .3s @ease-out; 67 | &:hover { 68 | background: #fff; 69 | color: @primary-color; 70 | border-color: transparent; 71 | } 72 | } 73 | } 74 | .git-button { 75 | display: flex; 76 | justify-content: center; 77 | margin-top: 24px; 78 | } 79 | } 80 | .bg-wrapper { 81 | position: absolute; 82 | top: 0; 83 | left: 0; 84 | width: 100%; 85 | height: 100%; 86 | display: flex; 87 | align-items: center; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /site/theme/static/home/index.less: -------------------------------------------------------------------------------- 1 | .home .page-wrapper, 2 | .home-wrapper .home-page-wrapper { 3 | width: 100%; 4 | position: relative; 5 | overflow: hidden; 6 | .page, 7 | .home-page { 8 | padding: 128px 24px; 9 | max-width: 1200px; 10 | margin: auto; 11 | } 12 | h1 { 13 | font-size: 32px; 14 | line-height: 45px; 15 | margin: 0 auto 64px; 16 | text-align: center; 17 | color: @text-color; 18 | } 19 | } 20 | .home .header.page-wrapper .page { 21 | padding: 0 24px; 22 | } 23 | 24 | .home { 25 | .header { 26 | box-shadow: 0 0 0 rgba(138, 166, 195, 0); 27 | position: absolute; 28 | width: 100%; 29 | z-index: 999; 30 | } 31 | } 32 | .home-button { 33 | min-width: 136px; 34 | height: 40px; 35 | line-height: 40px; 36 | text-align: center; 37 | border-radius: 20px; 38 | display: inline-block; 39 | font-size: 16px; 40 | box-sizing: content-box; 41 | .mouseHover(@home-button-shadow-color); 42 | } 43 | 44 | @media screen and (max-width: 767px) { 45 | .home-wrapper .home-page-wrapper { 46 | .home-page { 47 | padding: 56px 24px; 48 | >h1 { 49 | font-size: 24px; 50 | margin: 0 auto 32px; 51 | &.title-h1 { 52 | margin-bottom: 8px; 53 | } 54 | } 55 | >p { 56 | margin-bottom: 32px; 57 | } 58 | } 59 | } 60 | } 61 | 62 | @import './banner.less'; 63 | @import './page1.less'; 64 | @import './page2.less'; 65 | @import './page3.less'; 66 | @import './page4.less'; 67 | @import './responsive.less'; 68 | -------------------------------------------------------------------------------- /site/theme/static/home/page3.less: -------------------------------------------------------------------------------- 1 | .page3 { 2 | .page { 3 | h1 { 4 | margin: 128px auto 64px; 5 | } 6 | } 7 | .rc-autoresponsive { 8 | transition: height .3s @ease-out; 9 | } 10 | & &-content { 11 | min-height: 175px; 12 | &-header { 13 | margin-bottom: 64px; 14 | width: 100%; 15 | min-height: 32px; 16 | text-align: center; 17 | .ant-radio-button-wrapper { 18 | transition: border-color .3s @ease-out, box-shadow .3s @ease-out, color .3s @ease-out; 19 | border-radius: 4px; 20 | margin: 0 8px 8px; 21 | width: 100px; 22 | text-align: center; 23 | border: 1px solid @site-home-line; 24 | &:before { 25 | display: none; 26 | } 27 | } 28 | .ant-radio-button-wrapper-checked { 29 | background: @primary-color; 30 | border-color: @primary-color; 31 | color: #fff; 32 | } 33 | } 34 | &-item { 35 | border: 1px solid @site-home-line; 36 | border-radius: 4px; 37 | overflow: hidden; 38 | &.queue-anim-entering, 39 | &.queue-anim-leaving { 40 | transition: none !important; 41 | } 42 | img { 43 | display: block; 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /site/theme/static/home/page4.less: -------------------------------------------------------------------------------- 1 | .page4 { 2 | background: @primary-color; 3 | color: #fff; 4 | min-height: 292px; 5 | text-align: center; 6 | p { 7 | margin: 0 auto 40px; 8 | font-size: 14px; 9 | line-height: 20px; 10 | max-width: 930px; 11 | } 12 | .home-button { 13 | background: #fff; 14 | .mouseHover(#0028CA, 0, 8px, 16px); 15 | box-shadow: 0 4px 8px rgba(0, 40, 202, 0.75); 16 | } 17 | .bg { 18 | width: 1440px; 19 | height: 558px; 20 | position: absolute; 21 | top: 0; 22 | left: 50%; 23 | margin-left: -720px; 24 | svg { 25 | overflow: initial; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /site/theme/static/home/responsive.less: -------------------------------------------------------------------------------- 1 | @media only screen and (max-width: 767.99px) { 2 | .banner { 3 | height: 100vh; 4 | .bg-wrapper { 5 | #Page-1 { 6 | transform: translate(-30px, 80px); 7 | } 8 | #Group-8 { 9 | transform: translate(400px, 69px); 10 | } 11 | } 12 | .text-wrapper { 13 | padding: 0 24px; 14 | } 15 | } 16 | .page1 .page1-content { 17 | margin: 88px auto 0; 18 | min-height: 990px; 19 | .page1-item { 20 | margin-bottom: 64px; 21 | } 22 | } 23 | .page2 { 24 | min-height: 330px; 25 | } 26 | .home-wrapper .page-wrapper .page h1 { 27 | margin: 72px auto 64px; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /site/theme/static/index.less: -------------------------------------------------------------------------------- 1 | @import './antd.less'; 2 | @import './default.less'; 3 | @import './common.less'; 4 | @import './header.less'; 5 | @import './footer.less'; 6 | @import './responsive.less'; 7 | @import './home/index.less'; 8 | @import './page/index.less'; 9 | @import './preview-img.less'; 10 | @import '~antd/lib/modal/style/index.less'; 11 | -------------------------------------------------------------------------------- /site/theme/static/page/index.less: -------------------------------------------------------------------------------- 1 | .main-wrapper { 2 | background: #fff; 3 | margin: 0; 4 | border-radius: @border-radius-base; 5 | padding: 40px 0 0; 6 | position: relative; 7 | &.landing-move-leave { 8 | margin-top: 64px; 9 | } 10 | } 11 | 12 | .main-container { 13 | padding: 0 194px 144px 64px; 14 | margin-left: -1px; 15 | background: #fff; 16 | min-height: 800px; 17 | border-left: 1px solid #e9e9e9; 18 | position: relative; 19 | .markdown { 20 | background: #fff; 21 | } 22 | } 23 | 24 | .main-menu { 25 | z-index: 1; 26 | } 27 | 28 | .main-animate-wraper { 29 | position: relative; 30 | padding-top: 1px; 31 | } 32 | 33 | @import './markdown.less'; 34 | @import './highlight.less'; 35 | @import './page-nav.less'; 36 | @import './toc.less'; 37 | @import './responsive.less'; 38 | -------------------------------------------------------------------------------- /site/theme/static/page/page-nav.less: -------------------------------------------------------------------------------- 1 | .prev-next-nav { 2 | position: absolute; 3 | bottom: 0; 4 | left: 0; 5 | width: ~"calc(100% - 194px - 64px)"; 6 | margin-left: 64px; 7 | overflow: hidden; 8 | font-size: 14px; 9 | border-top: 1px solid @site-border-color-split; 10 | 11 | > .prev-page, 12 | > .next-page { 13 | padding: 0 24px; 14 | float: left; 15 | line-height: 72px; 16 | height: 72px; 17 | text-decoration: none; 18 | } 19 | 20 | > a.prev-page { 21 | i { 22 | transform: translateX(0); 23 | transition: transform .3s @ease-out; 24 | } 25 | &:hover i { 26 | color: @primary-color; 27 | transform: translateX(-3px); 28 | } 29 | } 30 | > .next-page { 31 | text-align: right; 32 | float: right; 33 | 34 | i { 35 | transform: translateX(0); 36 | transition: transform .3s @ease-out; 37 | } 38 | &:hover i { 39 | color: @primary-color; 40 | transform: translateX(3px); 41 | } 42 | } 43 | .chinese { 44 | margin-left: 0.5em; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /site/theme/static/page/responsive.less: -------------------------------------------------------------------------------- 1 | @media only screen and (max-width: 767.99px) { 2 | .markdown .file-logo { 3 | .ant-logo, .landing-logo { 4 | width: 100px; 5 | height: 100px; 6 | } 7 | } 8 | .toc { 9 | display: none; 10 | } 11 | .main-container { 12 | padding: 0 24px 144px; 13 | } 14 | .prev-next-nav { 15 | width: ~"calc(100% - 48px)"; 16 | margin: 0 24px; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /site/theme/static/page/toc.less: -------------------------------------------------------------------------------- 1 | .toc-affix { 2 | position: absolute; 3 | top: 8px; 4 | right: -174px; 5 | .ant-affix { 6 | background: #fff; 7 | } 8 | .ant-anchor { 9 | font-size: 12px; 10 | margin: 16px 0; 11 | border-left: 1px solid #ebedf0; 12 | list-style: none; 13 | a { 14 | padding-left: 16px; 15 | display: block; 16 | transition: all 0.3s ease; 17 | white-space: nowrap; 18 | overflow: hidden; 19 | text-overflow: ellipsis; 20 | color: @site-text-color; 21 | width: 110px; 22 | } 23 | .ant-anchor-link-active a { 24 | border-color: @primary-color; 25 | color: @primary-color; 26 | } 27 | .ant-anchor-ink:before { 28 | display: none; 29 | } 30 | .ant-anchor-link-title { 31 | padding: 0; 32 | } 33 | } 34 | } 35 | 36 | .toc-affix-bottom { 37 | position: absolute; 38 | bottom: 88px; 39 | right: 20px; 40 | .ant-affix { 41 | background: #fff; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /site/theme/static/style.js: -------------------------------------------------------------------------------- 1 | import 'rc-banner-anim/assets/index.css'; 2 | import 'rc-drawer/assets/index.css'; 3 | import 'react-github-button/assets/style.css'; 4 | import './index.less'; 5 | -------------------------------------------------------------------------------- /site/theme/template/Content/EditButton.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Tooltip } from 'antd'; 3 | import { EditOutlined } from '@ant-design/icons'; 4 | 5 | export default function EditButton({ 6 | title, 7 | filename, 8 | sourcePath = 'https://github.com/ant-design/ant-design-landing/edit/master/', 9 | }) { 10 | return ( 11 | <Tooltip title={title}> 12 | <a className="edit-button" target="_blank" href={`${sourcePath}${filename}`}> 13 | <EditOutlined /> 14 | </a> 15 | </Tooltip> 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /site/theme/template/Content/index.jsx: -------------------------------------------------------------------------------- 1 | import collect from 'bisheng/collect'; 2 | import MainContent from './MainContent'; 3 | import * as utils from '../utils'; 4 | 5 | export default collect(async (nextProps) => { 6 | const pathname = nextProps.location.pathname; 7 | 8 | const path = pathname.replace('-cn', ''); 9 | 10 | const pageDataPath = path.split('/'); 11 | 12 | if (/\/components/.test(path) && pageDataPath[1]) { 13 | const str = pageDataPath[1]; 14 | pageDataPath[1] = str.charAt(0).toUpperCase() + str.slice(1); 15 | } 16 | 17 | const pageData = nextProps.utils.get(nextProps.data, pageDataPath); 18 | 19 | // 路由跳转统一处理 20 | if (pathname === 'components') { 21 | location.href = '/components/AvatarList'; 22 | return; 23 | } 24 | 25 | if (!pageData) { 26 | throw 404; // eslint-disable-line no-throw-literal 27 | } 28 | const locale = utils.isZhCN(pathname) ? 'zh-CN' : 'en-US'; 29 | const pageDataPromise = typeof pageData === 'function' 30 | ? pageData() : (pageData[locale] || pageData.index[locale] || pageData.index)(); 31 | const demosFetcher = nextProps.utils.get(nextProps.data, [...pageDataPath, 'demo']); 32 | if (demosFetcher) { 33 | const [localizedPageData, demos] = await Promise.all([pageDataPromise, demosFetcher()]); 34 | return { localizedPageData, demos }; 35 | } 36 | return { localizedPageData: await pageDataPromise }; 37 | })(MainContent); 38 | -------------------------------------------------------------------------------- /site/theme/template/Home/component/ImageLoadComp.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TweenOne from 'rc-tween-one'; 3 | import { Spin } from 'antd'; 4 | 5 | const imgLoadData = {}; 6 | 7 | export default class ImageLoadComp extends React.PureComponent { 8 | constructor(props) { 9 | super(props); 10 | this.id = props.src; 11 | this.state = { 12 | isLoad: imgLoadData[this.id], 13 | anim: null, 14 | }; 15 | } 16 | 17 | onImageLoad = () => { 18 | if (!imgLoadData[this.id] || !this.state.isLoad) { 19 | this.setState({ 20 | isLoad: true, 21 | }, () => { 22 | imgLoadData[this.id] = true; 23 | }); 24 | } 25 | } 26 | 27 | onEnter = () => { 28 | this.setState({ 29 | anim: [ 30 | { 31 | backgroundPositionY: '100%', 32 | duration: 4000, 33 | }, 34 | { backgroundPositionY: '0%', duration: 4000 }, 35 | ], 36 | }); 37 | } 38 | 39 | onLeave = () => { 40 | this.setState({ 41 | anim: { backgroundPositionY: '0%' }, 42 | }); 43 | } 44 | 45 | render() { 46 | const { src, className } = this.props; 47 | const { isLoad, anim } = this.state; 48 | const enter = Array.isArray(anim); 49 | return ( 50 | <Spin spinning={!isLoad}> 51 | <TweenOne 52 | repeat={enter ? -1 : null} 53 | animation={anim} 54 | className={className || 'img'} 55 | style={{ backgroundImage: `url(${src})` }} 56 | onMouseEnter={this.onEnter} 57 | onMouseLeave={this.onLeave} 58 | /> 59 | <img alt="img" src={src} onLoad={this.onImageLoad} style={{ display: 'none' }} /> 60 | </Spin> 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /site/theme/template/Home/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { injectIntl } from 'react-intl'; 3 | import DocumentTitle from 'react-document-title'; 4 | 5 | import Banner from './Banner'; 6 | import Page1 from './Page1'; 7 | import Page2 from './Page2'; 8 | import Page3 from './Page3'; 9 | import Page4 from './Page4'; 10 | 11 | function Home(props) { 12 | return ( 13 | <DocumentTitle title={`Ant Design Landing Page - ${props.intl.formatMessage({ id: 'app.home.slogan' })}`}> 14 | <div className="home-wrapper"> 15 | <Banner isMobile={props.isMobile} /> 16 | <Page1 isMobile={props.isMobile} /> 17 | <Page2 isMobile={props.isMobile} /> 18 | <Page3 isMobile={props.isMobile} /> 19 | <Page4 isMobile={props.isMobile} /> 20 | </div> 21 | </DocumentTitle> 22 | ); 23 | } 24 | 25 | export default injectIntl(Home); 26 | -------------------------------------------------------------------------------- /site/theme/template/Home/utils.jsx: -------------------------------------------------------------------------------- 1 | /* eslint no-undef: 0 */ 2 | import React from 'react'; 3 | import ScrollParallax from 'rc-scroll-anim/lib/ScrollParallax'; 4 | import ticker from 'rc-tween-one/lib/ticker'; 5 | import TweenOne from 'rc-tween-one'; 6 | 7 | function ParallaxG(props) { 8 | return <ScrollParallax component="g" {...props} />; 9 | } 10 | 11 | export function svgBgToParallax(children, location, i = 0) { 12 | const svgChildren = React.Children.toArray(children).map((child, ii) => ( 13 | <ParallaxG 14 | key={ii.toString()} 15 | location={location} 16 | animation={{ 17 | y: (Math.random() * -200) - 80 - (i * 20), 18 | playScale: [0, Math.random() + 2], 19 | }} 20 | > 21 | {child} 22 | </ParallaxG> 23 | )); 24 | return svgChildren; 25 | } 26 | export function currentScrollTop() { 27 | return window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop; 28 | } 29 | export function windowHeight() { 30 | return window.innerHeight 31 | || document.documentElement.clientHeight || document.body.clientHeight; 32 | } 33 | 34 | export function scrollTo(number, _scrollTop) { 35 | const scrollTop = _scrollTop || currentScrollTop(); 36 | if (scrollTop !== number) { 37 | const tickerId = `scrollToTop-${Date.now()}`; 38 | const startFrame = ticker.frame; 39 | ticker.wake(tickerId, () => { 40 | const moment = (ticker.frame - startFrame) * ticker.perFrame; 41 | const ratio = TweenOne.easing.easeInOutCubic(moment, scrollTop, number, 450); 42 | window.scrollTo(window.scrollX, ratio); 43 | if (moment >= 450) { 44 | ticker.clear(tickerId); 45 | } 46 | }); 47 | } 48 | } 49 | 50 | // 图处预加载; 51 | const div = document.createElement('div'); 52 | div.style.display = 'none'; 53 | document.body.appendChild(div); 54 | [ 55 | ].forEach((src) => { 56 | const img = new Image(); 57 | img.src = src; 58 | div.appendChild(img); 59 | }); 60 | -------------------------------------------------------------------------------- /site/theme/template/Layout/Layout.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { IntlProvider } from 'react-intl'; 4 | import { ConfigProvider } from 'antd'; 5 | import zhCN from 'antd/es/locale/zh_CN'; 6 | import { enquireScreen } from 'enquire-js'; 7 | import Animate from 'rc-animate'; 8 | 9 | import enLocale from '../../en-US'; 10 | import cnLocale from '../../zh-CN'; 11 | import * as utils from '../utils'; 12 | 13 | import Header from './Header'; 14 | import Footer from './Footer'; 15 | 16 | let isMobile; 17 | enquireScreen((b) => { 18 | isMobile = b; 19 | }); 20 | class Layout extends React.PureComponent { 21 | static contextTypes = { 22 | router: PropTypes.object.isRequired, 23 | } 24 | 25 | constructor(props) { 26 | super(props); 27 | const { pathname } = props.location; 28 | const appLocale = utils.isZhCN(pathname) ? cnLocale : enLocale; 29 | 30 | this.state = { 31 | appLocale, 32 | isMobile, 33 | }; 34 | } 35 | 36 | componentDidMount() { 37 | enquireScreen((b) => { 38 | this.setState({ 39 | isMobile: !!b, 40 | }); 41 | }); 42 | } 43 | 44 | render() { 45 | const { children, ...restProps } = this.props; 46 | const { pathname } = this.props.location; 47 | const { appLocale } = this.state; 48 | const pathKey = pathname && pathname.split('/')[0];// (pathname.split('/')[1] || pathname.split('/')[0]); 49 | const childrenToRender = React.cloneElement(children, { 50 | ...children.props, 51 | isMobile: this.state.isMobile, 52 | key: pathKey, 53 | }); 54 | return ( 55 | <IntlProvider locale={appLocale.locale} messages={appLocale.messages}> 56 | <ConfigProvider locale={appLocale.locale === 'zh-CN' ? zhCN : null}> 57 | <div className={(pathname === '/' || pathname === 'index-cn') ? 'home' : ''}> 58 | <div className="header-placeholder" /> 59 | <Header {...restProps} isMobile={this.state.isMobile} /> 60 | <Animate component="div" transitionName="landing-move"> 61 | {childrenToRender} 62 | </Animate> 63 | <Footer {...restProps} isMobile={this.state.isMobile} /> 64 | </div> 65 | </ConfigProvider> 66 | </IntlProvider> 67 | ); 68 | } 69 | } 70 | 71 | export default Layout; 72 | -------------------------------------------------------------------------------- /site/theme/template/Layout/PhoneNav.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classnames from 'classnames'; 3 | import { polyfill } from 'react-lifecycles-compat'; 4 | 5 | import { Popover } from 'antd'; 6 | 7 | class PhoneNav extends React.PureComponent { 8 | static getDerivedStateFromProps(props, { prevProps, show }) { 9 | const nextState = { 10 | prevProps: props, 11 | }; 12 | if (prevProps && props !== prevProps && show) { 13 | nextState.show = false; 14 | } 15 | return nextState; 16 | } 17 | 18 | state = { 19 | show: false, 20 | } 21 | 22 | onMenuVisibleChange = (show) => { 23 | this.setState({ 24 | show, 25 | }); 26 | } 27 | 28 | render() { 29 | const { children } = this.props; 30 | const { show } = this.state; 31 | const barClassName = classnames('phone-nav-bar', { 32 | open: show, 33 | }); 34 | return ( 35 | <Popover 36 | overlayClassName="popover-menu" 37 | placement="bottomRight" 38 | content={children} 39 | trigger="click" 40 | visible={show} 41 | arrowPointAtCenter 42 | onVisibleChange={this.onMenuVisibleChange} 43 | > 44 | <div className="phone-nav-bar-wrapper"> 45 | <i className={barClassName} /> 46 | </div> 47 | </Popover> 48 | ); 49 | } 50 | } 51 | 52 | export default polyfill(PhoneNav); 53 | -------------------------------------------------------------------------------- /site/theme/template/Layout/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | // import { createLogger } from 'redux-logger'; 4 | import Layout from './Layout'; 5 | import '../../static/style'; 6 | 7 | if (typeof window !== 'undefined') { 8 | /* eslint-disable global-require */ 9 | require('../../static/style'); 10 | 11 | // Expose to iframe 12 | window.react = React; 13 | window['react-dom'] = ReactDOM; 14 | // window.antd = require('antd'); 15 | /* eslint-enable global-require */ 16 | } 17 | 18 | export default function Index(props) { 19 | return (<Layout {...props} />); 20 | } 21 | -------------------------------------------------------------------------------- /site/theme/template/NotFound.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'bisheng/router'; 3 | // import * as utils from './utils'; 4 | 5 | export default function NotFound() { 6 | return ( 7 | <div id="page-404"> 8 | <section> 9 | <h1>404</h1> 10 | <p> 11 | 你要找的页面不存在 12 | <Link to="dsf">返回首页</Link> 13 | </p> 14 | </section> 15 | <style 16 | dangerouslySetInnerHTML={{ 17 | __html: '#react-content { height: 100%; background-color: #fff }', 18 | }} 19 | /> 20 | </div> 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /site/theme/template/Other/Cases.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Row, Col } from 'antd'; 4 | 5 | import './cases.less'; 6 | 7 | export default class Demo extends React.PureComponent { 8 | render() { 9 | return ( 10 | <Row gutter={24}> 11 | {this.props.data.map((item) => ( 12 | <Col xl={12} sm={24} xs={24} key={item.title}> 13 | <a href={item.url} target="_black" className="cases-content-wrapper"> 14 | <div className="img-wrapper"><img src={item.img} width="100%" alt="img" /></div> 15 | <div> 16 | <h3>{item.title}</h3> 17 | <p>{item.content}</p> 18 | </div> 19 | </a> 20 | </Col> 21 | ))} 22 | </Row> 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /site/theme/template/Other/Download.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Row, Col } from 'antd'; 3 | import ImageLoadComp from '../Home/component/ImageLoadComp'; 4 | 5 | import './download.less'; 6 | 7 | export default function Download({ data }) { 8 | return ( 9 | <Row gutter={24}> 10 | {data.map((item) => ( 11 | <Col key={item.title} sm={24} md={12} xxl={8} className="resource-wrapper"> 12 | <a className="resource-cards" 13 | href={item.url} 14 | target="_blank" 15 | onClick={() => { 16 | if (!location.port && window.gtag) { 17 | window.gtag('event', `saveSKetch_${item.name}`); 18 | } 19 | }} 20 | > 21 | <ImageLoadComp className="img-wrapper" src={item.img} /> 22 | <div className="text-wrapper"> 23 | <h3>{item.title}</h3> 24 | <p>{item.content}</p> 25 | </div> 26 | </a> 27 | </Col> 28 | ))} 29 | </Row> 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /site/theme/template/Other/cases.less: -------------------------------------------------------------------------------- 1 | @import '../../static/antd.less'; 2 | @import '../../static/default.less'; 3 | .markdown .cases-content-wrapper { 4 | padding: 10px; 5 | background: #f2f4f5; 6 | border-radius: 4px; 7 | .mouseHover(#666); 8 | display: block; 9 | will-change: transform; 10 | margin-bottom: 24px; 11 | .img-wrapper { 12 | border-radius: 2px; 13 | overflow: hidden; 14 | } 15 | h3 { 16 | font-size: 16px; 17 | margin: 16px auto 8px; 18 | line-height: 1.5; 19 | } 20 | p { 21 | margin: auto; 22 | color: #314659; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /site/theme/template/Other/download.less: -------------------------------------------------------------------------------- 1 | @import '../../static/antd.less'; 2 | @import '../../static/default.less'; 3 | .resource-wrapper { 4 | margin-bottom: 24px; 5 | } 6 | .resource-cards { 7 | padding: 10px; 8 | background: #fff; 9 | border-radius: 4px; 10 | border: 1px solid #f0f0f0; 11 | .mouseHover(#999); 12 | display: block; 13 | .img-wrapper { 14 | border-radius: 2px; 15 | overflow: hidden; 16 | height: 310px; 17 | background-size: 100% auto; 18 | background-repeat: no-repeat; 19 | background-position: top center; 20 | background-color: #f0f0f0; 21 | } 22 | 23 | .text-wrapper { 24 | h3 { 25 | margin: 16px auto 8px; 26 | line-height: 1.5; 27 | } 28 | p { 29 | font-size: 12px; 30 | margin: auto; 31 | color: fade(@text-color, 75); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /site/theme/zh-CN.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | locale: 'zh-CN', 3 | messages: { 4 | 'app.header.menu.home': '首页', 5 | 'app.header.menu.language': '文档', 6 | 'app.header.menu.edit': '编辑器', 7 | 'app.home.introduce': 'Ant Design Landing 平台拥有丰富的各类首页模板,下载模板代码包,即可快速使用,也可使用首页编辑器,快速搭建一个属于你的专属首页', 8 | 'app.home.select-template': '丰富模板', 9 | 'app.home.enter-editor': '进入编辑器', 10 | 'app.home.module': '丰富的模块', 11 | 'app.home.features': '三大特征', 12 | 'app.home.fatures.language': '设计指引', 13 | 'app.home.fatures.sketch': 'Sketch 资源包', 14 | 'app.home.fatures.responsive': '响应式布局', 15 | 'app.home.templates': '丰富的模板', 16 | 'app.home.preview': '预览', 17 | 'app.home.edit': '编辑', 18 | 'app.home.download': '下载', 19 | 'app.home.edit-slogen': '所有模板与模块都基于 Ant Design 设计规范设计,你可以直接下载我们的模板和源文件,也可使用我们的编辑器,快速搭建一个属于你的专属首页', 20 | 'app.home.slogan': 'Ant Design Landing 模板与规范', 21 | 'app.content.edit-page': '在 Github 上编辑此页!', 22 | 'app.footer.repo': '源码仓库', 23 | 'app.footer.template': '模板仓库', 24 | 'app.footer.chinamirror': '国内镜像站点 🇨🇳', 25 | 'app.footer.scaffolds': '脚手架市场', 26 | 'app.footer.links': '相关站点', 27 | 'app.footer.data-vis': '蚂蚁数据可视化方案', 28 | 'app.footer.eggjs': '企业级 Node Web 开发框架', 29 | 'app.footer.motion': '设计动效', 30 | 'app.footer.kitchen': 'Sketch 工具集', 31 | 'app.footer.antd-library': 'Axure 部件库', 32 | 'app.footer.umi': 'React 应用开发框架', 33 | 'app.footer.dumi': '组件/文档研发工具', 34 | 'app.footer.dva': '数据流前端框架', 35 | 'app.footer.design-platform': '蚂蚁金服设计平台', 36 | 'app.footer.antux': '页面逻辑素材', 37 | 'app.footer.community': '社区', 38 | 'app.footer.issues': '讨论列表', 39 | 'app.footer.work-with-us': '加入我们', 40 | 'app.footer.author': '蚂蚁金服体验技术部出品 @ AFX', 41 | 'app.footer.resources': '相关资源', 42 | 'app.footer.more-product': '更多产品', 43 | 'app.footer.yuque': '语雀', 44 | 'app.footer.yuque.slogan': '知识创作·协作平台', 45 | 'app.footer.fengdie': '云凤蝶', 46 | 'app.footer.fengdie.slogan': '移动建站平台', 47 | 'app.footer.seeconf': '蚂蚁体验科技大会', 48 | 'app.footer.xcloud': '蚂蚁体验云', 49 | 'app.footer.lang': 'English', 50 | 'app.layout.notification.title': '关注下 Star 数', 51 | 'app.layout.notification.content': '我们需要您的支持,请点击按钮帮助我们增加 github star。', 52 | }, 53 | }; 54 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* eslint no-param-reassign: 0 */ 2 | // This config is for building dist files 3 | const getWebpackConfig = require('antd-tools/lib/getWebpackConfig'); 4 | 5 | const { webpack } = getWebpackConfig; 6 | 7 | // noParse still leave `require('./locale' + name)` in dist files 8 | // ignore is better: http://stackoverflow.com/q/25384360 9 | function ignoreMomentLocale(webpackConfig) { 10 | delete webpackConfig.module.noParse; 11 | webpackConfig.plugins.push(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)); 12 | } 13 | 14 | function externalMoment(config) { 15 | config.externals.moment = { 16 | root: 'moment', 17 | commonjs2: 'moment', 18 | commonjs: 'moment', 19 | amd: 'moment', 20 | }; 21 | } 22 | 23 | const webpackConfig = getWebpackConfig(false); 24 | if (process.env.RUN_ENV === 'PRODUCTION') { 25 | webpackConfig.forEach((config) => { 26 | ignoreMomentLocale(config); 27 | externalMoment(config); 28 | }); 29 | } 30 | 31 | module.exports = webpackConfig; 32 | --------------------------------------------------------------------------------