├── .babelrc ├── .editorconfig ├── .gitignore ├── LICENSE ├── app ├── app.js ├── entry.js ├── index.html ├── root.js └── views │ ├── home │ └── index.js │ └── tabs │ └── index.js ├── karma.conf.js ├── less ├── all.less ├── fonts │ ├── webui_iconfont.eot │ ├── webui_iconfont.svg │ ├── webui_iconfont.ttf │ └── webui_iconfont.woff ├── sui │ ├── accordion.less │ ├── badges.less │ ├── bars.less │ ├── base.less │ ├── buttons.less │ ├── calendar.less │ ├── cards.less │ ├── colors.less │ ├── content-block.less │ ├── demos.less │ ├── docs-baichuan.less │ ├── docs.less │ ├── fonts.less │ ├── forms.less │ ├── grid.less │ ├── icons.less │ ├── infinite.less │ ├── lists.less │ ├── mixins.less │ ├── modal.less │ ├── normalize.less │ ├── pages.less │ ├── panels.less │ ├── photo-browser.less │ ├── picker.less │ ├── preloader.less │ ├── pull-to-refresh.less │ ├── push.less │ ├── rem.less │ ├── scroller.less │ ├── searchbar.less │ ├── sm-extend.less │ ├── sm.less │ ├── swiper.less │ ├── tabs.less │ ├── text.less │ ├── themes.less │ └── variables.less └── webui │ └── index.less ├── package.json ├── src ├── Button.js ├── ButtonRow.js ├── Col.js ├── Icon.js ├── Image.js ├── Row.js ├── constant.js ├── core │ └── createEnhance.js ├── enhance │ ├── css.js │ ├── dom.js │ ├── index.js │ └── pureRender.js ├── footer │ ├── Footer.js │ └── FooterItem.js ├── header │ ├── Header.js │ └── HeaderItem.js ├── tabs │ ├── Tab.js │ ├── TabNav.js │ └── Tabs.js └── utils │ ├── shallowCompare.js │ └── shallowEqual.js ├── test ├── ButtonSpec.js └── index.js ├── webpack.config.js └── webpack.dev.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0, 3 | "optional": ["runtime"], 4 | "loose": ["all"] 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | #EditorConfig是一套用于统一代码工具的解决方案 2 | #EditorConfig可以帮助开发者在不同的编辑器和IDE之间定义和维护一致的代码风格。 3 | #EditorConfig包含一个用于定义代码格式的文件和一批编辑器插件, 4 | #这些插件可以让编辑器读取配置文件并依此格式化代码 5 | 6 | #常见配置 7 | # 8 | # indent_style:tab为hard-tabs,space为soft-tabs。 9 | # 10 | # indent_size:设置整数表示规定每级缩进的列数和soft-tabs的宽度(译注:空格数) 11 | # 。如果设定为tab,则会使用tab_width的值(如果已指定)。 12 | # 13 | # tab_width:设置整数用于指定替代tab的列数。默认值就是indent_size的值,一般无需指定。 14 | # 15 | # end_of_line:定义换行符,支持lf、cr和crlf。 16 | # 17 | # charset:编码格式,支持latin1、utf-8、utf-8-bom、utf-16be和utf-16le,不建议使用uft-8-bom。 18 | # 19 | # trim_trailing_whitespace:设为true表示会除去换行行首的任意空白字符,false反之。 20 | # 21 | # insert_final_newline:设为true表明使文件以一个空白行结尾,false反之。 22 | # 23 | # root:表明是最顶层的配置文件,发现设为true时,才会停止查找.editorconfig文件。 24 | 25 | root=true 26 | 27 | [*] 28 | end_of_line = lf 29 | insert_final_newline = true 30 | 31 | [*.js] 32 | charset = utf-8 33 | indent_style = space 34 | indent_size = 4 35 | 36 | [{package.json}] 37 | indent_style = space 38 | indent_size = 4 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### SublimeText ### 2 | *.sublime-workspace 3 | /.idea/ 4 | 5 | ### OSX ### 6 | .DS_Store 7 | .AppleDouble 8 | .LSOverride 9 | Icon 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear on external disk 15 | .Spotlight-V100 16 | .Trashes 17 | 18 | ### Windows ### 19 | # Windows image file caches 20 | Thumbs.db 21 | ehthumbs.db 22 | 23 | # Folder config file 24 | Desktop.ini 25 | 26 | # Recycle Bin used on file shares 27 | $RECYCLE.BIN/ 28 | 29 | # App specific 30 | 31 | node_modules/ 32 | .tmp 33 | /dist/ 34 | /src/main.js 35 | app/scripts/vendor/zepto/ 36 | 37 | #lib# 38 | /lib/ 39 | 40 | #npm# 41 | /npm-debug.log 42 | 43 | /app/extras/release/ 44 | 45 | /app/extras/build/ 46 | 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | import React , { Component } from 'react'; 2 | require("../less/all.less"); 3 | export default class App extends Component{ 4 | render=()=>{ 5 | return ( 6 |
7 | {this.props.children} 8 |
9 | ); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/entry.js: -------------------------------------------------------------------------------- 1 | import { render } from 'react-dom'; 2 | import Root from './root.js'; 3 | import createBrowserHistory from 'history/lib/createHashHistory'; 4 | let history = createBrowserHistory(); 5 | 6 | 7 | /*document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);*/ 8 | render( 9 | , 10 | document.getElementById('container') 11 | ); 12 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | React-mui 11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 |
19 |
20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/root.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liubo on 15/7/28. 3 | */ 4 | 5 | import React, { Component, PropTypes } from 'react'; 6 | import { Router, Route, Redirect } from 'react-router'; 7 | 8 | 9 | //视图 10 | import App from './app.js'; 11 | import Home from './views/home/index.js'; 12 | import Tabs from './views/tabs/index.js'; 13 | 14 | const routes = ( 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ) 23 | 24 | 25 | //自定义createElement方法 26 | const createElement = (Component, props) => { 27 | return 28 | } 29 | 30 | //Root 31 | export default class Root extends Component { 32 | render =()=> { 33 | 34 | return ( 35 |
36 | 37 |
38 | ); 39 | } 40 | } 41 | Root.propTypes = { 42 | history: PropTypes.object.isRequired 43 | }; 44 | -------------------------------------------------------------------------------- /app/views/home/index.js: -------------------------------------------------------------------------------- 1 | import React , { Component } from 'react'; 2 | import Button from '../../../src/Button'; 3 | import ButtonRow from '../../../src/ButtonRow'; 4 | import Header from '../../../src/header/Header'; 5 | import HeaderItem from '../../../src/header/HeaderItem'; 6 | import Footer from '../../../src/footer/Footer'; 7 | import FooterItem from '../../../src/footer/FooterItem'; 8 | export default class Home extends Component { 9 | 10 | render=()=>{ 11 | return ( 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {/*
22 | 23 | 24 |
25 | 26 |
27 | 28 | 29 |
30 | */} 31 |
32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/views/tabs/index.js: -------------------------------------------------------------------------------- 1 | import React , { Component } from 'react'; 2 | 3 | import Tabs from '../../../src/tabs/Tabs'; 4 | import Tab from '../../../src/tabs/Tab'; 5 | import Header from '../../../src/header/Header'; 6 | import HeaderItem from '../../../src/header/HeaderItem'; 7 | import Footer from '../../../src/footer/Footer'; 8 | import FooterItem from '../../../src/footer/FooterItem'; 9 | import ReactGestures from 'react-gestures'; 10 | export default class Home extends Component { 11 | constructor(){ 12 | super(); 13 | this.state={ 14 | activeKey:"1" 15 | } 16 | } 17 | onTabChange=(key)=>{ 18 | 19 | } 20 | onSwipeLeft=()=>{ 21 | alert("x11x"); 22 | } 23 | render=()=>{ 24 | let { activeKey } = this.state; 25 | return ( 26 |
27 |
28 | 29 | 30 |
31 |
32 | 33 | 34 |
35 |
36 | 37 | 38 | 39 |
这是全部的标签页
40 | 41 | 42 |
43 | 这是未付款的标签页 44 | 这是已付款的标签页 45 |
46 |
47 | 48 |
49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | module.exports = function(config){ 3 | config.set({ 4 | basePath: '', 5 | frameworks: [ 6 | 'mocha', 7 | 'sinon-chai' 8 | ], 9 | files: [ 10 | 'test/index.js' 11 | ], 12 | webpack:{ 13 | devtool: 'inline-source-map', 14 | module: { 15 | loaders: [ 16 | { 17 | test: /\.js$/, 18 | loader: 'babel-loader', 19 | exclude: /node_modules/ 20 | } 21 | ] 22 | } 23 | }, 24 | preprocessors: { 25 | 'test/index.js': [ 'webpack', 'sourcemap' ] 26 | }, 27 | webpackServer: { 28 | noInfo: true 29 | }, 30 | autoWatch: true, 31 | singleRun: true, 32 | port: 9876, 33 | colors: true, 34 | browsers: [ 'Chrome' ], 35 | 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /less/all.less: -------------------------------------------------------------------------------- 1 | @import url("sui/fonts.less"); 2 | @import url("sui/variables.less"); 3 | 4 | // Mixins 5 | @import url("sui/mixins.less"); 6 | 7 | // Normalize & Base CSS 8 | @import url("sui/rem.less"); 9 | @import url("sui/normalize.less"); 10 | @import url("sui/base.less"); 11 | @import url("sui/content-block.less"); 12 | 13 | @import url("sui/grid.less"); 14 | 15 | 16 | // Components 17 | //@import url("sui/text.less"); 18 | @import url("sui/bars.less"); 19 | //@import url("sui/badges.less"); 20 | //@import url("sui/lists.less"); 21 | //@import url("sui/forms.less"); 22 | //@import url("sui/searchbar.less"); 23 | @import url("sui/buttons.less"); 24 | //@import url("sui/tabs.less"); 25 | 26 | @import url("sui/pages.less"); 27 | //@import url("sui/scroller.less"); 28 | //@import url("sui/pull-to-refresh.less"); 29 | //@import url("sui/infinite.less"); 30 | //@import url("sui/modal.less"); 31 | //@import url("sui/preloader.less"); 32 | //@import url("sui/lists.less"); 33 | //@import url("sui/cards.less"); 34 | //@import url("sui/panels.less"); 35 | //@import url("sui/calendar.less"); 36 | //@import url("sui/picker.less"); 37 | 38 | 39 | 40 | @import url("sui/themes.less"); 41 | @import url("sui/colors.less"); 42 | 43 | 44 | 45 | @import url("webui/index.less"); 46 | -------------------------------------------------------------------------------- /less/fonts/webui_iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liugenpeng/react-webui/31a06db62af65b2801272817871cd271ffae70bb/less/fonts/webui_iconfont.eot -------------------------------------------------------------------------------- /less/fonts/webui_iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liugenpeng/react-webui/31a06db62af65b2801272817871cd271ffae70bb/less/fonts/webui_iconfont.ttf -------------------------------------------------------------------------------- /less/fonts/webui_iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liugenpeng/react-webui/31a06db62af65b2801272817871cd271ffae70bb/less/fonts/webui_iconfont.woff -------------------------------------------------------------------------------- /less/sui/accordion.less: -------------------------------------------------------------------------------- 1 | /* === Accordion === */ 2 | .list-block { 3 | .accordion-item-toggle { 4 | cursor: pointer; 5 | transition-duration: 300ms; 6 | .item-inner { 7 | padding-right: 1.75rem; 8 | background: no-repeat -webkit-calc(~"100% - 15px") center; 9 | background: no-repeat calc(~"100% - 15px") center; 10 | .encoded-svg-background(""); 11 | background-size: 0.5rem 1rem; 12 | 13 | } 14 | html:not(.watch-active-state) &:active, &.active-state { 15 | transition-duration: 0ms; 16 | background-color: #d9d9d9; 17 | > .item-inner { 18 | .hairline-color(bottom, transparent); 19 | } 20 | } 21 | } 22 | .accordion-item-toggle, .accordion-item > .item-link { 23 | .item-inner { 24 | transition-duration: 300ms; 25 | &:after { 26 | transition-duration: 300ms; 27 | } 28 | -webkit-transition-property: background-color; 29 | transition-property: background-color; 30 | } 31 | } 32 | .accordion-item-expanded { 33 | .accordion-item-toggle .item-inner, > .item-link .item-inner { 34 | .encoded-svg-background(""); 35 | background-size: 1rem 1rem; 36 | .hairline-color(bottom, transparent); 37 | } 38 | } 39 | .accordion-item { 40 | .content-block, .list-block { 41 | margin-top: 0; 42 | margin-bottom: 0; 43 | } 44 | ul { 45 | padding-left: 0; 46 | } 47 | } 48 | } 49 | .accordion-item-content { 50 | position: relative; 51 | overflow: hidden; 52 | height: 0; 53 | font-size: 0.7rem; 54 | transition-duration: 300ms; 55 | transform: translate3d(0,0,0); 56 | .accordion-item-expanded > &{ 57 | height: auto; 58 | } 59 | html.android-4 & { 60 | transform: none; 61 | } 62 | } 63 | .custom-accordion { 64 | padding-left: 0; 65 | padding-right: 0; 66 | .accordion-item-toggle { 67 | padding: 0 0.75rem; 68 | height: 2.2rem; 69 | line-height: 2.2rem; 70 | font-size: 0.85rem; 71 | color: @color-text; 72 | border-bottom: 1px solid rgba(0, 0, 0, 0.15); 73 | cursor: pointer; 74 | &:active { 75 | background: rgba(0, 0, 0, 0.15); 76 | } 77 | span { 78 | display: inline-block; 79 | margin-left: 0.75rem; 80 | } 81 | } 82 | .accordion-item{ 83 | &:last-child{ 84 | .accordion-item-toggle { 85 | border-bottom: none; 86 | } 87 | } 88 | } 89 | .icon-plus, 90 | .icon-minus { 91 | display: inline-block; 92 | width: 1.1rem; 93 | height: 1.1rem; 94 | border: 1px solid @color-text; 95 | border-radius: 100%; 96 | line-height: 1rem; 97 | text-align: center; 98 | &:before{ 99 | content: ""; 100 | } 101 | } 102 | .icon-minus { 103 | display: none; 104 | } 105 | .accordion-item-expanded{ 106 | .icon-minus { 107 | display: inline-block; 108 | } 109 | .icon-plus { 110 | display: none; 111 | } 112 | } 113 | .accordion-item-content { 114 | padding: 0 0.75rem; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /less/sui/badges.less: -------------------------------------------------------------------------------- 1 | // 2 | // Badges 3 | // -------------------------------------------------- 4 | 5 | .badge { 6 | display: inline-block; 7 | padding: 0.1rem 0.45rem 0.15rem; 8 | font-size: 0.6rem; 9 | line-height: 1; 10 | color: @color-text; 11 | background-color: rgba(0, 0, 0,.15); 12 | border-radius: 5rem; 13 | 14 | // Inverted badges have no background. 15 | &.badge-inverted { 16 | padding: 0 0.25rem 0 0; 17 | background-color: transparent; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /less/sui/bars.less: -------------------------------------------------------------------------------- 1 | // 2 | // Bars 3 | // -------------------------------------------------- 4 | 5 | .bar { 6 | position: absolute; 7 | right: 0; 8 | left: 0; 9 | z-index: 10; 10 | height: @bar-base-height; 11 | padding-right: @bar-side-spacing; 12 | padding-left: @bar-side-spacing; 13 | background-color: #f7f7f8; 14 | .hairline(bottom, @border-default-color); 15 | -webkit-backface-visibility: hidden; // Make sure the bar is visible when a modal animates in. 16 | backface-visibility: hidden; 17 | } 18 | 19 | // Modifier class to dock any bar below .bar-nav 20 | .bar-header-secondary { 21 | top: @bar-base-height; 22 | } 23 | 24 | // Modifier class for footer bars 25 | .bar-footer { 26 | bottom: 0; 27 | } 28 | 29 | 30 | // Modifier class to dock any bar above a standard bar 31 | .bar-footer-secondary { 32 | bottom: @bar-base-height; 33 | } 34 | 35 | // Modifier class to dock any bar above a .bar-tab 36 | .bar-footer-secondary-tab { 37 | bottom: @bar-tab-height; 38 | } 39 | 40 | // Give the footers the correct border 41 | .bar-footer, 42 | .bar-footer-secondary, 43 | .bar-footer-secondary-tab { 44 | .hairline(top, @border-default-color); 45 | .hairline-remove(bottom); 46 | } 47 | 48 | 49 | // Nav bar 50 | // -------------------------------------------------- 51 | 52 | // Bar docked to top of viewport for showing page title and actions 53 | .bar-nav { 54 | top: 0; 55 | } 56 | 57 | // Centered text in the .bar-nav 58 | // 59 | // We position the absolutely to make sure the title is always centered 60 | .title { 61 | position: absolute; 62 | display: block; 63 | width: 100%; 64 | padding: 0; 65 | margin: 0 (-@bar-side-spacing); 66 | font-size: @font-size-default; 67 | font-weight: @font-weight; 68 | line-height: @bar-base-height; 69 | color: @color-text; 70 | text-align: center; 71 | white-space: nowrap; 72 | } 73 | // Retain specified title color 74 | .title a { 75 | color: inherit; 76 | } 77 | 78 | 79 | // Tab bar 80 | // -------------------------------------------------- 81 | 82 | // Bar docked to bottom and used for primary app navigation 83 | .bar-tab { 84 | bottom: 0; 85 | width: 100%; 86 | height: @bar-tab-height; 87 | padding: 0; 88 | table-layout: fixed; 89 | .hairline(top, @border-default-color); 90 | .hairline-remove(bottom); 91 | 92 | // Navigational tab (Nested to be more specific for the icons in tab-items) 93 | .tab-item { 94 | position: relative; 95 | display: table-cell; 96 | width: 1%; 97 | height: @bar-tab-height; 98 | color: #929292; 99 | text-align: center; 100 | vertical-align: middle; 101 | 102 | // Active states for the tab bar 103 | &.active, 104 | &:active { 105 | color: @color-primary; 106 | } 107 | 108 | // Activity badge on an icon 109 | .badge { 110 | position: absolute; 111 | top: .1rem; 112 | left: 50%; 113 | z-index: 100; 114 | height: .8rem; 115 | min-width: .8rem; 116 | padding: 0 .2rem; 117 | font-size: .6rem; 118 | line-height: .8rem; 119 | color: white; 120 | vertical-align: top; 121 | background: red; 122 | border-radius: .5rem; 123 | margin-left: .1rem; 124 | } 125 | 126 | // Tab icon 127 | .icon { 128 | top: 0.15rem; 129 | width: 1.2rem; 130 | height: 1.2rem; 131 | font-size: 1.2rem; 132 | line-height: 1.2rem; 133 | padding-top: 0; 134 | padding-bottom: 0; 135 | 136 | // Make the text smaller if it's used with an icon ' 137 | ~ .tab-label { 138 | display: block; 139 | font-size: 0.55rem; 140 | position: relative; 141 | top: 0.15rem; 142 | } 143 | } 144 | } 145 | } 146 | 147 | // Bars with buttons 148 | // -------------------------------------------------- 149 | 150 | .bar .button { 151 | position: relative; 152 | top: 0.35rem; 153 | z-index: 20; // Position the buttons on top of .title 154 | margin-top: 0; 155 | font-weight: @font-weight-light; 156 | 157 | // Give buttons that are floated left and right side margin 158 | &.pull-right { 159 | margin-left: @bar-side-spacing; 160 | } 161 | &.pull-left { 162 | margin-right: @bar-side-spacing; 163 | } 164 | } 165 | 166 | // Bars with link buttons (Line the text up with content) 167 | .bar .button-link { 168 | top: 0; 169 | padding: 0; 170 | font-size: 0.8rem; 171 | line-height: @bar-base-height; 172 | height: @bar-base-height; 173 | color: @color-primary; 174 | border: 0; 175 | 176 | &:active, 177 | &.active { 178 | color: darken(@color-primary, 10%); 179 | } 180 | } 181 | 182 | // Bars with block buttons 183 | // 184 | // Add proper padding 185 | .bar .button-block { 186 | top: 0.35rem; 187 | font-size: 0.8rem; // Scale down font size to fit in bar. 188 | width: 100%; 189 | } 190 | 191 | // Nav buttons (Only applicable within bars) 192 | // 193 | // Buttons inside bars that sit closer against the viewport. 194 | .bar .button-nav { 195 | &.pull-left { 196 | margin-left: -0.25rem; 197 | 198 | .icon-left-nav { 199 | margin-right: -0.15rem; 200 | } 201 | } 202 | &.pull-right { 203 | margin-right: -0.25rem; 204 | 205 | .icon-right-nav { 206 | margin-left: -0.15rem; 207 | } 208 | } 209 | } 210 | 211 | 212 | // Bars with Ratchicons 213 | // -------------------------------------------------- 214 | 215 | .bar { 216 | .icon { 217 | position: relative; 218 | z-index: 20; // Position the buttons on top of .title 219 | padding: .5rem .1rem; 220 | font-size: 1rem; 221 | line-height: 1.2rem; 222 | } 223 | 224 | // Vertical center the larger icons in buttons. 225 | .button .icon { 226 | padding: 0; 227 | } 228 | 229 | // Handle carets in the titles 230 | .title .icon { 231 | padding: 0; 232 | 233 | // Specific postioning of the caret icon within a title. Used with popover.js. 234 | &.icon-caret { 235 | top: 0.2rem; 236 | margin-left: -0.25rem; 237 | } 238 | } 239 | } 240 | 241 | .bar-footer .icon { 242 | font-size: 1.2rem; 243 | line-height: 1.2rem; 244 | } 245 | 246 | // Bars for search forms 247 | // -------------------------------------------------- 248 | 249 | // Position/size search bar within the bar 250 | .bar input[type="search"] { 251 | height: 1.45rem; 252 | margin: 0.3rem 0; 253 | } 254 | -------------------------------------------------------------------------------- /less/sui/base.less: -------------------------------------------------------------------------------- 1 | // 2 | // Base styles 3 | // -------------------------------------------------- 4 | 5 | // Use box sizing on all the things! 6 | * { 7 | box-sizing: border-box; 8 | -webkit-tap-highlight-color: rgba(0,0,0,0); 9 | -webkit-touch-callout:none; 10 | } 11 | 12 | // We fix position the body and scroll `.content`. 13 | body { 14 | position: absolute; 15 | top: 0; 16 | right: 0; 17 | bottom: 0; 18 | left: 0; 19 | font-family: @font-family-default; 20 | font-size: @font-size-default; 21 | line-height: 1.5; 22 | color: @color-text; 23 | background: @color-bg; 24 | overflow: hidden; 25 | } 26 | 27 | a, input, textarea, select, button { 28 | outline: 0; 29 | } 30 | 31 | p { 32 | margin: 1em 0; 33 | } 34 | 35 | // Universal link styling 36 | a { 37 | color: @color-link; 38 | text-decoration: none; 39 | -webkit-tap-highlight-color: rgba(0,0,0,0); // Removes the dark touch outlines on links in webkit browsers. 40 | 41 | &:active { 42 | color: @color-link-active; 43 | } 44 | } 45 | 46 | .page { 47 | position: absolute; 48 | top: 0; 49 | right: 0; 50 | bottom: 0; 51 | left: 0; 52 | background: @color-bg; 53 | z-index: 2000; 54 | } 55 | 56 | // Wrapper to be used around all content not in .bar-title and .bar-tab 57 | .content { 58 | position: absolute; 59 | top: 0; 60 | right: 0; 61 | bottom: 0; 62 | left: 0; 63 | overflow: auto; 64 | -webkit-overflow-scrolling: touch; 65 | } 66 | 67 | // Hack to force all relatively and absolutely positioned elements still render while scrolling 68 | // Note: This is a bug for "-webkit-overflow-scrolling: touch" 69 | .content > * { 70 | //transform: translateZ(0); //这一行会导致三星 S4 android 4.2 无法滚动 71 | } 72 | 73 | // Pad top/bottom of content so it doesn't hide behind bars. 74 | // Note: For these to work, content must come after both bars in the markup 75 | .bar-nav ~ .content { 76 | top: @bar-base-height; 77 | } 78 | .bar-header-secondary ~ .content { 79 | top: (@bar-base-height*2); 80 | } 81 | 82 | // Footer bar margin 83 | .bar-footer ~ .content { 84 | bottom: @bar-base-height; 85 | } 86 | .bar-footer-secondary ~ .content { 87 | bottom: (@bar-base-height*2); 88 | } 89 | 90 | // Tab bar margin 91 | .bar-tab ~ .content { 92 | bottom: @bar-tab-height; 93 | } 94 | .bar-footer-secondary-tab ~ .content { 95 | bottom: (@bar-tab-height+@bar-base-height); 96 | } 97 | 98 | // Utility classes 99 | .content-padded { 100 | margin: @bar-side-spacing; 101 | } 102 | .text-center { 103 | text-align: center; 104 | } 105 | .pull-left { 106 | float: left; 107 | } 108 | .pull-right { 109 | float: right; 110 | } 111 | .clearfix { 112 | .clearfix(); 113 | } 114 | -------------------------------------------------------------------------------- /less/sui/buttons.less: -------------------------------------------------------------------------------- 1 | //Buttons 2 | .button { 3 | @btn-height: 1.35rem; 4 | @btn-big-height: 2.4rem; 5 | border: 1px solid @color-primary; 6 | color: @color-primary; 7 | text-decoration: none; 8 | text-align: center; 9 | display: block; 10 | border-radius: 0.25rem; 11 | line-height: (@btn-height - 0.1rem); 12 | box-sizing: border-box; 13 | -webkit-appearance: none; 14 | -moz-appearance: none; 15 | -ms-appearance: none; 16 | appearance: none; 17 | background: none; 18 | padding: 0 0.5rem; 19 | margin: 0; 20 | height: @btn-height; 21 | white-space: nowrap; 22 | position: relative; 23 | text-overflow:ellipsis; 24 | font-size: 0.7rem; 25 | font-family: inherit; 26 | cursor: pointer; 27 | input[type="submit"]&, input[type="button"]&{ 28 | width: 100%; 29 | } 30 | 31 | &:active { 32 | color: @color-primary-active; 33 | border-color: @color-primary-active; 34 | } 35 | &.button-round { 36 | border-radius: (@btn-height - 0.1rem); 37 | } 38 | &.active { 39 | &, &:active { 40 | color: @color-primary-active; 41 | border-color: @color-primary-active; 42 | } 43 | } 44 | &.button-big { 45 | font-size: 0.85rem; 46 | height: @btn-big-height; 47 | line-height: (@btn-big-height - 0.1rem); 48 | } 49 | &.button-fill { 50 | color:#fff; 51 | background: @color-primary; 52 | border: none; 53 | line-height: @btn-height; 54 | &.active, &:active { 55 | background: @color-primary-active; 56 | } 57 | &.button-big { 58 | line-height: @btn-big-height; 59 | } 60 | } 61 | .button-link { 62 | padding-top: 0.3rem; 63 | padding-bottom: 0.3rem; 64 | color: @color-primary; 65 | background-color: transparent; 66 | border: 0; 67 | } 68 | i.icon { 69 | &:first-child { 70 | margin-right: 0.5rem; 71 | } 72 | &:last-child { 73 | margin-left: 0.5rem; 74 | } 75 | &:first-child:last-child { 76 | margin-left: 0; 77 | margin-right: 0; 78 | } 79 | } 80 | } 81 | 82 | .button-variant(@color, @color-active) { 83 | border-color: @color; 84 | color: @color; 85 | &:active { 86 | border-color: @color-active; 87 | color: @color-active; 88 | } 89 | &.button-fill { 90 | color: white; 91 | background-color: @color; 92 | &:active { 93 | background-color: @color-active; 94 | } 95 | } 96 | } 97 | .button-themes() { 98 | &.button-light { 99 | .button-variant(@color-text-gray-light, @color-primary-active); 100 | color: @color-text-secondary; 101 | } 102 | &.button-dark { 103 | .button-variant(#6e727b, @color-primary-active); 104 | color: @color-text-secondary; 105 | } 106 | &.button-success { 107 | .button-variant(@color-success, @color-success-active); 108 | } 109 | &.button-danger { 110 | .button-variant(@color-danger, @color-danger-active); 111 | } 112 | &.button-warning { 113 | .button-variant(@color-warning, @color-warning-active); 114 | } 115 | } 116 | .button-themes(); 117 | 118 | .button { 119 | &, 120 | &.button-primary, 121 | &.button-success, 122 | &.button-danger, 123 | &.button-warning { 124 | &.disabled { 125 | .button-variant(#c8c9cb, #c8c9cb); 126 | cursor: not-allowed; 127 | } 128 | } 129 | } 130 | 131 | .buttons-row, 132 | .buttons-tab { 133 | .align-self(center); 134 | .flexbox(); 135 | .flex-wrap(nowrap); 136 | } 137 | 138 | .buttons-row { 139 | .button { 140 | border-radius: 0 0 0 0; 141 | margin-left: -1px; 142 | width: 100%; 143 | -webkit-box-flex:1; 144 | -ms-flex:1; 145 | border-color: @color-primary; 146 | color: @color-primary; 147 | &.active { 148 | background-color: @color-primary; 149 | color: white; 150 | z-index: 100; 151 | } 152 | &:active { 153 | } 154 | } 155 | .button:first-child { 156 | border-radius: 0.25rem 0 0 0.25rem; 157 | margin-left: 0; 158 | border-left-width: 1px; 159 | border-left-style: solid; 160 | } 161 | .button:last-child { 162 | border-radius: 0 0.25rem 0.25rem 0; 163 | } 164 | .button.button-round:first-child { 165 | border-radius: 1.35rem 0 0 1.35rem; 166 | } 167 | .button.button-round:last-child { 168 | border-radius: 0 1.35rem 1.35rem 0; 169 | } 170 | } 171 | 172 | .buttons-tab { 173 | background: white; 174 | position: relative; 175 | .hairline(bottom, #d0d0d0); 176 | .button { 177 | color: @color-text-secondary; 178 | font-size: 0.8rem; 179 | width: 100%; 180 | height: 2rem; 181 | line-height: 2rem; 182 | -webkit-box-flex:1; 183 | -ms-flex:1; 184 | border: 0; 185 | border-bottom: 2px solid transparent; 186 | border-radius: 0; 187 | 188 | &.active { 189 | color: @color-primary; 190 | border-color: @color-primary; 191 | z-index: 100; 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /less/sui/calendar.less: -------------------------------------------------------------------------------- 1 | /* === Calendar === */ 2 | .picker-calendar { 3 | background: #fff; 4 | height: 300px; 5 | width: 100%; 6 | overflow: hidden; 7 | @media (orientation: landscape) and (max-height: 415px) { 8 | &:not(.picker-modal-inline) { 9 | height: 220px; 10 | } 11 | } 12 | .picker-modal-inner { 13 | overflow: hidden; 14 | } 15 | } 16 | .popover.popover-picker-calendar { 17 | width: 320px; 18 | } 19 | 20 | .picker-calendar-week-days { 21 | height: 18px; 22 | background: #f7f7f8; 23 | .flexbox(); 24 | .hairline(bottom, #c4c4c4); 25 | font-size: 11px; 26 | box-sizing: border-box; 27 | position: relative; 28 | .picker-calendar-week-day { 29 | .flex-shrink(1); 30 | width: 100% / 7; 31 | width: ~"-webkit-calc(100% / 7)"; 32 | width: ~"-moz-calc(100% / 7)"; 33 | width: ~"calc(100% / 7)"; 34 | line-height: 17px; 35 | text-align: center; 36 | } 37 | + .picker-calendar-months { 38 | height: ~"-webkit-calc(100% - 18px)"; 39 | height: ~"-moz-calc(100% - 18px)"; 40 | height: ~"calc(100% - 18px)"; 41 | } 42 | } 43 | .picker-calendar-months { 44 | width: 100%; 45 | height: 100%; 46 | overflow: hidden; 47 | position: relative; 48 | } 49 | .picker-calendar-months-wrapper { 50 | position: relative; 51 | width: 100%; 52 | height: 100%; 53 | transition: 300ms; 54 | } 55 | .picker-calendar-month { 56 | .flexbox(); 57 | -webkit-box-orient: vertical; 58 | -moz-box-orient: vertical; 59 | -ms-flex-direction: column; 60 | -webkit-flex-direction: column; 61 | flex-direction: column; 62 | width: 100%; 63 | height: 100%; 64 | position: absolute; 65 | left: 0; 66 | top: 0; 67 | } 68 | .picker-calendar-row { 69 | height: 100% / 6; 70 | height: ~"-webkit-calc(100% / 6)"; 71 | height: ~"-moz-calc(100% / 6)"; 72 | height: ~"calc(100% / 6)"; 73 | .flexbox(); 74 | .flex-shrink(1); 75 | width: 100%; 76 | position: relative; 77 | .hairline(bottom, #ccc); 78 | &:last-child { 79 | .hairline-remove(bottom); 80 | } 81 | } 82 | .picker-calendar-day { 83 | .flex-shrink(1); 84 | .flexbox(); 85 | .justify-content(center); 86 | .align-items(center); 87 | box-sizing: border-box; 88 | width: 100% / 7; 89 | width: ~"-webkit-calc(100% / 7)"; 90 | width: ~"-moz-calc(100% / 7)"; 91 | width: ~"calc(100% / 7)"; 92 | text-align: center; 93 | color:@color-text; 94 | font-size: 15px; 95 | cursor: pointer; 96 | &.picker-calendar-day-weekend { 97 | } 98 | &.picker-calendar-day-prev, &.picker-calendar-day-next { 99 | color: @color-text-gray-light; 100 | } 101 | .picker-calendar-month-prev &, .picker-calendar-month-next & { 102 | 103 | } 104 | &.picker-calendar-day-disabled { 105 | color: #d4d4d4; 106 | cursor: auto; 107 | } 108 | &.picker-calendar-day-today span { 109 | background: #e3e3e3; 110 | } 111 | &.picker-calendar-day-selected span { 112 | background: @color-primary; 113 | color:#fff; 114 | } 115 | span { 116 | display: inline-block; 117 | border-radius: 100%; 118 | width: 30px; 119 | height: 30px; 120 | line-height: 30px; 121 | 122 | } 123 | } 124 | .picker-calendar-month-picker, .picker-calendar-year-picker { 125 | .flexbox(); 126 | .align-items(center); 127 | .justify-content(space-between); 128 | width: 50%; 129 | max-width: 200px; 130 | .flex-shrink(10); 131 | a.icon-only { 132 | min-width: 36px; 133 | } 134 | span { 135 | .flex-shrink(1); 136 | position: relative; 137 | overflow: hidden; 138 | text-overflow: ellipsis; 139 | } 140 | } 141 | // Inline and popover borders 142 | .popover .picker-calendar, .picker-calendar.picker-modal-inline { 143 | .picker-calendar-week-days { 144 | background: none; 145 | } 146 | .toolbar, .picker-calendar-week-days { 147 | .hairline-remove(top); 148 | .hairline-remove(bottom); 149 | } 150 | .toolbar ~ .picker-modal-inner .picker-calendar-months, .picker-calendar-week-days ~ .picker-calendar-months { 151 | .hairline(top, #c4c4c4); 152 | } 153 | } 154 | 155 | //修复toolbar 156 | .picker-modal .toolbar-inner { 157 | height: 2.2rem; 158 | .flexbox(); 159 | text-align: center; 160 | } 161 | 162 | //修复Android 4.1 上 toolbar元素宽度错误 163 | //因为它不能对 inline 的元素设置宽度 164 | .picker-calendar-month-picker, .picker-calendar-year-picker { 165 | display: block; 166 | line-height: 2.2rem; 167 | 168 | a.icon-only { 169 | float: left; 170 | width: 25%; 171 | height: 2.2rem; 172 | line-height: 2rem; //不知道为什么 2.2rem 无法上下对齐; 173 | } 174 | .current-month-value, .current-year-value { 175 | float: left; 176 | width: 50%; 177 | height: 2.2rem; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /less/sui/cards.less: -------------------------------------------------------------------------------- 1 | /* === Cards === */ 2 | .cards-list, .card .list-block { 3 | ul { 4 | background: none; 5 | } 6 | > ul { 7 | .hairline-remove(top); 8 | .hairline-remove(bottom); 9 | } 10 | } 11 | .card { 12 | background: #fff; 13 | box-shadow: 0 0.05rem 0.1rem rgba(0,0,0,0.3); 14 | margin: 0.5rem; 15 | position: relative; 16 | border-radius: 0.1rem; 17 | font-size: 0.7rem; 18 | .list-block, .content-block { 19 | margin: 0; 20 | } 21 | .row:not(.no-gutter) .col > & { 22 | margin-left: 0; 23 | margin-right: 0; 24 | } 25 | } 26 | .card-content { 27 | position: relative; 28 | } 29 | .card-content-inner { 30 | padding: 0.75rem; 31 | position: relative; 32 | > p:first-child { 33 | margin-top: 0; 34 | } 35 | > p:last-child { 36 | margin-bottom: 0; 37 | } 38 | > .list-block, >.content-block { 39 | margin: -0.75rem; 40 | } 41 | } 42 | .card-header, .card-footer { 43 | min-height: 2.2rem; 44 | position: relative; 45 | padding: 0.5rem 0.75rem; 46 | box-sizing: border-box; 47 | .flexbox(); 48 | .justify-content(space-between); 49 | .align-items(center); 50 | &[valign="top"] { 51 | .align-items(flex-start); 52 | } 53 | &[valign="bottom"] { 54 | .align-items(flex-end); 55 | } 56 | a.link { 57 | line-height: 2.2rem; 58 | height: 2.2rem; 59 | text-decoration: none; 60 | position: relative; 61 | margin-top: -0.5rem; 62 | margin-bottom: -0.5rem; 63 | .flexbox(); 64 | .justify-content(flex-start); 65 | .align-items(center); 66 | transition-duration: 300ms; 67 | html:not(.watch-active-state) &:active, &.active-state { 68 | opacity: 0.3; 69 | transition-duration: 0ms; 70 | } 71 | i+span, i+i, span+i, span+span { 72 | margin-left: 0.35rem; 73 | } 74 | i.icon { 75 | display: block; 76 | } 77 | } 78 | a.icon-only { 79 | min-width: 2.2rem; 80 | .flexbox(); 81 | .justify-content(center); 82 | .align-items(center); 83 | margin: 0; 84 | } 85 | } 86 | .card-header { 87 | border-radius: 0.1rem 0.1rem 0 0; 88 | font-size: 0.85rem; 89 | .hairline(bottom, #e1e1e1); 90 | .card-cover { 91 | width: 100%; 92 | display: block; 93 | } 94 | &.no-border { 95 | .hairline-remove(bottom); 96 | } 97 | &.no-padding { 98 | padding: 0; 99 | } 100 | } 101 | .card-footer { 102 | border-radius: 0 0 0.1rem 0.1rem; 103 | color: @color-text-secondary; 104 | .hairline(top, #e1e1e1); 105 | &.no-border { 106 | .hairline-remove(top); 107 | } 108 | 109 | } 110 | 111 | .facebook-card{ 112 | .card-header { 113 | display: block; 114 | padding: 0.5rem; 115 | } 116 | .facebook-avatar { 117 | float: left; 118 | } 119 | .facebook-name { 120 | margin-left: 2.2rem; 121 | font-size: 0.7rem; 122 | font-weight: 500; 123 | } 124 | .facebook-date { 125 | margin-left: 2.2rem; 126 | font-size: 0.65rem; 127 | color: @color-text-secondary; 128 | } 129 | .card-footer { 130 | background: #fafafa; 131 | } 132 | .card-footer{ 133 | a { 134 | color: @color-text-secondary; 135 | font-weight: 500; 136 | } 137 | } 138 | .card-content { 139 | img { 140 | display: block; 141 | } 142 | } 143 | .card-content-inner { 144 | padding: 0.75rem 0.5rem; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /less/sui/colors.less: -------------------------------------------------------------------------------- 1 | /* === Color Themes === */ 2 | .theme-mixin(@colorName, @color, @colorHex) { 3 | //Plain color and links 4 | //Buttons 5 | .theme-@{colorName} .button:not(.button-fill) { 6 | border-color: @color; 7 | color: @color; 8 | &:active { 9 | background-color: rgba(red(@color), green(@color), blue(@color), 0.15); 10 | } 11 | &.active { 12 | background-color: @color; 13 | color:#fff; 14 | } 15 | //恢复功能按钮的颜色 16 | .button-themes(); 17 | } 18 | .theme-@{colorName} .button.button-fill { 19 | background: @color; 20 | color:#fff; 21 | //恢复功能按钮的颜色 22 | .button-themes(); 23 | } 24 | //Icons 25 | .theme-@{colorName} { 26 | i.icon, i.icon& { 27 | color:@color; 28 | } 29 | } 30 | // Theme 31 | .theme-@{colorName} { 32 | a, .item-link.list-button { 33 | color: @color; 34 | } 35 | .bar& { 36 | a, a i { 37 | color:inherit; 38 | } 39 | a.active, a.active i { 40 | color:@color; 41 | } 42 | } 43 | .tab-item.active { 44 | color: @color; 45 | } 46 | .range-slider, .range-slider& { 47 | input[type="range"]::-webkit-slider-thumb:before { 48 | background-color: @color; 49 | } 50 | } 51 | .picker-calendar-day.picker-calendar-day-selected span { 52 | background-color: @color !important; 53 | } 54 | .buttons-tab:after { 55 | background: @color; 56 | } 57 | 58 | .modal-button { 59 | color: @color; 60 | } 61 | .actions-modal-button:not(.color-danger):not(.bg-danger) { 62 | color: @color; 63 | } 64 | } 65 | .swiper-pagination { 66 | .theme-@{colorName} & { 67 | .swiper-pagination-bullet-active { 68 | background-color: @color; 69 | } 70 | } 71 | } 72 | .swiper-button-next, .swiper-container-rtl .swiper-button-prev { 73 | .theme-@{colorName} & { 74 | .encoded-svg-background(""); 75 | } 76 | } 77 | .swiper-button-prev, .swiper-container-rtl .swiper-button-next { 78 | .theme-@{colorName} & { 79 | .encoded-svg-background(""); 80 | } 81 | } 82 | } 83 | .theme-mixin(e('green'), #3cac46, '3cac46'); 84 | .theme-mixin(e('pink'), #d94b73, 'd94b73'); 85 | .theme-mixin(e('yellow'), #efb51e, 'efb51e'); 86 | -------------------------------------------------------------------------------- /less/sui/content-block.less: -------------------------------------------------------------------------------- 1 | /* === Content Block === */ 2 | @contentBlockBorderColor: #c8c7cc; 3 | @contentBlockColor: #6d6d72; 4 | @contentBlockTitle: @contentBlockColor; 5 | .content-block { 6 | margin: 1.75rem 0; 7 | padding: 0 0.75rem; 8 | color: @contentBlockTitle; 9 | 10 | } 11 | .content-block-title { 12 | position: relative; 13 | overflow: hidden; 14 | margin: 0; 15 | white-space: nowrap; 16 | text-overflow: ellipsis; 17 | font-size: 0.7rem; 18 | text-transform: uppercase; 19 | line-height: 1; 20 | color: @contentBlockColor; 21 | margin: 1.75rem 0.75rem 0.5rem; 22 | + .list-block, + .content-block, +.card { 23 | margin-top: 0.5rem; 24 | } 25 | } 26 | .content-block-inner { 27 | background: #fff; 28 | padding: 0.5rem 0.75rem; 29 | margin-left: -0.75rem; 30 | width: 100%; 31 | position: relative; 32 | .hairline(top, @contentBlockBorderColor); 33 | .hairline(bottom, @contentBlockBorderColor); 34 | color: @color-text; 35 | } 36 | .content-block.inset { 37 | margin-left: 0.75rem; 38 | margin-right: 0.75rem; 39 | border-radius: 0.35rem; 40 | .content-block-inner { 41 | .hairline-remove(top); 42 | .hairline-remove(bottom); 43 | border-radius: 0.35rem; 44 | } 45 | } 46 | @media all and (min-width:768px) { 47 | .content-block.tablet-inset { 48 | margin-left: 0.75rem; 49 | margin-right: 0.75rem; 50 | border-radius: 0.35rem; 51 | } 52 | 53 | .content-block.tablet-inset .content-block-inner { 54 | .hairline-remove(top); 55 | .hairline-remove(bottom); 56 | border-radius: 0.35rem; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /less/sui/demos.less: -------------------------------------------------------------------------------- 1 | .grid-demo .row { 2 | text-align: center; 3 | +.row { 4 | margin-top: 0.75rem; 5 | } 6 | > [class*=col-] { 7 | border: 1px solid #ddd; 8 | } 9 | } 10 | 11 | .icons-demo .icon { 12 | width: 2.5rem; 13 | height: 2.5rem; 14 | margin: 0.15rem; 15 | font-size: 1.2rem; 16 | line-height: 2.5rem; 17 | text-align: center; 18 | background-color: #fff; 19 | border: 1px solid #ddd; 20 | border-radius: 1.25rem; 21 | display: inline-block; 22 | } 23 | -------------------------------------------------------------------------------- /less/sui/docs-baichuan.less: -------------------------------------------------------------------------------- 1 | @blue: #0089cd; 2 | .page-baichuan { 3 | color: #333; 4 | 5 | a { 6 | color: @blue; 7 | &:hover { 8 | color: #f60; 9 | } 10 | } 11 | .header { 12 | color: white; 13 | text-align: center; 14 | position: relative; 15 | height: 300px; 16 | 17 | .bg, .overlay { 18 | position: absolute; 19 | top: 0; 20 | right: 0; 21 | bottom: 0; 22 | left: 0; 23 | z-index: 1; 24 | } 25 | .bg { 26 | background: url(//gtms04.alicdn.com/tps/i4/TB15BwTIpXXXXXtXXXXdrcn8XXX-1196-304.png); 27 | background-repeat: no-repeat; 28 | background-position: center center; 29 | } 30 | .overlay { 31 | z-index: 2; 32 | background: radial-gradient(rgba(0,0,0,.6), rgba(0,0,0,.8)); 33 | } 34 | h2 { 35 | position: absolute; 36 | z-index: 3; 37 | font-size: 48px; 38 | font-weight: normal; 39 | margin: 0; 40 | padding: 0; 41 | top: 50%; 42 | left: 50%; 43 | margin-top: -36px; 44 | margin-left: -200px; 45 | } 46 | } 47 | p { 48 | margin: 0.5em 0; 49 | } 50 | .sub-header { 51 | background: #efefef; 52 | text-align: center; 53 | padding: 26px 0; 54 | font-size: 16px; 55 | h2 { 56 | font-size: 30px; 57 | font-weight: normal; 58 | margin: 10px; 59 | } 60 | } 61 | article { 62 | overflow: hidden; 63 | height: 510px; 64 | 65 | .article-inner { 66 | width: 960px; 67 | margin: auto; 68 | } 69 | 70 | &:nth-child(even) { 71 | background: rgba(0, 0, 0, .1); 72 | 73 | .monitor { 74 | float: right; 75 | } 76 | 77 | .phone { 78 | margin-left: 100px; 79 | } 80 | 81 | .text { 82 | padding-left: 50px; 83 | } 84 | } 85 | .monitor, .text { 86 | float: left; 87 | width: 50%; 88 | text-align: center; 89 | } 90 | 91 | .text { 92 | text-align: left; 93 | padding: 115px 0; 94 | font-size: 16px; 95 | h4 { 96 | font-size: 20px; 97 | margin: 10px 0; 98 | } 99 | .text-gray { 100 | margin: 30px 0 15px; 101 | font-size: 14px; 102 | } 103 | } 104 | 105 | .phone { 106 | margin-top: 110px; 107 | width: 228px; 108 | height: 401px; 109 | position: relative; 110 | border: 1px solid #999; 111 | border-radius: 28px 28px 0 0; 112 | background: white; 113 | &:after { 114 | content: " "; 115 | background: url(//gtms01.alicdn.com/tps/i1/TB1MT84IFXXXXaBXVXXG_XNJXXX-79-33.png) no-repeat; 116 | width: 79px; 117 | height: 33px; 118 | position: absolute; 119 | top: 10px; 120 | left: 50%; 121 | margin-left: -36px; 122 | } 123 | img { 124 | width: 198px; 125 | margin-top: 50px; 126 | border: 1px solid #aaa; 127 | border-bottom: 0; 128 | } 129 | .indicator { 130 | background: rgba(5, 200, 200, .3); 131 | border: 2px solid #12c1fa; 132 | position: absolute; 133 | top: 65px; 134 | left: 14px; 135 | width: 200px; 136 | height: 31px; 137 | display: none; 138 | } 139 | } 140 | .code { 141 | box-shadow: 0 0 3px 3px rgba(0,0,0,.1); 142 | width: 150px; 143 | } 144 | } 145 | 146 | .text-gray { 147 | color: #999; 148 | } 149 | 150 | .tabs { 151 | list-style: none; 152 | margin: 0 auto; 153 | max-width: 1400px; 154 | font-size: 20px; 155 | font-weight: bold; 156 | height: 80px; 157 | 158 | li { 159 | float: left; 160 | } 161 | 162 | a { 163 | display: inline-block; 164 | height: 80px; 165 | line-height: 40px; 166 | padding: 20px; 167 | color: #333; 168 | } 169 | 170 | li.active a { 171 | background: #319af5; 172 | color: white; 173 | } 174 | } 175 | 176 | .footer-second { 177 | //background: #3f4a53; 178 | background: #efefef; 179 | overflow: hidden; 180 | padding: 50px; 181 | text-align: center; 182 | font-size: 18px; 183 | 184 | .btn { 185 | display: inline-block; 186 | height: 42px; 187 | line-height: 42px; 188 | width: 120px; 189 | background: @blue; 190 | color: white; 191 | margin-top: 20px; 192 | 193 | &:hover { 194 | background: darken(@blue, 5%); 195 | } 196 | } 197 | 198 | &.fixed { 199 | position: fixed; 200 | bottom: 0; 201 | left: 0; 202 | right: 0; 203 | opacity: .8; 204 | } 205 | } 206 | 207 | .design { 208 | padding: 20px 0 70px 0; 209 | text-align: left; 210 | width: 960px; 211 | margin: auto; 212 | 213 | ul { 214 | margin: 0; 215 | padding: 0; 216 | list-style: none; 217 | } 218 | 219 | li { 220 | border: 2px solid #ccc; 221 | display: inline-block; 222 | position: relative; 223 | text-align: center; 224 | 225 | } 226 | 227 | a { 228 | display: block; 229 | width: 450px; 230 | margin: 0 auto; 231 | position: relative; 232 | color: #333; 233 | padding: 30px 50px; 234 | } 235 | 236 | .icon { 237 | position: absolute; 238 | height: 84px; 239 | line-height: 84px; 240 | width: 84px; 241 | border: 2px solid #ccc; 242 | border-radius: 100%; 243 | top: 50%; 244 | margin-top: -40px; 245 | left: 90px; 246 | font-size: 36px; 247 | color: #ccc; 248 | } 249 | 250 | .contents { 251 | margin-left: 160px; 252 | text-align: left; 253 | 254 | h4 { 255 | font-size: 20px; 256 | font-weight: normal; 257 | margin: 0; 258 | } 259 | } 260 | 261 | h2 { 262 | font-size: 20px; 263 | font-weight: normal; 264 | } 265 | p { 266 | font-size: 14px; 267 | color: #999; 268 | } 269 | 270 | li:hover { 271 | border-color: @blue; 272 | .icon { 273 | border-color: @blue; 274 | color: @blue; 275 | } 276 | } 277 | } 278 | 279 | .share { 280 | padding: 40px 0 70px 0; 281 | width: 960px; 282 | margin: auto; 283 | 284 | h2 { 285 | margin: 20px 0; 286 | font-size: 20px; 287 | } 288 | 289 | .img { 290 | width: 224px; 291 | height: 127px; 292 | display: block; 293 | border: 1px solid #ccc; 294 | position: relative; 295 | } 296 | 297 | .overlay { 298 | position: absolute; 299 | left: 0; 300 | right: 0; 301 | top: 0; 302 | bottom: 0; 303 | display: none; 304 | background: rgba(44, 120, 255, .8); 305 | 306 | .download { 307 | width: 100px; 308 | height: 38px; 309 | line-height: 38px; 310 | text-align: center; 311 | border: 1px solid white; 312 | color: white; 313 | position: absolute; 314 | left: 50%; 315 | top: 50%; 316 | margin-left: -50px; 317 | margin-top: -16px; 318 | font-size: 16px; 319 | } 320 | } 321 | 322 | .img:hover .overlay { 323 | display: block; 324 | } 325 | 326 | img { 327 | display: block; 328 | } 329 | 330 | ul { 331 | font-size: 14px; 332 | list-style: none; 333 | margin: 0; 334 | padding: 0; 335 | overflow: hidden; 336 | } 337 | 338 | li { 339 | text-align: center; 340 | float: left; 341 | width: 224px; 342 | overflow: hidden; 343 | + li { 344 | margin-left: 21px; 345 | } 346 | } 347 | 348 | h4 { 349 | font-size: 14px; 350 | margin-top: 10px; 351 | margin-bottom: 0; 352 | width: 300px; 353 | margin-left: -38px; 354 | } 355 | p { 356 | margin: 0; 357 | } 358 | } 359 | 360 | .footer { 361 | background: #3f4a53; 362 | overflow: hidden; 363 | text-align: center; 364 | color: white; 365 | padding: 30px 0; 366 | 367 | .links, 368 | .copyright { 369 | margin: 10px 0; 370 | } 371 | 372 | a { 373 | display: inline-block; 374 | margin: 0 10px; 375 | } 376 | a { 377 | color: white; 378 | &:hover { 379 | text-decoration: underline; 380 | } 381 | } 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /less/sui/fonts.less: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "iconfont-sm"; 3 | src: url('../fonts/webui_iconfont.eot'); /* IE9*/ 4 | src: url('../fonts/webui_iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('../fonts/webui_iconfont.woff') format('woff'), /* chrome、firefox */ 6 | url('../fonts/webui_iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ 7 | url('../fonts/webui_iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .icon { 11 | font-family:"iconfont-sm" !important; 12 | font-style:normal; 13 | -webkit-font-smoothing: antialiased; 14 | -webkit-text-stroke-width: 0.2px; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-app:before { content: "\e605"; } 19 | .icon-browser:before { content: "\e606"; } 20 | .icon-card:before { content: "\e607"; } 21 | .icon-cart:before { content: "\e600"; } 22 | .icon-code:before { content: "\e609"; } 23 | .icon-computer:before { content: "\e616"; } 24 | .icon-remove:before { content: "\e60a"; } 25 | .icon-download:before { content: "\e60b"; } 26 | .icon-edit:before { content: "\e60c"; } 27 | .icon-emoji:before { content: "\e615"; } 28 | .icon-star:before { content: "\e60e"; } 29 | .icon-friends:before { content: "\e601"; } 30 | .icon-gift:before { content: "\e618"; } 31 | .icon-phone:before { content: "\e60f"; } 32 | .icon-clock:before { content: "\e619"; } 33 | .icon-home:before { content: "\e602"; } 34 | .icon-menu:before { content: "\e60d"; } 35 | .icon-message:before { content: "\e617"; } 36 | .icon-me:before { content: "\e603"; } 37 | .icon-picture:before { content: "\e61a"; } 38 | .icon-share:before { content: "\e61b"; } 39 | .icon-settings:before { content: "\e604"; } 40 | .icon-refresh:before { content: "\e61c"; } 41 | .icon-caret:before { content: "\e610"; } 42 | .icon-down:before { content: "\e611"; } 43 | .icon-up:before { content: "\e612"; } 44 | .icon-right:before { content: "\e613"; } 45 | .icon-left:before { content: "\e614"; } 46 | .icon-check:before { content: "\e608"; } 47 | .icon-search:before { content: "\e61d"; } 48 | .icon-new:before { content: "\e61e"; } 49 | -------------------------------------------------------------------------------- /less/sui/forms.less: -------------------------------------------------------------------------------- 1 | /* === Forms === */ 2 | // Inputs 3 | .list-block { 4 | input[type="text"], input[type="password"], input[type="search"], input[type="email"], input[type="tel"], input[type="url"], input[type="date"], input[type="datetime-local"], input[type="time"], input[type="number"], select, textarea { 5 | -webkit-appearance: none; 6 | -moz-appearance: none; 7 | -ms-appearance: none; 8 | appearance: none; 9 | box-sizing: border-box; 10 | border: none; 11 | background: none; 12 | border-radius: 0 0 0 0; 13 | box-shadow: none; 14 | display: block; 15 | padding: 0 0 0 0.25rem; 16 | margin: 0; 17 | width: 100%; 18 | height: 2.15rem; 19 | color: @color-text; 20 | font-size: 0.85rem; 21 | font-family: inherit; 22 | } 23 | input[type="date"], input[type="datetime-local"] { 24 | line-height: 2.2rem; 25 | } 26 | select { 27 | -webkit-appearance: none; 28 | -moz-appearance: none; 29 | -ms-appearance: none; 30 | appearance: none; 31 | } 32 | .label { 33 | vertical-align: top; 34 | } 35 | textarea { 36 | height: 5rem; 37 | resize:none; 38 | line-height: 1.4; 39 | padding-top: 0.4rem; 40 | padding-bottom: 0.35rem; 41 | } 42 | } 43 | 44 | //Switch 45 | .label-switch { 46 | display: inline-block; 47 | vertical-align: middle; 48 | width: 2.6rem; 49 | border-radius: 0.8rem; 50 | box-sizing: border-box; 51 | height: 1.6rem; 52 | position: relative; 53 | cursor: pointer; 54 | .align-self(center); 55 | .checkbox { 56 | width: 2.6rem; 57 | border-radius: 0.8rem; 58 | box-sizing: border-box; 59 | height: 1.6rem; 60 | background: #e5e5e5; 61 | z-index: 0; 62 | margin: 0; 63 | padding: 0; 64 | -webkit-appearance: none; 65 | -moz-appearance: none; 66 | -ms-appearance: none; 67 | appearance: none; 68 | border:none; 69 | cursor: pointer; 70 | position: relative; 71 | transition-duration: 300ms; 72 | &:before { 73 | content:' '; 74 | position: absolute; 75 | left: 0.1rem; 76 | top: 0.1rem; 77 | width: 2.4rem; 78 | border-radius: 0.8rem; 79 | box-sizing: border-box; 80 | height: 1.4rem; 81 | background: #fff; 82 | z-index: 1; 83 | transition-duration: 300ms; 84 | transform: scale(1); 85 | } 86 | &:after { 87 | content:' '; 88 | height: 1.4rem; 89 | width: 1.4rem; 90 | border-radius: 1.4rem; 91 | background: #fff; 92 | position: absolute; 93 | z-index: 2; 94 | top: 0.1rem; 95 | left: 0.1rem; 96 | box-shadow: 0 0.1rem 0.25rem rgba(0,0,0,0.4); 97 | transform: translateX(0px); 98 | transition-duration: 300ms; 99 | } 100 | } 101 | input[type="checkbox"] { 102 | opacity: 0; 103 | position: absolute; 104 | width: 2.6rem; 105 | height: 1.6rem; 106 | z-index: 1; 107 | &:checked { 108 | &+ .checkbox { 109 | background: @color-success; 110 | &:before { 111 | transform: scale(0); 112 | } 113 | &:after { 114 | transform: translateX(1.1rem); 115 | } 116 | } 117 | } 118 | } 119 | } 120 | html.android { 121 | .label-switch input[type="checkbox"] { 122 | &+ .checkbox { 123 | transition-duration: 0; 124 | &:after, &:before { 125 | transition-duration: 0; 126 | } 127 | } 128 | } 129 | } 130 | 131 | // Slider 132 | .range-slider { 133 | width: 100%; 134 | position: relative; 135 | overflow: hidden; 136 | padding-left: 0.15rem; 137 | padding-right: 0.15rem; 138 | margin-left: -1px; 139 | .align-self(center); 140 | input[type="range"] { 141 | position: relative; 142 | height: 1.4rem; 143 | width: 100%; 144 | margin: 0.2rem 0 0.25rem 0; 145 | -webkit-appearance: none; 146 | -moz-appearance: none; 147 | -ms-appearance: none; 148 | appearance: none; 149 | background: -webkit-gradient(linear, 50% 0, 50% 100%, color-stop(0, #b7b8b7), color-stop(100%, #b7b8b7)); 150 | background: linear-gradient(to right, #b7b8b7 0, #b7b8b7 100%); 151 | background-position: center; 152 | background-size: 100% 0.1rem; 153 | background-repeat: no-repeat; 154 | outline: 0; 155 | } 156 | input[type="range"]:after { 157 | height: 0.1rem; 158 | background: #fff; 159 | content:' '; 160 | width: 0.25rem; 161 | top: 50%; 162 | margin-top: -1px; 163 | left: -0.25rem; 164 | z-index: 1; 165 | position: absolute; 166 | } 167 | input[type="range"]::-webkit-slider-thumb { 168 | -webkit-appearance: none; 169 | -moz-appearance: none; 170 | -ms-appearance: none; 171 | appearance: none; 172 | border: none; 173 | height: 1.4rem; 174 | width: 1.4rem; 175 | position: relative; 176 | background: none; 177 | } 178 | input[type="range"]::-webkit-slider-thumb:after { 179 | height: 1.4rem; 180 | width: 1.4rem; 181 | border-radius: 1.4rem; 182 | background: #fff; 183 | z-index: 10; 184 | box-shadow: 0 0.1rem 0.2rem rgba(0,0,0,0.4); 185 | position: absolute; 186 | left: 0; 187 | top: 0; 188 | content: ' '; 189 | } 190 | 191 | input[type="range"]::-webkit-slider-thumb:before { 192 | position: absolute; 193 | top: 50%; 194 | right: 100%; 195 | width: 100rem; 196 | height: 0.1rem; 197 | margin-top: -1px; 198 | z-index: 1; 199 | background: @color-primary; 200 | content: ' '; 201 | } 202 | } 203 | 204 | // Checkboxes 205 | label.label-checkbox { 206 | cursor: pointer; 207 | i.icon-form-checkbox { 208 | width: 1.1rem; 209 | height: 1.1rem; 210 | position: relative; 211 | border-radius: 1.1rem; 212 | border: 1px solid #c7c7cc; 213 | box-sizing: border-box; 214 | 215 | &:after { 216 | content:' '; 217 | position: absolute; 218 | left: 50%; 219 | margin-left: -0.3rem; 220 | top: 50%; 221 | margin-top: -0.2rem; 222 | width: 0.6rem; 223 | height: 0.45rem; 224 | } 225 | } 226 | input[type="checkbox"], input[type="radio"] { 227 | display: none; 228 | &:checked + .item-media{ 229 | i.icon-form-checkbox { 230 | border: none; 231 | background-color: @color-primary; 232 | } 233 | i.icon-form-checkbox:after { 234 | background: no-repeat center; 235 | .encoded-svg-background(""); 236 | -webkit-background-size: 0.6rem 0.45rem; 237 | background-size: 0.6rem 0.45rem; 238 | } 239 | } 240 | } 241 | } 242 | label.label-checkbox { 243 | transition-duration: 300ms; 244 | html:not(.watch-active-state) &:active, &.active-state { 245 | transition: 0ms; 246 | background-color: #d9d9d9; 247 | .item-inner { 248 | .hairline-color(bottom, transparent); 249 | } 250 | } 251 | } 252 | 253 | // Smart selects 254 | .smart-select { 255 | select { 256 | display: none; 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /less/sui/grid.less: -------------------------------------------------------------------------------- 1 | /* === Grid === */ 2 | .row { 3 | overflow: hidden; 4 | margin-left: -4%; 5 | > [class*="col-"], > [class*="tablet-"] { 6 | box-sizing: border-box; 7 | float: left; 8 | } 9 | &.no-gutter { 10 | margin-left: 0; 11 | } 12 | } 13 | @cols: 5, 10, 15, 20, 25, 100/3, 40, 50, 60, 100*(2/3), 75, 80, 85, 90, 95, 100; 14 | .row { 15 | .-(@i: length(@cols)) when (@i > 0) { 16 | @divider: e(extract(@cols, @i)); 17 | @className: `Math.floor(@{divider})`; 18 | @n: `100/parseFloat(@{divider})`; 19 | @n-1: @n - 1; 20 | @gutter: `4.0`; 21 | @d: `(100-@{gutter}*@{n})/@{n}`; 22 | .col-@{className} { 23 | width: ~"@{d}%"; 24 | margin-left: ~"@{gutter}%"; 25 | } 26 | &.no-gutter { 27 | @d: `100/@{n}`; 28 | .col-@{className} { 29 | width: ~"@{d}%"; 30 | margin: 0; 31 | } 32 | } 33 | .-((@i - 1)); 34 | } .-; 35 | } 36 | @media all and (min-width:768px) { 37 | .row { 38 | margin-left: -2%; 39 | } 40 | .row { 41 | .-(@i: length(@cols)) when (@i > 0) { 42 | @divider: e(extract(@cols, @i)); 43 | @className: `Math.floor(@{divider})`; 44 | @n: `100/parseFloat(@{divider})`; 45 | @n-1: @n - 1; 46 | @gutter: `2.0`; 47 | @d: `(100-@{gutter}*@{n})/@{n}`; 48 | .col-@{className} { 49 | width: ~"@{d}%"; 50 | margin-left: ~"@{gutter}%"; 51 | } 52 | &.no-gutter { 53 | @d: `100/@{n}`; 54 | .col-@{className} { 55 | width: ~"@{d}%"; 56 | margin: 0; 57 | } 58 | } 59 | .-((@i - 1)); 60 | } .-; 61 | } 62 | .row { 63 | .-(@i: length(@cols)) when (@i > 0) { 64 | @divider: e(extract(@cols, @i)); 65 | @className: `Math.floor(@{divider})`; 66 | @n: `100/parseFloat(@{divider})`; 67 | @n-1: @n - 1; 68 | @gutter: `2.0`; 69 | @d: `(100-@{gutter}*@{n})/@{n}`; 70 | .tablet-@{className} { 71 | width: ~"@{d}%"; 72 | margin-left: ~"@{gutter}%"; 73 | } 74 | &.no-gutter { 75 | @d: `100/@{n}`; 76 | .tablet-@{className} { 77 | width: ~"@{d}%"; 78 | margin: 0; 79 | } 80 | } 81 | .-((@i - 1)); 82 | } .-; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /less/sui/icons.less: -------------------------------------------------------------------------------- 1 | /* === Icons === */ 2 | i.icon { 3 | display: inline-block; 4 | vertical-align: middle; 5 | background-size: 100% auto; 6 | background-position: center; 7 | background-repeat: no-repeat; 8 | font-style: normal; 9 | position: relative; 10 | 11 | 12 | &.icon-next, &.icon-prev { 13 | width: 0.75rem; 14 | height: 0.75rem; 15 | } 16 | &.icon-next { 17 | .encoded-svg-background(""); 18 | } 19 | &.icon-prev { 20 | .encoded-svg-background(""); 21 | } 22 | &.icon-plus { 23 | width: 1.25rem; 24 | height: 1.25rem; 25 | font-size: 1.55rem; 26 | line-height: 1rem; 27 | text-align: center; 28 | font-weight: 100; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /less/sui/infinite.less: -------------------------------------------------------------------------------- 1 | .infinite-scroll-preloader { 2 | margin: 0.5rem; 3 | text-align: center; 4 | .preloader { 5 | width: 1.5rem; 6 | height: 1.5rem; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /less/sui/lists.less: -------------------------------------------------------------------------------- 1 | /* === Lists === */ 2 | @listBlockBorderColor: @color-split; 3 | @listBlockBg: #fff; 4 | @dividerBg: #F7F7F7; 5 | @dividerColor: @color-split; 6 | .list-block { 7 | margin: 1.75rem 0; 8 | font-size: 0.85rem; 9 | ul { 10 | background: @listBlockBg; 11 | list-style: none; 12 | padding: 0; 13 | margin: 0; 14 | position: relative; 15 | .hairline(top, @listBlockBorderColor); 16 | .hairline(bottom, @listBlockBorderColor); 17 | ul { 18 | .hairline-remove(top); 19 | .hairline-remove(bottom); 20 | padding-left: 2.25rem; 21 | } 22 | } 23 | 24 | .align-top, .align-top .item-content, .align-top .item-inner { 25 | .align-items(flex-start); 26 | } 27 | 28 | .inset() { 29 | margin-left: 0.75rem; 30 | margin-right: 0.75rem; 31 | border-radius: 0.35rem; 32 | .content-block-title { 33 | margin-left: 0; 34 | margin-right: 0; 35 | } 36 | ul { 37 | border-radius: 0.35rem; 38 | .hairline-remove(top); 39 | .hairline-remove(bottom); 40 | } 41 | li:first-child > a{ 42 | border-radius: 0.35rem 0.35rem 0 0; 43 | } 44 | li:last-child > a{ 45 | border-radius: 0 0 0.35rem 0.35rem; 46 | } 47 | li:first-child:last-child > a { 48 | border-radius: 0.35rem; 49 | } 50 | } 51 | &.inset { 52 | .inset() 53 | } 54 | &.tablet-inset { 55 | @media all and (min-width:768px) { 56 | .inset(); 57 | } 58 | } 59 | 60 | // List items 61 | li { 62 | box-sizing: border-box; 63 | position: relative; 64 | } 65 | 66 | .item-media { 67 | .flexbox(); 68 | .flex-shrink(0); 69 | .flex-wrap(nowrap); 70 | box-sizing: border-box; 71 | .align-items(center); 72 | padding-top: 0.35rem; 73 | padding-bottom: 0.4rem; 74 | i + i { 75 | margin-left: 0.25rem; 76 | } 77 | i + img { 78 | margin-left: 0.25rem; 79 | } 80 | } 81 | .item-media + .item-inner { 82 | margin-left: 0.75rem; 83 | } 84 | .item-inner { 85 | padding-right: 0.75rem; 86 | position: relative; 87 | .hairline(bottom, @listBlockBorderColor); 88 | width: 100%; 89 | padding-top: 0.4rem; 90 | padding-bottom: 0.35rem; 91 | min-height: 2.2rem; 92 | box-sizing: border-box; 93 | .flexbox(); 94 | -webkit-box-flex:1; 95 | -ms-flex:1; 96 | .justify-content(space-between); 97 | .align-items(center); 98 | } 99 | .item-title { 100 | .flex-shrink(1); 101 | white-space: nowrap; 102 | position: relative; 103 | overflow: hidden; 104 | text-overflow: ellipsis; 105 | max-width: 100%; 106 | 107 | &.label { 108 | width: 35%; 109 | .flex-shrink(0); 110 | margin: 4px 0; 111 | } 112 | } 113 | .item-input { 114 | width: 100%; 115 | margin-top: -0.4rem; 116 | margin-bottom: -0.35rem; 117 | -webkit-box-flex:1; 118 | -ms-flex:1; 119 | .flex-shrink(1); 120 | } 121 | .item-after { 122 | white-space: nowrap; 123 | color: @color-text-secondary; 124 | .flex-shrink(0); 125 | margin-left: 0.25rem; 126 | .flexbox(); 127 | max-height: 1.4rem; 128 | } 129 | .smart-select .item-after { 130 | max-width: 70%; 131 | overflow: hidden; 132 | text-overflow:ellipsis; 133 | position: relative; 134 | } 135 | .item-link { 136 | transition-duration: 300ms; 137 | display: block; 138 | color: inherit; 139 | 140 | .item-inner { 141 | padding-right: 1.5rem; 142 | background-image: url("@{imgBaseUrl}/i-list-chevron-right.png"); 143 | background-size: 0.7rem; 144 | background-repeat: no-repeat; 145 | background-position: 97% center; 146 | background-position: -webkit-calc(~"100% - .5rem") center; 147 | background-position: calc(~"100% - .5rem") center; 148 | } 149 | 150 | html:not(.watch-active-state) &:active, &.active-state { 151 | transition-duration: 0ms; 152 | background-color: #d9d9d9; 153 | .item-inner { 154 | .hairline-color(bottom, transparent); 155 | } 156 | } 157 | &.list-button { 158 | padding: 0 0.75rem; 159 | text-align: center; 160 | color: @color-primary; 161 | display: block; 162 | .hairline(bottom, @listBlockBorderColor); 163 | line-height: 2.15rem; 164 | } 165 | } 166 | .item-content { 167 | box-sizing: border-box; 168 | padding-left: 0.75rem; 169 | min-height: 2.2rem; 170 | .flexbox(); 171 | .justify-content(space-between); 172 | .align-items(center); 173 | } 174 | // Label after List block 175 | .list-block-label { 176 | margin: 0.5rem 0 1.75rem; 177 | padding: 0 0.75rem; 178 | font-size: 0.7rem; 179 | color: @color-text-secondary; 180 | } 181 | 182 | // Swipe outs 183 | .swipeout { 184 | overflow: hidden; 185 | -webkit-transform-style: preserve-3d; 186 | transform-style: preserve-3d; 187 | } 188 | .swipeout.deleting { 189 | transition-duration: 300ms; 190 | .swipeout-content { 191 | transform: translateX(-100%); 192 | } 193 | } 194 | .swipeout.transitioning { 195 | .swipeout-content, .swipeout-actions-right a, .swipeout-actions-left a, .swipeout-overswipe { 196 | -webkit-transition: 300ms; 197 | transition: 300ms; 198 | } 199 | } 200 | .swipeout-content { 201 | position: relative; 202 | z-index: 10; 203 | } 204 | .swipeout-overswipe { 205 | -webkit-transition: 200ms left; 206 | transition: 200ms left; 207 | } 208 | .swipeout-actions-left, .swipeout-actions-right { 209 | position: absolute; 210 | top: 0; 211 | height: 100%; 212 | .flexbox(); 213 | a { 214 | padding: 0 1.5rem; 215 | color:#fff; 216 | background: #c7c7cc; 217 | .flexbox(); 218 | .align-items(center); 219 | position: relative; 220 | left: 0; 221 | &:after { 222 | content:''; 223 | position: absolute; 224 | top: 0; 225 | width: 600%; 226 | height: 100%; 227 | background: inherit; 228 | z-index: -1; 229 | } 230 | } 231 | a.swipeout-delete { 232 | background: @color-danger; 233 | } 234 | } 235 | .swipeout-actions-right { 236 | right: 0%; 237 | transform: translateX(100%); 238 | a:after { 239 | left: 100%; 240 | margin-left: -1px; 241 | } 242 | } 243 | .swipeout-actions-left { 244 | left: 0%; 245 | transform: translateX(-100%); 246 | a:after { 247 | right: 100%; 248 | margin-right: -1px; 249 | } 250 | } 251 | .item-subtitle { 252 | font-size: 0.75rem; 253 | position: relative; 254 | overflow: hidden; 255 | white-space: nowrap; 256 | max-width: 100%; 257 | text-overflow: ellipsis; 258 | } 259 | .item-text { 260 | font-size: 0.75rem; 261 | color: @color-text-secondary; 262 | line-height: 1.05rem; 263 | position: relative; 264 | overflow: hidden; 265 | height: 2.1rem; 266 | text-overflow:ellipsis; 267 | -webkit-line-clamp: 2; 268 | -webkit-box-orient: vertical; 269 | display: -webkit-box; 270 | } 271 | &.media-list, li.media-item { 272 | .item-title { 273 | font-weight: 500; 274 | } 275 | .item-inner { 276 | display: block; 277 | padding-top: 0.5rem; 278 | padding-bottom: 0.45rem; 279 | .align-self(stretch); 280 | } 281 | .item-media { 282 | padding-top: 0.45rem; 283 | padding-bottom: 0.5rem; 284 | img { 285 | display: block; 286 | } 287 | } 288 | .item-title-row { 289 | .flexbox(); 290 | .justify-content(space-between); 291 | } 292 | } 293 | .list-group { 294 | ul { 295 | &:after, &:before { 296 | z-index: 11; 297 | } 298 | } 299 | + .list-group ul { 300 | .hairline-remove(top); 301 | } 302 | } 303 | .item-divider, .list-group-title { 304 | background: @dividerBg; 305 | .hairline(top, @listBlockBorderColor); 306 | margin-top: -1px; 307 | padding: 0.2rem 0.75rem; 308 | white-space: nowrap; 309 | position: relative; 310 | max-width: 100%; 311 | text-overflow: ellipsis; 312 | overflow: hidden; 313 | color: @dividerColor; 314 | } 315 | .list-group-title { 316 | position: relative; 317 | position: -webkit-sticky; 318 | position: -moz-sticky; 319 | position: sticky; 320 | top: 0; 321 | z-index: 20; 322 | margin-top: 0; 323 | .hairline-remove(top); 324 | } 325 | // Sortable 326 | 327 | .sortable-handler { 328 | position: absolute; 329 | right: 0; 330 | top: 0; 331 | bottom: 1px; 332 | z-index: 10; 333 | background-repeat: no-repeat; 334 | background-size: 0.9rem 0.6rem; 335 | background-image: url("@{imgBaseUrl}/i-sortable-handler.png"); 336 | background-position: center; 337 | width: 1.75rem; 338 | opacity: 0; 339 | visibility: hidden; 340 | right: 0; 341 | } 342 | &.sortable { 343 | .item-inner { 344 | transition-duration: 300ms; 345 | } 346 | } 347 | &.sortable-opened { 348 | .sortable-handler { 349 | visibility: visible; 350 | opacity: 1; 351 | } 352 | .item-inner, .item-link .item-inner { 353 | padding-right: 1.5rem; 354 | } 355 | .item-link .item-inner, .item-link .item-title-row { 356 | background-image: none; 357 | } 358 | } 359 | &.sortable-sorting { 360 | li { 361 | transition-duration: 300ms; 362 | } 363 | } 364 | li.sorting { 365 | z-index: 50; 366 | background: rgba(255,255,255,0.8); 367 | box-shadow: 0 0.1rem 0.4rem rgba(0,0,0,0.6); 368 | transition-duration: 0ms; 369 | .item-inner { 370 | .hairline-remove(bottom); 371 | } 372 | } 373 | 374 | // Last-childs 375 | li { 376 | &:last-child { 377 | .list-button { 378 | .hairline-remove(bottom); 379 | } 380 | } 381 | &:last-child, &:last-child li:last-child { 382 | .item-inner { 383 | .hairline-remove(bottom); 384 | } 385 | } 386 | li:last-child, &:last-child li { 387 | .item-inner { 388 | .hairline(bottom, @listBlockBorderColor); 389 | } 390 | } 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /less/sui/mixins.less: -------------------------------------------------------------------------------- 1 | .scrollable(){ 2 | overflow: auto; 3 | -webkit-overflow-scrolling: touch; 4 | } 5 | .flexbox() { 6 | display: -webkit-box; 7 | display: -ms-flexbox; 8 | display: -webkit-flex; 9 | display: flex; 10 | } 11 | .flex-wrap(@fw) when (@fw = nowrap) { 12 | -webkit-box-lines: single; 13 | -moz-box-lines: single; 14 | -webkit-flex-wrap: nowrap; 15 | -ms-flex-wrap: none; 16 | -ms-flex-wrap: nowrap; 17 | flex-wrap: nowrap; 18 | } 19 | .flex-wrap(@fw) when (@fw = wrap) { 20 | -webkit-box-lines: multiple; 21 | -moz-box-lines: multiple; 22 | -webkit-flex-wrap: wrap; 23 | -ms-flex-wrap: wrap; 24 | flex-wrap: wrap; 25 | } 26 | .flex-wrap(@fw) when not (@fw = wrap) and not (@fw = nowrap) { 27 | -webkit-flex-wrap: @fw; 28 | -ms-flex-wrap: @fw; 29 | flex-wrap: @fw; 30 | } 31 | .flex-shrink(@fs) { 32 | -webkit-flex-shrink: @fs; 33 | -ms-flex: 0 @fs auto; 34 | flex-shrink: @fs; 35 | } 36 | .justify-content(@jc) when (@jc = flex-start) { 37 | -webkit-box-pack: start; 38 | -ms-flex-pack: start; 39 | -webkit-justify-content: flex-start; 40 | justify-content: flex-start; 41 | } 42 | .justify-content(@jc) when (@jc = flex-end) { 43 | -webkit-box-pack: end; 44 | -ms-flex-pack: end; 45 | -webkit-justify-content: flex-end; 46 | justify-content: flex-end; 47 | } 48 | .justify-content(@jc) when (@jc = space-between) { 49 | -webkit-box-pack: justify; 50 | -ms-flex-pack: justify; 51 | -webkit-justify-content: space-between; 52 | justify-content: space-between; 53 | } 54 | .justify-content(@jc) when not (@jc = flex-start) and not (@jc = flex-end) and not (@jc = space-between) { 55 | -webkit-box-pack: @jc; 56 | -ms-flex-pack: @jc; 57 | -webkit-justify-content: @jc; 58 | justify-content: @jc; 59 | } 60 | .align-items(@ai) when (@ai = flex-start) { 61 | -webkit-box-align: start; 62 | -ms-flex-align: start; 63 | -webkit-align-items: flex-start; 64 | align-items: flex-start; 65 | } 66 | .align-items(@ai) when (@ai = flex-end) { 67 | -webkit-box-align: end; 68 | -ms-flex-align: end; 69 | -webkit-align-items: flex-end; 70 | align-items: flex-end; 71 | } 72 | .align-items(@ai) when not (@ai = flex-start) and not (@ai = flex-end) { 73 | -webkit-box-align: @ai; 74 | -ms-flex-align: @ai; 75 | -webkit-align-items: @ai; 76 | align-items: @ai; 77 | } 78 | .align-content(@ai) { 79 | -ms-flex-line-pack: @ai; 80 | -webkit-align-content: @ai; 81 | align-content: @ai; 82 | } 83 | .align-self(@as) { 84 | -ms-flex-item-align: @as; 85 | -webkit-align-self: @as; 86 | align-self: @as; 87 | } 88 | .clearfix() { 89 | &:before, 90 | &:after { 91 | content: " "; 92 | display: table; 93 | } 94 | &:after { 95 | clear: both; 96 | } 97 | } 98 | .hairline(@position, @color) when (@position = top) { 99 | &:before { 100 | content: ''; 101 | position: absolute; 102 | left: 0; 103 | top: 0; 104 | bottom: auto; 105 | right: auto; 106 | height: 1px; 107 | width: 100%; 108 | background-color: @color; 109 | display: block; 110 | z-index: 15; 111 | transform-origin: 50% 0%; 112 | @media only screen and (-webkit-min-device-pixel-ratio: 2) { 113 | transform: scaleY(0.5); 114 | } 115 | @media only screen and (-webkit-min-device-pixel-ratio: 3) { 116 | transform: scaleY(0.33); 117 | } 118 | } 119 | } 120 | .hairline(@position, @color) when (@position = left) { 121 | &:before { 122 | content: ''; 123 | position: absolute; 124 | left: 0; 125 | top: 0; 126 | bottom: auto; 127 | right: auto; 128 | width: 1px; 129 | height: 100%; 130 | background-color: @color; 131 | display: block; 132 | z-index: 15; 133 | transform-origin: 0% 50%; 134 | @media only screen and (-webkit-min-device-pixel-ratio: 2) { 135 | transform: scaleY(0.5); 136 | } 137 | @media only screen and (-webkit-min-device-pixel-ratio: 3) { 138 | transform: scaleY(0.33); 139 | } 140 | } 141 | } 142 | .hairline(@position, @color) when (@position = bottom) { 143 | &:after { 144 | content: ''; 145 | position: absolute; 146 | left: 0; 147 | bottom: 0; 148 | right: auto; 149 | top: auto; 150 | height: 1px; 151 | width: 100%; 152 | background-color: @color; 153 | display: block; 154 | z-index: 15; 155 | transform-origin: 50% 100%; 156 | @media only screen and (-webkit-min-device-pixel-ratio: 2) { 157 | transform: scaleY(0.5); 158 | } 159 | @media only screen and (-webkit-min-device-pixel-ratio: 3) { 160 | transform: scaleY(0.33); 161 | } 162 | } 163 | } 164 | .hairline(@position, @color) when (@position = right) { 165 | &:after { 166 | content: ''; 167 | position: absolute; 168 | right: 0; 169 | top: 0; 170 | left: auto; 171 | bottom: auto; 172 | width: 1px; 173 | height: 100%; 174 | background-color: @color; 175 | display: block; 176 | z-index: 15; 177 | transform-origin: 100% 50%; 178 | @media only screen and (-webkit-min-device-pixel-ratio: 2) { 179 | transform: scaleY(0.5); 180 | } 181 | @media only screen and (-webkit-min-device-pixel-ratio: 3) { 182 | transform: scaleY(0.33); 183 | } 184 | } 185 | } 186 | // For right and bottom 187 | .hairline-remove(@position) when not (@position = left) and not (@position = top) { 188 | &:after { 189 | display: none; 190 | } 191 | } 192 | // For left and top 193 | .hairline-remove(@position) when not (@position = right) and not (@position = bottom) { 194 | &:before { 195 | display: none; 196 | } 197 | } 198 | // For right and bottom 199 | .hairline-color(@position, @color) when not (@position = left) and not (@position = top) { 200 | &:after { 201 | background-color: @color; 202 | } 203 | } 204 | // For left and top 205 | .hairline-color(@position, @color) when not (@position = right) and not (@position = bottom) { 206 | &:before { 207 | background-color: @color; 208 | } 209 | } 210 | 211 | // Encoded SVG Background 212 | .encoded-svg-background(@svg) { 213 | @url: `encodeURIComponent(@{svg})`; 214 | background-image: url("data:image/svg+xml;charset=utf-8,@{url}"); 215 | } 216 | 217 | // Preserve3D 218 | .preserve3d() { 219 | -webkit-transform-style: preserve-3d; 220 | -moz-transform-style: preserve-3d; 221 | -ms-transform-style: preserve-3d; 222 | transform-style: preserve-3d; 223 | } 224 | 225 | //from ratchet 226 | .linear-gradient(@color-from, @color-to) { 227 | background-color: @color-from; // Old browsers 228 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%,@color-from), color-stop(100%,@color-to)); // Chrome, Safari4+ 229 | background-image: -webkit-linear-gradient(top, @color-from 0%, @color-to 100%); // Chrome10+, Safari5.1+ 230 | background-image: -moz-linear-gradient(top, @color-from 0%, @color-to 100%); // FF3.6+ 231 | background-image: -ms-linear-gradient(top, @color-from 0%, @color-to 100%); // IE10+ 232 | background-image: -o-linear-gradient(top, @color-from 0%, @color-to 100%); // Opera 11.10+ 233 | background-image: linear-gradient(to bottom, @color-from 0%, @color-to 100%); // W3C 234 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#{@color-from}', endColorstr='#{@color-to}', GradientType=0 ); // IE6-9 235 | } 236 | .directional-gradient(@color-from, @color-to, @deg: 45deg) { 237 | background-color: @color-from; // Old browsers 238 | background-image: -webkit-gradient(linear, left bottom, right top, color-stop(0%,@color-from), color-stop(100%,@color-to)); // Chrome, Safari4+ 239 | background-image: -webkit-linear-gradient(@deg, @color-from 0%, @color-to 100%); // Chrome10+, Safari5.1+ 240 | background-image: -moz-linear-gradient(@deg, @color-from 0%, @color-to 100%); // FF3.6+ 241 | background-image: -ms-linear-gradient(@deg, @color-from 0%, @color-to 100%); // IE10+ 242 | background-image: -o-linear-gradient(@deg, @color-from 0%, @color-to 100%); // Opera 11.10+ 243 | background-image: linear-gradient(@deg, @color-from 0%, @color-to 100%); // W3C 244 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#{@color-from}', endColorstr='#{@color-to}', GradientType=1 ); // IE6-9 245 | } 246 | 247 | .hairline(@type, @color, @offset) when (@type = single) { 248 | background-image: url("data:image/svg+xml;utf8,"); 249 | background-position: @offset 100%; 250 | } 251 | .hairline(@type, @color, @offset) when (@type = double) { 252 | background-image: url("data:image/svg+xml;utf8,"), 253 | url("data:image/svg+xml;utf8,"); 254 | background-position: @offset 100%, @offset 0; 255 | background-repeat: no-repeat; 256 | } 257 | 258 | 259 | //已删除的mixin 260 | /*.transition(@d) { 261 | -webkit-transition-duration: @d; 262 | transition-duration: @d; 263 | } 264 | .delay(@d) { 265 | -webkit-transition-delay: @d; 266 | transition-delay: @d; 267 | } 268 | .transform(@t) { 269 | -webkit-transform: @t; 270 | transform: @t; 271 | } 272 | .transform-origin(@to) { 273 | -webkit-transform-origin: @to; 274 | transform-origin: @to; 275 | } 276 | .translate3d(@x:0, @y:0, @z:0) { 277 | -webkit-transform: translate3d(@x,@y,@z); 278 | transform: translate3d(@x,@y,@z); 279 | } 280 | .animation(@a) { 281 | -webkit-animation: @a; 282 | animation: @a; 283 | } 284 | .border-box(){ 285 | -webkit-box-sizing: border-box; 286 | -moz-box-sizing: border-box; 287 | box-sizing: border-box; 288 | } 289 | .box-shadow(@bs) { 290 | -webkit-box-shadow: @bs; 291 | box-shadow: @bs; 292 | } 293 | .animation-name(@name) { 294 | -webkit-animation-name: @name; 295 | -moz-animation-name: @name; 296 | animation-name: @name; 297 | } 298 | .animation-duration(@duration) { 299 | -webkit-animation-duration: @duration; 300 | -moz-animation-duration: @duration; 301 | animation-duration: @duration; 302 | } 303 | .animation-direction(@direction) { 304 | -webkit-animation-direction: @direction; 305 | -moz-animation-direction: @direction; 306 | animation-direction: @direction; 307 | } 308 | */ 309 | -------------------------------------------------------------------------------- /less/sui/modal.less: -------------------------------------------------------------------------------- 1 | /* === Modals === */ 2 | @modalBgColor:#e8e8e8; 3 | @modalButonColor : @color-primary; 4 | @modalButonBg: @modalBgColor; 5 | @modalButonActiveBg:#d4d4d4; 6 | @modalDuration:400ms; 7 | @actionsModalDuration:300ms; 8 | @actionsModalButtonBg: rgba(243,243,243,0.95); 9 | @actionsModalActiveButtonBg:#dcdcdc; 10 | @popoverBg: rgba(255,255,255,0.95); 11 | @popupDuration: 400ms; 12 | @gray: #8e8e93; 13 | .modal-overlay, .preloader-indicator-overlay, .popup-overlay { 14 | position: absolute; 15 | left: 0; 16 | top: 0; 17 | width: 100%; 18 | height: 100%; 19 | background: rgba(0,0,0,0.4); 20 | z-index: 10600; 21 | visibility: hidden; 22 | opacity: 0; 23 | transition-duration: @modalDuration; 24 | &.modal-overlay-visible { 25 | visibility: visible; 26 | opacity: 1; 27 | } 28 | } 29 | .popup-overlay { 30 | z-index: 10200; 31 | } 32 | .modal { 33 | width: 13.5rem; 34 | position: absolute; 35 | z-index: 11000; 36 | left: 50%; 37 | margin-left: -6.75rem; 38 | margin-top: 0; 39 | top: 50%; 40 | text-align: center; 41 | border-radius: 0.35rem; 42 | opacity: 0; 43 | transform: translate3d(0,0,0) scale(1.185); 44 | transition-property: transform, opacity; 45 | color: @color-text; 46 | display: none; 47 | &.modal-in { 48 | opacity: 1; 49 | transition-duration: @modalDuration; 50 | transform: translate3d(0,0,0) scale(1); 51 | } 52 | &.modal-out { 53 | opacity: 0; 54 | z-index: 11000-1; 55 | transition-duration: @modalDuration; 56 | transform: translate3d(0,0,0) scale(0.815); 57 | } 58 | } 59 | .modal-inner { 60 | padding: 0.75rem; 61 | .hairline(bottom, #b5b5b5); 62 | border-radius: 0.35rem 0.35rem 0 0; 63 | position: relative; 64 | background: @modalBgColor; 65 | } 66 | .modal-title { 67 | font-weight: 500; 68 | font-size: 0.9rem; 69 | text-align: center; 70 | +.modal-text { 71 | margin-top: 0.25rem; 72 | } 73 | } 74 | .modal-buttons { 75 | height: 2.2rem; 76 | overflow: hidden; 77 | .flexbox(); 78 | .justify-content(center); 79 | &.modal-buttons-vertical { 80 | display: block; 81 | height: auto; 82 | } 83 | } 84 | .modal-button { 85 | width: 100%; 86 | padding: 0 0.25rem; 87 | height: 2.2rem; 88 | font-size: 0.85rem; 89 | line-height: 2.2rem; 90 | text-align: center; 91 | color: @modalButonColor; 92 | background: @modalButonBg; 93 | display: block; 94 | position: relative; 95 | white-space: nowrap; 96 | text-overflow:ellipsis; 97 | overflow: hidden; 98 | cursor: pointer; 99 | box-sizing: border-box; 100 | .hairline(right, #b5b5b5); 101 | -webkit-box-flex:1; 102 | -ms-flex:1; 103 | &:first-child { 104 | border-radius: 0 0 0 0.35rem; 105 | } 106 | &:last-child { 107 | .hairline-remove(right); 108 | border-radius: 0 0 0.35rem 0; 109 | } 110 | &:first-child:last-child { 111 | border-radius: 0 0 0.35rem 0.35rem; 112 | } 113 | &.modal-button-bold { 114 | font-weight: 500; 115 | } 116 | html:not(.watch-active-state) &:active, &.active-state { 117 | background: @modalButonActiveBg; 118 | } 119 | .modal-buttons-vertical & { 120 | .hairline-remove(right); 121 | .hairline-remove(top); 122 | .hairline(bottom, #b5b5b5); 123 | border-radius: 0; 124 | &:last-child { 125 | border-radius: 0 0 0.35rem 0.35rem; 126 | .hairline-remove(bottom); 127 | } 128 | } 129 | } 130 | .modal-no-buttons { 131 | .modal-inner { 132 | border-radius: 0.35rem; 133 | .hairline-remove(bottom); 134 | } 135 | .modal-buttons { 136 | display: none; 137 | } 138 | } 139 | // Action sheet 140 | .actions-modal { 141 | position: absolute; 142 | left: 0; 143 | bottom: 0; 144 | z-index: 11000; 145 | width: 100%; 146 | transform: translate3d(0,100%,0); 147 | &.modal-in { 148 | transition-duration: @actionsModalDuration; 149 | transform: translate3d(0,0,0); 150 | } 151 | &.modal-out { 152 | z-index: 11000-1; 153 | transition-duration: @actionsModalDuration; 154 | transform: translate3d(0,100%,0); 155 | } 156 | } 157 | .actions-modal-group { 158 | margin: 0.4rem; 159 | } 160 | .actions-modal-button, .actions-modal-label { 161 | width: 100%; 162 | text-align: center; 163 | font-weight: normal; 164 | margin: 0; 165 | background: @actionsModalButtonBg; 166 | box-sizing: border-box; 167 | display: block; 168 | position: relative; 169 | .hairline(bottom, #d2d2d6); 170 | a { 171 | text-decoration: none; 172 | color: inherit; 173 | } 174 | b { 175 | font-weight: 500; 176 | } 177 | &.actions-modal-button-bold { 178 | font-weight: 500; 179 | } 180 | &.actions-modal-button-danger { 181 | color: @color-danger; 182 | } 183 | &.color-danger { 184 | color: @color-danger; 185 | } 186 | &.bg-danger { 187 | background: @color-danger; 188 | color: white; 189 | &:active { 190 | background: @color-danger-active; 191 | } 192 | } 193 | &:first-child { 194 | border-radius: 0.2rem 0.2rem 0 0; 195 | } 196 | &:last-child { 197 | .hairline-remove(bottom); 198 | border-radius: 0 0 0.2rem 0.2rem; 199 | } 200 | &:first-child:last-child { 201 | border-radius: 0.2rem; 202 | } 203 | &.disabled { 204 | opacity: 0.95; 205 | color:@gray; 206 | } 207 | } 208 | .actions-modal-button { 209 | cursor: pointer; 210 | line-height: 2.15rem; 211 | font-size:1rem; 212 | color: @color-primary; 213 | &:active, &.active-state { 214 | background: @actionsModalActiveButtonBg; 215 | } 216 | } 217 | .actions-modal-label { 218 | font-size: 0.7rem; 219 | line-height: 1.3; 220 | min-height: 2.2rem; 221 | padding: 0.4rem 0.5rem; 222 | color: @color-text-secondary; 223 | .flexbox(); 224 | .justify-content(center); 225 | .align-items(center); 226 | } 227 | // Prompt 228 | input.modal-text-input { 229 | box-sizing: border-box; 230 | height: 1.5rem; 231 | background: #fff; 232 | margin: 0; 233 | margin-top: 0.75rem; 234 | padding: 0 0.25rem; 235 | border: 1px solid #a0a0a0; 236 | border-radius: 0.25rem; 237 | width: 100%; 238 | font-size: 0.7rem; 239 | font-family: inherit; 240 | display: block; 241 | box-shadow: 0 0 0 rgba(0,0,0,0); 242 | appearance: none; 243 | + input.modal-text-input { 244 | margin-top: 0.25rem; 245 | } 246 | &.modal-text-input-double { 247 | border-radius: 0.25rem 0.25rem 0 0; 248 | + input.modal-text-input { 249 | margin-top: 0; 250 | border-top: 0; 251 | border-radius: 0 0 0.25rem 0.25rem; 252 | } 253 | } 254 | } 255 | // Popover 256 | .popover { 257 | width: 16rem; 258 | background:@popoverBg; 259 | z-index: 11000; 260 | margin: 0; 261 | top: 0; 262 | opacity: 0; 263 | left: 0; 264 | border-radius: 0.35rem; 265 | position: absolute; 266 | display: none; 267 | transform: none; 268 | transition-property: opacity; 269 | &.modal-in { 270 | transition-duration: @actionsModalDuration; 271 | opacity: 1; 272 | } 273 | .list-block { 274 | margin: 0; 275 | ul { 276 | background: none; 277 | } 278 | &:first-child { 279 | ul { 280 | .hairline-remove(top); 281 | border-radius: 0.35rem 0.35rem 0 0; 282 | } 283 | li:first-child a{ 284 | border-radius: 0.35rem 0.35rem 0 0; 285 | } 286 | } 287 | &:last-child { 288 | ul { 289 | .hairline-remove(bottom); 290 | border-radius: 0 0 0.35rem 0.35rem; 291 | } 292 | li:last-child a{ 293 | border-radius: 0 0 0.35rem 0.35rem; 294 | } 295 | } 296 | &:first-child:last-child { 297 | li:first-child:last-child a, ul:first-child:last-child { 298 | border-radius: 0.35rem; 299 | } 300 | } 301 | + .list-block { 302 | margin-top: 1.75rem; 303 | } 304 | } 305 | } 306 | .popover-angle { 307 | width: 1.3rem; 308 | height: 1.3rem; 309 | position: absolute; 310 | left: -1.3rem; 311 | top: 0; 312 | z-index: 100; 313 | overflow: hidden; 314 | &:after { 315 | content:' '; 316 | background: @popoverBg; 317 | width: 1.3rem; 318 | height: 1.3rem; 319 | position: absolute; 320 | left: 0; 321 | top: 0; 322 | border-radius: 1.5rem; 323 | transform: rotate(45deg); 324 | } 325 | &.on-left { 326 | left: -1.3rem; 327 | &:after { 328 | left: 0.95rem; 329 | top: 0; 330 | } 331 | } 332 | &.on-right { 333 | left: 100%; 334 | &:after { 335 | left: -0.95rem; 336 | top: 0; 337 | } 338 | } 339 | &.on-top { 340 | left: 0; 341 | top: -1.3rem; 342 | &:after { 343 | left: 0; 344 | top: 0.95rem; 345 | } 346 | } 347 | &.on-bottom { 348 | left: 0; 349 | top: 100%; 350 | &:after { 351 | left: 0; 352 | top: -0.95rem; 353 | } 354 | } 355 | } 356 | .popover-inner { 357 | .scrollable(); 358 | } 359 | .actions-popover { 360 | .list-block + .list-block { 361 | margin-top: 1rem; 362 | } 363 | .list-block ul { 364 | background: #fff; 365 | } 366 | } 367 | .actions-popover-label { 368 | padding: 0.4rem 0.5rem; 369 | color: @color-text-secondary; 370 | font-size: 0.65rem; 371 | line-height: 1.3; 372 | text-align: center; 373 | position: relative; 374 | .hairline(bottom, #d2d2d6); 375 | &:last-child { 376 | .hairline-remove(bottom); 377 | } 378 | } 379 | // Popup 380 | .popup, .login-screen { 381 | position: absolute; 382 | left: 0; 383 | top: 0; 384 | width: 100%; 385 | height: 100%; 386 | z-index: 10400; 387 | background: #fff; 388 | box-sizing: border-box; 389 | display: none; 390 | .scrollable(); 391 | transition-property: transform; 392 | transform: translate3d(0,100%,0); 393 | &.modal-in, &.modal-out { 394 | transition-duration: @popupDuration; 395 | } 396 | &.modal-in { 397 | transform: translate3d( 0,0,0); 398 | } 399 | &.modal-out { 400 | transform: translate3d( 0,100%,0); 401 | } 402 | } 403 | .login-screen.modal-in, .login-screen.modal-out { 404 | display: block; 405 | } 406 | 407 | html.with-statusbar-overlay { 408 | // iPhone with statusbar overlay 409 | .popup { 410 | height: ~"-webkit-calc(100% -1rem)"; 411 | height: ~"calc(100% - 1rem)"; 412 | top: 1rem; 413 | } 414 | .popup-overlay { 415 | z-index: 9800; 416 | } 417 | @media all and (max-width:629px), (max-height:629px) { 418 | .popup { 419 | height: ~"-webkit-calc(100% - 1rem)"; 420 | height: ~"calc(100% - 1rem)"; 421 | top: 1rem; 422 | } 423 | .popup-overlay { 424 | z-index: 9800; 425 | } 426 | } 427 | .login-screen, .popup.tablet-fullscreen { 428 | height: ~"-webkit-calc(100% - 1rem)"; 429 | height: ~"calc(100% - 1rem)"; 430 | top: 1rem; 431 | } 432 | } 433 | 434 | //Preloaders modals 435 | .modal .preloader { 436 | width: 1.7rem; 437 | height: 1.7rem; 438 | } 439 | .preloader-indicator-overlay { 440 | visibility: visible; 441 | opacity: 0; 442 | background: none; 443 | } 444 | .preloader-indicator-modal { 445 | position: absolute; 446 | left: 50%; 447 | top: 50%; 448 | padding: 0.4rem; 449 | margin-left: -1.25rem; 450 | margin-top: -1.25rem; 451 | background: rgba(0,0,0,0.8); 452 | z-index: 11000; 453 | border-radius: 0.25rem; 454 | .preloader { 455 | display: block; 456 | width: 1.7rem; 457 | height: 1.7rem; 458 | } 459 | } 460 | 461 | // Picker Modal 462 | .picker-modal { 463 | position: absolute; 464 | left: 0; 465 | bottom: 0; 466 | width: 100%; 467 | height: 13rem; 468 | z-index: 11500; 469 | display: none; 470 | transition-property: transform; 471 | background: #cfd5da; 472 | transform: translate3d( 0,100%,0); 473 | &.modal-in, &.modal-out { 474 | transition-duration: 400ms; 475 | } 476 | &.modal-in { 477 | transform: translate3d(0,0,0); 478 | } 479 | &.modal-out { 480 | transform: translate3d(0,100%,0); 481 | } 482 | .picker-modal-inner { 483 | height: 100%; 484 | position: relative; 485 | } 486 | .toolbar { 487 | .hairline(top, @color-text-gray); 488 | position: relative; 489 | width: 100%; 490 | + .picker-modal-inner { 491 | height: ~"-webkit-calc(100% - 2.2rem)"; 492 | height: ~"-moz-calc(100% - 2.2rem)"; 493 | height: ~"calc(100% - 2.2rem)"; 494 | } 495 | } 496 | &.picker-modal-inline, .popover & { 497 | display: block; 498 | position: relative; 499 | background: none; 500 | z-index: inherit; 501 | transform: translate3d(0,0,0); 502 | .toolbar { 503 | .hairline-remove(top); 504 | .hairline(bottom, @color-text-gray); 505 | } 506 | } 507 | .popover & { 508 | width: auto; 509 | .toolbar { 510 | background: none; 511 | } 512 | } 513 | } 514 | 515 | //toast 516 | 517 | .toast { 518 | background: rgba(0, 0, 0, .8); 519 | border-radius: 1rem; 520 | color: white; 521 | padding: 0 .8rem; 522 | height: 2rem; 523 | line-height: 2rem; 524 | font-size: 0.8rem; 525 | width: auto; 526 | } 527 | -------------------------------------------------------------------------------- /less/sui/normalize.less: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | // 4 | // 1. Set default font family to sans-serif. 5 | // 2. Prevent iOS and IE text size adjust after device orientation change, 6 | // without disabling user zoom. 7 | // 8 | 9 | html { 10 | font-family: sans-serif; // 1 11 | -ms-text-size-adjust: 100%; // 2 12 | -webkit-text-size-adjust: 100%; // 2 13 | } 14 | 15 | // 16 | // Remove default margin. 17 | // 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | // HTML5 display definitions 24 | // ========================================================================== 25 | 26 | // 27 | // Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | // Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | // and Firefox. 30 | // Correct `block` display not defined for `main` in IE 11. 31 | // 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | // 50 | // 1. Correct `inline-block` display not defined in IE 8/9. 51 | // 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | // 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; // 1 59 | vertical-align: baseline; // 2 60 | } 61 | 62 | // 63 | // Prevent modern browsers from displaying `audio` without controls. 64 | // Remove excess height in iOS 5 devices. 65 | // 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | // 73 | // Address `[hidden]` styling not present in IE 8/9/10. 74 | // Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. 75 | // 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | // Links 83 | // ========================================================================== 84 | 85 | // 86 | // Remove the gray background color from active links in IE 10. 87 | // 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | // 94 | // Improve readability of focused elements when they are also in an 95 | // active/hover state. 96 | // 97 | 98 | a:active, 99 | a:hover { 100 | outline: 0; 101 | } 102 | 103 | // Text-level semantics 104 | // ========================================================================== 105 | 106 | // 107 | // Address styling not present in IE 8/9/10/11, Safari, and Chrome. 108 | // 109 | 110 | abbr[title] { 111 | border-bottom: 1px dotted; 112 | } 113 | 114 | // 115 | // Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 116 | // 117 | 118 | b, 119 | strong { 120 | font-weight: bold; 121 | } 122 | 123 | // 124 | // Address styling not present in Safari and Chrome. 125 | // 126 | 127 | dfn { 128 | font-style: italic; 129 | } 130 | 131 | // 132 | // Address variable `h1` font-size and margin within `section` and `article` 133 | // contexts in Firefox 4+, Safari, and Chrome. 134 | // 135 | 136 | h1 { 137 | font-size: 2em; 138 | margin: 0.67em 0; 139 | } 140 | 141 | // 142 | // Address styling not present in IE 8/9. 143 | // 144 | 145 | mark { 146 | background: #ff0; 147 | color: #000; 148 | } 149 | 150 | // 151 | // Address inconsistent and variable font size in all browsers. 152 | // 153 | 154 | small { 155 | font-size: 80%; 156 | } 157 | 158 | // 159 | // Prevent `sub` and `sup` affecting `line-height` in all browsers. 160 | // 161 | 162 | sub, 163 | sup { 164 | font-size: 75%; 165 | line-height: 0; 166 | position: relative; 167 | vertical-align: baseline; 168 | } 169 | 170 | sup { 171 | top: -0.5em; 172 | } 173 | 174 | sub { 175 | bottom: -0.25em; 176 | } 177 | 178 | // Embedded content 179 | // ========================================================================== 180 | 181 | // 182 | // Remove border when inside `a` element in IE 8/9/10. 183 | // 184 | 185 | img { 186 | border: 0; 187 | } 188 | 189 | // 190 | // Correct overflow not hidden in IE 9/10/11. 191 | // 192 | 193 | svg:not(:root) { 194 | overflow: hidden; 195 | } 196 | 197 | // Grouping content 198 | // ========================================================================== 199 | 200 | // 201 | // Address margin not present in IE 8/9 and Safari. 202 | // 203 | 204 | figure { 205 | margin: 1em 40px; 206 | } 207 | 208 | // 209 | // Address differences between Firefox and other browsers. 210 | // 211 | 212 | hr { 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | // 218 | // Contain overflow in all browsers. 219 | // 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | // 226 | // Address odd `em`-unit font size rendering in all browsers. 227 | // 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | // Forms 238 | // ========================================================================== 239 | 240 | // 241 | // Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | // styling of `select`, unless a `border` property is set. 243 | // 244 | 245 | // 246 | // 1. Correct color not being inherited. 247 | // Known issue: affects color of disabled elements. 248 | // 2. Correct font properties not being inherited. 249 | // 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | // 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; // 1 258 | font: inherit; // 2 259 | margin: 0; // 3 260 | } 261 | 262 | // 263 | // Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | // 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | // 271 | // Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | // All other form control elements do not inherit `text-transform` values. 273 | // Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | // Correct `select` style inheritance in Firefox. 275 | // 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | // 283 | // 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | // and `video` controls. 285 | // 2. Correct inability to style clickable `input` types in iOS. 286 | // 3. Improve usability and consistency of cursor style between image-type 287 | // `input` and others. 288 | // 289 | 290 | button, 291 | html input[type="button"], // 1 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; // 2 295 | cursor: pointer; // 3 296 | } 297 | 298 | // 299 | // Re-set default cursor for disabled elements. 300 | // 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | // 308 | // Remove inner padding and border in Firefox 4+. 309 | // 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | // 318 | // Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | // the UA stylesheet. 320 | // 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | // 327 | // It's recommended that you don't attempt to style these elements. 328 | // Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | // 330 | // 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | // 2. Remove excess padding in IE 8/9/10. 332 | // 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; // 1 337 | padding: 0; // 2 338 | } 339 | 340 | // 341 | // Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | // `font-size` values of the `input`, it causes the cursor style of the 343 | // decrement button to change from `default` to `text`. 344 | // 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | // 352 | // 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | // 2. Address `box-sizing` set to `border-box` in Safari and Chrome. 354 | // 355 | 356 | input[type="search"] { 357 | -webkit-appearance: textfield; // 1 358 | box-sizing: content-box; // 2 359 | } 360 | 361 | // 362 | // Remove inner padding and search cancel button in Safari and Chrome on OS X. 363 | // Safari (but not Chrome) clips the cancel button when the search input has 364 | // padding (and `textfield` appearance). 365 | // 366 | 367 | input[type="search"]::-webkit-search-cancel-button, 368 | input[type="search"]::-webkit-search-decoration { 369 | -webkit-appearance: none; 370 | } 371 | 372 | // 373 | // Define consistent border, margin, and padding. 374 | // 375 | 376 | fieldset { 377 | border: 1px solid #c0c0c0; 378 | margin: 0 2px; 379 | padding: 0.35em 0.625em 0.75em; 380 | } 381 | 382 | // 383 | // 1. Correct `color` not being inherited in IE 8/9/10/11. 384 | // 2. Remove padding so people aren't caught out if they zero out fieldsets. 385 | // 386 | 387 | legend { 388 | border: 0; // 1 389 | padding: 0; // 2 390 | } 391 | 392 | // 393 | // Remove default vertical scrollbar in IE 8/9/10/11. 394 | // 395 | 396 | textarea { 397 | overflow: auto; 398 | } 399 | 400 | // 401 | // Don't inherit the `font-weight` (applied by a rule above). 402 | // NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 403 | // 404 | 405 | optgroup { 406 | font-weight: bold; 407 | } 408 | 409 | // Tables 410 | // ========================================================================== 411 | 412 | // 413 | // Remove most spacing between table cells. 414 | // 415 | 416 | table { 417 | border-collapse: collapse; 418 | border-spacing: 0; 419 | } 420 | 421 | td, 422 | th { 423 | padding: 0; 424 | } 425 | -------------------------------------------------------------------------------- /less/sui/pages.less: -------------------------------------------------------------------------------- 1 | /* === Pages === */ 2 | 3 | // Pages animations 4 | @pageDuration: 400ms; 5 | 6 | .page { 7 | box-sizing: border-box; 8 | position: absolute; 9 | left: 0; 10 | top: 0; 11 | width: 100%; 12 | height: 100%; 13 | background: #efeff4; 14 | display: none; 15 | 16 | &.page-current, 17 | &.page-from-center-to-left, 18 | &.page-from-center-to-right, 19 | &.page-from-right-to-center, 20 | &.page-from-left-to-center { 21 | display: block; 22 | } 23 | } 24 | .page-left { 25 | opacity: 0.5; 26 | transform: translate3d(-20%); 27 | } 28 | .page-right { 29 | transform: translate3d(100%); 30 | } 31 | 32 | //Class that will trigger transition during page custom transitions (like swipe-back) 33 | .page-transitioning { 34 | &, .swipeback-page-shadow { 35 | transition: @pageDuration; 36 | } 37 | } 38 | // From/to Right To/from Center animations 39 | .page-from-right-to-center { 40 | animation: pageFromRightToCenter @pageDuration forwards; 41 | z-index: 2002; 42 | } 43 | .page-from-center-to-right { 44 | animation: pageFromCenterToRight @pageDuration forwards; 45 | z-index: 2002; 46 | } 47 | 48 | @keyframes pageFromRightToCenter { 49 | from { 50 | transform: translate3d(100%,0,0); 51 | opacity: .9; 52 | } 53 | to { 54 | transform: translate3d(0,0,0); 55 | opacity: 1; 56 | } 57 | } 58 | 59 | @keyframes pageFromCenterToRight { 60 | from { 61 | transform: translate3d(0,0,0); 62 | opacity: 1; 63 | } 64 | to { 65 | transform: translate3d(100%,0,0); 66 | opacity: .9; 67 | } 68 | } 69 | 70 | 71 | // From/to Center To/from Left animations 72 | .page-from-center-to-left { 73 | animation: pageFromCenterToLeft @pageDuration forwards; 74 | } 75 | .page-from-left-to-center { 76 | animation: pageFromLeftToCenter @pageDuration forwards; 77 | } 78 | 79 | @keyframes pageFromCenterToLeft { 80 | from { 81 | opacity: 1; 82 | transform: translate3d(0,0,0); 83 | } 84 | to { 85 | opacity: 0.5; 86 | transform: translate3d(-20%,0,0); 87 | } 88 | } 89 | 90 | @keyframes pageFromLeftToCenter { 91 | from { 92 | opacity: .5; 93 | transform: translate3d(-20%,0,0); 94 | } 95 | to { 96 | opacity: 1; 97 | transform: translate3d(0,0,0); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /less/sui/panels.less: -------------------------------------------------------------------------------- 1 | /* === Panels === */ 2 | @panelWidth: 12rem; 3 | @panelsDuration: 400ms; 4 | .panel-overlay { 5 | position: absolute; 6 | left: 0; 7 | top: 0; 8 | width: 100%; 9 | height: 100%; 10 | background: rgba(0,0,0,0); 11 | opacity: 0; 12 | z-index: 5999; 13 | display: none; 14 | } 15 | .panel { 16 | z-index: 1000; 17 | display: none; 18 | background: #111; 19 | color: white; 20 | box-sizing: border-box; 21 | .scrollable(); 22 | position: absolute; 23 | width: @panelWidth; 24 | top: 0; 25 | height: 100%; 26 | transform: translate3d(0, 0, 0); 27 | transition: transform @panelsDuration; 28 | 29 | &.panel-left { 30 | &.panel-cover { 31 | z-index: 6000; 32 | left: -@panelWidth; 33 | } 34 | &.panel-reveal { 35 | left: 0; 36 | } 37 | } 38 | &.panel-right { 39 | &.panel-cover { 40 | z-index: 6000; 41 | right: -@panelWidth; 42 | } 43 | &.panel-reveal { 44 | right: 0; 45 | } 46 | } 47 | } 48 | body.with-panel-left-cover, body.with-panel-right-cover { 49 | .page { 50 | transform: translate3d(0, 0, 0); 51 | transition: transform @panelsDuration; 52 | } 53 | .panel-overlay { 54 | display: block; 55 | } 56 | } 57 | body.with-panel-left-reveal, body.with-panel-right-reveal { 58 | .page { 59 | transition: @panelsDuration; 60 | -webkit-transition-property: -webkit-transform; 61 | -moz-transition-property: -moz-transform; 62 | transition-property: transform; 63 | } 64 | .panel-overlay { 65 | display: block; 66 | } 67 | } 68 | body.with-panel-left-reveal { 69 | .page { 70 | transform: translate3d(@panelWidth, 0, 0); 71 | } 72 | .panel-overlay { 73 | margin-left: @panelWidth; 74 | } 75 | } 76 | body.with-panel-left-cover { 77 | .panel-left { 78 | transform: translate3d(@panelWidth, 0, 0); 79 | } 80 | } 81 | body.with-panel-right-reveal { 82 | .page { 83 | transform: translate3d(-@panelWidth, 0, 0); 84 | } 85 | .panel-overlay { 86 | margin-left: -@panelWidth; 87 | } 88 | } 89 | body.with-panel-right-cover { 90 | .panel-right { 91 | transform: translate3d(-@panelWidth, 0, 0); 92 | } 93 | } 94 | body.panel-closing { 95 | .page { 96 | transition: @panelsDuration; 97 | -webkit-transition-property: -webkit-transform; 98 | -moz-transition-property: -moz-transform; 99 | transition-property: transform; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /less/sui/photo-browser.less: -------------------------------------------------------------------------------- 1 | /* === Photo Browser === */ 2 | 3 | .photo-browser { 4 | position: absolute; 5 | left: 0; 6 | top: 0; 7 | width: 100%; 8 | height: 100%; 9 | z-index: 10500; 10 | // opacity: 0; 11 | // display: none; 12 | // transform: translate3d(0, 0, 0); 13 | .bar-tab .tab-item .icon { 14 | width: 14px; 15 | height: 14px; 16 | margin-top: -5px; 17 | } 18 | .bar-tab~.photo-browser-captions { 19 | bottom: 52px; 20 | -webkit-transform: translate3d(0,0,0); 21 | transform: translate3d(0,0,0); 22 | } 23 | &.photo-browser-in { 24 | display: block; 25 | animation: photoBrowserIn 400ms forwards; 26 | } 27 | &.photo-browser-out { 28 | display: block; 29 | animation: photoBrowserOut 400ms forwards; 30 | } 31 | html.with-statusbar-overlay & { 32 | height: ~"-webkit-calc(100% - 1rem)"; 33 | height: ~"calc(100% - 1rem)"; 34 | top: 1rem; 35 | } 36 | .popup > &, 37 | body > & { 38 | .navbar, .toolbar { 39 | transform: translate3d(0, 0, 0); 40 | } 41 | } 42 | .page[data-page="photo-browser-slides"] { 43 | background: none; 44 | } 45 | //add 46 | .page { 47 | box-sizing: border-box; 48 | position: absolute; 49 | left: 0; 50 | top: 0; 51 | width: 100%; 52 | height: 100%; 53 | background: #efeff4; 54 | } 55 | .view { 56 | overflow: hidden; 57 | -webkit-box-sizing: border-box; 58 | -moz-box-sizing: border-box; 59 | box-sizing: border-box; 60 | position: relative; 61 | width: 100%; 62 | height: 100%; 63 | z-index: 5000; 64 | } 65 | } 66 | 67 | .page[data-page="photo-browser-slides"] { 68 | .toolbar a { 69 | color: @color-success; 70 | } 71 | } 72 | 73 | .photo-browser-popup { 74 | background: none; 75 | } 76 | 77 | .photo-browser, 78 | .view[data-page="photo-browser-slides"] { 79 | .navbar, .toolbar { 80 | background: rgba(247, 247, 247, 0.95); 81 | transition: 400ms; 82 | } 83 | } 84 | 85 | .view[data-page="photo-browser-slides"] .page[data-page="photo-browser-slides"] { 86 | .navbar, .toolbar { 87 | transform: translate3d(0, 0, 0); 88 | } 89 | } 90 | 91 | .photo-browser-exposed { 92 | .navbar, .toolbar { 93 | opacity: 0; 94 | visibility: hidden; 95 | pointer-events: none; 96 | } 97 | .photo-browser-swiper-container { 98 | background: #000; 99 | } 100 | } 101 | 102 | .photo-browser-of { 103 | margin: 0 0.25rem; 104 | } 105 | 106 | .photo-browser-captions { 107 | pointer-events: none; 108 | position: absolute; 109 | left: 0; 110 | width: 100%; 111 | bottom: 0; 112 | z-index: 10; 113 | opacity: 1; 114 | transition: 400ms; 115 | &.photo-browser-captions-exposed { 116 | opacity: 0; 117 | } 118 | } 119 | 120 | .toolbar ~ .photo-browser-captions { 121 | bottom: 2.2rem; 122 | transform: translate3d(0, 0rem, 0); 123 | .photo-browser-exposed & { 124 | transform: translate3d(0, 2.2rem, 0); 125 | } 126 | &.photo-browser-captions-exposed { 127 | transformt: ranslate3d(0, 0rem, 0); 128 | } 129 | } 130 | 131 | .photo-browser-caption { 132 | box-sizing: border-box; 133 | transition: 300ms; 134 | position: absolute; 135 | bottom: 0; 136 | left: 0; 137 | opacity: 0; 138 | padding: 0.2rem 0.25px; 139 | width: 100%; 140 | text-align: center; 141 | color: #fff; 142 | background: rgba(0, 0, 0, 0.8); 143 | &:empty { 144 | display: none; 145 | } 146 | &.photo-browser-caption-active { 147 | opacity: 1; 148 | } 149 | .photo-browser-captions-light & { 150 | background: rgba(255, 255, 255, 0.8); 151 | color: @color-text; 152 | } 153 | .photo-browser-exposed & { 154 | color: #fff; 155 | background: rgba(0, 0, 0, 0.8); 156 | } 157 | } 158 | 159 | .photo-browser-swiper-container { 160 | position: absolute; 161 | left: 0; 162 | top: 0; 163 | width: 100%; 164 | height: 100%; 165 | overflow: hidden; 166 | background: #fff; 167 | transition: 400ms; 168 | } 169 | 170 | .photo-browser-swiper-wrapper { 171 | position: absolute; 172 | left: 0; 173 | top: 0; 174 | width: 100%; 175 | height: 100%; 176 | padding: 0; 177 | display: flex; 178 | } 179 | 180 | .photo-browser-link-inactive { 181 | opacity: 0.3; 182 | } 183 | 184 | .photo-browser-slide { 185 | width: 100%; 186 | height: 100%; 187 | position: relative; 188 | overflow: hidden; 189 | display: flex; 190 | justify-content: center; 191 | align-items: center; 192 | flex-shrink: 0; 193 | box-sizing: border-box; 194 | &.transitioning { 195 | transition: 400ms; 196 | } 197 | span.photo-browser-zoom-container { 198 | width: 100%; 199 | text-align: center; 200 | display: none; 201 | } 202 | img { 203 | width: auto; 204 | height: auto; 205 | max-width: 100%; 206 | max-height: 100%; 207 | display: none; 208 | } 209 | &.swiper-slide-active, 210 | &.swiper-slide-next, 211 | &.swiper-slide-prev { 212 | span.photo-browser-zoom-container { 213 | display: block; 214 | } 215 | img { 216 | display: inline; 217 | } 218 | &.photo-browser-slide-lazy { 219 | .preloader { 220 | display: block; 221 | } 222 | } 223 | } 224 | iframe { 225 | width: 100%; 226 | height: 100%; 227 | } 228 | .preloader { 229 | display: none; 230 | position: absolute; 231 | width: 2.1rem; 232 | height: 2.1rem; 233 | margin-left: -2.1rem; 234 | margin-top: -2.1rem; 235 | left: 50%; 236 | top: 50%; 237 | } 238 | } 239 | 240 | .photo-browser-dark { 241 | .navbar, .toolbar { 242 | background: rgba(30, 30, 30, 0.8); 243 | // .hairline-remove(top); 244 | // .hairline-remove(bottom); 245 | &:before { 246 | display: none; 247 | } 248 | &:after { 249 | display: none; 250 | } 251 | color:#fff; 252 | a { 253 | color: #fff; 254 | } 255 | } 256 | .photo-browser-swiper-container { 257 | background: #000; 258 | } 259 | } 260 | 261 | @keyframes photoBrowserIn { 262 | 0% { 263 | transform: translate3d(0, 0, 0) scale(0.5); 264 | opacity: 0; 265 | } 266 | 100% { 267 | transform: translate3d(0, 0, 0) scale(1); 268 | opacity: 1; 269 | } 270 | } 271 | 272 | @keyframes photoBrowserOut { 273 | 0% { 274 | transform: translate3d(0, 0, 0) scale(1); 275 | opacity: 1; 276 | } 277 | 100% { 278 | transform: translate3d(0, 0, 0) scale(0.5); 279 | opacity: 0; 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /less/sui/picker.less: -------------------------------------------------------------------------------- 1 | /* === Columns Picker === */ 2 | .picker-columns { 3 | width: 100%; 4 | height: 13rem; 5 | z-index: 11500; 6 | &.picker-modal-inline, .popover & { 7 | height: 10rem; 8 | } 9 | @media (orientation: landscape) and (max-height: 415px) { 10 | &:not(.picker-modal-inline) { 11 | height: 10rem; 12 | } 13 | } 14 | } 15 | .popover.popover-picker-columns { 16 | width: 14rem; 17 | } 18 | .picker-items { 19 | .flexbox(); 20 | .justify-content(center); 21 | padding: 0; 22 | text-align: right; 23 | font-size: 1.2rem; 24 | -webkit-mask-box-image: -webkit-linear-gradient(bottom, transparent, transparent 5%, white 20%, white 80%, transparent 95%, transparent); 25 | -webkit-mask-box-image: linear-gradient(to top, transparent, transparent 5%, white 20%, white 80%, transparent 95%, transparent); 26 | } 27 | .bar + .picker-items { 28 | height: (13rem - 2.2rem); 29 | } 30 | .picker-items-col { 31 | overflow: hidden; 32 | position: relative; 33 | max-height: 100%; 34 | 35 | &.picker-items-col-left { 36 | text-align: left; 37 | } 38 | &.picker-items-col-center { 39 | text-align: center; 40 | } 41 | &.picker-items-col-right { 42 | text-align: right; 43 | } 44 | &.picker-items-col-divider { 45 | color: @color-text; 46 | .flexbox(); 47 | .align-items(center); 48 | } 49 | } 50 | .picker-items-col-wrapper { 51 | transition: 300ms; 52 | 53 | -webkit-transition-timing-function: ease-out; 54 | transition-timing-function: ease-out; 55 | } 56 | .picker-item { 57 | height: 36px; 58 | line-height: 36px; 59 | padding: 0 10px; 60 | white-space: nowrap; 61 | position: relative; 62 | overflow: hidden; 63 | text-overflow: ellipsis; 64 | color: @color-text-gray; 65 | left: 0; 66 | top: 0; 67 | width: 100%; 68 | box-sizing: border-box; 69 | transition: 300ms; 70 | .picker-items-col-absolute &{ 71 | position: absolute; 72 | } 73 | &.picker-item-far { 74 | pointer-events: none; 75 | } 76 | &.picker-selected { 77 | color: @color-text; 78 | transform: translate3d(0,0,0); 79 | transform: rotateX(0deg); 80 | } 81 | &.picker-before-selected { 82 | } 83 | &.picker-after-selected { 84 | } 85 | } 86 | .picker-center-highlight { 87 | height: 36px; 88 | box-sizing: border-box; 89 | position: absolute; 90 | left: 0; 91 | width: 100%; 92 | top: 50%; 93 | margin-top: -18px; 94 | .hairline(top, #a8abb0); 95 | .hairline(bottom, #a8abb0); 96 | pointer-events: none; 97 | } 98 | // 3D Picker 99 | .picker-3d { 100 | .picker-items { 101 | overflow: hidden; 102 | -webkit-perspective: 1200px; 103 | perspective: 1200px; 104 | } 105 | .picker-items-col, .picker-items-col-wrapper, .picker-item { 106 | -webkit-transform-style: preserve-3d; 107 | transform-style: preserve-3d; 108 | } 109 | .picker-items-col { 110 | overflow: visible; 111 | } 112 | .picker-item { 113 | -webkit-transform-origin: center center -110px; 114 | transform-origin: center center -110px; 115 | -webkit-backface-visibility: hidden; 116 | backface-visibility: hidden; 117 | -webkit-transition-timing-function: ease-out; 118 | transition-timing-function: ease-out; 119 | } 120 | } 121 | 122 | .picker-modal .bar { 123 | position: relative; 124 | top: 0; 125 | .hairline(top, #a8abb0); 126 | .hairline(bottom, #a8abb0); 127 | } 128 | .picker-modal .bar .title { 129 | color: @color-text-secondary; 130 | font-weight: normal; 131 | } 132 | 133 | .city-picker { 134 | .col-province { 135 | width: 5rem; 136 | } 137 | .col-city { 138 | width: 6rem; 139 | } 140 | .col-district { 141 | width: 5rem; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /less/sui/preloader.less: -------------------------------------------------------------------------------- 1 | /* === Preloader === */ 2 | .preloader { 3 | display: inline-block; 4 | width: 1rem; 5 | height: 1rem; 6 | -webkit-transform-origin: 50%; 7 | transform-origin: 50%; 8 | -webkit-animation: preloader-spin 1s steps(12, end) infinite; 9 | animation: preloader-spin 1s steps(12, end) infinite; 10 | } 11 | .preloader:after { 12 | display: block; 13 | content: ""; 14 | width: 100%; 15 | height: 100%; 16 | .encoded-svg-background(""); 17 | background-position: 50%; 18 | background-size: 100%; 19 | background-repeat: no-repeat; 20 | 21 | } 22 | .preloader-white:after { 23 | .encoded-svg-background(""); 24 | } 25 | @-webkit-keyframes preloader-spin { 26 | 100% { 27 | -webkit-transform: rotate(360deg); 28 | } 29 | } 30 | @keyframes preloader-spin { 31 | 100% { 32 | transform: rotate(360deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /less/sui/pull-to-refresh.less: -------------------------------------------------------------------------------- 1 | /* === Pull To Refresh === */ 2 | @layerHeight: 2.2rem; 3 | .pull-to-refresh-layer { 4 | position: relative; 5 | // margin-top: -44px; 6 | left:0; 7 | top:0; 8 | width:100%; 9 | height:@layerHeight; 10 | 11 | .preloader { 12 | position: absolute; 13 | left: 50%; 14 | top: 50%; 15 | margin-left: -0.5rem; 16 | margin-top: -0.5rem; 17 | visibility: hidden; 18 | } 19 | .pull-to-refresh-arrow { 20 | width: 0.65rem; 21 | height: 1rem; 22 | position: absolute; 23 | left: 50%; 24 | top: 50%; 25 | margin-left: -0.15rem; 26 | margin-top: -0.5rem; 27 | background: no-repeat center; 28 | .encoded-svg-background(""); 29 | background-size: 0.65rem 1rem; 30 | z-index: 10; 31 | transform: rotate(0deg) translate3d(0,0,0); 32 | transition-duration: 300ms; 33 | } 34 | 35 | } 36 | .pull-to-refresh-content { 37 | transform: translate3d(0, 0, 0); 38 | &.transitioning, &.refreshing { 39 | transition: transform 400ms; 40 | } 41 | &:not(.refreshing) { 42 | .pull-to-refresh-layer .preloader { 43 | animation:none; 44 | } 45 | } 46 | &.refreshing { 47 | .pull-to-refresh-arrow { 48 | visibility: hidden; 49 | transition-duration: 0ms; 50 | } 51 | .preloader { 52 | visibility: visible; 53 | } 54 | } 55 | &.pull-up { 56 | .pull-to-refresh-arrow { 57 | transform: rotate(180deg) translate3d(0,0,0); 58 | } 59 | } 60 | 61 | } 62 | .pull-to-refresh-content { 63 | top: -@layerHeight; 64 | &.refreshing { 65 | transform: translate3d(0, @layerHeight, 0); 66 | } 67 | } 68 | .bar-nav ~ .pull-to-refresh-content, 69 | .bar-footer ~ .pull-to-refresh-content, 70 | .bar-tab ~ .pull-to-refresh-content { 71 | top: 0; 72 | &.refreshing { 73 | transform: translate3d(0, @layerHeight, 0); 74 | } 75 | } 76 | .bar-header-secondary ~ .pull-to-refresh-content, 77 | .bar-footer-secondary ~ .pull-to-refresh-content { 78 | top: 2.2rem; 79 | } 80 | -------------------------------------------------------------------------------- /less/sui/push.less: -------------------------------------------------------------------------------- 1 | // 2 | // Push styles (to be used with push.js) 3 | // -------------------------------------------------- 4 | 5 | .content { 6 | // Fade animation 7 | &.fade { 8 | left: 0; 9 | opacity: 0; 10 | transition: opacity .4s; 11 | 12 | &.in { 13 | opacity: 1; 14 | } 15 | } 16 | 17 | // Slide animation 18 | &.sliding { 19 | z-index: 2; 20 | transition: transform .4s; 21 | transform: translate3d(0, 0, 0); 22 | 23 | &.left { 24 | z-index: 1; 25 | transform: translate3d(-100%, 0, 0); 26 | } 27 | 28 | &.right { 29 | z-index: 3; 30 | transform: translate3d(100%, 0, 0); 31 | } 32 | } 33 | } 34 | 35 | // Add chevrons to elements 36 | .navigate-left, 37 | .navigate-right, 38 | .push-left, 39 | .push-right { 40 | &:after { 41 | position: absolute; 42 | top: 50%; 43 | display: inline-block; 44 | font-family: Ratchicons; 45 | font-size: inherit; 46 | line-height: 1; 47 | color: #bbb; 48 | text-decoration: none; 49 | -webkit-font-smoothing: antialiased; 50 | transform: translateY(-50%); 51 | } 52 | } 53 | .navigate-left:after, 54 | .push-left:after { 55 | left: 0.75rem; 56 | content: '\e822'; 57 | } 58 | .navigate-right:after, 59 | .push-right:after{ 60 | right: 0.75rem; 61 | content: '\e826'; 62 | } 63 | -------------------------------------------------------------------------------- /less/sui/rem.less: -------------------------------------------------------------------------------- 1 | // 2 | // Rem 3 | // -------------------------------------------------- 4 | 5 | // Vertical screen 6 | 7 | //375屏幕为 20px,以此为基础计算出每一种宽度的字体大小 8 | //375以下不变,375以上等比放大 9 | 10 | @baseWidth: 375px; 11 | @baseFont: 20px; 12 | 13 | html { 14 | font-size: @baseFont; //默认当做320px宽度的屏幕来处理 15 | } 16 | 17 | @bps: 400px, 414px, 480px; 18 | 19 | .loop(@i: 1) when (@i <= length(@bps)) { //注意less数组是从1开始的 20 | @bp: extract(@bps, @i); 21 | @font: @bp/@baseWidth*@baseFont; 22 | @media only screen and (min-width: @bp){ 23 | html { 24 | font-size: @font !important; 25 | } 26 | } 27 | .loop((@i + 1)); 28 | }; 29 | .loop; 30 | -------------------------------------------------------------------------------- /less/sui/scroller.less: -------------------------------------------------------------------------------- 1 | .content-inner { 2 | box-sizing: border-box; 3 | //防止margin合并 4 | border-top: 1px solid transparent; 5 | margin-top: -1px; 6 | padding-bottom: 0.5rem; 7 | } 8 | .javascript-scroll{ 9 | overflow: hidden; 10 | } 11 | -------------------------------------------------------------------------------- /less/sui/searchbar.less: -------------------------------------------------------------------------------- 1 | /* === Search Bar === */ 2 | @searchbarBorderColor: #b4b4b4; 3 | @searchbarSize: 2.2rem; 4 | .searchbar { 5 | padding: 8px 0; 6 | overflow: hidden; 7 | height: @searchbarSize; 8 | .align-items(center); 9 | 10 | .searchbar-cancel { 11 | margin-right: -3rem; 12 | width: 2.2rem; //注意,这里比 2.5rem 要小,因为如果位置刚好一样,可能在动画的过程中出现抖动 13 | float: right; 14 | height: 1.4rem; 15 | line-height: 1.4rem; 16 | text-align: center; 17 | transition: all .3s; 18 | opacity: 0; 19 | transform: translate3d(0,0,0); 20 | } 21 | 22 | .search-input { 23 | transform: translate3d(0,0,0); 24 | margin-right: 0; 25 | transition: all .3s; 26 | 27 | input { 28 | margin: 0; 29 | height: 1.4rem; 30 | } 31 | } 32 | 33 | &.searchbar-active { 34 | .searchbar-cancel { 35 | margin-right: 0; 36 | opacity: 1; 37 | 38 | + .search-input { 39 | margin-right: 2.5rem; 40 | } 41 | } 42 | } 43 | } 44 | 45 | .search-input { 46 | position: relative; 47 | input { 48 | box-sizing: border-box; 49 | width: 100%; 50 | height: 1.4rem; 51 | display: block; 52 | border: none; 53 | appearance: none; 54 | border-radius: 0.25rem; 55 | font-family: inherit; 56 | color: @color-text; 57 | font-size: 0.7rem; 58 | font-weight: normal; 59 | padding: 0 0.5rem; 60 | background-color: #fff; 61 | border: 1px solid @searchbarBorderColor; 62 | &::-webkit-input-placeholder { 63 | color: @color-text-gray-light; 64 | opacity: 1; 65 | } 66 | } 67 | .icon { 68 | position: absolute; 69 | font-size: 0.9rem; 70 | color: @searchbarBorderColor; 71 | top: 50%; 72 | left: 0.3rem; 73 | transform: translate3D(0,-50%,0); 74 | } 75 | 76 | label + input { 77 | padding-left: 1.4rem; 78 | } 79 | 80 | } 81 | 82 | .bar .searchbar { 83 | margin: 0 -0.5rem; 84 | padding: 0.4rem 0.5rem; 85 | background: rgba(0, 0, 0, .1); 86 | 87 | .search-input input { 88 | border: 0; 89 | } 90 | .searchbar-cancel { 91 | color: @color-text-secondary; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /less/sui/sm-extend.less: -------------------------------------------------------------------------------- 1 | // Variables 2 | @import "variables.less"; 3 | 4 | // Mixins 5 | @import "mixins.less"; 6 | 7 | //幻灯片和图片浏览器 8 | @import "photo-browser.less"; 9 | @import "swiper.less"; 10 | -------------------------------------------------------------------------------- /less/sui/sm.less: -------------------------------------------------------------------------------- 1 | 2 | // Variables 3 | @import "variables.less"; 4 | 5 | // Mixins 6 | @import "mixins.less"; 7 | 8 | // Normalize & Base CSS 9 | @import "rem.less"; 10 | @import "normalize.less"; 11 | @import "base.less"; 12 | @import "content-block.less"; 13 | 14 | @import "grid.less"; 15 | @import "icons.less"; 16 | 17 | // Components 18 | @import "text.less"; 19 | @import "bars.less"; 20 | @import "badges.less"; 21 | @import "lists.less"; 22 | @import "forms.less"; 23 | @import "searchbar.less"; 24 | @import "buttons.less"; 25 | @import "tabs.less"; 26 | 27 | @import "pages.less"; 28 | @import "scroller.less"; 29 | @import "pull-to-refresh.less"; 30 | @import "infinite.less"; 31 | @import "modal.less"; 32 | @import "preloader.less"; 33 | @import "lists.less"; 34 | @import "cards.less"; 35 | @import "panels.less"; 36 | @import "calendar.less"; 37 | @import "picker.less"; 38 | 39 | @import "fonts.less"; 40 | 41 | @import "themes.less"; 42 | @import "colors.less"; 43 | -------------------------------------------------------------------------------- /less/sui/swiper.less: -------------------------------------------------------------------------------- 1 | /* === Swiper === */ 2 | .swiper-container { 3 | margin:0 auto; 4 | position:relative; 5 | overflow:hidden; 6 | padding-bottom: 30px; //for pagination 7 | /* Fix of Webkit flickering */ 8 | z-index:1; 9 | } 10 | .swiper-container-no-flexbox { 11 | .swiper-slide { 12 | float: left; 13 | } 14 | } 15 | .swiper-container-vertical > .swiper-wrapper{ 16 | -webkit-box-orient: vertical; 17 | -moz-box-orient: vertical; 18 | -ms-flex-direction: column; 19 | -webkit-flex-direction: column; 20 | flex-direction: column; 21 | } 22 | .swiper-wrapper { 23 | position:relative; 24 | width: 100%; 25 | height: 100%; 26 | z-index: 1; 27 | display: -webkit-box; 28 | display: -moz-box; 29 | display: -ms-flexbox; 30 | display: -webkit-flex; 31 | display: flex; 32 | .preserve3d(); 33 | 34 | -webkit-transition-property:-webkit-transform; 35 | -moz-transition-property:-moz-transform; 36 | -o-transition-property:-o-transform; 37 | -ms-transition-property:-ms-transform; 38 | transition-property:transform; 39 | 40 | -webkit-box-sizing: content-box; 41 | -moz-box-sizing: content-box; 42 | box-sizing: content-box; 43 | } 44 | .swiper-container-android .swiper-slide, .swiper-wrapper { 45 | -webkit-transform:translate3d(0px,0,0); 46 | -moz-transform:translate3d(0px,0,0); 47 | -o-transform:translate(0px,0px); 48 | -ms-transform:translate3d(0px,0,0); 49 | transform:translate3d(0px,0,0); 50 | } 51 | .swiper-container-multirow > .swiper-wrapper { 52 | -webkit-box-lines: multiple; 53 | -moz-box-lines: multiple; 54 | -ms-fles-wrap: wrap; 55 | -webkit-flex-wrap: wrap; 56 | flex-wrap: wrap; 57 | } 58 | .swiper-container-free-mode > .swiper-wrapper { 59 | -webkit-transition-timing-function: ease-out; 60 | -moz-transition-timing-function: ease-out; 61 | -ms-transition-timing-function: ease-out; 62 | -o-transition-timing-function: ease-out; 63 | transition-timing-function: ease-out; 64 | margin: 0 auto; 65 | } 66 | .swiper-slide { 67 | .preserve3d(); 68 | -webkit-flex-shrink: 0; 69 | -ms-flex: 0 0 auto; 70 | flex-shrink: 0; 71 | width: 100%; 72 | height: 100%; 73 | position: relative; 74 | } 75 | 76 | /* a11y */ 77 | .swiper-container .swiper-notification { 78 | position: absolute; 79 | left: 0; 80 | top: 0; 81 | pointer-events: none; 82 | opacity: 0; 83 | z-index: -1000; 84 | } 85 | 86 | /* IE10 Windows Phone 8 Fixes */ 87 | .swiper-wp8-horizontal { 88 | -ms-touch-action: pan-y; 89 | touch-action: pan-y; 90 | } 91 | .swiper-wp8-vertical { 92 | -ms-touch-action: pan-x; 93 | touch-action: pan-x; 94 | } 95 | /* Arrows */ 96 | .swiper-button-prev, .swiper-button-next { 97 | position: absolute; 98 | top: 50%; 99 | width: 27px; 100 | height: 44px; 101 | margin-top: -22px; 102 | z-index: 10; 103 | cursor: pointer; 104 | -moz-background-size: 27px 44px; 105 | -webkit-background-size: 27px 44px; 106 | background-size: 27px 44px; 107 | background-position: center; 108 | background-repeat: no-repeat; 109 | &.swiper-button-disabled { 110 | opacity: 0.35; 111 | cursor: auto; 112 | pointer-events: none; 113 | } 114 | } 115 | .swiper-button-prev, .swiper-container-rtl .swiper-button-next { 116 | .encoded-svg-background(""); 117 | left: 10px; 118 | right: auto; 119 | } 120 | .swiper-button-next, .swiper-container-rtl .swiper-button-prev { 121 | .encoded-svg-background(""); 122 | right: 10px; 123 | left: auto; 124 | } 125 | /* Pagination Styles */ 126 | .swiper-pagination { 127 | position: absolute; 128 | text-align: center; 129 | -webkit-transition: 300ms; 130 | -moz-transition: 300ms; 131 | -o-transition: 300ms; 132 | transition: 300ms; 133 | -webkit-transform: translate3d(0,0,0); 134 | -ms-transform: translate3d(0,0,0); 135 | -o-transform: translate3d(0,0,0); 136 | transform: translate3d(0,0,0); 137 | z-index: 10; 138 | &.swiper-pagination-hidden { 139 | opacity: 0; 140 | } 141 | } 142 | .swiper-pagination-bullet { 143 | width: 8px; 144 | height: 8px; 145 | display: inline-block; 146 | border-radius: 100%; 147 | background: #000; 148 | opacity: 0.2; 149 | } 150 | .swiper-pagination-bullet-active { 151 | opacity: 1; 152 | background: #007aff; 153 | } 154 | .swiper-container-vertical { 155 | > .swiper-pagination { 156 | right: 10px; 157 | top: 50%; 158 | -webkit-transform:translate3d(0px,-50%,0); 159 | -moz-transform:translate3d(0px,-50%,0); 160 | -o-transform:translate(0px,-50%); 161 | -ms-transform:translate3d(0px,-50%,0); 162 | transform:translate3d(0px,-50%,0); 163 | .swiper-pagination-bullet { 164 | margin: 5px 0; 165 | display: block; 166 | } 167 | } 168 | } 169 | .swiper-container-horizontal { 170 | > .swiper-pagination { 171 | bottom: 10px; 172 | left: 0; 173 | width: 100%; 174 | .swiper-pagination-bullet { 175 | margin: 0 5px; 176 | } 177 | } 178 | } 179 | /* 3D Container */ 180 | .swiper-container-3d { 181 | -webkit-perspective: 1200px; 182 | -moz-perspective: 1200px; 183 | -o-perspective: 1200px; 184 | perspective: 1200px; 185 | .swiper-wrapper, .swiper-slide, .swiper-slide-shadow-left, .swiper-slide-shadow-right, .swiper-slide-shadow-top, .swiper-slide-shadow-bottom, .swiper-cube-shadow { 186 | .preserve3d(); 187 | } 188 | .swiper-slide-shadow-left, .swiper-slide-shadow-right, .swiper-slide-shadow-top, .swiper-slide-shadow-bottom { 189 | position:absolute; 190 | left:0; 191 | top:0; 192 | width:100%; 193 | height:100%; 194 | pointer-events:none; 195 | z-index: 10; 196 | } 197 | .swiper-slide-shadow-left { 198 | background-image: -webkit-gradient(linear, left top, right top, from(rgba(0,0,0,0.5)), to(rgba(0,0,0,0))); /* Safari 4+, Chrome */ 199 | background-image: -webkit-linear-gradient(right, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Chrome 10+, Safari 5.1+, iOS 5+ */ 200 | background-image: -moz-linear-gradient(right, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Firefox 3.6-15 */ 201 | background-image: -o-linear-gradient(right, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Opera 11.10-12.00 */ 202 | background-image: linear-gradient(to left, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Firefox 16+, IE10, Opera 12.50+ */ 203 | } 204 | .swiper-slide-shadow-right { 205 | background-image: -webkit-gradient(linear, right top, left top, from(rgba(0,0,0,0.5)), to(rgba(0,0,0,0))); /* Safari 4+, Chrome */ 206 | background-image: -webkit-linear-gradient(left, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Chrome 10+, Safari 5.1+, iOS 5+ */ 207 | background-image: -moz-linear-gradient(left, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Firefox 3.6-15 */ 208 | background-image: -o-linear-gradient(left, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Opera 11.10-12.00 */ 209 | background-image: linear-gradient(to right, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Firefox 16+, IE10, Opera 12.50+ */ 210 | } 211 | .swiper-slide-shadow-top { 212 | background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,0.5)), to(rgba(0,0,0,0))); /* Safari 4+, Chrome */ 213 | background-image: -webkit-linear-gradient(bottom, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Chrome 10+, Safari 5.1+, iOS 5+ */ 214 | background-image: -moz-linear-gradient(bottom, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Firefox 3.6-15 */ 215 | background-image: -o-linear-gradient(bottom, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Opera 11.10-12.00 */ 216 | background-image: linear-gradient(to top, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Firefox 16+, IE10, Opera 12.50+ */ 217 | } 218 | .swiper-slide-shadow-bottom { 219 | background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(0,0,0,0.5)), to(rgba(0,0,0,0))); /* Safari 4+, Chrome */ 220 | background-image: -webkit-linear-gradient(top, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Chrome 10+, Safari 5.1+, iOS 5+ */ 221 | background-image: -moz-linear-gradient(top, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Firefox 3.6-15 */ 222 | background-image: -o-linear-gradient(top, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Opera 11.10-12.00 */ 223 | background-image: linear-gradient(to bottom, rgba(0,0,0,0.5), rgba(0,0,0,0)); /* Firefox 16+, IE10, Opera 12.50+ */ 224 | } 225 | } 226 | /* Coverflow */ 227 | .swiper-container-coverflow { 228 | .swiper-wrapper { 229 | /* Windows 8 IE 10 fix */ 230 | -ms-perspective:1200px; 231 | } 232 | 233 | } 234 | /* Fade */ 235 | .swiper-container-fade { 236 | &.swiper-container-free-mode { 237 | .swiper-slide { 238 | -webkit-transition-timing-function: ease-out; 239 | -moz-transition-timing-function: ease-out; 240 | -ms-transition-timing-function: ease-out; 241 | -o-transition-timing-function: ease-out; 242 | transition-timing-function: ease-out; 243 | } 244 | } 245 | .swiper-slide { 246 | pointer-events: none; 247 | } 248 | .swiper-slide-active { 249 | pointer-events: auto; 250 | } 251 | } 252 | /* Cube */ 253 | .swiper-container-cube { 254 | overflow: visible; 255 | .swiper-slide { 256 | pointer-events: none; 257 | visibility: hidden; 258 | -webkit-transform-origin: 0 0; 259 | -moz-transform-origin: 0 0; 260 | -ms-transform-origin: 0 0; 261 | transform-origin: 0 0; 262 | -webkit-backface-visibility: hidden; 263 | -moz-backface-visibility: hidden; 264 | -ms-backface-visibility: hidden; 265 | backface-visibility: hidden; 266 | width: 100%; 267 | height: 100%; 268 | } 269 | &.swiper-container-rtl .swiper-slide{ 270 | -webkit-transform-origin: 100% 0; 271 | -moz-transform-origin: 100% 0; 272 | -ms-transform-origin: 100% 0; 273 | transform-origin: 100% 0; 274 | } 275 | .swiper-slide-active, .swiper-slide-next, .swiper-slide-prev, .swiper-slide-next + .swiper-slide { 276 | pointer-events: auto; 277 | visibility: visible; 278 | } 279 | .swiper-cube-shadow { 280 | position: absolute; 281 | left: 0; 282 | bottom: 0px; 283 | width: 100%; 284 | height: 100%; 285 | background: #000; 286 | opacity: 0.6; 287 | -webkit-filter: blur(50px); 288 | filter: blur(50px); 289 | } 290 | &.swiper-container-vertical .swiper-cube-shadow { 291 | z-index: 0; 292 | } 293 | } 294 | /* Scrollbar */ 295 | .swiper-scrollbar { 296 | border-radius: 10px; 297 | position: relative; 298 | -ms-touch-action: none; 299 | background: rgba(0,0,0,0.1); 300 | .swiper-container-horizontal > & { 301 | position: absolute; 302 | left: 1%; 303 | bottom: 3px; 304 | z-index: 50; 305 | height: 5px; 306 | width: 98%; 307 | } 308 | .swiper-container-vertical > & { 309 | position: absolute; 310 | right: 3px; 311 | top: 1%; 312 | z-index: 50; 313 | width: 5px; 314 | height: 98%; 315 | } 316 | } 317 | .swiper-scrollbar-drag { 318 | height: 100%; 319 | width: 100%; 320 | position: relative; 321 | background: rgba(0,0,0,0.5); 322 | border-radius: 10px; 323 | left: 0; 324 | top: 0; 325 | } 326 | .swiper-scrollbar-cursor-drag { 327 | cursor: move; 328 | } 329 | /* Preloader */ 330 | .swiper-slide .preloader { 331 | width: 42px; 332 | height: 42px; 333 | position: absolute; 334 | left: 50%; 335 | top: 50%; 336 | margin-left: -21px; 337 | margin-top: -21px; 338 | z-index: 10; 339 | } 340 | 341 | 342 | .swiper-slide img { 343 | display: block; 344 | } 345 | -------------------------------------------------------------------------------- /less/sui/tabs.less: -------------------------------------------------------------------------------- 1 | /* === Tabs === */ 2 | .tabs { 3 | .tab { 4 | display: none; 5 | } 6 | .tab.active { 7 | display: block; 8 | } 9 | } 10 | .tabs-animated-wrap { 11 | position: relative; 12 | width: 100%; 13 | overflow: hidden; 14 | height: 100%; 15 | >.tabs { 16 | .flexbox(); 17 | height: 100%; 18 | transition: 300ms; 19 | >.tab { 20 | width: 100%; 21 | display: block; 22 | .flex-shrink(0); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /less/sui/text.less: -------------------------------------------------------------------------------- 1 | .color-default { 2 | color: @color-text; 3 | } 4 | 5 | .color-gray { 6 | color: #999; 7 | } 8 | 9 | .color-primary { 10 | color: @color-primary; 11 | } 12 | 13 | .color-success { 14 | color: @color-success; 15 | } 16 | .color-danger { 17 | color: @color-danger; 18 | } 19 | .color-warning { 20 | color: @color-warning; 21 | } 22 | 23 | .text-center { 24 | text-align: center; 25 | } 26 | -------------------------------------------------------------------------------- /less/sui/themes.less: -------------------------------------------------------------------------------- 1 | /*========================== 2 | Framework7 Layouts Themes 3 | ==========================*/ 4 | @import url('mixins.less'); 5 | /* === Dark layout === */ 6 | .theme-dark { 7 | @pageBg: #222426; 8 | @barsBg: #131313; 9 | @barsBorder: #333; 10 | @barsText: #fff; 11 | @tabBarText: #fff; 12 | @text: #ddd; 13 | @lightText: #bbb; 14 | @strongText: #fff; 15 | @activeLink: #29292f; 16 | @blockBg: #1c1d1f; 17 | @blockBorder: #393939; 18 | @blockStrongBg: #1c1d1f; 19 | @dividerBg: #1a1a1a; 20 | @itemAfterText: @lightText; 21 | @searchbarBg: #333; 22 | @searchbarBorder: #333; 23 | @swipeoutButton: #444; 24 | @checkboxBorder: @blockBorder; 25 | background-color: @pageBg; 26 | .bar, .bar& { 27 | .hairline-color(bottom, @barsBorder); 28 | background-color: @barsBg; 29 | color:@barsText; 30 | 31 | } 32 | .title { 33 | color: @barsText; 34 | } 35 | .bar-nav, .bar-tab, 36 | .bar-nav&, .bar-tab& { 37 | .hairline-color(top, @barsBorder); 38 | background-color: @barsBg; 39 | color: @tabBarText; 40 | } 41 | .tab-item { 42 | color: @tabBarText; 43 | &.active { 44 | color: @color-primary; 45 | } 46 | } 47 | // Picker 48 | .picker-calendar-week-days { 49 | color:#fff; 50 | background-color: @barsBg; 51 | } 52 | .popover .picker-modal, .picker-modal.picker-modal-inline { 53 | .picker-center-highlight { 54 | .hairline-color(top, @barsBorder); 55 | .hairline-color(bottom, @barsBorder); 56 | } 57 | .picker-item.picker-selected { 58 | color:#fff; 59 | } 60 | .picker-calendar-week-days { 61 | color: #fff; 62 | } 63 | .picker-calendar-day { 64 | color:#fff; 65 | &.picker-calendar-day-prev, &.picker-calendar-day-next { 66 | color: #777; 67 | } 68 | &.picker-calendar-day-disabled { 69 | color: #555; 70 | } 71 | &.picker-calendar-day-today span { 72 | background: #444; 73 | } 74 | } 75 | .picker-calendar-week-days, .picker-calendar-row { 76 | .hairline-color(bottom, @barsBorder); 77 | } 78 | .toolbar ~ .picker-modal-inner .picker-calendar-months, .picker-calendar-week-days ~ .picker-calendar-months { 79 | .hairline-color(top, @barsBorder); 80 | } 81 | 82 | } 83 | .popover .picker-modal { 84 | .toolbar { 85 | .hairline-color(bottom, @barsBorder); 86 | } 87 | } 88 | // Photo Browser 89 | .photo-browser, .photo-browser&, .view[data-page="photo-browser-slides"], .view[data-page="photo-browser-slides"]& { 90 | .navbar, .toolbar { 91 | background: rgba(red(@barsBg), green(@barsBg), blue(@barsBg), 0.95); 92 | } 93 | } 94 | .tabbar a:not(.active) { 95 | color:@tabBarText; 96 | } 97 | .page, .login-screen-content, .page&, .panel, .panel&, .content { 98 | background-color: @pageBg; 99 | color:@text; 100 | } 101 | .content-block-title { 102 | color:@strongText; 103 | } 104 | .content-block, .content-block& { 105 | color:@lightText; 106 | } 107 | .content-block-inner { 108 | background: @blockStrongBg; 109 | color:@text; 110 | .hairline-color(top, @blockBorder); 111 | .hairline-color(bottom, @blockBorder); 112 | } 113 | .list-block, .list-block& { 114 | ul { 115 | background: @blockBg; 116 | .hairline-color(top, @blockBorder); 117 | .hairline-color(bottom, @blockBorder); 118 | } 119 | &.inset ul{ 120 | background: @blockStrongBg; 121 | } 122 | &.notifications > ul { 123 | background: none; 124 | } 125 | .item-title, .item-subtitle { 126 | color: @lightText; 127 | } 128 | } 129 | .card { 130 | background: @blockBg; 131 | } 132 | .card-header{ 133 | .hairline-color(bottom, @blockBorder); 134 | } 135 | .card-footer { 136 | .hairline-color(top, @blockBorder); 137 | color:@lightText; 138 | } 139 | .popover, .popover& { 140 | background: rgba(0,0,0,0.8); 141 | .popover-angle:after { 142 | background: rgba(0,0,0,0.8); 143 | } 144 | .list-block ul { 145 | background: none; 146 | } 147 | 148 | } 149 | .actions-popover .list-block ul { 150 | .hairline-color(top, @blockBorder); 151 | .hairline-color(bottom, @blockBorder); 152 | } 153 | .actions-popover .actions-popover-label { 154 | .hairline-color(bottom, @blockBorder); 155 | } 156 | li.sorting { 157 | background-color: @activeLink; 158 | } 159 | .swipeout-actions-left a, .swipeout-actions-right a { 160 | background-color: @swipeoutButton; 161 | } 162 | .item-inner, .list-block ul ul li:last-child .item-inner { 163 | .hairline-color(bottom, @blockBorder); 164 | } 165 | .item-after { 166 | color:@itemAfterText; 167 | } 168 | .item-link, label.label-checkbox, label.label-radio { 169 | html:not(.watch-active-state) &:active, &.active-state { 170 | background-color: @activeLink; 171 | } 172 | } 173 | .item-link.list-button { 174 | .hairline-color(bottom, @blockBorder); 175 | } 176 | .list-block-label { 177 | color:@lightText; 178 | } 179 | .item-divider, .list-group-title { 180 | background: @dividerBg; 181 | color:@lightText; 182 | .hairline-color(top, @blockBorder); 183 | } 184 | 185 | // Searchbar 186 | .searchbar { 187 | background: @searchbarBg; 188 | .hairline-color(bottom, @searchbarBorder); 189 | } 190 | 191 | // Forms 192 | .list-block, .list-block& { 193 | input[type="text"], input[type="password"], input[type="email"], input[type="tel"], input[type="url"], input[type="date"], input[type="datetime-local"], input[type="number"], select, textarea { 194 | color:@strongText; 195 | } 196 | } 197 | .label-switch .checkbox { 198 | background-color: @checkboxBorder; 199 | &:before { 200 | background-color: @blockBg; 201 | } 202 | } 203 | .range-slider input[type="range"]:after { 204 | background: @blockBg; 205 | } 206 | 207 | .buttons-tab { 208 | background: @barsBg; 209 | 210 | .tab-link:not(.active) { 211 | color: @text; 212 | } 213 | } 214 | 215 | } 216 | 217 | /* === White layout === */ 218 | .theme-white { 219 | @pageBg: #fff; 220 | @barsBg: #fff; 221 | @barsBorder: #ddd; 222 | @barsText: #000; 223 | @tabBarText: #777; 224 | @text: #000; 225 | @lightText: #777; 226 | @strongText: #777; 227 | @activeLink: #eee; 228 | @blockBg: @pageBg; 229 | @blockBorder: #ddd; 230 | @blockStrongBg: #fafafa; 231 | @dividerBg: #f7f7f7; 232 | @itemAfterText: #8e8e93; 233 | @searchbarBg: #c9c9ce; 234 | @searchbarBorder: #b4b4b4; 235 | @swipeoutButton: #c7c7cc; 236 | @checkboxBorder: #e5e5e5; 237 | .navbar, .navbar&, .subnavbar, .subnavbar& { 238 | .hairline-color(bottom, @barsBorder); 239 | background-color: @barsBg; 240 | color:@barsText; 241 | } 242 | .toolbar, .toolbar& { 243 | .hairline-color(top, @barsBorder); 244 | background-color: @barsBg; 245 | color:@barsText; 246 | } 247 | // Picker 248 | .popover .picker-modal, .picker-modal.picker-modal-inline { 249 | .picker-center-highlight { 250 | .hairline-color(top, @barsBorder); 251 | .hairline-color(bottom, @barsBorder); 252 | } 253 | .picker-calendar-week-days, .picker-calendar-row { 254 | .hairline-color(bottom, @barsBorder); 255 | } 256 | .toolbar ~ .picker-modal-inner .picker-calendar-months, .picker-calendar-week-days ~ .picker-calendar-months { 257 | .hairline-color(top, @barsBorder); 258 | } 259 | } 260 | .popover .picker-modal { 261 | .toolbar { 262 | .hairline-color(bottom, @barsBorder); 263 | } 264 | } 265 | // Photo Browser 266 | .photo-browser, .photo-browser&, .view[data-page="photo-browser-slides"], .view[data-page="photo-browser-slides"]& { 267 | .navbar, .toolbar { 268 | background: rgba(red(@barsBg), green(@barsBg), blue(@barsBg), 0.95); 269 | } 270 | } 271 | .tabbar a:not(.active) { 272 | color:@tabBarText; 273 | } 274 | .page, .login-screen-content, .page&, .panel, .panel& { 275 | background-color: @pageBg; 276 | color: @text; 277 | } 278 | .content-block-title { 279 | color:@strongText; 280 | } 281 | .content-block, .content-block& { 282 | color:@lightText; 283 | } 284 | .content-block-inner { 285 | background: @blockStrongBg; 286 | color:@text; 287 | .hairline-color(bottom, @blockBorder); 288 | .hairline-color(top, @blockBorder); 289 | } 290 | .list-block, .list-block& { 291 | ul { 292 | background: @blockBg; 293 | .hairline-color(bottom, @blockBorder); 294 | .hairline-color(top, @blockBorder); 295 | } 296 | &.inset ul{ 297 | background: @blockStrongBg; 298 | } 299 | &.notifications > ul { 300 | background: none; 301 | } 302 | } 303 | .popover-inner > .list-block ul { 304 | background: none; 305 | } 306 | li.sorting { 307 | background-color: @activeLink; 308 | } 309 | .swipeout-actions-left a, .swipeout-actions-right a { 310 | background-color: @swipeoutButton; 311 | } 312 | .item-inner, .list-block ul ul li:last-child .item-inner { 313 | border-color: @blockBorder; 314 | .hairline-color(bottom, @blockBorder); 315 | } 316 | .item-after { 317 | color:@itemAfterText; 318 | } 319 | .item-link, label.label-checkbox, label.label-radio { 320 | html:not(.watch-active-state) &:active, &.active-state { 321 | background-color: @activeLink; 322 | } 323 | } 324 | .item-link.list-button { 325 | .hairline-color(bottom, @blockBorder); 326 | } 327 | .list-block-label { 328 | color:@lightText; 329 | } 330 | .item-divider, .list-group-title { 331 | background: @dividerBg; 332 | color:@lightText; 333 | .hairline-color(top, @blockBorder); 334 | } 335 | 336 | // Searchbar 337 | .searchbar { 338 | background: @searchbarBg; 339 | .hairline-color(bottom, @searchbarBorder); 340 | } 341 | 342 | // Forms 343 | .list-block, .list-block& { 344 | input[type="text"], input[type="password"], input[type="email"], input[type="tel"], input[type="url"], input[type="date"], input[type="datetime-local"], input[type="number"], select, textarea { 345 | color:@strongText; 346 | } 347 | } 348 | .label-switch .checkbox { 349 | background-color: @checkboxBorder; 350 | &:before { 351 | background-color: @blockBg; 352 | } 353 | } 354 | .range-slider input[type="range"]:after { 355 | background: @blockBg; 356 | } 357 | } 358 | -------------------------------------------------------------------------------- /less/sui/variables.less: -------------------------------------------------------------------------------- 1 | // 2 | // Variables 3 | // -------------------------------------------------- 4 | 5 | // Type 6 | // -------------------------------------------------- 7 | @font-family-default: "Helvetica Neue", Helvetica, sans-serif; 8 | @font-size-default: 0.85rem; 9 | @font-weight: 500; 10 | @font-weight-light: 400; 11 | @line-height-default: 1.05rem; 12 | 13 | 14 | //img 15 | @imgBaseUrl: "../img"; 16 | 17 | // Colors 18 | // -------------------------------------------------- 19 | 20 | 21 | // 主色 22 | @color-primary: #0894ec; 23 | @color-danger: #f6383a; 24 | @color-warning: #f60; 25 | @color-success: #4cd964; 26 | 27 | @color-primary-active: #0a8ddf; 28 | @color-danger-active: darken(@color-danger, 10%); 29 | @color-warning-active: darken(@color-warning, 10%); 30 | @color-success-active: darken(@color-success, 10%); 31 | 32 | @color-split: #e7e7e7; //分割线的颜色 33 | @color-bg: #eee; 34 | @color-text: #3d4145; //文案色 35 | @color-text-secondary: #5f646e; //次级文案 36 | @color-text-gray: #999; //灰色文案 37 | @color-text-gray-light: #ccc; //更灰色文案 38 | 39 | //链接色 40 | @color-link: @color-primary; //链接色有可能不同于主色 41 | @color-link-active: @color-primary-active; //链接色有可能不同于主色 42 | 43 | // Bars 44 | // -------------------------------------------------- 45 | 46 | @bar-base-height: 2.2rem; 47 | @bar-tab-height: 2.5rem; 48 | @bar-side-spacing: 0.5rem; 49 | 50 | 51 | // Cards 52 | // -------------------------------------------------- 53 | 54 | @card-bg: #fff; 55 | 56 | 57 | // Buttons 58 | // -------------------------------------------------- 59 | 60 | @button-font-size: 0.6rem; 61 | 62 | 63 | // Transitions 64 | // -------------------------------------------------- 65 | 66 | @timing-fuction: cubic-bezier(.1,.5,.1,1); // Inspired by @c2prods 67 | 68 | 69 | // Borders 70 | // -------------------------------------------------- 71 | 72 | @border-default-width: 1px; 73 | @border-default-color: @color-split; 74 | @border-default: @border-default-width solid @border-default-color; 75 | @border-radius: 0.3rem; 76 | -------------------------------------------------------------------------------- /less/webui/index.less: -------------------------------------------------------------------------------- 1 | html, body { 2 | position: relative; 3 | height: 100%; 4 | width: 100%; 5 | overflow-x: hidden; 6 | -webkit-tap-highlight-color: transparent; 7 | } 8 | div{ 9 | cursor:pointer; 10 | } 11 | .tabs .tab { 12 | display: none; 13 | } 14 | .tabs .tab.active { 15 | display: block; 16 | } 17 | 18 | .buttons-tab .button.disabled{ 19 | color: #c8c9cb 20 | } 21 | 22 | .buttons-tab .button.disabled:active{ 23 | border-bottom:transparent; 24 | } 25 | 26 | .view, .views { 27 | position: relative; 28 | width: 100%; 29 | height: 100%; 30 | z-index: 5000; 31 | } 32 | .views { 33 | overflow: auto; 34 | -webkit-overflow-scrolling: touch; 35 | } 36 | .view { 37 | overflow: hidden; 38 | box-sizing: border-box; 39 | } 40 | .pages { 41 | position: relative; 42 | width: 100%; 43 | height: 100%; 44 | overflow: hidden; 45 | 46 | } 47 | .page { 48 | box-sizing: border-box; 49 | position: absolute; 50 | left: 0; 51 | top: 0; 52 | bottom:0; 53 | width: 100%; 54 | height: 100%; 55 | background: #efeff4; 56 | -webkit-transform: translate3d(0,0,0); 57 | transform: translate3d(0,0,0); 58 | display:block; 59 | } 60 | 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-webui", 3 | "version": "0.0.1", 4 | "title": "Ant Design", 5 | "description": "基于framework7的react的移动端组件库", 6 | "homepage": "https://github.com/liugenpeng/react-mui", 7 | "main": "lib/index", 8 | "author": "Liugenpeng", 9 | "contributors": [ 10 | "react-mui" 11 | ], 12 | "keywords": [ 13 | "react", 14 | "framework7", 15 | "react-component", 16 | "javascript", 17 | "ui" 18 | ], 19 | "scripts": { 20 | "babel": "babel src --out-dir lib", 21 | "start": "webpack-dev-server --config webpack.dev.config.js --progress --colors", 22 | "test": "karma start" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "git+https://github.com/liugenpeng/react-mui.git" 27 | }, 28 | "bugs": { 29 | "url": "https://github.com/liugenpeng/react-mui/issues" 30 | }, 31 | "license": "MIT", 32 | "peerDependencies": { 33 | "react": ">=0.14.3", 34 | "react-dom": ">=0.14.3" 35 | }, 36 | "devDependencies": { 37 | "autoprefixer-loader": "~2.0.0", 38 | "babel": "^5.8.23", 39 | "babel-core": "^5.8.25", 40 | "babel-eslint": "^4.1.3", 41 | "babel-loader": "^5.3.2", 42 | "babel-plugin-dev-expression": "^0.1.0", 43 | "babel-runtime": "^5.8.29", 44 | "chai": "^3.3.0", 45 | "classnames": "^2.2.0", 46 | "colors": "^1.1.2", 47 | "css-loader": "^0.21.0", 48 | "es5-shim": "^4.3.1", 49 | "file-loader": "^0.8.4", 50 | "json-loader": "^0.5.3", 51 | "karma": "~0.13.10", 52 | "karma-chrome-launcher": "~0.2.1", 53 | "karma-cli": "0.1.1", 54 | "karma-coverage": "^0.5.2", 55 | "karma-coveralls": "^1.1.2", 56 | "karma-firefox-launcher": "~0.1.6", 57 | "karma-mocha": "~0.2.0", 58 | "karma-mocha-reporter": "^1.1.1", 59 | "karma-sinon-chai": "^1.1.0", 60 | "karma-sourcemap-loader": "^0.3.5", 61 | "karma-webpack": "^1.7.0", 62 | "less": "^2.5.3", 63 | "less-loader": "^2.2.1", 64 | "lodash": "^3.10.1", 65 | "react-addons-test-utils": "^0.14.3", 66 | "react-router": "^1.0.0-rc3", 67 | "sinon": "^1.17.1", 68 | "sinon-chai": "^2.8.0", 69 | "style-loader": "^0.13.0", 70 | "url-loader": "^0.5.6", 71 | "webpack": "^1.12.2", 72 | "webpack-dev-middleware": "^1.2.0", 73 | "webpack-dev-server": "^1.12.0" 74 | }, 75 | "dependencies": { 76 | "react-fastclick": "^1.0.3", 77 | "react-gestures": "^0.1.8", 78 | "react-hammerjs": "^0.4.2", 79 | "react-swipe": "^3.0.0", 80 | "react-swipeable": "^3.0.2", 81 | "swipe-js-iso": ">=2.0.0" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Button.js: -------------------------------------------------------------------------------- 1 | import React , { Component , PropTypes } from 'react'; 2 | import { css,pureRender } from './enhance/index'; 3 | import createEnhance from './core/createEnhance'; 4 | 5 | @createEnhance(css) 6 | export default class Button extends Component{ 7 | static displayName = "Button"; 8 | static propTypes = { 9 | color:PropTypes.string, 10 | disabled:PropTypes.bool, 11 | fill:PropTypes.bool, 12 | big:PropTypes.bool, 13 | round:PropTypes.bool, 14 | active:PropTypes.bool, 15 | wrap:PropTypes.bool 16 | }; 17 | static get defaultProps(){ 18 | return { 19 | disabled:false, 20 | fill:false, 21 | big:false, 22 | round:false, 23 | active:false, 24 | href:"javascript:;", 25 | wrap:true 26 | } 27 | } 28 | _getColorClassName=(color)=>{ 29 | return !color ? "":`button-${color}`; 30 | } 31 | render=()=>{ 32 | const { color , disabled , fill , 33 | big , round , active , inline , href , 34 | className, children ,wrap, ...other 35 | } = this.props; 36 | 37 | let classesSet = { 38 | disabled, 39 | "button-fill":fill, 40 | "button-big":big, 41 | "button-round":round, 42 | active 43 | }; 44 | let colorCls = this._getColorClassName(color); 45 | 46 | let buttonEl = ( 47 | 48 | { children } 49 | 50 | ); 51 | let resultElement ; 52 | resultElement = wrap ? (

{buttonEl}

):(buttonEl); 53 | return resultElement 54 | 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/ButtonRow.js: -------------------------------------------------------------------------------- 1 | import React , { Component , PropTypes } from 'react'; 2 | import { css,pureRender } from './enhance/index'; 3 | import createEnhance from './core/createEnhance' 4 | 5 | @createEnhance(css) 6 | export default class ButtonRow extends Component{ 7 | static displayName = "ButtonRow"; 8 | render=()=>{ 9 | const { 10 | className , 11 | children , 12 | round , 13 | color , 14 | big , 15 | ...other 16 | } = this.props; 17 | 18 | let cloneProps = { 19 | fill:false, 20 | wrap:false, 21 | big, 22 | color, 23 | round 24 | }; 25 | let buttons = React.Children.map(children,(button)=>{ 26 | return React.cloneElement(button,cloneProps); 27 | }); 28 | return ( 29 |

30 | {buttons} 31 |

32 | ); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/Col.js: -------------------------------------------------------------------------------- 1 | import React , { Component } from 'react'; 2 | import { css , pureRender } from './enhance/index'; 3 | import createEnhance from './core/createEnhance'; 4 | import constant from './constant'; 5 | @createEnhance(css,pureRender) 6 | export default class Col extends Component{ 7 | static propTypes= { 8 | ComponentClass:React.PropTypes.string, 9 | width:React.PropTypes.string 10 | }; 11 | static defaultProps = { 12 | width:"100", 13 | ComponentClass: 'div' 14 | }; 15 | 16 | render=()=>{ 17 | 18 | const { 19 | ComponentClass, 20 | className , 21 | children , 22 | width , 23 | ...other 24 | } = this.props; 25 | 26 | let classes = {}; 27 | let widthClassName = constant.COLS[width] ? constant.COLS[width] : constant["100"]; 28 | 29 | return ( 30 | 33 | {children} 34 | 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Icon.js: -------------------------------------------------------------------------------- 1 | import React , { Component } from 'react'; 2 | import { css,pureRender } from './enhance/index'; 3 | import createEnhance from './core/createEnhance' 4 | /** 5 | * 图标组件 6 | */ 7 | @createEnhance(css,pureRender) 8 | export default class Icon extends Component{ 9 | static propTypes = { 10 | fontSize:React.PropTypes.string, 11 | color:React.PropTypes.string 12 | }; 13 | 14 | render=()=>{ 15 | const { fontSize , color , icon , ...other } = this.props; 16 | const iconClassName = "icon-"+icon; 17 | const iconStyle = { 18 | fontSize, 19 | color 20 | }; 21 | return ( 22 | 23 | ); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/Image.js: -------------------------------------------------------------------------------- 1 | import React , { Component } from 'react'; 2 | import { css,pureRender } from './enhance/index'; 3 | import createEnhance from './core/createEnhance' 4 | 5 | /** 6 | * Image 组件 7 | * author:LGP 8 | */ 9 | @createEnhance(css,pureRender) 10 | export default class Image extends Component{ 11 | static propTypes= { 12 | src:React.PropTypes.string, 13 | responsive: React.PropTypes.bool, 14 | rounded: React.PropTypes.bool, 15 | circle: React.PropTypes.bool, 16 | thumbnail: React.PropTypes.bool 17 | }; 18 | static defaultProps = { 19 | responsive: false, // 是否自适应 20 | rounded: false, // 方形 21 | circle: false, // 原型 22 | thumbnail: false // 缩略图 23 | }; 24 | 25 | render=()=>{ 26 | const { 27 | responsive , rounded , circle , 28 | thumbnail , className , 29 | ...other 30 | } = this.props; 31 | const classes = { 32 | 'img-responsive': responsive, 33 | 'img-rounded': rounded, 34 | 'img-circle':circle, 35 | 'img-thumbnail': thumbnail 36 | }; 37 | return ( 38 | 39 | ); 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/Row.js: -------------------------------------------------------------------------------- 1 | import React , { Component } from 'react'; 2 | import { css , pureRender } from './enhance/index'; 3 | import createEnhance from './core/createEnhance'; 4 | 5 | @createEnhance(css,pureRender) 6 | export default class Row extends Component{ 7 | static propTypes= { 8 | ComponentClass:React.PropTypes.string 9 | }; 10 | static defaultProps = { 11 | ComponentClass: 'div' 12 | }; 13 | 14 | render=()=>{ 15 | 16 | const { 17 | ComponentClass, 18 | className , 19 | children , 20 | ...other 21 | } = this.props; 22 | 23 | return ( 24 | 27 | {children} 28 | 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/constant.js: -------------------------------------------------------------------------------- 1 | const constant = { 2 | COLS: { 3 | '5': 'col-5', 4 | '10': 'col-10', 5 | '15': 'col-15', 6 | '20': 'col-20', 7 | '25': 'col-25', 8 | '33': 'col-33', 9 | '40': 'col-30', 10 | '50': 'col-50', 11 | '60': 'col-60', 12 | '66': 'col-66', 13 | '75': 'col-75', 14 | '80': 'col-80', 15 | '85': 'col-85', 16 | '90': 'col-90', 17 | '95': 'col-95', 18 | '100': 'col-100' 19 | } 20 | } 21 | export default constant; 22 | -------------------------------------------------------------------------------- /src/core/createEnhance.js: -------------------------------------------------------------------------------- 1 | import React , { Component } from 'react'; 2 | import classNames from 'classnames'; 3 | /** 4 | * 组件增强器,动态添加功能 5 | */ 6 | export default function createEnhance(...utilsList){ 7 | let utis = Array.from(utilsList); 8 | return function wrapWithEnhance(WrappedComponent){ 9 | utis.forEach((util)=>{ 10 | for(var k in util){ 11 | if(k == "__esModule") continue; 12 | if(util.hasOwnProperty(k)){ 13 | WrappedComponent.prototype[k] = util[k]; 14 | } 15 | } 16 | }); 17 | return WrappedComponent; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/enhance/css.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames'; 2 | 3 | export function mergeClass(...classList){ 4 | return classNames(...classList); 5 | } 6 | -------------------------------------------------------------------------------- /src/enhance/dom.js: -------------------------------------------------------------------------------- 1 | export function getDom(){ 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/enhance/index.js: -------------------------------------------------------------------------------- 1 | import * as css from './css'; 2 | import * as dom from './dom'; 3 | import * as pureRender from './pureRender'; 4 | export { 5 | css, 6 | dom, 7 | pureRender 8 | }; 9 | -------------------------------------------------------------------------------- /src/enhance/pureRender.js: -------------------------------------------------------------------------------- 1 | import shallowCompare from '../utils/shallowEqual'; 2 | export function shouldComponentUpdate(nextProps,nextState){ 3 | return shallowCompare(this, nextProps, nextState) 4 | } 5 | -------------------------------------------------------------------------------- /src/footer/Footer.js: -------------------------------------------------------------------------------- 1 | import React , { Component } from 'react'; 2 | import { css , pureRender } from '../enhance/index'; 3 | import createEnhance from '../core/createEnhance'; 4 | /** 5 | * Foote导航 6 | */ 7 | @createEnhance(css) 8 | export default class Footer extends Component{ 9 | 10 | render=()=>{ 11 | const { 12 | className , 13 | children , 14 | 15 | ...other 16 | } = this.props; 17 | 18 | return ( 19 | 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/footer/FooterItem.js: -------------------------------------------------------------------------------- 1 | import React , { Component , PropTypes } from 'react'; 2 | import { css , pureRender } from '../enhance/index'; 3 | import Icon from '../Icon'; 4 | import createEnhance from '../core/createEnhance'; 5 | /** 6 | * FooterItem 组件(底部导航栏子组件) 7 | * author:LGP 8 | */ 9 | @createEnhance(css,pureRender) 10 | export default class FooterItem extends Component{ 11 | static propTypes = { 12 | active:PropTypes.bool, 13 | disabled:PropTypes.bool 14 | }; 15 | static defaultProps = { 16 | active:false, 17 | disabled:false 18 | }; 19 | 20 | render=()=>{ 21 | let { 22 | className , 23 | icon , 24 | active, 25 | text , 26 | disabled , 27 | ...other 28 | } = this.props; 29 | 30 | 31 | const classSet = { 32 | disabled, 33 | active 34 | } 35 | //图标组件 36 | const iconComponent = !icon ? null : ( 37 | 38 | ); 39 | //文本 40 | const textComponent = iconComponent ? ( 41 | 42 | {text} 43 | 44 | ) : text; 45 | //拼装整体组件 46 | let contentComponent ; 47 | 48 | return ( 49 | 50 | {iconComponent} 51 | {textComponent} 52 | 53 | ); 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/header/Header.js: -------------------------------------------------------------------------------- 1 | import React , { Component } from 'react'; 2 | import { css , pureRender } from '../enhance/index'; 3 | import createEnhance from '../core/createEnhance'; 4 | 5 | /** 6 | * Header组件(导航栏) 7 | * author:LGP 8 | */ 9 | @createEnhance(css) 10 | export default class Header extends Component{ 11 | static propTypes = { 12 | title:React.PropTypes.string 13 | }; 14 | render=()=>{ 15 | const { 16 | className , 17 | children , 18 | title , 19 | ...other 20 | } = this.props; 21 | //title组件 22 | const titleComponent = !title ? null : ( 23 |

{title}

24 | ); 25 | return ( 26 |
27 | { children } 28 | { titleComponent } 29 |
30 | ); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/header/HeaderItem.js: -------------------------------------------------------------------------------- 1 | import React , { Component , PropTypes } from 'react'; 2 | import { css , pureRender } from '../enhance/index'; 3 | import Icon from '../Icon'; 4 | import createEnhance from '../core/createEnhance'; 5 | /** 6 | * NavItem 组件(导航栏子组件) 7 | * author:LGP 8 | */ 9 | @createEnhance(css,pureRender) 10 | export default class HeaderItem extends Component{ 11 | static propTypes = { 12 | link:PropTypes.bool, 13 | disabled:PropTypes.bool, 14 | position:PropTypes.string, 15 | ComponentClass:React.PropTypes.string 16 | }; 17 | static defaultProps = { 18 | link:false, 19 | disabled:false, 20 | ComponentClass:"button" 21 | }; 22 | 23 | render=()=>{ 24 | let { 25 | className , 26 | icon , 27 | text , 28 | position , 29 | link , 30 | disabled , 31 | ComponentClass , 32 | ...other 33 | } = this.props; 34 | 35 | const isLeft = position == "left" ; 36 | 37 | const classSet = { 38 | disabled, 39 | "button-link":link, 40 | "pull-left":isLeft, 41 | "pull-right":!isLeft 42 | } 43 | 44 | //图标组件 45 | const iconComponent = !icon ? null : ( 46 | 47 | ); 48 | 49 | //拼装整体组件 50 | let contentComponent ; 51 | ComponentClass = !ComponentClass ? "a":ComponentClass; 52 | 53 | return ( 54 | 55 | {iconComponent} 56 | {text} 57 | 58 | ); 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/tabs/Tab.js: -------------------------------------------------------------------------------- 1 | import React , { Component , PropTypes } from 'react'; 2 | import { css , pureRender } from '../enhance/index'; 3 | import createEnhance from '../core/createEnhance'; 4 | import Swipeable from 'react-swipeable'; 5 | @createEnhance(css) 6 | export default class Tab extends Component{ 7 | static displayName = "Tab"; 8 | static propTypes = { 9 | onDestroy: PropTypes.func, 10 | }; 11 | componentWillUnmount=()=>{ 12 | const { onDestroy } = this.props; 13 | onDestroy && onDestroy(); 14 | } 15 | render=()=>{ 16 | const { 17 | title , 18 | disabled , 19 | active , 20 | className, 21 | children , 22 | ...other 23 | } = this.props; 24 | /*let childs = React.Children.map(children,(item)=>{ 25 | 26 | return ( 27 | 28 | {
{item}
} 29 |
30 | ); 31 | }) */ 32 | 33 | return ( 34 | 35 |
36 |
37 | 41 |
42 | { children } 43 |
44 |
45 | 46 |
47 |
48 | ); 49 | } 50 | handlerSwipedRight=(e,dis)=>{ 51 | const { onSwipedRight } = this.props; 52 | if(dis<=-50){ 53 | onSwipedRight && onSwipedRight(); 54 | } 55 | } 56 | handlerSwipedLeft=(e,dis)=>{ 57 | const { onSwipedLeft } = this.props; 58 | if(dis>=50){ 59 | onSwipedLeft && onSwipedLeft(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/tabs/TabNav.js: -------------------------------------------------------------------------------- 1 | import React , { Component , PropTypes } from 'react'; 2 | import { css , pureRender } from '../enhance/index'; 3 | import createEnhance from '../core/createEnhance'; 4 | import Button from '../Button'; 5 | @createEnhance(css) 6 | export default class TabNav extends Component{ 7 | static displayName = "TabNav"; 8 | static propTypes = { 9 | onTabClick: PropTypes.func 10 | }; 11 | onTabClick=(key)=>{ 12 | const { onTabClick ,disabled } = this.props; 13 | 14 | onTabClick && onTabClick(key); 15 | } 16 | getNavs=(children)=>{ 17 | const { panels, activeKey } = this.props; 18 | const rst = []; 19 | React.Children.forEach(panels, (child,index)=> { 20 | const { key , props } = child; 21 | const { disabled , title } = props; 22 | 23 | let events = {} , conf = {} ; 24 | if(!disabled){ 25 | events = { 26 | onClick: this.onTabClick.bind(this, key), 27 | }; 28 | } 29 | 30 | 31 | if (activeKey == key) { 32 | conf = { 33 | ref:'activeTab', 34 | cls:'active' 35 | }; 36 | } 37 | 38 | let cls = activeKey == key ? "active" : ""; 39 | rst.push( 40 | 45 | ); 46 | }); 47 | 48 | return rst; 49 | } 50 | render=()=>{ 51 | const { 52 | className, 53 | children , 54 | ...other 55 | } = this.props; 56 | 57 | let tabNavs = this.getNavs(children); 58 | 59 | return ( 60 |
61 | { tabNavs } 62 |
63 | ); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/tabs/Tabs.js: -------------------------------------------------------------------------------- 1 | import React , { Component , PropTypes } from 'react'; 2 | import { css } from '../enhance/index'; 3 | import createEnhance from '../core/createEnhance'; 4 | import TabNav from './TabNav'; 5 | 6 | //获取默认的activeKey 7 | function getDefaultActiveKey(props){ 8 | let activeKey; 9 | 10 | React.Children.forEach(props.children, (child) => { 11 | if (!activeKey && !child.props.disabled) { 12 | activeKey = child.key; 13 | } 14 | }); 15 | 16 | return activeKey; 17 | } 18 | 19 | @createEnhance(css) 20 | export default class Tabs extends Component{ 21 | constructor(props,context){ 22 | super(props,context); 23 | let _activeKey ; 24 | let { activeKey , defaultActiveKey } = props; 25 | if(activeKey){ 26 | _activeKey = activeKey 27 | }else if(defaultActiveKey){ 28 | _activeKey = defaultActiveKey; 29 | }else{ 30 | _activeKey = getDefaultActiveKey(props); 31 | } 32 | 33 | this.renderPanels = {}; 34 | this.state ={ 35 | activeKey:_activeKey 36 | }; 37 | } 38 | 39 | componentWillReceiveProps=(nextProps)=>{ 40 | let { activeKey:newActiveKey } = this.state; 41 | if ('activeKey' in nextProps) { 42 | newActiveKey = nextProps.activeKey; 43 | } 44 | let found; 45 | React.Children.forEach(nextProps.children, (child) => { 46 | if (child.key == newActiveKey) { 47 | found = true; 48 | } 49 | }); 50 | if (found) { 51 | this.setActiveTab(newActiveKey); 52 | } else { 53 | this.setActiveTab(getDefaultActiveKey(nextProps)); 54 | } 55 | } 56 | render=()=>{ 57 | const { 58 | children 59 | } = this.props; 60 | const { activeKey } = this.state; 61 | 62 | let { tab } = this._getTabs(children); 63 | 64 | return ( 65 |
66 | 71 | 72 |
73 |
74 | {tab} 75 |
76 |
77 |
78 | ); 79 | 80 | } 81 | hanlderSwipedLeft=()=>{ 82 | const { activeKey } = this.state ; 83 | const tabCount = React.Children.count(this.props.children); 84 | let newActiveKey = Number.parseInt(activeKey,10)+1; 85 | if(newActiveKey<=tabCount){ 86 | this.setActiveTab(newActiveKey); 87 | } 88 | 89 | } 90 | hanlderSwipedRight=()=>{ 91 | const { activeKey } = this.state ; 92 | 93 | let newActiveKey = Number.parseInt(activeKey,10)-1; 94 | if(newActiveKey>=1){ 95 | this.setActiveTab(newActiveKey); 96 | } 97 | } 98 | onTabDestroy=()=>{ 99 | this.renderPanels[key] = void 0; 100 | } 101 | onTabClick=(key)=>{ 102 | const { onTabClick, onTabChange } = this.props; 103 | const { activeKey } = this.state; 104 | onTabClick && onTabClick(key); 105 | if (activeKey !== key) { 106 | this.setActiveTab(key,onTabChange); 107 | } 108 | } 109 | //设置活动的tab 110 | setActiveTab=(newActiveKey,cb)=>{ 111 | 112 | this.setState({ 113 | activeKey:newActiveKey 114 | },()=>{ 115 | setTimeout(()=>{ 116 | cb && cb(); 117 | },0) 118 | }); 119 | } 120 | _getTabs=(children)=>{ 121 | const { props , state, renderPanels } = this; 122 | const { activeKey }= state; 123 | const tab = [] , tabNav = []; 124 | let active ; 125 | 126 | //遍历子节点 127 | React.Children.forEach(children, (child,index) => { 128 | 129 | const { key , props} = child; 130 | const { title } = props; 131 | 132 | active = ( activeKey == key ); 133 | 134 | 135 | if (active || renderPanels[key]) { 136 | child = active ? child : renderPanels[key]; 137 | renderPanels[key] = React.cloneElement(child, { 138 | active, 139 | onDestroy: this.onTabDestroy.bind(this, key), 140 | onSwipedLeft:this.hanlderSwipedLeft.bind(this,key), 141 | onSwipedRight:this.hanlderSwipedRight.bind(this,key) 142 | }); 143 | tab.push(renderPanels[key]); 144 | } else { 145 | //懒加载 146 | tab.push(React.cloneElement(child, { 147 | active: false, 148 | onSwipedLeft:this.hanlderSwipedLeft.bind(this,key), 149 | onSwipedRight:this.hanlderSwipedRight.bind(this,key) 150 | }, []) 151 | ); 152 | } 153 | }); 154 | return { 155 | tab 156 | }; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/utils/shallowCompare.js: -------------------------------------------------------------------------------- 1 | var shallowEqual = require("./shallowEqual"); 2 | export function shallowCompare(instance, nextProps, nextState) { 3 | return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState); 4 | } 5 | -------------------------------------------------------------------------------- /src/utils/shallowEqual.js: -------------------------------------------------------------------------------- 1 | export default function shallowEqual(objA, objB) { 2 | debugger; 3 | if (objA === objB) { 4 | return true; 5 | } 6 | 7 | if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { 8 | return false; 9 | } 10 | 11 | var keysA = Object.keys(objA); 12 | var keysB = Object.keys(objB); 13 | 14 | if (keysA.length !== keysB.length) { 15 | return false; 16 | } 17 | 18 | // Test for A's keys different from B. 19 | var bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB); 20 | for (var i = 0; i < keysA.length; i++) { 21 | if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) { 22 | return false; 23 | } 24 | } 25 | 26 | return true; 27 | } 28 | -------------------------------------------------------------------------------- /test/ButtonSpec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactTestUtils from 'react-addons-test-utils'; 3 | import ReactDOM from 'react-dom'; 4 | import Button from '../src/Button'; 5 | describe('Button',()=>{ 6 | it('should output an a',()=>{ 7 | let instance = ReactTestUtils.renderIntoDocument( 8 | 11 | ); 12 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'A'); 13 | }); 14 | it('should output className button',()=>{ 15 | let instance = ReactTestUtils.renderIntoDocument( 16 | 19 | ); 20 | assert.equal(ReactDOM.findDOMNode(instance).className, 'button'); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | import 'es5-shim'; 2 | 3 | beforeEach(() => { 4 | sinon.stub(console, 'error'); 5 | }); 6 | 7 | afterEach(function checkNoUnexpectedWarnings() { 8 | 9 | if (typeof console.error.restore === 'function') { 10 | assert(!console.error.called, () => { 11 | return `${console.error.getCall(0).args[0]} \nIn '${this.currentTest.fullTitle()}'`; 12 | }); 13 | console.error.restore(); 14 | } 15 | }); 16 | 17 | var context = require.context('.', true,/Spec$/); 18 | context.keys().forEach(context); 19 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liubo on 15/3/11. 3 | */ 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | var webpack = require('webpack'); 7 | 8 | 9 | 10 | 11 | 12 | module.exports = function(options) { 13 | 14 | var entry = { 15 | app:'./app/entry.js' 16 | ,common:[ 17 | "react" 18 | ,"react-dom" 19 | ,"react-router" 20 | ] 21 | } 22 | 23 | 24 | // 凡是遇到jsx结尾的,都用jsx-loader这个插件来加载, 25 | // 且启用harmony模式 26 | var loaders = [ 27 | { 28 | test: /\.js?$/ 29 | ,exclude: /(node_modules|bower_components)/ 30 | ,loader: 'babel' 31 | ,query: { 32 | optional: ['runtime'], 33 | stage: 0 34 | } 35 | } 36 | ,{ test: /\.css$/, loader: 'style-loader!css-loader' } 37 | ,{ test: /\.less$/, loader: 'style-loader!css-loader!less-loader' } 38 | ,{ test: /\.(ttf|eot|svg)?$/, loader: "file-loader" } 39 | ,{ test: /\.png$/, loader: "file-loader" } 40 | ,{test: /\.woff$/, loader: "url?limit=10000&minetype=application/font-woff"} 41 | ] 42 | 43 | 44 | 45 | var publicPath = "http:// 10.129.10.45:8080/" ; 46 | 47 | 48 | var output = { 49 | path: path.join(__dirname, "./app/extras/", "build") 50 | ,publicPath: publicPath 51 | ,filename: '[name].js' 52 | ,sourceMapFilename: "[file].map" 53 | ,chunkFilename: "[id].js" 54 | ,hotUpdateMainFilename: "update.json" 55 | ,hotUpdateChunkFilename: "[id].update.js" 56 | }; 57 | 58 | 59 | 60 | //deps.forEach(function (dep) { 61 | // var depPath = path.resolve(nodeRoot, dep); 62 | // alias[dep.split(path.sep)[0]] = depPath; 63 | // noParse.push(depPath); 64 | //}); 65 | 66 | //console.log(alias); 67 | 68 | //加载插件 69 | var plugins = [ 70 | new webpack.ProvidePlugin({ 71 | React: "react" 72 | ,ReactDom: "react-dom" 73 | ,ReactRouter: "react-router" 74 | 75 | //,_: "lodash" 76 | }) 77 | 78 | ,new webpack.DefinePlugin({ 79 | __DEV__: JSON.stringify(JSON.parse(options.devServer || 'false')) 80 | }) 81 | //,new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 20 }) 82 | ,new webpack.optimize.CommonsChunkPlugin("common", "common.js" + (options.longTermCaching && !options.prerender ? "?[chunkhash]" : "")) 83 | ]; 84 | 85 | 86 | var devServer = { 87 | contentBase: "./app" 88 | //,host: (options.hotComponents)? IPv4 : 89 | ,host:"10.129.10.45" 90 | ,port: "8080" 91 | ,inline: true 92 | ,hot: options.hotComponents 93 | ,colors: true 94 | } 95 | 96 | return { 97 | entry: entry 98 | ,output: output 99 | ,devtool: options.devtool 100 | ,resolve: { 101 | extensions: ['', '.js', '.jsx', '.css'] 102 | } 103 | ,devServer: devServer 104 | ,plugins:plugins 105 | ,module: { 106 | loaders: loaders 107 | } 108 | ,debug: true 109 | }; 110 | } 111 | -------------------------------------------------------------------------------- /webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./webpack.config")({ 2 | devServer: true, 3 | minimize: false, 4 | devtool: "eval", 5 | hotComponents: false, 6 | debug: true 7 | }); 8 | --------------------------------------------------------------------------------