├── .babelrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .postcssrc.js ├── LICENSE ├── README.md ├── build ├── build.js ├── check-versions.js ├── logo.png ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── changelog.md ├── compatibility.md ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── index.html ├── package-lock.json ├── package.json ├── screenshot ├── buttons-group.png ├── buttons.png ├── contacts.png ├── form.png ├── grid.png ├── list.png ├── modal.png ├── tab.png └── vcode.png ├── src ├── assets │ ├── images │ │ ├── avatar │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ ├── 8.png │ │ │ ├── gf.png │ │ │ └── torvalds.png │ │ ├── form │ │ │ ├── i-form-calendar.png │ │ │ ├── i-form-comment.png │ │ │ ├── i-form-email.png │ │ │ ├── i-form-gender.png │ │ │ ├── i-form-name.png │ │ │ ├── i-form-password.png │ │ │ ├── i-form-settings.png │ │ │ ├── i-form-tel.png │ │ │ ├── i-form-toggle.png │ │ │ ├── i-form-url.png │ │ │ ├── i-list-chevron-right.png │ │ │ └── i-sortable-handler.png │ │ ├── home │ │ │ ├── button.png │ │ │ ├── calendar.png │ │ │ ├── circle.png │ │ │ ├── column.png │ │ │ ├── contacts.png │ │ │ ├── form.png │ │ │ ├── grid.png │ │ │ ├── home.png │ │ │ ├── list.png │ │ │ ├── menu.png │ │ │ ├── modal.png │ │ │ ├── noti.png │ │ │ ├── page.png │ │ │ ├── person.png │ │ │ ├── preloader.png │ │ │ ├── result.png │ │ │ ├── scroll.png │ │ │ ├── search.png │ │ │ ├── side.png │ │ │ ├── slide.png │ │ │ ├── star.png │ │ │ ├── tab.png │ │ │ ├── toast.png │ │ │ └── window.png │ │ ├── icon-list.png │ │ ├── icon_nav_actionSheet.png │ │ ├── icon_nav_article.png │ │ ├── icon_nav_calendar.png │ │ ├── icon_nav_city.png │ │ ├── icon_nav_datetime.png │ │ ├── icon_nav_dialog.png │ │ ├── icon_nav_icons.png │ │ ├── icon_nav_msg.png │ │ ├── icon_nav_panel.png │ │ ├── icon_nav_photo.png │ │ ├── icon_nav_picker.png │ │ ├── icon_nav_progress.png │ │ ├── icon_nav_ptr.png │ │ ├── icon_nav_search_bar.png │ │ ├── icon_nav_select.png │ │ ├── icon_nav_swiper.png │ │ ├── icon_nav_tab.png │ │ ├── icon_nav_toast.png │ │ ├── icon_nav_up.png │ │ ├── pic_article.png │ │ ├── present.png │ │ ├── slide │ │ │ ├── 0.jpg │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ └── 3.jpg │ │ ├── swiper-1.jpg │ │ ├── swiper-2.jpg │ │ ├── swiper-3.jpg │ │ ├── swiper-4.jpg │ │ └── vcode.jpg │ └── logo.png ├── components │ ├── actions │ │ ├── ActionButton.vue │ │ ├── ActionGroup.vue │ │ ├── Actions.vue │ │ ├── actions.less │ │ └── index.js │ ├── buttons │ │ ├── button-group.less │ │ ├── button-group.vue │ │ ├── button.less │ │ ├── button.vue │ │ ├── index.js │ │ └── variables.less │ ├── calendar │ │ ├── calendar.less │ │ ├── calendar.vue │ │ ├── index.js │ │ └── store.js │ ├── circle-progress │ │ └── index.vue │ ├── column │ │ ├── column.less │ │ └── index.js │ ├── content │ │ └── index.vue │ ├── footer │ │ ├── footer.less │ │ ├── footer.vue │ │ ├── index.js │ │ ├── item.vue │ │ ├── second.less │ │ └── second.vue │ ├── form │ │ ├── form.less │ │ ├── form.vue │ │ ├── index.js │ │ └── item.vue │ ├── grid │ │ ├── grid.less │ │ └── index.js │ ├── header │ │ ├── header.less │ │ ├── header.vue │ │ ├── index.js │ │ ├── link.less │ │ ├── link.vue │ │ ├── second.less │ │ ├── second.vue │ │ ├── simple-header.vue │ │ ├── title.less │ │ ├── title.vue │ │ └── variables.less │ ├── icons │ │ ├── icons.less │ │ └── index.vue │ ├── list │ │ ├── index.js │ │ ├── item.vue │ │ ├── list.less │ │ └── list.vue │ ├── mixins.less │ ├── modal │ │ ├── Alert.vue │ │ ├── Confirm.vue │ │ ├── Modal.vue │ │ ├── Prompt.vue │ │ ├── index.js │ │ └── modal.less │ ├── overlay │ │ ├── index.vue │ │ └── overlay.less │ ├── page │ │ ├── index.js │ │ ├── page.less │ │ ├── page.vue │ │ └── style.less │ ├── popover │ │ ├── index.js │ │ ├── item.less │ │ ├── item.vue │ │ ├── popover.less │ │ └── popover.vue │ ├── popup │ │ ├── index.vue │ │ └── popup.less │ ├── popwindow │ │ ├── index.vue │ │ └── popwindow.less │ ├── preloader │ │ ├── index.vue │ │ └── preloader.less │ ├── result │ │ ├── index.vue │ │ └── result.less │ ├── scroll │ │ ├── index.vue │ │ └── scroll.less │ ├── searchbar │ │ ├── index.vue │ │ └── searchbar.less │ ├── side-panel │ │ ├── index.vue │ │ └── side.less │ ├── slide │ │ ├── index.js │ │ ├── slide.less │ │ ├── slide.vue │ │ ├── wrapper.less │ │ └── wrapper.vue │ ├── stars │ │ ├── index.vue │ │ └── stars.less │ ├── switcher │ │ ├── index.vue │ │ └── switcher.less │ ├── tab │ │ ├── Tab.vue │ │ ├── TabItem.vue │ │ ├── index.js │ │ └── tabs.less │ ├── toast │ │ ├── index.vue │ │ └── toast.less │ └── variables.less ├── db.js ├── demos │ ├── About.vue │ ├── Actions.vue │ ├── Buttons.vue │ ├── Calendar.vue │ ├── CircleProgress.vue │ ├── Column.vue │ ├── Contacts.vue │ ├── Form.vue │ ├── Grid.vue │ ├── Home.vue │ ├── Icons.vue │ ├── Index.vue │ ├── List.vue │ ├── Modal.vue │ ├── Noti.vue │ ├── Page.vue │ ├── PopWindow.vue │ ├── Popover.vue │ ├── Popup.vue │ ├── Preloader.vue │ ├── Result.vue │ ├── Scroll.vue │ ├── Search.vue │ ├── Searchbar.vue │ ├── SidePanel.vue │ ├── Slide.vue │ ├── Stars.vue │ ├── Tab.vue │ └── Toast.vue ├── directives │ ├── back-link.js │ ├── swipe.js │ └── transitionend.js ├── lib │ └── weui.css ├── main.js ├── util.js └── vum.js ├── static └── .gitkeep ├── test └── unit │ ├── .eslintrc │ ├── index.js │ ├── karma.conf.js │ └── specs │ └── Hello.spec.js └── todo.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false 5 | }], 6 | "stage-2" 7 | ], 8 | "plugins": ["transform-runtime"], 9 | "env": { 10 | "test": { 11 | "presets": ["env", "stage-2"], 12 | "plugins": ["transform-es2015-modules-commonjs", "dynamic-import-node"] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | sourceType: 'module' 5 | }, 6 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 7 | extends: 'standard', 8 | // required to lint *.vue files 9 | plugins: [ 10 | 'html' 11 | ], 12 | // add your custom rules here 13 | 'rules': { 14 | // allow paren-less arrow functions 15 | 'arrow-parens': 0, 16 | // allow debugger during development 17 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | selenium-debug.log 6 | test/unit/coverage 7 | test/e2e/reports 8 | .sass-cache/ 9 | _site/ 10 | *.swp 11 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | build/ 2 | config/ 3 | test/ 4 | node_modules/ 5 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "postcss-import": {}, 7 | "autoprefixer": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 connors and other contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-mobile - V2.0.0-rc.1 2 | 3 | > An UI Framework build with Vue.js 4 | 5 | ***vum is update to vue@2.0! checkout to `v0.1.1` for vue@1.x.*** 6 | 7 | Click [http://demo.getvum.com/](http://demo.getvum.com/) or scan vcode to see live demos: 8 | 9 | 10 | 11 | ## What is? 12 | 13 | vue-mobile is an UI Framework build with Vue.js for SPA: 14 | 15 | - Full Page Structure - header, content, footer 16 | - Page transition support by vue-router 17 | - Bunch of Powerful Components, easy to use and extend 18 | - high performance CSS3 Animation 19 | - 1px border for all components - as well as round border 20 | - Write with Vue - the most important 21 | 22 | ## Love Vue 23 | 24 | Vue is the best View Layer Framework I have ever seen: 25 | 26 | - Elegant API 27 | - Two way binding, Components 28 | - Easy to build large scale App 29 | - Wonderful Components Organization. 30 | 31 | ## Progress 32 | 33 | - [x] Page 34 | - [x] Buttons 35 | - [x] Column 36 | - [x] Grid 37 | - [x] List 38 | - [ ] Cards 39 | - [x] Contacts 40 | - [x] Form 41 | - [x] Icons 42 | 43 | - [x] Modal 44 | - [x] Preloader 45 | - [x] Tab 46 | - [x] Scroll 47 | - [x] Popup 48 | - [x] Actions 49 | - [x] Toast 50 | - [x] Search Bar 51 | - [x] Calendar 52 | - [ ] Photo Browser 53 | - [x] Swiper 54 | 55 | ## Build Setup 56 | 57 | ``` bash 58 | # install dependencies 59 | npm install 60 | 61 | # serve with hot reload at localhost:8080 62 | npm run dev 63 | 64 | # build for production with minification 65 | npm run build 66 | 67 | # run unit tests 68 | npm run unit 69 | ``` 70 | 71 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 72 | 73 | ## Get Start 74 | 75 | Two way to create a project with vum? 76 | 77 | ### clone source code directly 78 | 79 | 1. Clone this repo to your work dir 80 | 2. `npm install` to install dependences 81 | 3. `npm run dev` to run dev server with hot reload. 82 | 4. Open `http://localhost:8088` in your browser, then you can see the demos 83 | 5. Change to dir `src/demos`, modify what you want, and remove unused pages 84 | 85 | That's all! You can do it :) Do not forget to reinit git. 86 | 87 | 88 | ### use npm 89 | 90 | 1. Create your project, [vue-cli](https://github.com/vuejs/vue-cli) is recommend 91 | 2. `npm install vum` in the root of your project 92 | 3. Import the components you wanted in `src` 93 | 94 | 95 | ## Thanks 96 | 97 | The css style of components comes from: 98 | 99 | - [Framework7](http://idangero.us/framework7/) 100 | - [Light7](http://light7.org/) 101 | - [WeUI](http://weui.io/) 102 | - [MSUI](http://m.sui.taobao.org/) 103 | - [Ratchet](http://goratchet.com/) 104 | - [vue-strap](https://yuche.github.io/vue-strap/) 105 | 106 | And vui-mobile could never be completed without these: 107 | 108 | - [Vue](http://vuejs.org/) 109 | - [vue-router](http://router.vuejs.org/en/basic.html) 110 | - [Less](http://lesscss.org/) 111 | - [Webpack](https://webpack.github.io/) 112 | 113 | # Stay In Touch 114 | 115 | Please make sure that you have some knowledge about vue.js before join QQ group: 116 | 117 | - QQ Group: 581532614 118 | 119 | # Screenshot 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, function (err, stats) { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | function exec (cmd) { 7 | return require('child_process').execSync(cmd).toString().trim() 8 | } 9 | 10 | const versionRequirements = [ 11 | { 12 | name: 'node', 13 | currentVersion: semver.clean(process.version), 14 | versionRequirement: packageConfig.engines.node 15 | } 16 | ] 17 | 18 | if (shell.which('npm')) { 19 | versionRequirements.push({ 20 | name: 'npm', 21 | currentVersion: exec('npm --version'), 22 | versionRequirement: packageConfig.engines.npm 23 | }) 24 | } 25 | 26 | module.exports = function () { 27 | const warnings = [] 28 | for (let i = 0; i < versionRequirements.length; i++) { 29 | const mod = versionRequirements[i] 30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 31 | warnings.push(mod.name + ': ' + 32 | chalk.red(mod.currentVersion) + ' should be ' + 33 | chalk.green(mod.versionRequirement) 34 | ) 35 | } 36 | } 37 | 38 | if (warnings.length) { 39 | console.log('') 40 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 41 | console.log() 42 | for (let i = 0; i < warnings.length; i++) { 43 | const warning = warnings[i] 44 | console.log(' ' + warning) 45 | } 46 | console.log() 47 | process.exit(1) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/build/logo.png -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const pkg = require('../package.json') 6 | 7 | exports.assetsPath = function (_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 9 | ? config.build.assetsSubDirectory 10 | : config.dev.assetsSubDirectory 11 | return path.posix.join(assetsSubDirectory, _path) 12 | } 13 | 14 | exports.cssLoaders = function (options) { 15 | options = options || {} 16 | 17 | const cssLoader = { 18 | loader: 'css-loader', 19 | options: { 20 | sourceMap: options.sourceMap 21 | } 22 | } 23 | 24 | var postcssLoader = { 25 | loader: 'postcss-loader', 26 | options: { 27 | sourceMap: options.sourceMap 28 | } 29 | } 30 | 31 | // generate loader string to be used with extract text plugin 32 | function generateLoaders (loader, loaderOptions) { 33 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 34 | if (loader) { 35 | loaders.push({ 36 | loader: loader + '-loader', 37 | options: Object.assign({}, loaderOptions, { 38 | sourceMap: options.sourceMap 39 | }) 40 | }) 41 | } 42 | 43 | // Extract CSS when that option is specified 44 | // (which is the case during production build) 45 | if (options.extract) { 46 | return ExtractTextPlugin.extract({ 47 | use: loaders, 48 | fallback: 'vue-style-loader' 49 | }) 50 | } else { 51 | return ['vue-style-loader'].concat(loaders) 52 | } 53 | } 54 | 55 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 56 | return { 57 | css: generateLoaders(), 58 | postcss: generateLoaders(), 59 | less: generateLoaders('less'), 60 | sass: generateLoaders('sass', { indentedSyntax: true }), 61 | scss: generateLoaders('sass'), 62 | stylus: generateLoaders('stylus'), 63 | styl: generateLoaders('stylus') 64 | } 65 | } 66 | 67 | // Generate loaders for standalone style files (outside of .vue) 68 | exports.styleLoaders = function (options) { 69 | const output = [] 70 | const loaders = exports.cssLoaders(options) 71 | for (const extension in loaders) { 72 | const loader = loaders[extension] 73 | output.push({ 74 | test: new RegExp('\\.' + extension + '$'), 75 | use: loader 76 | }) 77 | } 78 | return output 79 | } 80 | 81 | exports.createNotifierCallback = function () { 82 | const notifier = require('node-notifier') 83 | 84 | return (severity, errors) => { 85 | if (severity !== 'error') { 86 | return 87 | } 88 | const error = errors[0] 89 | 90 | const filename = error.file && error.file.split('!').pop() 91 | notifier.notify({ 92 | title: pkg.name, 93 | message: severity + ': ' + error.name, 94 | subtitle: filename || '', 95 | icon: path.join(__dirname, 'logo.png') 96 | }) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | 10 | module.exports = { 11 | loaders: utils.cssLoaders({ 12 | sourceMap: sourceMapEnabled, 13 | extract: isProduction 14 | }), 15 | cssSourceMap: sourceMapEnabled, 16 | cacheBusting: config.dev.cacheBusting, 17 | transformToRequire: { 18 | video: 'src', 19 | source: 'src', 20 | img: 'src', 21 | image: 'xlink:href' 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | module.exports = { 12 | context: path.resolve(__dirname, '../'), 13 | entry: { 14 | app: './src/main.js' 15 | }, 16 | output: { 17 | path: config.build.assetsRoot, 18 | filename: '[name].js', 19 | publicPath: process.env.NODE_ENV === 'production' 20 | ? config.build.assetsPublicPath 21 | : config.dev.assetsPublicPath 22 | }, 23 | resolve: { 24 | extensions: ['.js', '.vue', '.json'], 25 | alias: { 26 | 'vue$': 'vue/dist/vue.esm.js', 27 | '@': resolve('src'), 28 | } 29 | }, 30 | module: { 31 | rules: [ 32 | ...(config.dev.useEslint? [{ 33 | test: /\.(js|vue)$/, 34 | loader: 'eslint-loader', 35 | enforce: 'pre', 36 | include: [resolve('src'), resolve('test')], 37 | options: { 38 | formatter: require('eslint-friendly-formatter'), 39 | emitWarning: !config.dev.showEslintErrorsInOverlay 40 | } 41 | }] : []), 42 | { 43 | test: /\.vue$/, 44 | loader: 'vue-loader' 45 | }, 46 | { 47 | test: /\.js$/, 48 | loader: 'babel-loader', 49 | include: [resolve('src'), resolve('test')] 50 | }, 51 | { 52 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 53 | loader: 'url-loader', 54 | options: { 55 | limit: 10000, 56 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 57 | } 58 | }, 59 | { 60 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 61 | loader: 'url-loader', 62 | options: { 63 | limit: 10000, 64 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 65 | } 66 | }, 67 | { 68 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 69 | loader: 'url-loader', 70 | options: { 71 | limit: 10000, 72 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 73 | } 74 | } 75 | ] 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./webpack.base.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | const portfinder = require('portfinder') 10 | 11 | const devWebpackConfig = merge(baseWebpackConfig, { 12 | module: { 13 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 14 | }, 15 | // cheap-module-eval-source-map is faster for development 16 | devtool: config.dev.devtool, 17 | 18 | // these devServer options should be customized in /config/index.js 19 | devServer: { 20 | clientLogLevel: 'warning', 21 | historyApiFallback: true, 22 | hot: true, 23 | compress: true, 24 | host: process.env.HOST || config.dev.host, 25 | port: process.env.PORT || config.dev.port, 26 | open: config.dev.autoOpenBrowser, 27 | overlay: config.dev.errorOverlay ? { 28 | warnings: false, 29 | errors: true, 30 | } : false, 31 | publicPath: config.dev.assetsPublicPath, 32 | proxy: config.dev.proxyTable, 33 | quiet: true, // necessary for FriendlyErrorsPlugin 34 | watchOptions: { 35 | poll: config.dev.poll, 36 | } 37 | }, 38 | plugins: [ 39 | new webpack.DefinePlugin({ 40 | 'process.env': require('../config/dev.env') 41 | }), 42 | new webpack.HotModuleReplacementPlugin(), 43 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 44 | new webpack.NoEmitOnErrorsPlugin(), 45 | // https://github.com/ampedandwired/html-webpack-plugin 46 | new HtmlWebpackPlugin({ 47 | filename: 'index.html', 48 | template: 'index.html', 49 | inject: true 50 | }), 51 | ] 52 | }) 53 | 54 | module.exports = new Promise((resolve, reject) => { 55 | portfinder.basePort = process.env.PORT || config.dev.port 56 | portfinder.getPort((err, port) => { 57 | if (err) { 58 | reject(err) 59 | } else { 60 | // publish the new Port, necessary for e2e tests 61 | process.env.PORT = port 62 | // add port to devServer config 63 | devWebpackConfig.devServer.port = port 64 | 65 | // Add FriendlyErrorsPlugin 66 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 67 | compilationSuccessInfo: { 68 | messages: [`Your application is running here: http://${config.dev.host}:${port}`], 69 | }, 70 | onErrors: config.dev.notifyOnErrors 71 | ? utils.createNotifierCallback() 72 | : undefined 73 | })) 74 | 75 | resolve(devWebpackConfig) 76 | } 77 | }) 78 | }) 79 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # v2.0.0-beta 2 | 3 | VUM has been upgrade to vue@2.0 ! 4 | 5 | **note: v2.x is not compatable with v0.x** 6 | 7 | important change from Vue@1.0 to Vue@2.0: 8 | 9 | - two way props bind is not support in vue2, use instance method and custom event instead, so all 'modal' like components usage is changed! 10 | - only one root element! 11 | - `this === undefined` in directive 12 | - add '.native' when use native event, eg: '@click' => '@click.native' 13 | 14 | # V0.1.1 - 2016/10/23 15 | - New component: Circle Progress 16 | - fix bug: [#29](https://github.com/vum-team/vum/issues/29) 17 | -------------------------------------------------------------------------------- /compatibility.md: -------------------------------------------------------------------------------- 1 | # Android 2 | 3 | ## switch 导致页面无法滚动 4 | 5 | - 环境:米4 安卓5.1.1 MIUI7.0 微信6.3.25 6 | - 重现步骤:在List 中使用 switch 的时候,如果超出一屏高度,则会导致页面无法滚动或者很难滚动 7 | - 原因:显示按钮的伪元素的 `translate3d` 属性导致的 8 | - 解决方法:`-webkit-backface-visibility: hidden;` 9 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.2.4 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | // CSS Sourcemaps off by default because relative paths are "buggy" 44 | // with this option, according to the CSS-Loader README 45 | // (https://github.com/webpack/css-loader#sourcemaps) 46 | // In our experience, they generally work as expected, 47 | // just be aware of this issue when enabling this option. 48 | cssSourceMap: false, 49 | }, 50 | 51 | build: { 52 | // Template for index.html 53 | index: path.resolve(__dirname, '../dist/index.html'), 54 | 55 | // Paths 56 | assetsRoot: path.resolve(__dirname, '../dist'), 57 | assetsSubDirectory: 'static', 58 | assetsPublicPath: '/', 59 | 60 | /** 61 | * Source Maps 62 | */ 63 | 64 | productionSourceMap: true, 65 | // https://webpack.js.org/configuration/devtool/#production 66 | devtool: '#source-map', 67 | 68 | // Gzip off by default as many popular static hosts such as 69 | // Surge or Netlify already gzip all static assets for you. 70 | // Before setting to `true`, make sure to: 71 | // npm install --save-dev compression-webpack-plugin 72 | productionGzip: false, 73 | productionGzipExtensions: ['js', 'css'], 74 | 75 | // Run the build command with an extra argument to 76 | // View the bundle analyzer report after build finishes: 77 | // `npm run build --report` 78 | // Set to `true` or `false` to always turn it on or off 79 | bundleAnalyzerReport: process.env.npm_config_report 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const devEnv = require('./dev.env') 4 | 5 | module.exports = merge(devEnv, { 6 | NODE_ENV: '"testing"' 7 | }) 8 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | VUM 11 | 12 | 13 |
14 | 15 | 16 | 17 |
18 | 19 | 20 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vum", 3 | "version": "2.0.0-rc.2", 4 | "description": "A Vue.js project", 5 | "author": "hongxun.li ", 6 | "main": "./src/vum.js", 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "unit": "jest --config test/unit/jest.conf.js --coverage", 11 | "test": "npm run unit", 12 | "lint": "eslint --ext .js,.vue src test/unit/specs", 13 | "build": "node build/build.js" 14 | }, 15 | "dependencies": { 16 | "vue": "^2.5.2", 17 | "vue-router": "^3.0.1" 18 | }, 19 | "devDependencies": { 20 | "autoprefixer": "^7.1.2", 21 | "babel-core": "^6.22.1", 22 | "babel-eslint": "^7.1.1", 23 | "babel-jest": "^21.0.2", 24 | "babel-loader": "^7.1.1", 25 | "babel-plugin-dynamic-import-node": "^1.2.0", 26 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", 27 | "babel-plugin-transform-runtime": "^6.22.0", 28 | "babel-preset-env": "^1.3.2", 29 | "babel-preset-stage-2": "^6.22.0", 30 | "babel-register": "^6.22.0", 31 | "chalk": "^2.0.1", 32 | "copy-webpack-plugin": "^4.0.1", 33 | "css-loader": "^0.28.7", 34 | "eslint": "^3.19.0", 35 | "eslint-config-standard": "^10.2.1", 36 | "eslint-friendly-formatter": "^3.0.0", 37 | "eslint-loader": "^1.7.1", 38 | "eslint-plugin-html": "^3.0.0", 39 | "eslint-plugin-import": "^2.7.0", 40 | "eslint-plugin-node": "^5.2.0", 41 | "eslint-plugin-promise": "^3.4.0", 42 | "eslint-plugin-standard": "^3.0.1", 43 | "eventsource-polyfill": "^0.9.6", 44 | "extract-text-webpack-plugin": "^3.0.0", 45 | "fastclick": "^1.0.6", 46 | "file-loader": "^1.1.4", 47 | "friendly-errors-webpack-plugin": "^1.6.1", 48 | "html-webpack-plugin": "^2.30.1", 49 | "jest": "^21.2.0", 50 | "jest-serializer-vue": "^0.3.0", 51 | "less": "^2.7.3", 52 | "less-loader": "^4.0.5", 53 | "moment": "^2.19.2", 54 | "node-notifier": "^5.1.2", 55 | "optimize-css-assets-webpack-plugin": "^3.2.0", 56 | "ora": "^1.2.0", 57 | "portfinder": "^1.0.13", 58 | "postcss-import": "^11.0.0", 59 | "postcss-loader": "^2.0.8", 60 | "rimraf": "^2.6.0", 61 | "semver": "^5.3.0", 62 | "shelljs": "^0.7.6", 63 | "url-loader": "^0.5.8", 64 | "vue-jest": "^1.0.2", 65 | "vue-loader": "^13.3.0", 66 | "vue-style-loader": "^3.0.3", 67 | "vue-template-compiler": "^2.5.2", 68 | "webpack": "^3.6.0", 69 | "webpack-bundle-analyzer": "^2.9.0", 70 | "webpack-dev-server": "^2.9.1", 71 | "webpack-merge": "^4.1.0" 72 | }, 73 | "engines": { 74 | "node": ">= 4.0.0", 75 | "npm": ">= 3.0.0" 76 | }, 77 | "browserslist": [ 78 | "> 1%", 79 | "last 2 versions", 80 | "not ie <= 8" 81 | ] 82 | } 83 | -------------------------------------------------------------------------------- /screenshot/buttons-group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/screenshot/buttons-group.png -------------------------------------------------------------------------------- /screenshot/buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/screenshot/buttons.png -------------------------------------------------------------------------------- /screenshot/contacts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/screenshot/contacts.png -------------------------------------------------------------------------------- /screenshot/form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/screenshot/form.png -------------------------------------------------------------------------------- /screenshot/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/screenshot/grid.png -------------------------------------------------------------------------------- /screenshot/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/screenshot/list.png -------------------------------------------------------------------------------- /screenshot/modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/screenshot/modal.png -------------------------------------------------------------------------------- /screenshot/tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/screenshot/tab.png -------------------------------------------------------------------------------- /screenshot/vcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/screenshot/vcode.png -------------------------------------------------------------------------------- /src/assets/images/avatar/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/avatar/1.png -------------------------------------------------------------------------------- /src/assets/images/avatar/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/avatar/2.png -------------------------------------------------------------------------------- /src/assets/images/avatar/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/avatar/3.png -------------------------------------------------------------------------------- /src/assets/images/avatar/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/avatar/4.png -------------------------------------------------------------------------------- /src/assets/images/avatar/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/avatar/5.png -------------------------------------------------------------------------------- /src/assets/images/avatar/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/avatar/6.png -------------------------------------------------------------------------------- /src/assets/images/avatar/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/avatar/7.png -------------------------------------------------------------------------------- /src/assets/images/avatar/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/avatar/8.png -------------------------------------------------------------------------------- /src/assets/images/avatar/gf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/avatar/gf.png -------------------------------------------------------------------------------- /src/assets/images/avatar/torvalds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/avatar/torvalds.png -------------------------------------------------------------------------------- /src/assets/images/form/i-form-calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-form-calendar.png -------------------------------------------------------------------------------- /src/assets/images/form/i-form-comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-form-comment.png -------------------------------------------------------------------------------- /src/assets/images/form/i-form-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-form-email.png -------------------------------------------------------------------------------- /src/assets/images/form/i-form-gender.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-form-gender.png -------------------------------------------------------------------------------- /src/assets/images/form/i-form-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-form-name.png -------------------------------------------------------------------------------- /src/assets/images/form/i-form-password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-form-password.png -------------------------------------------------------------------------------- /src/assets/images/form/i-form-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-form-settings.png -------------------------------------------------------------------------------- /src/assets/images/form/i-form-tel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-form-tel.png -------------------------------------------------------------------------------- /src/assets/images/form/i-form-toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-form-toggle.png -------------------------------------------------------------------------------- /src/assets/images/form/i-form-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-form-url.png -------------------------------------------------------------------------------- /src/assets/images/form/i-list-chevron-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-list-chevron-right.png -------------------------------------------------------------------------------- /src/assets/images/form/i-sortable-handler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/form/i-sortable-handler.png -------------------------------------------------------------------------------- /src/assets/images/home/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/button.png -------------------------------------------------------------------------------- /src/assets/images/home/calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/calendar.png -------------------------------------------------------------------------------- /src/assets/images/home/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/circle.png -------------------------------------------------------------------------------- /src/assets/images/home/column.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/column.png -------------------------------------------------------------------------------- /src/assets/images/home/contacts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/contacts.png -------------------------------------------------------------------------------- /src/assets/images/home/form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/form.png -------------------------------------------------------------------------------- /src/assets/images/home/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/grid.png -------------------------------------------------------------------------------- /src/assets/images/home/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/home.png -------------------------------------------------------------------------------- /src/assets/images/home/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/list.png -------------------------------------------------------------------------------- /src/assets/images/home/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/menu.png -------------------------------------------------------------------------------- /src/assets/images/home/modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/modal.png -------------------------------------------------------------------------------- /src/assets/images/home/noti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/noti.png -------------------------------------------------------------------------------- /src/assets/images/home/page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/page.png -------------------------------------------------------------------------------- /src/assets/images/home/person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/person.png -------------------------------------------------------------------------------- /src/assets/images/home/preloader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/preloader.png -------------------------------------------------------------------------------- /src/assets/images/home/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/result.png -------------------------------------------------------------------------------- /src/assets/images/home/scroll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/scroll.png -------------------------------------------------------------------------------- /src/assets/images/home/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/search.png -------------------------------------------------------------------------------- /src/assets/images/home/side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/side.png -------------------------------------------------------------------------------- /src/assets/images/home/slide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/slide.png -------------------------------------------------------------------------------- /src/assets/images/home/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/star.png -------------------------------------------------------------------------------- /src/assets/images/home/tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/tab.png -------------------------------------------------------------------------------- /src/assets/images/home/toast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/toast.png -------------------------------------------------------------------------------- /src/assets/images/home/window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/home/window.png -------------------------------------------------------------------------------- /src/assets/images/icon-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon-list.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_actionSheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_actionSheet.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_article.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_calendar.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_city.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_city.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_datetime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_datetime.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_dialog.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_icons.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_msg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_msg.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_panel.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_photo.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_picker.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_progress.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_ptr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_ptr.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_search_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_search_bar.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_select.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_swiper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_swiper.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_tab.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_toast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_toast.png -------------------------------------------------------------------------------- /src/assets/images/icon_nav_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/icon_nav_up.png -------------------------------------------------------------------------------- /src/assets/images/pic_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/pic_article.png -------------------------------------------------------------------------------- /src/assets/images/present.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/present.png -------------------------------------------------------------------------------- /src/assets/images/slide/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/slide/0.jpg -------------------------------------------------------------------------------- /src/assets/images/slide/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/slide/1.jpg -------------------------------------------------------------------------------- /src/assets/images/slide/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/slide/2.jpg -------------------------------------------------------------------------------- /src/assets/images/slide/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/slide/3.jpg -------------------------------------------------------------------------------- /src/assets/images/swiper-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/swiper-1.jpg -------------------------------------------------------------------------------- /src/assets/images/swiper-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/swiper-2.jpg -------------------------------------------------------------------------------- /src/assets/images/swiper-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/swiper-3.jpg -------------------------------------------------------------------------------- /src/assets/images/swiper-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/swiper-4.jpg -------------------------------------------------------------------------------- /src/assets/images/vcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/images/vcode.jpg -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/actions/ActionButton.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/components/actions/ActionGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/components/actions/Actions.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 43 | -------------------------------------------------------------------------------- /src/components/actions/actions.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | 4 | @actionsModalButtonBg: rgba(243,243,243,0.95); 5 | @actionsModalActiveButtonBg:#dcdcdc; 6 | 7 | .popup-modal.actions-modal { 8 | background: transparent; 9 | } 10 | 11 | .action-group { 12 | margin: 0.4rem; 13 | } 14 | .action-button, .action-label { 15 | width: 100%; 16 | text-align: center; 17 | font-weight: normal; 18 | margin: 0; 19 | background: @actionsModalButtonBg; 20 | box-sizing: border-box; 21 | display: block; 22 | position: relative; 23 | .hairline(bottom, #d2d2d6); 24 | a { 25 | text-decoration: none; 26 | color: inherit; 27 | } 28 | b { 29 | font-weight: 500; 30 | } 31 | &.color-gray { 32 | color: @color-text-gray; 33 | } 34 | &.color-danger { 35 | color: @color-danger; 36 | } 37 | &.bg-danger { 38 | background: @color-danger; 39 | color: white; 40 | &:active { 41 | background: @color-danger-active; 42 | } 43 | } 44 | &:first-child { 45 | border-radius: 0.2rem 0.2rem 0 0; 46 | } 47 | &:last-child { 48 | .hairline-remove(bottom); 49 | border-radius: 0 0 0.2rem 0.2rem; 50 | } 51 | &:first-child:last-child { 52 | border-radius: 0.2rem; 53 | } 54 | &.disabled { 55 | opacity: 0.95; 56 | color:@color-text-gray; 57 | } 58 | } 59 | .action-button { 60 | cursor: pointer; 61 | line-height: 2.15rem; 62 | font-size: .9rem; 63 | color: @color-primary; 64 | &:active, &.active-state { 65 | background: @actionsModalActiveButtonBg; 66 | } 67 | } 68 | .action-label { 69 | font-size: 0.7rem; 70 | line-height: 1.3; 71 | min-height: 2.2rem; 72 | padding: 0.4rem 0.5rem; 73 | color: @color-text-secondary; 74 | .flexbox(); 75 | .justify-content(center); 76 | .align-items(center); 77 | } 78 | -------------------------------------------------------------------------------- /src/components/actions/index.js: -------------------------------------------------------------------------------- 1 | import Actions from './Actions' 2 | import ActionButton from './ActionButton' 3 | import ActionGroup from './ActionGroup' 4 | import './actions.less' 5 | 6 | export { 7 | Actions, 8 | ActionButton, 9 | ActionGroup 10 | } 11 | -------------------------------------------------------------------------------- /src/components/buttons/button-group.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import './variables.less'; 3 | @import '../mixins.less'; 4 | 5 | .buttons-group, 6 | .buttons-tab { 7 | z-index: 10; 8 | .align-self(center); 9 | .flexbox(); 10 | .flex-wrap(nowrap); 11 | } 12 | 13 | .buttons-group { 14 | margin: 1rem 0; 15 | .button { 16 | border-radius: 0 0 0 0; 17 | width: 100%; 18 | -webkit-box-flex:1; 19 | -ms-flex:1; 20 | .hairline(left, @color-primary-active); 21 | &.active { 22 | background-color: @color-primary-active; 23 | color: white; 24 | z-index: 100; 25 | } 26 | &:active { 27 | } 28 | } 29 | .button:first-child { 30 | border-radius: 0.25rem 0 0 0.25rem; 31 | .hairline-remove(left); 32 | } 33 | .button:last-child { 34 | border-radius: 0 0.25rem 0.25rem 0; 35 | } 36 | .button.button-round:first-child { 37 | border-radius: 1.35rem 0 0 1.35rem; 38 | } 39 | .button.button-round:last-child { 40 | border-radius: 0 1.35rem 1.35rem 0; 41 | } 42 | } 43 | 44 | .buttons-group.button-bordered { 45 | border-radius: .25rem; 46 | .hairline-border(@color-primary, .25rem); 47 | 48 | .button { 49 | position: relative; 50 | z-index: 1; 51 | &:before { 52 | background-color: @color-primary; 53 | } 54 | .hairline-border-remove(); 55 | &.active, 56 | &:active { 57 | background-color: @color-primary; 58 | color: white; 59 | } 60 | } 61 | 62 | &.button-round { 63 | .hairline-border(@color-primary, @btn-height); 64 | .button { 65 | &:first-child { 66 | border-radius: @btn-height 0 0 @btn-height; 67 | } 68 | &:last-child { 69 | border-radius: 0 @btn-height @btn-height 0; 70 | } 71 | } 72 | &.button-small { 73 | .hairline-border(@color-primary, @btn-small-height); 74 | .button { 75 | &:first-child { 76 | border-radius: @btn-small-height 0 0 @btn-small-height; 77 | } 78 | &:last-child { 79 | border-radius: 0 @btn-small-height @btn-small-height 0; 80 | } 81 | } 82 | } 83 | &.button-large { 84 | .hairline-border(@color-primary, @btn-large-height); 85 | .button { 86 | &:first-child { 87 | border-radius: @btn-large-height 0 0 @btn-large-height; 88 | } 89 | &:last-child { 90 | border-radius: 0 @btn-large-height @btn-large-height 0; 91 | } 92 | } 93 | } 94 | } 95 | } 96 | 97 | .buttons-tab { 98 | background: white; 99 | position: relative; 100 | .hairline(bottom, #d0d0d0); 101 | .button { 102 | color: @color-text-secondary; 103 | font-size: 0.8rem; 104 | width: 100%; 105 | height: 2rem; 106 | line-height: 2rem; 107 | -webkit-box-flex:1; 108 | -ms-flex:1; 109 | border: 0; 110 | border-bottom: 1px solid transparent; 111 | border-radius: 0; 112 | background-color: transparent; 113 | 114 | &.active { 115 | color: @color-primary; 116 | border-color: @color-primary; 117 | background: transparent; 118 | z-index: 100; 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/components/buttons/button-group.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 38 | 39 | 43 | -------------------------------------------------------------------------------- /src/components/buttons/button.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import './variables.less'; 3 | @import '../mixins.less'; 4 | 5 | .button { 6 | color: white; 7 | border: 0; 8 | background-color: @color-primary; 9 | text-decoration: none; 10 | text-align: center; 11 | display: block; 12 | border-radius: 0.25rem; 13 | line-height: @btn-height; 14 | box-sizing: border-box; 15 | appearance: none; 16 | padding: 0 0.8rem; 17 | margin: 0; 18 | height: @btn-height; 19 | white-space: nowrap; 20 | position: relative; 21 | text-overflow:ellipsis; 22 | font-size: 0.8rem; 23 | cursor: pointer; 24 | input[type="submit"]&, input[type="button"]&{ 25 | width: 100%; 26 | } 27 | 28 | &:active { 29 | background-color: @color-primary-active; 30 | } 31 | &.button-round, 32 | .button-round & { 33 | &, &:after { 34 | border-radius: (@btn-height - 0.1rem); 35 | } 36 | 37 | &.button-large:after { 38 | border-radius: (@btn-large-height - 0.1rem); 39 | } 40 | } 41 | &.active { 42 | &, &:active { 43 | background-color: @color-primary-active; 44 | } 45 | } 46 | &.button-large, 47 | .button-large & { 48 | font-size: 0.9rem; 49 | height: @btn-large-height; 50 | line-height: @btn-large-height; 51 | } 52 | &.button-small, 53 | .button-small & { 54 | font-size: 0.7rem; 55 | display: inline-block; 56 | height: @btn-small-height; 57 | line-height: @btn-small-height; 58 | } 59 | i.icon { 60 | &:first-child { 61 | margin-right: 0.5rem; 62 | } 63 | &:last-child { 64 | margin-left: 0.5rem; 65 | } 66 | &:first-child:last-child { 67 | margin-left: 0; 68 | margin-right: 0; 69 | } 70 | } 71 | } 72 | 73 | .button-variant(@color, @color-active) { 74 | background: @color; 75 | &:active { 76 | background: @color-active; 77 | } 78 | } 79 | 80 | .button-light { 81 | .button-variant(#f7f7f7, #dedede); 82 | .hairline-border(rgba(0,0,0,.2), .25rem); 83 | color: @color-text-secondary; 84 | } 85 | .button-dark { 86 | .button-variant(#6e727b, @color-primary-active); 87 | color: @color-text-secondary; 88 | } 89 | .button-success { 90 | .button-variant(@color-success, @color-success-active); 91 | } 92 | .button-danger { 93 | .button-variant(@color-danger, @color-danger-active); 94 | } 95 | .button-warning { 96 | .button-variant(@color-warning, @color-warning-active); 97 | } 98 | 99 | .button { 100 | &, 101 | &.button-light, 102 | &.button-primary, 103 | &.button-success, 104 | &.button-danger, 105 | &.button-warning { 106 | &.disabled { 107 | .hairline-border-remove(); 108 | .button-variant(#c8c9cb, #c8c9cb); 109 | color: white; 110 | cursor: not-allowed; 111 | } 112 | } 113 | } 114 | 115 | 116 | .bordered-variant(@color, @color-active) { 117 | color: @color; 118 | &:after { 119 | border-color: @color; 120 | } 121 | &:active { 122 | color: white; 123 | background-color: @color-active; 124 | &:after { 125 | border-color: @color-active; 126 | } 127 | } 128 | } 129 | 130 | .button.button-bordered, 131 | .button-bordered .button { 132 | background-color: transparent; 133 | .hairline-border(@color-primary, .25rem); 134 | 135 | .bordered-variant(@color-primary, @color-primary-active); 136 | 137 | .button-round &, 138 | &.button-round { 139 | &:after { 140 | border-radius: @btn-height; 141 | } 142 | &.button-large, 143 | .button-large & { 144 | &:after { 145 | border-radius: @btn-large-height; 146 | } 147 | } 148 | } 149 | 150 | &.button-success { 151 | .bordered-variant(@color-success, @color-success-active); 152 | } 153 | 154 | &.button-warning { 155 | .bordered-variant(@color-warning, @color-warning-active); 156 | } 157 | 158 | &.button-danger { 159 | .bordered-variant(@color-danger, @color-danger-active); 160 | } 161 | 162 | &.disabled, 163 | &[disabled] { 164 | color: #c8c9cb; 165 | background: transparent; 166 | cursor: not-allowed; 167 | &:after { 168 | border-color: #c8c8cb; 169 | } 170 | &:active { 171 | background-color: transparent; 172 | color: #c8c9cb; 173 | &:after { 174 | border-color: #c8c8cb; 175 | } 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/components/buttons/button.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 44 | 45 | 49 | -------------------------------------------------------------------------------- /src/components/buttons/index.js: -------------------------------------------------------------------------------- 1 | import Button from './button' 2 | import ButtonGroup from './button-group' 3 | 4 | export { 5 | Button, 6 | ButtonGroup 7 | } 8 | -------------------------------------------------------------------------------- /src/components/buttons/variables.less: -------------------------------------------------------------------------------- 1 | // Buttons 2 | @btn-height: 2rem; 3 | @btn-large-height: 2.5rem; 4 | @btn-small-height: 1.6rem; 5 | @button-font-size: 0.6rem; 6 | -------------------------------------------------------------------------------- /src/components/calendar/calendar.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | 4 | .calendar { 5 | text-align: center; 6 | } 7 | 8 | .toolbar { 9 | display: flex; 10 | font-size: .85rem; 11 | line-height: 2.2rem; 12 | height: 2.2rem; 13 | background: #f7f7f8; 14 | } 15 | 16 | .icon-prev, 17 | .icon-next { 18 | width: 0.75rem; 19 | height: 0.75rem; 20 | display: inline-block; 21 | background-size: 100% auto; 22 | background-position: center; 23 | background-repeat: no-repeat; 24 | 25 | &.disabled { 26 | opacity: .3; 27 | } 28 | } 29 | 30 | .year-value, .month-value { 31 | width: 2rem; 32 | } 33 | 34 | 35 | .icon { 36 | display: inline-block; 37 | vertical-align: middle; 38 | background-size: 100% auto; 39 | background-position: center; 40 | background-repeat: no-repeat; 41 | font-style: normal; 42 | position: relative; 43 | width: 2.5rem; 44 | height: 100%; 45 | 46 | &.icon-next, &.icon-prev { 47 | background-size: 0.75rem 0.75rem; 48 | } 49 | 50 | &.icon-next { 51 | .encoded-svg-background(""); 52 | } 53 | &.icon-prev { 54 | .encoded-svg-background(""); 55 | } 56 | } 57 | 58 | .weekdays { 59 | position: relative; 60 | .hairline(bottom, #ccc); 61 | } 62 | 63 | .year-picker, 64 | .month-picker { 65 | flex: 1; 66 | height: 100%; 67 | display: flex; 68 | align-items: center; 69 | justify-content: space-around; 70 | } 71 | 72 | .weekdays { 73 | display: flex; 74 | font-size: .6rem; 75 | background: #f7f7f8; 76 | } 77 | 78 | .weekday { 79 | flex: 1; 80 | } 81 | 82 | .months { 83 | overflow: hidden; 84 | } 85 | 86 | .months-inner { 87 | width: 100%; 88 | display: flex; 89 | position: relative; 90 | left: -100%; 91 | -webkit-backface-visibility: hidden; 92 | } 93 | 94 | .transition .months-inner { 95 | transition: transform .3s; 96 | } 97 | 98 | .month { 99 | font-size: .75rem; 100 | width: 100%; 101 | flex-shrink: 0; 102 | } 103 | 104 | .date { 105 | height: 2rem; 106 | line-height: 2rem; 107 | float: left; 108 | width: 14.2857%; 109 | position: relative; 110 | .hairline(bottom, #ccc); 111 | 112 | span { 113 | display: inline-block; 114 | height: 1.5rem; 115 | line-height: 1.5rem; 116 | width: 1.5rem; 117 | border-radius: .75rem; 118 | 119 | } 120 | &.today span { 121 | background-color: #e3e3e3; 122 | } 123 | &.selected span { 124 | background-color: @color-primary; 125 | color: white; 126 | } 127 | 128 | &.next-date, &.prev-date, &.disabled { 129 | color: @color-text-gray; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/components/calendar/index.js: -------------------------------------------------------------------------------- 1 | import Calendar from './calendar.vue' 2 | export default Calendar 3 | -------------------------------------------------------------------------------- /src/components/circle-progress/index.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 136 | 137 | 156 | -------------------------------------------------------------------------------- /src/components/column/column.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | 4 | .row { 5 | overflow: hidden; 6 | margin-left: -4%; 7 | > [class*="col-"], > [class*="tablet-"] { 8 | box-sizing: border-box; 9 | float: left; 10 | } 11 | &.no-gutter { 12 | margin-left: 0; 13 | } 14 | } 15 | @cols: 5, 10, 15, 20, 25, 100/3, 40, 50, 60, 100*(2/3), 75, 80, 85, 90, 95, 100; 16 | .row { 17 | .-(@i: length(@cols)) when (@i > 0) { 18 | @divider: e(extract(@cols, @i)); 19 | @className: `Math.floor(@{divider})`; 20 | @n: `100/parseFloat(@{divider})`; 21 | @n-1: @n - 1; 22 | @gutter: `4.0`; 23 | @d: `(100-@{gutter}*@{n})/@{n}`; 24 | .col-@{className} { 25 | width: ~"@{d}%"; 26 | margin-left: ~"@{gutter}%"; 27 | } 28 | &.no-gutter { 29 | @d: `100/@{n}`; 30 | .col-@{className} { 31 | width: ~"@{d}%"; 32 | margin: 0; 33 | } 34 | } 35 | .-((@i - 1)); 36 | } .-; 37 | } 38 | @media all and (min-width:768px) { 39 | .row { 40 | margin-left: -2%; 41 | } 42 | .row { 43 | .-(@i: length(@cols)) when (@i > 0) { 44 | @divider: e(extract(@cols, @i)); 45 | @className: `Math.floor(@{divider})`; 46 | @n: `100/parseFloat(@{divider})`; 47 | @n-1: @n - 1; 48 | @gutter: `2.0`; 49 | @d: `(100-@{gutter}*@{n})/@{n}`; 50 | .col-@{className} { 51 | width: ~"@{d}%"; 52 | margin-left: ~"@{gutter}%"; 53 | } 54 | &.no-gutter { 55 | @d: `100/@{n}`; 56 | .col-@{className} { 57 | width: ~"@{d}%"; 58 | margin: 0; 59 | } 60 | } 61 | .-((@i - 1)); 62 | } .-; 63 | } 64 | .row { 65 | .-(@i: length(@cols)) when (@i > 0) { 66 | @divider: e(extract(@cols, @i)); 67 | @className: `Math.floor(@{divider})`; 68 | @n: `100/parseFloat(@{divider})`; 69 | @n-1: @n - 1; 70 | @gutter: `2.0`; 71 | @d: `(100-@{gutter}*@{n})/@{n}`; 72 | .tablet-@{className} { 73 | width: ~"@{d}%"; 74 | margin-left: ~"@{gutter}%"; 75 | } 76 | &.no-gutter { 77 | @d: `100/@{n}`; 78 | .tablet-@{className} { 79 | width: ~"@{d}%"; 80 | margin: 0; 81 | } 82 | } 83 | .-((@i - 1)); 84 | } .-; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/components/column/index.js: -------------------------------------------------------------------------------- 1 | import './column.less' 2 | -------------------------------------------------------------------------------- /src/components/content/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /src/components/footer/footer.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | 4 | @footer-height: 2.8rem; 5 | 6 | // modifier class for footer bars 7 | .footer { 8 | background-color: #f7f7f8; 9 | position: absolute; 10 | bottom: 0; 11 | z-index: 100; 12 | .hairline(top, @border-default-color); 13 | .hairline-remove(bottom); 14 | } 15 | 16 | // footer bar margin 17 | .footer ~ .page-content { 18 | bottom: @footer-height; 19 | } 20 | // bar docked to bottom and used for primary app navigation 21 | .footer { 22 | bottom: 0; 23 | width: 100%; 24 | height: @footer-height; 25 | padding: 0; 26 | .hairline(top, @border-default-color); 27 | .hairline-remove(bottom); 28 | z-index: 9000; //less than popup 29 | transition-duration: 400ms; 30 | display: flex; 31 | 32 | // navigational tab (nested to be more specific for the icons in tab-items) 33 | .footer-item { 34 | position: relative; 35 | height: @footer-height; 36 | color: #929292; 37 | text-align: center; 38 | flex: 1; 39 | width: 100%; 40 | 41 | display: flex; 42 | flex-direction: column; 43 | align-items: center; 44 | justify-content: center; 45 | 46 | // active states for the tab bar 47 | &.active, 48 | &:active { 49 | color: @color-primary; 50 | } 51 | 52 | // activity badge on an icon 53 | .badge { 54 | position: absolute; 55 | top: .1rem; 56 | left: 50%; 57 | z-index: 100; 58 | height: .9rem; 59 | min-width: .9rem; 60 | padding: 0 .2rem; 61 | font-size: .6rem; 62 | line-height: .9rem; 63 | color: white; 64 | vertical-align: top; 65 | background: red; 66 | border-radius: .5rem; 67 | margin-left: .1rem; 68 | } 69 | 70 | // tab icon 71 | .icon { 72 | top: .1rem; 73 | width: 1.3rem; 74 | height: 1.3rem; 75 | font-size: 1.3rem; 76 | line-height: 1.3rem; 77 | padding-top: 0; 78 | padding-bottom: 0; 79 | display: inline-block; 80 | vertical-align: middle; 81 | 82 | // make the text smaller if it's used with an icon ' 83 | ~ label { 84 | display: block; 85 | font-size: 0.65rem; 86 | position: relative; 87 | top: 0.15rem; 88 | } 89 | } 90 | } 91 | } 92 | 93 | .footer .icon { 94 | font-size: 1.2rem; 95 | line-height: 1.2rem; 96 | } 97 | 98 | // bars for search forms 99 | // -------------------------------------------------- 100 | 101 | // position/size search bar within the bar 102 | .bar input[type="search"] { 103 | height: 1.45rem; 104 | margin: 0.3rem 0; 105 | } 106 | -------------------------------------------------------------------------------- /src/components/footer/footer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /src/components/footer/index.js: -------------------------------------------------------------------------------- 1 | import Footer from './footer' 2 | import SecondFooter from './second' 3 | import Item from './item' 4 | 5 | const FooterItem = Item 6 | 7 | export { 8 | Footer, 9 | SecondFooter, 10 | FooterItem, 11 | 12 | // for old version 13 | Item 14 | } 15 | -------------------------------------------------------------------------------- /src/components/footer/item.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/components/footer/second.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | 4 | @footer-height: 2.8rem; 5 | 6 | @height: 2.8rem; 7 | 8 | // modifier class to dock any bar above a standard bar 9 | .footer-secondary { 10 | padding: .4rem; 11 | height: @height; 12 | position: absolute; 13 | width: 100%; 14 | bottom: @footer-height; 15 | .hairline(top, @border-default-color); 16 | .hairline-remove(bottom); 17 | } 18 | 19 | .footer-secondary ~ .page-content { 20 | bottom: (@footer-height + @height); 21 | } 22 | -------------------------------------------------------------------------------- /src/components/footer/second.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /src/components/form/form.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /src/components/form/index.js: -------------------------------------------------------------------------------- 1 | import Form from './form' 2 | import Item from './item' 3 | import './form.less' 4 | 5 | const FormItem = Item 6 | 7 | export { 8 | Form, 9 | FormItem 10 | } 11 | -------------------------------------------------------------------------------- /src/components/form/item.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | -------------------------------------------------------------------------------- /src/components/grid/grid.less: -------------------------------------------------------------------------------- 1 | .grids { 2 | position: relative; 3 | overflow: hidden; 4 | } 5 | .grids { 6 | &:before { 7 | content: " "; 8 | position: absolute; 9 | box-sizing: border-box; 10 | left: 0; 11 | top: 0; 12 | width: 200%; 13 | height: 200%; 14 | border: 1px solid #D9D9D9; 15 | color: #D9D9D9; 16 | transform-origin: 0 0; 17 | transform: scale(0.5); 18 | } 19 | } 20 | 21 | .grid { 22 | position: relative; 23 | float: left; 24 | padding: 20px 10px; 25 | width: 33.33333333%; 26 | box-sizing: border-box; 27 | text-decoration: none; 28 | } 29 | .grids-small .grid { 30 | width: 25%; 31 | padding: 15px 8px; 32 | } 33 | .grid:before { 34 | content: " "; 35 | position: absolute; 36 | right: 0; 37 | top: 0; 38 | width: 1px; 39 | height: 100%; 40 | border-right: 1px solid #D9D9D9; 41 | color: #D9D9D9; 42 | transform-origin: 100% 0; 43 | transform: scaleX(0.5); 44 | } 45 | .grid:after { 46 | content: " "; 47 | position: absolute; 48 | left: 0; 49 | bottom: 0; 50 | width: 100%; 51 | height: 1px; 52 | border-bottom: 1px solid #D9D9D9; 53 | color: #D9D9D9; 54 | -webkit-transform-origin: 0 100%; 55 | transform-origin: 0 100%; 56 | -webkit-transform: scaleY(0.5); 57 | transform: scaleY(0.5); 58 | } 59 | .grid:active { 60 | background-color: #E4E4E4; 61 | } 62 | .grid_icon { 63 | width: 28px; 64 | height: 28px; 65 | margin: 0 auto; 66 | } 67 | .grid_icon img { 68 | display: block; 69 | width: 100%; 70 | height: 100%; 71 | } 72 | .grid_icon + .grid_label { 73 | margin: 5px 0 0; 74 | } 75 | .grid_label { 76 | display: block; 77 | text-align: center; 78 | color: #000; 79 | font-size: 14px; 80 | } 81 | -------------------------------------------------------------------------------- /src/components/grid/index.js: -------------------------------------------------------------------------------- 1 | import './grid.less' 2 | -------------------------------------------------------------------------------- /src/components/header/header.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | @import './variables.less'; 4 | 5 | .nav ~ .page-content { 6 | top: @nav-height; 7 | } 8 | 9 | // 10 | // bars 11 | // -------------------------------------------------- 12 | 13 | .nav { 14 | position: absolute; 15 | top: 0; 16 | right: 0; 17 | left: 0; 18 | z-index: 10; 19 | height: @nav-height; 20 | padding-right: @bar-side-spacing; 21 | padding-left: @bar-side-spacing; 22 | background-color: #f7f7f8; 23 | .hairline(bottom, @border-default-color); 24 | backface-visibility: hidden; 25 | } 26 | -------------------------------------------------------------------------------- /src/components/header/header.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /src/components/header/index.js: -------------------------------------------------------------------------------- 1 | import Header from './header' 2 | import SecondHeader from './second' 3 | import Link from './link' 4 | import Title from './title' 5 | import SimpleHeader from './simple-header' 6 | 7 | const HeaderLink = Link 8 | const HeaderTitle = Title 9 | 10 | export { 11 | Header, 12 | SecondHeader, 13 | HeaderLink, 14 | HeaderTitle, 15 | SimpleHeader, 16 | 17 | // for old version 18 | Link, 19 | Title 20 | } 21 | -------------------------------------------------------------------------------- /src/components/header/link.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | @import './variables.less'; 4 | 5 | .nav .button { 6 | position: relative; 7 | top: 0.35rem; 8 | z-index: 20; // position the buttons on top of .title 9 | margin-top: 0; 10 | font-weight: @font-weight-light; 11 | background: transparent; 12 | color: @color-primary; 13 | 14 | &:active { 15 | background: transparent; 16 | } 17 | 18 | &.left { 19 | float: left; 20 | 21 | &.edge { 22 | margin-left: -.2rem; 23 | } 24 | } 25 | 26 | &.right { 27 | float: right; 28 | &.edge { 29 | margin-right: -.2rem; 30 | } 31 | } 32 | } 33 | 34 | // bars with link buttons (line the text up with page-content) 35 | .nav .button-link { 36 | top: 0; 37 | padding: 0; 38 | font-size: 0.8rem; 39 | line-height: @nav-height; 40 | height: @nav-height; 41 | color: @color-primary; 42 | border: 0; 43 | 44 | &:active, 45 | &.active { 46 | color: darken(@color-primary, 10%); 47 | } 48 | } 49 | 50 | // bars with block buttons 51 | // 52 | // add proper padding 53 | .nav .button-block { 54 | top: 0.35rem; 55 | font-size: 0.8rem; // scale down font size to fit in bar. 56 | width: 100%; 57 | } 58 | -------------------------------------------------------------------------------- /src/components/header/link.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | 22 | 25 | -------------------------------------------------------------------------------- /src/components/header/second.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | @import './variables.less'; 4 | 5 | .nav-secondary ~ .page-content { 6 | top: (@nav-height*2); 7 | } 8 | 9 | // modifier class to dock any bar below .nav 10 | .nav-secondary { 11 | top: @nav-height; 12 | position: absolute; 13 | right: 0; 14 | left: 0; 15 | z-index: 10; 16 | .hairline(bottom, @border-default-color); 17 | backface-visibility: hidden; 18 | height: @nav-height; 19 | } 20 | -------------------------------------------------------------------------------- /src/components/header/second.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /src/components/header/simple-header.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 40 | -------------------------------------------------------------------------------- /src/components/header/title.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import './variables.less'; 3 | 4 | .title { 5 | position: absolute; 6 | left: 0; 7 | display: block; 8 | width: 100%; 9 | padding: 0; 10 | margin: 0; 11 | font-size: @font-size-default; 12 | font-weight: @font-weight; 13 | line-height: @nav-height; 14 | color: @color-text; 15 | text-align: center; 16 | white-space: nowrap; 17 | } 18 | // retain specified title color 19 | .title a { 20 | color: inherit; 21 | } 22 | -------------------------------------------------------------------------------- /src/components/header/title.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /src/components/header/variables.less: -------------------------------------------------------------------------------- 1 | @nav-height: 2.2rem; 2 | @bar-side-spacing: 0.5rem; 3 | -------------------------------------------------------------------------------- /src/components/icons/icons.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | 4 | @font-face { 5 | font-family: 'iconfont-vuem'; 6 | src: url('//at.alicdn.com/t/font_1472697628_3911114.eot'); /* IE9*/ 7 | src: url('//at.alicdn.com/t/font_1472697628_3911114.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 8 | url('//at.alicdn.com/t/font_1472697628_3911114.woff') format('woff'), /* chrome、firefox */ 9 | url('//at.alicdn.com/t/font_1472697628_3911114.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ 10 | url('//at.alicdn.com/t/font_1472697628_3911114.svg#iconfont-vuem') format('svg'); /* iOS 4.1- */ 11 | } 12 | 13 | .icon { 14 | font-style: normal; 15 | font-family: 'iconfont-vuem'; 16 | 17 | &.icon-success:before { 18 | content: "\e600"; 19 | } 20 | 21 | &.icon-error:before { 22 | content: "\e601"; 23 | } 24 | 25 | &.icon-back:before { 26 | content: "\e602"; 27 | } 28 | 29 | &.icon-search:before { 30 | content: "\e603"; 31 | } 32 | 33 | &.icon-clear:before { 34 | content: "\e604"; 35 | } 36 | &.icon-error-fill:before { 37 | content: "\e605"; 38 | } 39 | &.icon-success-fill:before { 40 | content: "\e606"; 41 | } 42 | &.icon-forbidden-fill:before { 43 | content: "\e607"; 44 | } 45 | &.icon-link:before { 46 | content: "\e608"; 47 | } 48 | &.icon-star:before { 49 | content: "\e609"; 50 | } 51 | &.icon-star-fill:before { 52 | content: "\e60a"; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/components/icons/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 19 | -------------------------------------------------------------------------------- /src/components/list/index.js: -------------------------------------------------------------------------------- 1 | import List from './list' 2 | import ListItem from './item' 3 | import './list.less' 4 | 5 | export { 6 | List, 7 | ListItem 8 | } 9 | -------------------------------------------------------------------------------- /src/components/list/item.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 34 | -------------------------------------------------------------------------------- /src/components/list/list.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 37 | -------------------------------------------------------------------------------- /src/components/modal/Alert.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 57 | -------------------------------------------------------------------------------- /src/components/modal/Confirm.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 71 | -------------------------------------------------------------------------------- /src/components/modal/Modal.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 58 | 59 | 62 | -------------------------------------------------------------------------------- /src/components/modal/Prompt.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 86 | 87 | 101 | -------------------------------------------------------------------------------- /src/components/modal/index.js: -------------------------------------------------------------------------------- 1 | import Modal from './Modal' 2 | import Alert from './Alert' 3 | import Confirm from './Confirm' 4 | import Prompt from './Prompt' 5 | 6 | export { 7 | Modal, 8 | Alert, 9 | Confirm, 10 | Prompt 11 | } 12 | -------------------------------------------------------------------------------- /src/components/modal/modal.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | 4 | @modalBgColor: #e8e8e8; 5 | @modalButonColor : @color-primary; 6 | @modalButonBg: @modalBgColor; 7 | @modalButonActiveBg: #d4d4d4; 8 | @modalDuration: 300ms; 9 | 10 | .modal { 11 | width: 13.5rem; 12 | position: fixed; 13 | z-index: 11000; 14 | left: 50%; 15 | margin-left: -6.75rem; 16 | margin-top: 0; 17 | top: 50%; 18 | text-align: center; 19 | border-radius: 0.35rem; 20 | opacity: 1; 21 | transform: translate3d(0,-50%,0) scale(1); 22 | transition-property: transform, opacity; 23 | transition-duration: @modalDuration; 24 | color: @color-text; 25 | 26 | &.modal-enter, 27 | &.modal-leave-active { 28 | opacity: 0; 29 | z-index: 11000-1; 30 | transform: translate3d(0,-50%,0) scale(0.815); 31 | } 32 | } 33 | .modal-inner { 34 | padding: 0.75rem; 35 | .hairline(bottom, #b5b5b5); 36 | border-radius: 0.35rem 0.35rem 0 0; 37 | position: relative; 38 | background: @modalBgColor; 39 | } 40 | .modal-title { 41 | font-weight: 500; 42 | font-size: 0.9rem; 43 | text-align: center; 44 | +.modal-text { 45 | margin-top: 0.25rem; 46 | } 47 | } 48 | .modal-buttons { 49 | height: 2.2rem; 50 | overflow: hidden; 51 | .flexbox(); 52 | .justify-content(center); 53 | &.modal-buttons-vertical { 54 | display: block; 55 | height: auto; 56 | } 57 | } 58 | .modal-button { 59 | width: 100%; 60 | padding: 0 0.25rem; 61 | height: 2.2rem; 62 | font-size: 0.85rem; 63 | line-height: 2.2rem; 64 | text-align: center; 65 | color: @modalButonColor; 66 | background: @modalButonBg; 67 | display: block; 68 | position: relative; 69 | white-space: nowrap; 70 | text-overflow:ellipsis; 71 | overflow: hidden; 72 | cursor: pointer; 73 | box-sizing: border-box; 74 | .hairline(right, #b5b5b5); 75 | -webkit-box-flex:1; 76 | -ms-flex:1; 77 | &:first-child { 78 | border-radius: 0 0 0 0.35rem; 79 | } 80 | &:last-child { 81 | .hairline-remove(right); 82 | border-radius: 0 0 0.35rem 0; 83 | } 84 | &:first-child:last-child { 85 | border-radius: 0 0 0.35rem 0.35rem; 86 | } 87 | &.modal-button-bold { 88 | font-weight: 500; 89 | } 90 | &.modal-button-cancel { 91 | color: @color-text-secondary; 92 | } 93 | &.modal-button-disabled { 94 | color: @color-text-gray; 95 | &:active { 96 | background: @modalBgColor; 97 | } 98 | } 99 | &:not(.modal-button-disabled):active { 100 | background: @modalButonActiveBg; 101 | } 102 | .modal-buttons-vertical & { 103 | .hairline-remove(right); 104 | .hairline-remove(top); 105 | .hairline(bottom, #b5b5b5); 106 | border-radius: 0; 107 | &:last-child { 108 | border-radius: 0 0 0.35rem 0.35rem; 109 | .hairline-remove(bottom); 110 | } 111 | } 112 | } 113 | .modal-no-buttons { 114 | .modal-inner { 115 | border-radius: 0.35rem; 116 | .hairline-remove(bottom); 117 | } 118 | .modal-buttons { 119 | display: none; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/components/overlay/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 31 | 32 | 35 | -------------------------------------------------------------------------------- /src/components/overlay/overlay.less: -------------------------------------------------------------------------------- 1 | .overlay { 2 | position: fixed; 3 | bottom: 0; 4 | left: 0; 5 | right: 0; 6 | height: 0; 7 | width: 100%; 8 | height: 100%; 9 | z-index: 10; 10 | transition: opacity .3s; 11 | opacity: 1; 12 | 13 | .inner { 14 | position: absolute; 15 | bottom: 0; 16 | left: 0; 17 | right: 0; 18 | height: 0; 19 | width: 100%; 20 | height: 100%; 21 | background-color: rgba(0, 0, 0, .6); 22 | 23 | } 24 | &.transparent .inner { 25 | background-color: transparent; 26 | } 27 | 28 | &.overlay-enter, 29 | &.overlay-leave-active { 30 | opacity: 0; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/components/page/index.js: -------------------------------------------------------------------------------- 1 | import './style.less' 2 | import './page.less' 3 | -------------------------------------------------------------------------------- /src/components/page/page.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | 4 | //page 5 | .page, .view { 6 | box-sizing: border-box; 7 | position: absolute; 8 | left: 0; 9 | top: 0; 10 | bottom: 0; 11 | right: 0; 12 | width: 100%; 13 | height: 100%; 14 | } 15 | 16 | //page transition 17 | .fade-enter-active, .fade-leave-active { 18 | transition: opacity .3s; 19 | } 20 | .fade-enter, .fade-leave-active { 21 | opacity: 0; 22 | } 23 | 24 | .slide-enter-active, .slide-leave-active { 25 | opacity: 1; 26 | transform: translate3d(0, 0, 0); 27 | transition: all .3s; 28 | } 29 | .slide-enter { 30 | opacity: 0; 31 | transform: translate3d(70%, 0, 0); 32 | } 33 | .slide-leave-active { 34 | opacity: 0; 35 | transform: translate3d(-70%, 0, 0); 36 | } 37 | 38 | .transition-reverse { 39 | .slide-enter { 40 | opacity: 0; 41 | transform: translate3d(-70%, 0, 0); 42 | } 43 | .slide-leave-active { 44 | opacity: 0; 45 | transform: translate3d(70%, 0, 0); 46 | } 47 | } 48 | 49 | // page content 50 | .page-content { 51 | position: absolute; 52 | top: 0; 53 | right: 0; 54 | bottom: 0; 55 | left: 0; 56 | overflow: auto; 57 | -webkit-overflow-scrolling: touch; 58 | } 59 | 60 | .content-padded { 61 | margin: .5rem; 62 | } 63 | -------------------------------------------------------------------------------- /src/components/page/page.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/components/page/style.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | 3 | // font size 4 | 5 | @baseWidth: 375px; 6 | @baseFont: 20px; 7 | 8 | html { 9 | font-size: @baseFont; 10 | } 11 | 12 | html, body { 13 | margin: 0; 14 | padding: 0; 15 | } 16 | 17 | * { 18 | -moz-box-sizing: border-box; 19 | box-sizing: border-box; 20 | 21 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 22 | -webkit-touch-callout: none; 23 | } 24 | 25 | body { 26 | position: absolute; 27 | top: 0; 28 | right: 0; 29 | bottom: 0; 30 | left: 0; 31 | overflow: hidden; 32 | font-family: "Helvetica Neue", Helvetica, sans-serif; 33 | font-size: .85rem; 34 | line-height: 1.5; 35 | color: #3d4145; 36 | } 37 | 38 | // fix fastclick bug: https://github.com/ftlabs/fastclick/issues/60 39 | label > * { 40 | pointer-events: none; 41 | } 42 | 43 | // rem 44 | @bps: 400px, 414px, 480px; 45 | 46 | .loop(@i: 1) when (@i <= length(@bps)) { 47 | @bp: extract(@bps, @i); 48 | @font: @bp/@baseWidth*@baseFont; 49 | @media only screen and (min-width: @bp){ 50 | html { 51 | font-size: @font !important; 52 | } 53 | } 54 | .loop((@i + 1)); 55 | }; 56 | .loop; 57 | 58 | 59 | // style 60 | a { 61 | text-decoration: none; 62 | color: #61749b; 63 | } 64 | 65 | .pull-right { 66 | float: right; 67 | } 68 | .pull-left { 69 | float: left; 70 | } 71 | 72 | 73 | .badge { 74 | display: inline-block; 75 | padding: .1rem .45rem .15rem; 76 | font-size: .6rem; 77 | line-height: 1; 78 | color: #3d4145; 79 | background-color: rgba(0, 0, 0, .15); 80 | border-radius: 5rem; 81 | } 82 | -------------------------------------------------------------------------------- /src/components/popover/index.js: -------------------------------------------------------------------------------- 1 | import Popover from './popover.vue' 2 | import PopoverItem from './item' 3 | 4 | export { 5 | Popover, 6 | PopoverItem 7 | } 8 | -------------------------------------------------------------------------------- /src/components/popover/item.less: -------------------------------------------------------------------------------- 1 | @import '../mixins.less'; 2 | @border-color: rgba(0, 0, 0, .2); 3 | 4 | .item { 5 | width: auto; 6 | padding: .3rem; 7 | 8 | + .item { 9 | position: relative; 10 | .hairline(top, @border-color); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/popover/item.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /src/components/popover/popover.less: -------------------------------------------------------------------------------- 1 | @import '../mixins.less'; 2 | 3 | @border-color: rgba(0, 0, 0, .2); 4 | .popover { 5 | .hairline-border(@border-color, .25rem); 6 | position: absolute; 7 | width: auto; 8 | padding: 1px .3rem; // 1px for border not be hide by inner div 9 | background-color: white; 10 | text-align: center; 11 | font-size: .8rem; 12 | min-width: 3rem; 13 | max-width: 6rem; 14 | transition: opacity .3s; 15 | 16 | opacity: 1; 17 | display: block; 18 | 19 | &.popover-enter, 20 | &.popover-leave-active { 21 | opacity: 0; 22 | } 23 | } 24 | 25 | .angle { 26 | width: .5rem; 27 | height: .5rem; 28 | .hairline-border(@border-color, 0); 29 | background-color: white; 30 | position: absolute; 31 | bottom: -.25rem; 32 | left: 50%; 33 | margin-left: -.25rem; 34 | z-index: 1; 35 | transform: rotate(45deg); 36 | transform-origin: center center; 37 | } 38 | 39 | .bottom .angle { 40 | bottom: initial; 41 | top: -.25rem; 42 | } 43 | 44 | .inner { 45 | position: relative; 46 | z-index: 10; 47 | background-color: white; 48 | } 49 | -------------------------------------------------------------------------------- /src/components/popover/popover.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 141 | 142 | 145 | -------------------------------------------------------------------------------- /src/components/popup/index.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 73 | 74 | 77 | -------------------------------------------------------------------------------- /src/components/popup/popup.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | 3 | .popup-modal { 4 | width: 100%; 5 | max-height: 100%; 6 | position: fixed; 7 | z-index: 100; 8 | bottom: 0; 9 | border-radius: 0; 10 | opacity: 0.6; 11 | 12 | color: @color-text; 13 | transition-duration: .3s; 14 | height: auto; 15 | background: #EFEFF4; 16 | 17 | transition-property: transform, opacity; 18 | 19 | overflow-x: hidden; 20 | overflow-y: auto; 21 | 22 | opacity: 1; 23 | display: block; 24 | transform: translate3d(0,0,0); 25 | 26 | &.popup-modal-enter, 27 | &.popup-modal-leave-active { 28 | transform: translate3d(0, 100%, 0); 29 | } 30 | 31 | &.full { 32 | height: 100%; 33 | } 34 | 35 | .modal-content { 36 | height: 100%; 37 | overflow: auto; 38 | box-sizing: border-box; 39 | } 40 | 41 | .nav ~ .modal-content { 42 | padding-top: 2.2rem; 43 | } 44 | 45 | .toolbar .modal-content { 46 | padding-top: 2.2rem; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/components/popwindow/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 48 | 49 | 52 | -------------------------------------------------------------------------------- /src/components/popwindow/popwindow.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | 3 | .popwindow-modal { 4 | width: 80%; 5 | margin-left: 10%; 6 | top: 50%; 7 | height: 80%; 8 | position: absolute; 9 | z-index: 100; 10 | border-radius: 0; 11 | 12 | color: @color-text; 13 | transition-duration: .3s; 14 | background: #EFEFF4; 15 | 16 | transition-property: transform, opacity; 17 | 18 | overflow-x: hidden; 19 | overflow-y: auto; 20 | 21 | opacity: 1; 22 | display: block; 23 | transform: translate3d(0, -50%, 0) scale(1); 24 | 25 | &.popwindow-modal-enter, 26 | &.popwindow-modal-leave-active { 27 | transform: scale(.6); 28 | transform: translate3d(0, -50%, 0) scale(.6); 29 | opacity: 0; 30 | } 31 | 32 | .modal-content { 33 | height: 100%; 34 | overflow: auto; 35 | box-sizing: border-box; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/components/preloader/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 42 | 43 | 46 | -------------------------------------------------------------------------------- /src/components/preloader/preloader.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | 4 | .preloader-modal { 5 | position: fixed; 6 | left: 50%; 7 | top: 50%; 8 | padding: 0.4rem; 9 | margin-left: -1.25rem; 10 | margin-top: -1.25rem; 11 | background: rgba(0,0,0,0.8); 12 | z-index: 11000; 13 | border-radius: 0.25rem; 14 | transition: opacity .3s; 15 | opacity: 1; 16 | 17 | &.preloader-modal-enter, 18 | &.preloader-modal-leave-active { 19 | opacity: 0; 20 | } 21 | 22 | .preloader { 23 | .preloader(); 24 | display: block; 25 | width: 1.7rem; 26 | height: 1.7rem; 27 | } 28 | 29 | .preloader-white { 30 | .preloader-white(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/components/result/index.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 40 | 41 | 45 | -------------------------------------------------------------------------------- /src/components/result/result.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | @import '../mixins.less'; 3 | 4 | .result { 5 | padding: .75rem; 6 | text-align: center; 7 | height: 100%; 8 | position: relative; 9 | 10 | .brand-icon { 11 | font-size: 5.5rem; 12 | color: @color-primary; 13 | line-height: 1; 14 | margin: 1rem 0 .5rem 0; 15 | 16 | } 17 | 18 | .result-error, 19 | .result-forbidden { 20 | .brand-icon { 21 | color: @color-danger; 22 | } 23 | } 24 | 25 | h1 { 26 | font-size: 1rem; 27 | font-weight: normal; 28 | margin: 0 0 .5rem 0; 29 | } 30 | 31 | .text { 32 | margin: .2rem 0 0 0; 33 | color: @color-text-gray; 34 | font-size: .75rem; 35 | } 36 | 37 | .buttons { 38 | margin-top: 1.5rem; 39 | .button + .button { 40 | margin-top: .75rem; 41 | } 42 | } 43 | .bottom { 44 | position: absolute; 45 | bottom: 1rem; 46 | left: 0; 47 | width: 100%; 48 | font-size: .7rem; 49 | color: #61749b; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/components/scroll/index.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 146 | 149 | -------------------------------------------------------------------------------- /src/components/scroll/scroll.less: -------------------------------------------------------------------------------- 1 | /* === Pull To Refresh === */ 2 | @import '../variables.less'; 3 | @import '../mixins.less'; 4 | 5 | @layerHeight: 2.2rem; 6 | .pull-to-refresh-layer { 7 | position: relative; 8 | left:0; 9 | top:0; 10 | width:100%; 11 | height:@layerHeight; 12 | color: @color-text-gray; 13 | 14 | .preloader { 15 | visibility: hidden; 16 | .preloader; 17 | } 18 | .pull-to-refresh-arrow { 19 | width: 0.65rem; 20 | height: 1rem; 21 | background: no-repeat center; 22 | .encoded-svg-background(""); 23 | background-size: 0.65rem 1rem; 24 | z-index: 10; 25 | transform: rotate(0deg) translate3d(0,0,0); 26 | transition-duration: 300ms; 27 | } 28 | 29 | } 30 | .scroll { 31 | position: absolute; 32 | top: 0; 33 | right: 0; 34 | bottom: 0; 35 | left: 0; 36 | overflow: auto; 37 | -webkit-overflow-scrolling: touch; 38 | 39 | &.content { 40 | position: absolute; 41 | } 42 | 43 | &.touching .scroll-inner { 44 | transition-duration: 0ms; 45 | } 46 | &:not(.refreshing) { 47 | .pull-to-refresh-layer .preloader { 48 | animation:none; 49 | } 50 | } 51 | &.refreshing { 52 | .pull-to-refresh-arrow { 53 | visibility: hidden; 54 | transition-duration: 0ms; 55 | } 56 | .preloader { 57 | visibility: visible; 58 | } 59 | } 60 | &.pull-up { 61 | .pull-to-refresh-arrow { 62 | transform: rotate(180deg) translate3d(0,0,0); 63 | } 64 | } 65 | 66 | } 67 | .scroll-inner { 68 | position: absolute; 69 | top: -@layerHeight; 70 | width: 100%; 71 | transition-duration: 300ms; 72 | } 73 | 74 | .label-down, .label-up, .label-refresh { 75 | display: none; 76 | width: 9rem; 77 | text-align: center; 78 | } 79 | 80 | .label-refresh { 81 | width: 5rem; 82 | } 83 | 84 | .pull-down .label-down, 85 | .pull-up .label-up, 86 | .refreshing .label-refresh { 87 | display: block; 88 | padding-left: .5rem; 89 | } 90 | 91 | .pull-to-refresh-layer { 92 | display: flex; 93 | align-items: center; 94 | justify-content: center; 95 | } 96 | 97 | .infinite-layer { 98 | height: 2.2rem; 99 | display: flex; 100 | align-items: center; 101 | justify-content: center; 102 | color: @color-text-gray; 103 | } 104 | 105 | .infinite-preloader { 106 | .preloader; 107 | margin-right: .5rem; 108 | } 109 | -------------------------------------------------------------------------------- /src/components/searchbar/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 66 | 67 | 70 | -------------------------------------------------------------------------------- /src/components/searchbar/searchbar.less: -------------------------------------------------------------------------------- 1 | @import '../mixins.less'; 2 | 3 | .search-bar { 4 | position: relative; 5 | padding: 8px 10px; 6 | display: flex; 7 | box-sizing: border-box; 8 | background-color: #EFEFF4; 9 | &:before { 10 | .hairline(#c7c7c7, top); 11 | } 12 | &:after { 13 | .hairline(#c7c7c7, bottom); 14 | } 15 | &.focus { 16 | .search-cancel { 17 | display: block; 18 | } 19 | .search-text { 20 | display: none; 21 | } 22 | } 23 | } 24 | .search-outer { 25 | position: relative; 26 | flex: auto; 27 | background-color: #EFEFF4; 28 | &:after { 29 | content: ''; 30 | position: absolute; 31 | left: 0; 32 | top:0; 33 | width: 200%; 34 | height: 200%; 35 | transform: scale(.5); 36 | transform-origin: 0 0; 37 | border-radius: 10px; 38 | border: 1px solid #E6E6EA; 39 | box-sizing: border-box; 40 | background: #FFFFFF; 41 | } 42 | } 43 | .search-inner { 44 | position: relative; 45 | padding-left: 30px; 46 | padding-right: 30px; 47 | height: 100%; 48 | width: 100%; 49 | box-sizing: border-box; 50 | z-index: 1; 51 | .search-input { 52 | padding: 4px 0; 53 | width: 100%; 54 | height: 20/14em; 55 | border: 0; 56 | font-size: 14px; 57 | line-height: 20/14em; 58 | box-sizing: content-box; 59 | background: transparent; 60 | &:focus { 61 | outline: none; 62 | } 63 | } 64 | .icon-search { 65 | position: absolute; 66 | left: 10px; 67 | top: 0px; 68 | line-height: 28px; 69 | font-size: 14px; 70 | color: #aaa; 71 | } 72 | .icon-clear { 73 | position: absolute; 74 | top: 0px; 75 | right: 0; 76 | padding: 0 10px; 77 | line-height: 28px; 78 | color: #aaa; 79 | } 80 | } 81 | .search-text { 82 | position: absolute; 83 | top: 1px; 84 | right: 1px; 85 | bottom: 1px; 86 | left: 1px; 87 | z-index: 2; 88 | border-radius: 3px; 89 | text-align: center; 90 | color: #9B9B9B; 91 | background: #FFFFFF; 92 | span { 93 | display: inline-block; 94 | font-size: 14px; 95 | } 96 | .icon-search { 97 | font-size: 14px; 98 | vertical-align: 1px; 99 | color: #aaa; 100 | } 101 | } 102 | .search-cancel { 103 | display: none; 104 | margin-left: 10px; 105 | line-height: 28px; 106 | white-space: nowrap; 107 | color: #09BB07; 108 | } 109 | .search-input:not(:valid) ~ .icon-clear { 110 | display: none; 111 | } 112 | 113 | //干掉input[search]默认的clear button 114 | input[type="search"]::-webkit-search-decoration, 115 | input[type="search"]::-webkit-search-cancel-button, 116 | input[type="search"]::-webkit-search-results-button, 117 | input[type="search"]::-webkit-search-results-decoration { 118 | display: none; 119 | } 120 | -------------------------------------------------------------------------------- /src/components/side-panel/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 83 | 84 | 87 | -------------------------------------------------------------------------------- /src/components/side-panel/side.less: -------------------------------------------------------------------------------- 1 | @import '../mixins.less'; 2 | 3 | .slide-wrap { 4 | position: absolute; 5 | width: 100%; 6 | height: 100%; 7 | top: 0; 8 | left: 0; 9 | z-index: 10000; 10 | } 11 | 12 | .side { 13 | width: 13rem; 14 | height: 100%; 15 | z-index: 10000; 16 | position: absolute; 17 | transition: transform .3s; 18 | transform: translate3d(0, 0, 0); 19 | 20 | &.side-enter, 21 | &.side-leave-active { 22 | transform: translate3d(-100%, 0, 0); 23 | } 24 | } 25 | 26 | .panel { 27 | width: 100%; 28 | height: 100%; 29 | position: absolute; 30 | top: 0; 31 | background-color: white; 32 | transition: transform .3s; 33 | } 34 | 35 | .touching .panel { 36 | transition: none; 37 | } 38 | -------------------------------------------------------------------------------- /src/components/slide/index.js: -------------------------------------------------------------------------------- 1 | import Wrapper from './wrapper' 2 | import Slide from './slide' 3 | 4 | const SlideWrapper = Wrapper 5 | export { 6 | Slide, 7 | SlideWrapper 8 | } 9 | -------------------------------------------------------------------------------- /src/components/slide/slide.less: -------------------------------------------------------------------------------- 1 | .slide { 2 | width: 100vw; 3 | min-height: 10rem; 4 | flex-shrink: 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/components/slide/slide.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 21 | 22 | 34 | -------------------------------------------------------------------------------- /src/components/slide/wrapper.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | 3 | .slide-wrap { 4 | overflow: hidden; 5 | width: 100%; 6 | position: relative; 7 | } 8 | .slide-inner { 9 | display: flex; 10 | } 11 | 12 | .transition .slide-inner { 13 | transition: transform .3s; 14 | } 15 | 16 | .bullets { 17 | position: absolute; 18 | left: 0; 19 | bottom: .3rem; 20 | width: 100%; 21 | display: flex; 22 | align-items: center; 23 | justify-content: center; 24 | } 25 | 26 | .bullet { 27 | width: 8px; 28 | height: 8px; 29 | border-radius: 4px; 30 | background: white; 31 | margin: 0 4px; 32 | opacity: .6; 33 | 34 | &.active { 35 | background-color: @color-primary; 36 | opacity: .9; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/components/slide/wrapper.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 138 | 139 | 142 | -------------------------------------------------------------------------------- /src/components/stars/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 46 | 47 | 50 | -------------------------------------------------------------------------------- /src/components/stars/stars.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | .stars { 3 | display: flex; 4 | align-items: center; 5 | justify-content: flex-start; 6 | color: @color-primary; 7 | 8 | .star + .star { 9 | margin-left: .2rem; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/components/switcher/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 38 | 39 | 42 | -------------------------------------------------------------------------------- /src/components/switcher/switcher.less: -------------------------------------------------------------------------------- 1 | @import "../variables.less"; 2 | @import "../mixins.less"; 3 | 4 | //Switch 5 | .label-switch { 6 | display: inline-block; 7 | vertical-align: middle; 8 | width: 52px; 9 | border-radius: 16px; 10 | box-sizing: border-box; 11 | height: 32px; 12 | position: relative; 13 | cursor: pointer; 14 | .align-self(center); 15 | .hairline-border(#e5e5e5, 16px); 16 | .checkbox { 17 | width: 52px; 18 | border-radius: 16px; 19 | box-sizing: border-box; 20 | position: absolute; 21 | top: 0; 22 | left: 0; 23 | height: 32px; 24 | z-index: 1; 25 | margin: 0; 26 | padding: 0; 27 | -webkit-appearance: none; 28 | -moz-appearance: none; 29 | -ms-appearance: none; 30 | appearance: none; 31 | border:none; 32 | cursor: pointer; 33 | position: relative; 34 | transition: 300ms; 35 | -webkit-backface-visibility: hidden; 36 | &:before { 37 | content:' '; 38 | position: absolute; 39 | left: 2px; 40 | top: 2px; 41 | width: 48px; 42 | border-radius: 16px; 43 | box-sizing: border-box; 44 | height: 28px; 45 | background: #fff; 46 | z-index: 1; 47 | transition: 300ms; 48 | transform: scale(1); 49 | } 50 | &:after { 51 | content:' '; 52 | height: 28px; 53 | width: 28px; 54 | border-radius: 28px; 55 | background: #fff; 56 | position: absolute; 57 | z-index: 2; 58 | top: 2px; 59 | left: 2px; 60 | box-shadow: 0 2px 5px rgba(0,0,0,0.4); 61 | transform: translate3d(0, 0, 0); 62 | transition: 300ms; 63 | } 64 | } 65 | input[type="checkbox"] { 66 | display: none; 67 | &:checked { 68 | &+ .checkbox { 69 | background: #4cd964; 70 | &:before { 71 | transform: scale(0); 72 | } 73 | &:after { 74 | transform: translate3d(20px, 0, 0); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/components/tab/Tab.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 61 | 62 | 65 | -------------------------------------------------------------------------------- /src/components/tab/TabItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 49 | -------------------------------------------------------------------------------- /src/components/tab/index.js: -------------------------------------------------------------------------------- 1 | import Tab from './Tab' 2 | import TabItem from './TabItem' 3 | 4 | export { 5 | Tab, 6 | TabItem 7 | } 8 | -------------------------------------------------------------------------------- /src/components/tab/tabs.less: -------------------------------------------------------------------------------- 1 | /* === Tabs === */ 2 | .tabs { 3 | .pull-to-refresh-content { 4 | top: 0; 5 | height: 100%; 6 | &:refreshing { 7 | top: 2.2rem; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/toast/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 62 | 63 | 66 | -------------------------------------------------------------------------------- /src/components/toast/toast.less: -------------------------------------------------------------------------------- 1 | @import '../mixins.less'; 2 | 3 | .toast-modal { 4 | position: absolute; 5 | left: 50%; 6 | top: 50%; 7 | padding: .5rem 1.1rem; 8 | transform: translate3d(-50%, -50%, 0) scale(1.2); 9 | background: rgba(0,0,0,0.6); 10 | z-index: 11000; 11 | border-radius: 0.25rem; 12 | transition: transform .3s, opacity .3s; 13 | color: white; 14 | text-align: center; 15 | min-width: 5.5rem; 16 | opacity: 1; 17 | 18 | &.toast-modal-enter { 19 | opacity: 0; 20 | transform: translate3d(-50%, -50%, 0) scale(0.8); 21 | } 22 | &.toast-modal-leave-active { 23 | opacity: 0; 24 | transform: translate3d(-50%, -50%, 0) scale(1.2); 25 | } 26 | } 27 | 28 | .icon-wrap { 29 | margin: .2rem 0; 30 | } 31 | 32 | .text { 33 | margin: .2rem 0; 34 | font-size: .8rem; 35 | } 36 | 37 | .icon { 38 | font-size: 1.8rem; 39 | } 40 | -------------------------------------------------------------------------------- /src/components/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: #04BE02; 23 | @color-danger: #f6383a; 24 | @color-warning: #f60; 25 | @color-success: #4cd964; 26 | 27 | @color-primary-active: darken(@color-primary, 10%); 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 | @timing-fuction: cubic-bezier(.1,.5,.1,1); // Inspired by @c2prods 44 | 45 | 46 | // Borders 47 | // -------------------------------------------------- 48 | 49 | @border-default-width: 1px; 50 | @border-default-color: @color-split; 51 | @border-default: @border-default-width solid @border-default-color; 52 | @border-radius: 0.3rem; 53 | -------------------------------------------------------------------------------- /src/db.js: -------------------------------------------------------------------------------- 1 | const localStorage = window.sessionStorage 2 | const JSON = window.JSON 3 | 4 | export default { 5 | get (name) { 6 | let value = localStorage.getItem(name) 7 | if (/^\{.*\}$/.test(value)) value = JSON.parse(value) 8 | return value 9 | }, 10 | set (name, value) { 11 | if (typeof value === typeof {}) value = JSON.stringify(value) 12 | return localStorage.setItem(name, value) 13 | }, 14 | remove (name) { 15 | return localStorage.removeItem(name) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/demos/About.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 28 | -------------------------------------------------------------------------------- /src/demos/Actions.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 41 | -------------------------------------------------------------------------------- /src/demos/Calendar.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 57 | -------------------------------------------------------------------------------- /src/demos/CircleProgress.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 57 | -------------------------------------------------------------------------------- /src/demos/Column.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 46 | 47 | 57 | -------------------------------------------------------------------------------- /src/demos/Contacts.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 91 | -------------------------------------------------------------------------------- /src/demos/Form.vue: -------------------------------------------------------------------------------- 1 | 103 | 104 | 122 | -------------------------------------------------------------------------------- /src/demos/Icons.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 37 | 38 | 44 | -------------------------------------------------------------------------------- /src/demos/Index.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 59 | 60 | 85 | -------------------------------------------------------------------------------- /src/demos/Modal.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 54 | -------------------------------------------------------------------------------- /src/demos/Noti.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 25 | -------------------------------------------------------------------------------- /src/demos/Page.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 78 | 79 | 97 | -------------------------------------------------------------------------------- /src/demos/PopWindow.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 42 | -------------------------------------------------------------------------------- /src/demos/Popup.vue: -------------------------------------------------------------------------------- 1 | 66 | 67 | 82 | -------------------------------------------------------------------------------- /src/demos/Preloader.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 43 | -------------------------------------------------------------------------------- /src/demos/Result.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 37 | -------------------------------------------------------------------------------- /src/demos/Scroll.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 71 | -------------------------------------------------------------------------------- /src/demos/Search.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | -------------------------------------------------------------------------------- /src/demos/Searchbar.vue: -------------------------------------------------------------------------------- 1 | 9 | 32 | -------------------------------------------------------------------------------- /src/demos/SidePanel.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 58 | -------------------------------------------------------------------------------- /src/demos/Slide.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 29 | -------------------------------------------------------------------------------- /src/demos/Stars.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 61 | -------------------------------------------------------------------------------- /src/demos/Tab.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 61 | -------------------------------------------------------------------------------- /src/demos/Toast.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 35 | -------------------------------------------------------------------------------- /src/directives/back-link.js: -------------------------------------------------------------------------------- 1 | export default { 2 | inserted (el) { 3 | el.addEventListener('click', function () { 4 | window.history.back() 5 | }) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/directives/swipe.js: -------------------------------------------------------------------------------- 1 | const _point = (e) => { 2 | if (e.touches) { 3 | return { 4 | x: e.touches[0].clientX, 5 | y: e.touches[0].clientY 6 | } 7 | } else { 8 | return { 9 | x: e.pageX, 10 | y: e.pageY 11 | } 12 | } 13 | } 14 | 15 | export default { 16 | inserted (el, binding) { 17 | const arg = binding.arg 18 | const v = binding.value 19 | 20 | let touching = false 21 | let startPoint, startTime, diff, movePoint 22 | 23 | const start = (e) => { 24 | touching = true 25 | const point = _point(e) 26 | startPoint = point 27 | startTime = +new Date() 28 | if (arg === 'start') v(startPoint) 29 | diff = { 30 | x: 0, 31 | y: 0 32 | } 33 | } 34 | 35 | const move = (e) => { 36 | if (!touching) return false 37 | e.preventDefault() 38 | const point = _point(e) 39 | movePoint = point 40 | diff = { 41 | x: point.x - startPoint.x, 42 | y: point.y - startPoint.y 43 | } 44 | if (arg === 'move') v(point, diff, +new Date() - startTime) 45 | } 46 | 47 | const end = (e) => { 48 | if (arg === 'end') v(movePoint, diff, +new Date() - startTime) 49 | touching = false 50 | } 51 | 52 | el.addEventListener('touchstart', start) 53 | el.addEventListener('touchmove', move) 54 | el.addEventListener('touchend', end) 55 | el.addEventListener('mousedown', start) 56 | el.addEventListener('mousemove', move) 57 | el.addEventListener('mouseup', end) 58 | 59 | // for unbind 60 | if (arg === 'start') el._start = start 61 | if (arg === 'move') el._move = move 62 | if (arg === 'end') el._end = end 63 | }, 64 | unbind (el, binding) { 65 | el.removeEventListener('touchstart', el._start) 66 | el.removeEventListener('touchmove', el._move) 67 | el.removeEventListener('touchend', el._end) 68 | el.removeEventListener('mousedown', el._start) 69 | el.removeEventListener('mousemove', el._move) 70 | el.removeEventListener('mouseup', el._end) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/directives/transitionend.js: -------------------------------------------------------------------------------- 1 | export default { 2 | bind (el, binding) { 3 | el.addEventListener('transitionend', (e) => binding.value(e)) 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import FastClick from 'fastclick' 4 | 5 | import Vum from './vum.js' 6 | 7 | // demos 8 | import Index from './demos/Index' 9 | import Page from './demos/Page' 10 | import Buttons from './demos/Buttons' 11 | import Column from './demos/Column' 12 | import Grid from './demos/Grid' 13 | import Modal from './demos/Modal' 14 | import List from './demos/List' 15 | import Contacts from './demos/Contacts' 16 | import Form from './demos/Form' 17 | import Icons from './demos/Icons' 18 | import Tab from './demos/Tab' 19 | import Scroll from './demos/Scroll' 20 | import Popup from './demos/Popup' 21 | import PopWindow from './demos/PopWindow' 22 | import Preloader from './demos/Preloader' 23 | import Actions from './demos/Actions' 24 | import Toast from './demos/Toast' 25 | import Searchbar from './demos/Searchbar' 26 | import Calendar from './demos/Calendar' 27 | import Result from './demos/Result' 28 | import Slide from './demos/Slide' 29 | import SidePanel from './demos/SidePanel' 30 | import Popover from './demos/Popover' 31 | import Stars from './demos/Stars' 32 | import CircleProgress from './demos/CircleProgress' 33 | 34 | Vue.use(Router) 35 | Vue.use(Vum) 36 | 37 | let router = new Router({ 38 | routes: [ 39 | { 40 | path: '/', 41 | name: 'index', 42 | component: Index 43 | }, 44 | { 45 | path: '/page', 46 | component: Page 47 | }, 48 | { 49 | path: '/buttons', 50 | component: Buttons 51 | }, 52 | { 53 | path: '/column', 54 | component: Column 55 | }, 56 | { 57 | path: '/grid', 58 | component: Grid 59 | }, 60 | { 61 | path: '/modal', 62 | component: Modal 63 | }, 64 | { 65 | path: '/list', 66 | component: List 67 | }, 68 | { 69 | path: '/contacts', 70 | component: Contacts 71 | }, 72 | { 73 | path: '/form', 74 | component: Form 75 | }, 76 | { 77 | path: '/icons', 78 | name: 'icons', 79 | component: Icons 80 | }, 81 | { 82 | path: '/tab', 83 | component: Tab 84 | }, 85 | { 86 | path: '/scroll', 87 | component: Scroll 88 | }, 89 | { 90 | path: '/popup', 91 | component: Popup 92 | }, 93 | { 94 | path: '/popwindow', 95 | component: PopWindow 96 | }, 97 | { 98 | path: '/preloader', 99 | component: Preloader 100 | }, 101 | { 102 | path: '/toast', 103 | name: 'toast', 104 | component: Toast 105 | }, 106 | { 107 | path: '/actions', 108 | component: Actions 109 | }, 110 | { 111 | path: '/searchbar', 112 | component: Searchbar 113 | }, 114 | { 115 | path: '/calendar', 116 | component: Calendar 117 | }, 118 | { 119 | path: '/result', 120 | name: 'result', 121 | component: Result 122 | }, 123 | { 124 | path: '/slide', 125 | name: 'slide', 126 | component: Slide 127 | }, 128 | { 129 | path: '/side-panel', 130 | name: 'side-panel', 131 | component: SidePanel 132 | }, 133 | { 134 | path: '/popover', 135 | name: 'popover', 136 | component: Popover 137 | }, 138 | { 139 | path: '/stars', 140 | name: 'stars', 141 | component: Stars 142 | }, 143 | { 144 | path: '/circle', 145 | name: 'circle', 146 | component: CircleProgress 147 | } 148 | ] 149 | }) 150 | 151 | new Vue({ 152 | router 153 | }).$mount('#app') 154 | 155 | Vum.router(router) 156 | 157 | FastClick.attach(document.body) 158 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | export default { 2 | extend (a, b) { 3 | for (var i in b) { 4 | if (b.hasOwnProperty(i) && b[i]) { 5 | a[i] = b[i] 6 | } 7 | } 8 | }, 9 | isParent (children, parent) { 10 | if (!parent) return false 11 | while (children) { 12 | if (children === parent) return true 13 | children = children.parentNode 14 | } 15 | return false 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/vum.js: -------------------------------------------------------------------------------- 1 | import BackLink from './directives/back-link' 2 | import Swipe from './directives/swipe' 3 | import Transitionend from './directives/transitionend' 4 | import db from './db' 5 | import Vue from 'vue' 6 | 7 | /** 8 | * vue-router does not support reverse transition 9 | */ 10 | 11 | class RouterConfig { 12 | constructor (router) { 13 | this.router = router 14 | } 15 | config () { 16 | const router = this.router 17 | this.router.beforeEach(function (to, from, next) { 18 | console.log(to, from, next) 19 | try { 20 | const _to = to.path 21 | const _from = from.path 22 | const scrollTop = router.app.$el.querySelector('.page-content').scrollTop 23 | const h = db.get(_to) 24 | if ((h && h.history) || (_from && _from.indexOf(_to) === 0)) { 25 | router.app.$el.className = 'transition-reverse' 26 | h.history = false 27 | db.set(_to, h) 28 | } else { 29 | db.set(_from, { 30 | scrollTop: scrollTop, 31 | history: true 32 | }) 33 | router.app.$el.className = '' 34 | } 35 | } catch (e) { 36 | // swallo error 37 | console.log(e) 38 | } 39 | next() 40 | }) 41 | this.router.afterEach(function (to, from, next) { 42 | const h = db.get(to.path) 43 | if (h && h.scrollTop) { 44 | Vue.nextTick(() => { 45 | console.log('should scroll to' + h.scrollTop) 46 | const _to = router.app.$el.querySelectorAll('.page-content')[1] 47 | if (_to) _to.scrollTop = h.scrollTop // TODO: 48 | }) 49 | } 50 | }) 51 | } 52 | } 53 | 54 | export default { 55 | install (Vue) { 56 | Vue.directive('back-link', BackLink) 57 | Vue.directive('swipe', Swipe) 58 | Vue.directive('transitionend', Transitionend) 59 | }, 60 | router (router) { 61 | const rc = new RouterConfig(router) 62 | rc.config() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vum-team/vum/f4753a770bff60bda2c039b79c9cfc273427da82/static/.gitkeep -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | // Polyfill fn.bind() for PhantomJS 2 | /* eslint-disable no-extend-native */ 3 | Function.prototype.bind = require('function-bind') 4 | 5 | // require all test files (files that ends with .spec.js) 6 | var testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | var srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var path = require('path') 7 | var merge = require('webpack-merge') 8 | var baseConfig = require('../../build/webpack.base.conf') 9 | var utils = require('../../build/utils') 10 | var webpack = require('webpack') 11 | var projectRoot = path.resolve(__dirname, '../../') 12 | 13 | var webpackConfig = merge(baseConfig, { 14 | // use inline sourcemap for karma-sourcemap-loader 15 | module: { 16 | loaders: utils.styleLoaders() 17 | }, 18 | devtool: '#inline-source-map', 19 | vue: { 20 | loaders: { 21 | js: 'isparta' 22 | } 23 | }, 24 | plugins: [ 25 | new webpack.DefinePlugin({ 26 | 'process.env': require('../../config/test.env') 27 | }) 28 | ] 29 | }) 30 | 31 | // no need for app entry during tests 32 | delete webpackConfig.entry 33 | 34 | // make sure isparta loader is applied before eslint 35 | webpackConfig.module.preLoaders = webpackConfig.module.preLoaders || [] 36 | webpackConfig.module.preLoaders.unshift({ 37 | test: /\.js$/, 38 | loader: 'isparta', 39 | include: path.resolve(projectRoot, 'src') 40 | }) 41 | 42 | // only apply babel for test files when using isparta 43 | webpackConfig.module.loaders.some(function (loader, i) { 44 | if (loader.loader === 'babel') { 45 | loader.include = path.resolve(projectRoot, 'test/unit') 46 | return true 47 | } 48 | }) 49 | 50 | module.exports = function (config) { 51 | config.set({ 52 | // to run in additional browsers: 53 | // 1. install corresponding karma launcher 54 | // http://karma-runner.github.io/0.13/config/browsers.html 55 | // 2. add it to the `browsers` array below. 56 | browsers: ['PhantomJS'], 57 | frameworks: ['mocha', 'sinon-chai'], 58 | reporters: ['spec', 'coverage'], 59 | files: ['./index.js'], 60 | preprocessors: { 61 | './index.js': ['webpack', 'sourcemap'] 62 | }, 63 | webpack: webpackConfig, 64 | webpackMiddleware: { 65 | noInfo: true 66 | }, 67 | coverageReporter: { 68 | dir: './coverage', 69 | reporters: [ 70 | { type: 'lcov', subdir: '.' }, 71 | { type: 'text-summary' } 72 | ] 73 | } 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /test/unit/specs/Hello.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Hello from 'src/components/Hello' 3 | 4 | describe('Hello.vue', () => { 5 | it('should render correct contents', () => { 6 | const vm = new Vue({ 7 | template: '
', 8 | components: { Hello } 9 | }).$mount() 10 | expect(vm.$el.querySelector('.hello h1').textContent).to.contain('Hello World!') 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | - searchbar 中 `click.native` 失效,反而 `click` 可用,应该是fastclick导致的 2 | --------------------------------------------------------------------------------