├── .eslintignore
├── example
├── alert.doc
├── card.doc
├── menu.doc
├── navbar.doc
├── tabs.doc
├── pagination.doc
├── date-time-picker.doc
├── modal.doc
├── button.doc
├── drop-down.doc
├── date-time-picker
│ ├── test.vue
│ ├── align.vue
│ ├── date-time-picker.md
│ ├── range.vue
│ └── base.vue
├── alert
│ ├── basic.vue
│ ├── helper.vue
│ └── with-close.vue
├── button
│ ├── button.md
│ ├── base.vue
│ ├── disable.vue
│ ├── outline.vue
│ ├── size.vue
│ └── icon-button.vue
├── menu
│ └── basic.vue
├── tabs
│ ├── router-tabs.vue
│ └── base.vue
├── pagination
│ └── basic.vue
├── drop-down
│ ├── drop-down.md
│ ├── drop-down-menu.vue
│ ├── slot.vue
│ ├── no-auto-close.vue
│ ├── base.vue
│ └── width.vue
├── card
│ ├── base.vue
│ └── with-header-footer.vue
├── navbar
│ └── basic.vue
└── modal
│ └── basic.vue
├── src
├── component
│ ├── mixin
│ │ ├── tabs-mixin.js
│ │ ├── drop-down-mixin.js
│ │ └── prop-fill.js
│ ├── menu
│ │ ├── sub-menu.vue
│ │ ├── index.js
│ │ ├── index.vue
│ │ └── menu-item.vue
│ ├── pagination
│ │ ├── index.js
│ │ └── index.vue
│ ├── alert
│ │ ├── alert-link.vue
│ │ ├── alert-heading.vue
│ │ └── alert.vue
│ ├── navbar
│ │ ├── navbar-nav.vue
│ │ ├── navbar-brand.vue
│ │ ├── index.js
│ │ ├── index.vue
│ │ ├── nav-group.vue
│ │ └── nav-item.vue
│ ├── svg-icon
│ │ ├── props-mixin.js
│ │ ├── chevron-down.vue
│ │ ├── chevron-left.vue
│ │ ├── chevron-right.vue
│ │ ├── chevron-up.vue
│ │ ├── arrow-back.vue
│ │ ├── arrow-forward.vue
│ │ ├── event-note.vue
│ │ ├── av-time.vue
│ │ └── svg-icon.vue
│ ├── drop-down
│ │ ├── drop-down-menu-divider.vue
│ │ ├── drop-down-menu-item.vue
│ │ ├── drop-down-menu.vue
│ │ └── drop-down.vue
│ ├── card
│ │ ├── card-text.vue
│ │ ├── card-block.vue
│ │ ├── card-link.vue
│ │ ├── card-title.vue
│ │ ├── card-image.vue
│ │ └── card.vue
│ ├── button
│ │ ├── icon-button.vue
│ │ └── button.vue
│ ├── tabs
│ │ ├── tabs-mixin.js
│ │ ├── router-tabs.vue
│ │ ├── tab.vue
│ │ └── tabs.vue
│ ├── modal
│ │ ├── backdrop.vue
│ │ ├── modal.vue
│ │ └── notification.vue
│ └── date-picker
│ │ ├── month-picker.vue
│ │ ├── year-picker.vue
│ │ ├── date-picker.vue
│ │ ├── util.js
│ │ ├── time-picker.vue
│ │ ├── date-time-picker.js
│ │ └── date-time-picker.vue
├── util
│ ├── index.js
│ ├── dom.js
│ └── EventListener.js
├── style
│ ├── base.styl
│ ├── variable.styl
│ ├── component
│ │ ├── dropdown.styl
│ │ └── date-time-picker.styl
│ ├── index.styl
│ ├── transition.styl
│ ├── button.styl
│ └── normalize.css
└── index.js
├── test
├── build
│ ├── dev.sh
│ ├── webpack.build.min.js
│ ├── makeWebpackConfig.js
│ ├── webpack.config.test.js
│ ├── webpack.build.js
│ ├── webpack.build.doc.js
│ ├── karma.conf.js
│ └── webpack.config.dev.js
├── test.js
├── .eslintrc
└── unit
│ ├── demo_spec
│ └── drop-down-base.js
│ └── demo_test.js
├── demo-loader
├── Readme.md
├── index.js
├── selector.js
├── loader.js
└── .eslintrc
├── .babelrc
├── doc
├── index.vue
├── index.html
├── app.vue
├── menu.vue
├── doc.js
├── code-panel.vue
├── router.js
└── doc.styl
├── .gitignore
├── .editorconfig
├── .travis.yml
├── Readme.md
├── server.js
├── CHANGELOG.md
├── .eslintrc.js
├── package.json
└── gulpfile.js
/.eslintignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/alert.doc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/card.doc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/menu.doc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/navbar.doc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/tabs.doc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/pagination.doc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/date-time-picker.doc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/modal.doc:
--------------------------------------------------------------------------------
1 | placeholder
--------------------------------------------------------------------------------
/example/button.doc:
--------------------------------------------------------------------------------
1 | placeholder
--------------------------------------------------------------------------------
/example/drop-down.doc:
--------------------------------------------------------------------------------
1 | placeholder
--------------------------------------------------------------------------------
/src/component/mixin/tabs-mixin.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/build/dev.sh:
--------------------------------------------------------------------------------
1 | node server.js & gulp test-watch
2 |
--------------------------------------------------------------------------------
/example/date-time-picker/test.vue:
--------------------------------------------------------------------------------
1 |
2 | This is
3 |
4 |
--------------------------------------------------------------------------------
/src/util/index.js:
--------------------------------------------------------------------------------
1 | import * as dom from './dom'
2 |
3 | export default {
4 | dom
5 | }
6 |
--------------------------------------------------------------------------------
/demo-loader/Readme.md:
--------------------------------------------------------------------------------
1 | # issue
2 | 1. 首次启动编译两次
3 | 2. 文件删除和新增在重新编译的时候不会被编译进去(可能是因为cacheable)
4 |
--------------------------------------------------------------------------------
/src/style/base.styl:
--------------------------------------------------------------------------------
1 | //@import "~normalize.css";
2 |
3 | * {
4 | outline: none !important;
5 | }
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-0"],
3 | "plugins": ["transform-runtime"]
4 | }
5 |
--------------------------------------------------------------------------------
/src/component/menu/sub-menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/src/component/pagination/index.js:
--------------------------------------------------------------------------------
1 | import pagination from './index.vue'
2 |
3 | export default pagination
4 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | const testsContext = require.context('.', true, /_test$/)
2 | testsContext.keys().forEach(testsContext)
3 |
--------------------------------------------------------------------------------
/src/component/alert/alert-link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/component/alert/alert-heading.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/component/navbar/navbar-nav.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/doc/index.vue:
--------------------------------------------------------------------------------
1 |
2 | X-VUE
3 | 基于bootstrap的vue组件库
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/src/component/navbar/navbar-brand.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/src/component/svg-icon/props-mixin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | size: {
4 | // type: [Number, String],
5 | default: 24
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/component/drop-down/drop-down-menu-divider.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/src/component/menu/index.js:
--------------------------------------------------------------------------------
1 | import Menu from './index.vue'
2 |
3 | export MenuItem from './menu-item.vue'
4 |
5 | export SubMenu from './sub-menu.vue'
6 |
7 | export default Menu
8 |
--------------------------------------------------------------------------------
/src/component/menu/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/src/component/menu/menu-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | npm-debug.log
4 | dist
5 | .idea
6 | coverage
7 | bower_components
8 | *.swp
9 | *.swo
10 | ngrok.config.json
11 | *.cache
12 | doc-build
13 | source
14 |
--------------------------------------------------------------------------------
/src/component/card/card-text.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/src/component/card/card-block.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/doc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | x-vue doc
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [src/**/*.{js, vue}]
4 | indent_style = space
5 | indent_size = 2
6 |
7 | end_of_line = lf
8 | insert_final_newline = true
9 |
10 | charset = utf-8
11 |
12 | trim_trailing_whitespace = true
--------------------------------------------------------------------------------
/demo-loader/index.js:
--------------------------------------------------------------------------------
1 | var selectorPath = require.resolve('./selector.js')
2 |
3 | module.exports = function (source) {
4 |
5 | source = source.replace(/![^!]*selector\.js/g, '!' + selectorPath)
6 |
7 | return source
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "4.1"
4 | - "4.0"
5 |
6 | before_script:
7 | - npm install -g gulp
8 | script: gulp
9 | after_script:
10 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
11 |
--------------------------------------------------------------------------------
/src/style/variable.styl:
--------------------------------------------------------------------------------
1 | //// font weight
2 | //$font-weight-base: 100;
3 | //
4 | //// line height
5 | //$line-height-base: 48px;
6 | //
7 | //// color
8 | //$color-default: #ffffff;
9 | //$color-font-default: #333333;
10 |
11 | $z-index-drop-down = 1000;
12 |
--------------------------------------------------------------------------------
/src/style/component/dropdown.styl:
--------------------------------------------------------------------------------
1 | @import "../variable";
2 |
3 | .drop-down-content{
4 | position : absolute;
5 | //left: 0;
6 | top: 100%;
7 | margin-top: 5px;
8 | z-index: $z-index-drop-down;
9 | min-width: 160px;
10 | white-space: nowrap;
11 | }
12 |
--------------------------------------------------------------------------------
/example/alert/basic.vue:
--------------------------------------------------------------------------------
1 |
2 | This is warning alert
3 | This is success alert
4 | This is danger alert
5 | This is info alert
6 |
7 |
--------------------------------------------------------------------------------
/src/component/button/icon-button.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
--------------------------------------------------------------------------------
/test/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "globals": {
3 | "$": true,
4 | "jQuery": true,
5 | "before": true,
6 | "after": true,
7 | "beforeEach": true,
8 | "afterEach": true,
9 | "it": true,
10 | "app": true,
11 | "Vue": true
12 | },
13 | "rules": {
14 |
15 | }
16 | }
--------------------------------------------------------------------------------
/src/component/navbar/index.js:
--------------------------------------------------------------------------------
1 | import Navbar from './index.vue'
2 |
3 | export NavbarBrand from './navbar-brand.vue'
4 |
5 | export NavItem from './nav-item.vue'
6 |
7 | export NavbarNav from './navbar-nav.vue'
8 |
9 | export NavGroup from './nav-group.vue'
10 |
11 | export default Navbar
12 |
--------------------------------------------------------------------------------
/src/style/index.styl:
--------------------------------------------------------------------------------
1 | @import "base";
2 | //@import "button";
3 | //@import "normalize.css";
4 |
5 | // components style
6 | //@import "component/dropdown";
7 |
8 | @import "transition";
9 |
10 |
11 | // components
12 | @import "component/dropdown";
13 | @import "component/date-time-picker";
14 |
15 | // add test
16 |
--------------------------------------------------------------------------------
/test/build/webpack.build.min.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack')
2 | const buildConfig = require('./webpack.build')
3 |
4 | buildConfig.output.filename = 'x-vue.min.js'
5 |
6 | buildConfig.plugins.push(new webpack.optimize.UglifyJsPlugin({
7 | compress: {
8 | warnings: false
9 | }
10 | }))
11 |
12 | module.exports = buildConfig
13 |
--------------------------------------------------------------------------------
/src/component/mixin/drop-down-mixin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | label: {
4 | type: String,
5 | default: ''
6 | },
7 | // 显示按钮的形态
8 | // OK
9 | btnType: {
10 | type: String,
11 | default: ''
12 | },
13 | disabled: {
14 | type: Boolean,
15 | default: false
16 | },
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/example/alert/helper.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | this is alert with alert link
4 |
5 |
6 | This is alert header
7 |
8 | this is alert content, say what you want to say here
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/example/button/button.md:
--------------------------------------------------------------------------------
1 | ### 说明
2 | 这里是说明
3 |
4 | ### Props
5 | name | type | default | explain
6 | --- | --- | --- | ---
7 | type | String | 'secondary' | primary success info secondary danger warning link
8 | outline | Boolean | false | 是否只有边框上色
9 | size | String | '' | 'lg', 'sm'
10 | block | Boolean | false | is block
11 | disabled | Boolean | false | is disable
12 |
--------------------------------------------------------------------------------
/src/component/tabs/tabs-mixin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | type: {
4 | type: String,
5 | default: 'tabs'
6 | }
7 | },
8 | computed: {
9 | classes() {
10 | let classes = {
11 | 'nav': true,
12 | 'nav-tabs': this.type === 'tabs',
13 | 'nav-pills': this.type === 'pills'
14 | }
15 | return classes
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/component/svg-icon/chevron-down.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
--------------------------------------------------------------------------------
/src/component/svg-icon/chevron-left.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
--------------------------------------------------------------------------------
/src/component/svg-icon/chevron-right.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
--------------------------------------------------------------------------------
/src/component/svg-icon/chevron-up.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
--------------------------------------------------------------------------------
/example/date-time-picker/align.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/example/menu/basic.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
20 |
--------------------------------------------------------------------------------
/src/component/svg-icon/arrow-back.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
--------------------------------------------------------------------------------
/src/component/svg-icon/arrow-forward.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
--------------------------------------------------------------------------------
/src/component/card/card-link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
21 |
--------------------------------------------------------------------------------
/src/component/drop-down/drop-down-menu-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
24 |
--------------------------------------------------------------------------------
/doc/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
25 |
--------------------------------------------------------------------------------
/src/component/navbar/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
25 |
--------------------------------------------------------------------------------
/src/util/dom.js:
--------------------------------------------------------------------------------
1 | export function getBodyScrollTop() {
2 | let scrollTop
3 | if (typeof window.pageYOffset !== 'undefined') { // pageYOffset指的是滚动条顶部到网页顶部的距离
4 | scrollTop = window.pageYOffset
5 | } else if (typeof document.compatMode !== 'undefined' && document.compatMode !== 'BackCompat') {
6 | scrollTop = document.documentElement.scrollTop
7 | } else if (typeof document.body !== 'undefined') {
8 | scrollTop = document.body.scrollTop
9 | }
10 | return scrollTop
11 | }
12 |
--------------------------------------------------------------------------------
/src/component/svg-icon/event-note.vue:
--------------------------------------------------------------------------------
1 |
2 | >
3 |
4 |
5 |
16 |
--------------------------------------------------------------------------------
/src/component/mixin/prop-fill.js:
--------------------------------------------------------------------------------
1 | /*
2 | learn from vue-mdl https://github.com/posva/vue-mdl/blob/develop/src/mixins/prop-fill.js
3 | */
4 |
5 | // When declaring a prop with no value it should be evaluated to true
6 | // but '' is falsy. As a solution add the
7 | export default {
8 | beforeCompile () {
9 | for (let prop of Object.keys(this._props)) {
10 | let data = this._props[prop]
11 | if (data.options.fill && data.raw === '') {
12 | this[prop] = prop
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/component/navbar/nav-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
28 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # Intro
2 | Vue + Bootstrap4 components
3 |
4 | For detail, [view doc](https://x-front-team.github.io/x-vue/)
5 |
6 | # Install
7 | ```
8 | npm i x-vue
9 | ```
10 |
11 | # Usage
12 | ```
13 | import vue from 'vue'
14 | import XVue from 'x-vue'
15 | vue.use(XVue)
16 | ```
17 |
18 | # Development
19 | clone the project
20 | ```
21 | npm install
22 | npm start
23 | ```
24 |
25 | # 文档如何生成
26 | 在example根目录下加入某个组件为名字的`.doc`文件,如`button.doc`,然后创建一个button文件夹,
27 | 在该文件夹中随意创建多个demo,以`.vue`为后缀,然后在`router.js`中引用这个`.doc`文件
28 |
--------------------------------------------------------------------------------
/src/component/navbar/nav-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
27 |
--------------------------------------------------------------------------------
/example/tabs/router-tabs.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
27 |
--------------------------------------------------------------------------------
/src/style/transition.styl:
--------------------------------------------------------------------------------
1 | .drop
2 | &-transition
3 | transition: transform .45s cubic-bezier(0.23, 1, 0.32, 1) 0s, opacity .45s cubic-bezier(0.23, 1, 0.32, 1) 0s;
4 | transform: scaleY(1);
5 | transform-origin: left top 0;
6 | &-enter, &-leave
7 | transform-origin: left top 0;
8 | transform: scaleY(0);
9 | opacity: 0;
10 |
11 |
12 | .fade
13 | &-transition
14 | transition: opacity .3s;
15 | &-enter, &-leave
16 | opacity: 0;
17 |
18 | .slide-down
19 | &-transition
20 | transition: .3s;
21 | &-enter, &-leave
22 | opacity: 0;
23 | transform: translateY(-30px)
24 |
25 |
--------------------------------------------------------------------------------
/example/pagination/basic.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
26 |
--------------------------------------------------------------------------------
/example/drop-down/drop-down.md:
--------------------------------------------------------------------------------
1 | # Props
2 | name | type | default | explain
3 | --- | --- | --- | ---
4 | label | String | '' | 默认按钮显示的文字
5 | disabled | Boolean | false | 是否禁用
6 | closeOnLoseFocus | Boolean | true | 是否在失去焦点时关闭下拉框
7 | btnType | String | '' | bootstrap button style
8 | position | String | right | 'left' or 'right' 对齐方式
9 | toggle | Boolean | true | 是否点击按钮进行切换,如果时否,点击只打开
10 | showDropDown | Boolean | false | 双向属性,强制通过外部控制是否显示下拉框
11 | classNames | String, Object, Array | '' | 用classnames进行序列化,将传入的class加载drop-content上
12 |
13 |
14 | # slot
15 | ### default
16 | dropdown里面显示的内容
17 |
18 | ### btn
19 | dropdown触发的按钮,默认是一个button
20 |
--------------------------------------------------------------------------------
/example/alert/with-close.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | click to close
4 |
5 |
6 |
7 |
21 |
22 |
31 |
--------------------------------------------------------------------------------
/src/component/card/card-title.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
31 |
--------------------------------------------------------------------------------
/src/component/svg-icon/av-time.vue:
--------------------------------------------------------------------------------
1 |
2 | >
3 |
4 |
5 |
16 |
--------------------------------------------------------------------------------
/example/button/base.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | primary
5 | success
6 | info
7 | danger
8 | warning
9 | secondary
10 | link
11 |
12 |
13 |
14 |
15 |
20 |
21 |
24 |
--------------------------------------------------------------------------------
/example/card/base.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | This is card title
6 | This is card subtitle
7 |
8 |
9 |
10 | this is card text
11 | link
12 |
13 |
14 |
15 |
16 |
17 |
26 |
--------------------------------------------------------------------------------
/example/button/disable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | primary
5 | toggle it
6 |
7 |
8 |
9 |
10 |
15 |
16 |
30 |
--------------------------------------------------------------------------------
/example/drop-down/drop-down-menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
34 |
--------------------------------------------------------------------------------
/src/component/svg-icon/svg-icon.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
33 |
--------------------------------------------------------------------------------
/example/button/outline.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | primary
5 | success
6 | info
7 | danger
8 | warning
9 | secondary
10 | link
11 |
12 |
13 |
14 |
15 |
20 |
21 |
24 |
--------------------------------------------------------------------------------
/example/button/size.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | small button
5 | nromal button
6 | large button
7 | block small button
8 | block normal button
9 | block large button
10 |
11 |
12 |
13 |
14 |
19 |
20 |
23 |
--------------------------------------------------------------------------------
/example/card/with-header-footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | This is card title
6 | This is card subtitle
7 |
8 |
9 |
10 | this is card text
11 | link
12 |
13 |
14 |
15 |
16 |
17 |
26 |
--------------------------------------------------------------------------------
/test/build/makeWebpackConfig.js:
--------------------------------------------------------------------------------
1 |
2 | function Config(base) {
3 | this.base = base
4 | this.entry = []
5 | }
6 |
7 | Config.prototype.build = function () {
8 | // return this.config
9 | }
10 |
11 | Config.prototype.entry = function (entry) {
12 | this.entry = entry instanceof Array ? entry : [entry]
13 | return this
14 | }
15 |
16 | Config.prototype.addEntry = function (entry) {
17 | if (this.entry instanceof Array) {
18 | this.entry.push(entry)
19 | } else {
20 | throw new TypeError('only use addEntry when your entry is an array')
21 | }
22 | return this
23 | }
24 |
25 | Config.prototype.style = function (options) {
26 | this.style = options
27 | return this
28 | }
29 |
30 | function make() {
31 | return new Config()
32 | }
33 |
34 | module.exports = make
35 |
--------------------------------------------------------------------------------
/src/component/modal/backdrop.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
18 |
19 |
36 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const webpack = require('webpack')
3 |
4 | const config = require('./build/webpack.config.dev')
5 |
6 | const app = express()
7 | const compiler = webpack(config)
8 |
9 | const serverOpts = {
10 | // noInfo: true,
11 | publicPath: config.output.publicPath,
12 | stats: {
13 | colors: true,
14 | chunks: false
15 | }
16 | }
17 |
18 | app.use(require('webpack-dev-middleware')(compiler, serverOpts))
19 | app.use(require('webpack-hot-middleware')(compiler))
20 |
21 | // app.get('*', function (req, res) {
22 | // res.sendFile(path.join(__dirname, './dist/index.html'))
23 | // })
24 |
25 | app.listen(3333, '0.0.0.0', (err) => {
26 | if (err) {
27 | console.error(err)
28 | return
29 | }
30 |
31 | console.log('Listening at http://localhost:3333')
32 | })
33 |
34 |
--------------------------------------------------------------------------------
/src/component/tabs/router-tabs.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
35 |
--------------------------------------------------------------------------------
/doc/menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
15 |
20 |
37 |
--------------------------------------------------------------------------------
/example/navbar/basic.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Navbar
5 |
6 | Home
7 | Features
8 | Pricing
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
32 |
--------------------------------------------------------------------------------
/example/modal/basic.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
size有sm,md,lg, 默认md
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
38 |
--------------------------------------------------------------------------------
/test/unit/demo_spec/drop-down-base.js:
--------------------------------------------------------------------------------
1 |
2 | describe('drop down base demo', () => {
3 | let
4 | container = $('#x-vue-demo-drop-down-base'),
5 | linkDown = $('#x-vue-demo-drop-down-base-link'),
6 | primaryDown = $('#x-vue-demo-drop-down-base-primary'),
7 | successDown = $('#x-vue-demo-drop-down-base-success'),
8 | infoDown = $('#x-vue-demo-drop-down-base-info'),
9 | dangerDown = $('#x-vue-demo-drop-down-base-danger')
10 |
11 |
12 | it('exists', () => {
13 | container.should.exist
14 | linkDown.should.exist
15 | primaryDown.should.exist
16 | successDown.should.exist
17 | infoDown.should.exist
18 | dangerDown.should.exist
19 | })
20 |
21 | it('will show drop down after btn click', (done) => {
22 | linkDown.find('.dropdown-toggle').click()
23 | Vue.nextTick(() => {
24 | $('#x-vue-demo-drop-down-base-card-link').should.exist
25 | done()
26 | })
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/example/date-time-picker/date-time-picker.md:
--------------------------------------------------------------------------------
1 | # USAGE
2 | ```html
3 |
4 | ```
5 |
6 | # params
7 | name | type | default | explain
8 | --- | --- | --- | ---
9 | format | String | 'yyyy-MM-dd' | 格式化时间,同时根据是否有`hh:mm:ss`来判断是否显示时间选择器
10 | highlightToday | Boolean | true | 是否高亮今天
11 | closeOnSelected | Boolean | true | 选择确定之后是否关闭选择器(未实现)
12 | maxDate | anything | '' | 可以被转成毫秒数的值,控制最大选择日期
13 | minDate | anything | '' | 可以被转成毫秒数的值,控制最小选择日期
14 |
15 | # range
16 | ```html
17 |
22 |
23 |
28 | ```
29 | 通过:range.start[end]来控制区间,同一个name的start和end处于一个区间
30 |
--------------------------------------------------------------------------------
/example/button/icon-button.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | success
6 | info
7 | danger
8 | warning
9 | secondary
10 | link
11 |
12 |
13 |
14 |
15 |
20 |
21 |
31 |
--------------------------------------------------------------------------------
/example/drop-down/slot.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 | this is slot content
10 |
11 |
12 |
13 |
14 | Slot Button
15 | you can make your btn what you want by slot btn
16 |
17 |
18 |
19 |
20 |
21 |
33 |
36 |
--------------------------------------------------------------------------------
/doc/doc.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import XVue from '../src'
3 |
4 | Vue.config.debug = true
5 |
6 | import 'bootstrap/dist/css/bootstrap.css'
7 | // import 'font-awesome/css/font-awesome.css'
8 | import '../src/style/index.styl'
9 | import './doc.styl'
10 | import 'highlight.js/styles/default.css'
11 | import 'highlight.js/styles/monokai-sublime.css'
12 |
13 | // import card from '../component/card/card.vue'
14 | // import cardTitle from '../component/card/card-title.vue'
15 | // import cardText from '../component/card/card-text.vue'
16 | // import cardBlock from '../component/card/card-block.vue'
17 | import codePanel from './code-panel.vue'
18 | //
19 | // Vue.component('card', card)
20 | // Vue.component('card-title', cardTitle)
21 | // Vue.component('card-text', cardText)
22 | // Vue.component('card-block', cardBlock)
23 | Vue.component('code-panel', codePanel)
24 |
25 | Vue.use(XVue)
26 |
27 |
28 | import router from './router'
29 | import App from './app.vue'
30 |
31 | router.start(App, '#root')
32 |
33 |
--------------------------------------------------------------------------------
/src/util/EventListener.js:
--------------------------------------------------------------------------------
1 | const EventListener = {
2 | /**
3 | * Listen to DOM events during the bubble phase.
4 | *
5 | * @param {DOMEventTarget} target DOM element to register listener on.
6 | * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
7 | * @param {function} callback Callback function.
8 | * @return {object} Object with a `remove` method.
9 | */
10 | listen(target, eventType, callback) {
11 | if (target.addEventListener) {
12 | target.addEventListener(eventType, callback, false)
13 | return {
14 | remove() {
15 | target.removeEventListener(eventType, callback, false)
16 | }
17 | }
18 | } else if (target.attachEvent) {
19 | target.attachEvent('on' + eventType, callback)
20 | return {
21 | remove() {
22 | target.detachEvent('on' + eventType, callback)
23 | }
24 | }
25 | }
26 | throw new TypeError('can\'t add listener')
27 | }
28 | }
29 |
30 | export default EventListener
31 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # v-0.1.9
2 | 1. 修改src中源文件的路径引用都为相对路径,保证编译的source文件能用
3 |
4 | # v-0.1.7
5 | 1. 修改目录结构,将源文件都放入src目录下
6 | 2. 发布到npm加入source文件夹,是编译成es5的js,并将其中的index.js作为入口文件
7 |
8 | # v-0.1.5
9 | 1. 分页组件增加显示第一页和最后一页的选型
10 |
11 | # v-0.1.3
12 | 1. 修改date-time-picker的样式文件,将所有样式包在x-date-time-picker-container里面
13 | 2. 增加drop-down的classNames props,以便于对drop-down进行一些定制
14 |
15 | # v-0.1.2
16 | 1. 增加外部改变日期控件value的时候校验生成的日期是否合法
17 | 2. 修改日期控件顶部切换日期和时间的控制器的dom结构,使用row必须在外部包一层container
18 | 3. 日期控件增加左右对其
19 |
20 | # v-0.1.0
21 | 1. 发布到github开源
22 | 2. 完善webpack配置,不再重复配置
23 | 3. 增加deploy_doc脚本,自动部署文档到github/gh-pages
24 | 4. 去掉无用的组件和文档页面
25 |
26 | # v-0.0.61
27 | 1. 增加drop-down的onLoseFocus方法props
28 |
29 | # v-0.0.60
30 | 1. 去掉时间控件中的repeat方法(导致ie不兼容)
31 | 2. 修改生成日期列表的最大最小时间对比方法,旧方法设置时间会出现临界值问题
32 |
33 | # v-0.0.59
34 | 1. 完善文档机制,提供一个页面同名.md文件,自动编译显示在页面底部
35 | 2. 修改drop向右靠齐的机制,转为document.body.clientWidth - element.rect.right
36 |
37 | # v-0.0.56 (2016-7-12)
38 | 1. 本地打包发布在package-min的时候会出现模版字符串style里面的变量消失,结果是依赖包太老的问题
39 |
40 | # v-0.0.10 (2016-5-11)
41 | 1. fix dropdown btn slot not toggle dropdown
42 | 2. change btn slot to `span` not `a`
43 |
--------------------------------------------------------------------------------
/example/date-time-picker/range.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
16 |
17 |
18 |
19 |
34 |
--------------------------------------------------------------------------------
/doc/code-panel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{filename}}
5 |
<>
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
27 |
28 |
48 |
--------------------------------------------------------------------------------
/example/tabs/base.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is Tab1
5 | This is Tab2
6 | This is Tab3
7 |
8 |
9 |
10 | tab类型:
11 | tabs
12 | pills
13 |
14 |
15 |
16 | 选中tab:
17 | tab1
18 | tab2
19 | tab3
20 |
21 |
22 | tab2 name:
23 |
24 |
25 |
30 |
41 |
--------------------------------------------------------------------------------
/src/component/card/card-image.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | loading placeholder
4 |
5 |
6 |
11 |
12 |
57 |
--------------------------------------------------------------------------------
/test/build/webpack.config.test.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const webpack = require('webpack')
3 |
4 | module.exports = {
5 | entry: path.join(__dirname, '../test/test.js'),
6 | output: {
7 | path: path.resolve(__dirname, '../test'),
8 | filename: 'test.js'
9 | },
10 | resolve: {
11 | alias: {
12 | component: path.resolve(__dirname, '../component')
13 | }
14 | },
15 | module: {
16 | loaders: [
17 | {
18 | test: /\.js$/,
19 | loader: 'babel',
20 | exclude: /node_modules/
21 | },
22 | {
23 | test: /\.vue$/,
24 | loader: 'vue'
25 | }
26 | ],
27 | postLoaders: [
28 | {
29 | test: /\.*/,
30 | include: /component|example/,
31 | loader: 'istanbul-instrumenter'
32 | }
33 | ]
34 | },
35 | plugins: [
36 | new webpack.DefinePlugin({
37 | 'process.env': {
38 | NODE_ENV: '"production"'
39 | }
40 | }),
41 | new webpack.ProvidePlugin({
42 | $: 'jquery',
43 | jQuery: 'jquery',
44 | 'window.jQuery': 'jquery'
45 | })
46 | ],
47 | devServer: {
48 | contentBase: './test',
49 | noInfo: true
50 | },
51 | devtool: '#source-map'
52 | }
53 |
--------------------------------------------------------------------------------
/example/drop-down/no-auto-close.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 | No auto close
12 | you can not close me only if you click the close btn
13 | 关闭
14 |
15 |
16 |
17 |
18 |
19 |
28 |
43 |
--------------------------------------------------------------------------------
/src/component/alert/alert.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 | {{msg}}
8 |
9 |
10 |
11 |
12 |
52 |
--------------------------------------------------------------------------------
/test/build/webpack.build.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const webpack = require('webpack')
3 | const autoprefixer = require('autoprefixer')
4 |
5 | function postcss() {
6 | return [
7 | autoprefixer({
8 | browsers: '> 1%'
9 | })
10 | ]
11 | }
12 |
13 | module.exports = {
14 | devtool: 'cheap-source-map',
15 | entry: {
16 | app: path.join(__dirname, '../component/index.js')
17 | },
18 | externals: {
19 | 'vue': 'vue'
20 | },
21 | debug: true,
22 | output: {
23 | path: path.join(__dirname, '../dist'),
24 | filename: 'x-vue.js',
25 | library: 'XVue',
26 | libraryTarget: 'umd',
27 | umdNamedDefine: true
28 | },
29 | resolve: {},
30 | module: {
31 | preLoaders: [
32 | { test: /\.(js|vue)$/, loader: 'eslint-loader', exclude: /node_modules/ }
33 | ],
34 | loaders: [
35 | { test: /\.js$/, loader: 'babel', exclude: /node_modules/ },
36 | { test: /\.vue/, loader: 'vue' },
37 | { test: /\.scss/, loader: 'style-loader!css-loader!postcss-loader!sass-loader' }
38 | ]
39 | },
40 | vue: {
41 | postcss
42 | },
43 | postcss,
44 | plugins: [
45 | new webpack.DefinePlugin({
46 | 'process.env': {
47 | NODE_ENV: '"production"'
48 | }
49 | }),
50 | new webpack.optimize.OccurenceOrderPlugin()
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/demo-loader/selector.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var parse = require('vue-loader/lib/parser')
3 | var loaderUtils = require('loader-utils')
4 | var marked = require('marked')
5 |
6 | marked.setOptions({
7 | gfm: true,
8 | tables: true,
9 | breaks: false,
10 | pedantic: false,
11 | sanitize: false,
12 | smartLists: true,
13 | smartypants: false,
14 | highlight: function(code, lang) {
15 | return require('highlight.js').highlight(lang, code).value;
16 | },
17 | });
18 |
19 | module.exports = function (content) {
20 | this.cacheable()
21 | var query = loaderUtils.parseQuery(this.query)
22 | var filename = path.basename(this.resourcePath)
23 | var parts = parse(content, filename, this.sourceMap)
24 | var part = parts[query.type][query.index]
25 | if (query.type === 'template') {
26 |
27 | var source = part.content
28 |
29 |
30 | var template_header = '' +
31 | '\n' +
32 | ' \n' +
33 | marked(`\`\`\`html\n ${content} \n\`\`\``) +
34 | '
\n' +
35 | ' \n'
36 |
37 | var template_footer = '' +
38 | '
\n' +
39 | '\n'
40 |
41 | source = template_header + source + template_footer
42 |
43 | console.log(this._compiler)
44 |
45 | part.content = source
46 |
47 | }
48 | this.callback(null, part.content, part.map)
49 | }
50 |
--------------------------------------------------------------------------------
/test/build/webpack.build.doc.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const webpack = require('webpack')
3 | const autoprefixer = require('autoprefixer')
4 |
5 | function postcss() {
6 | return [
7 | autoprefixer({
8 | browsers: '> 1%'
9 | })
10 | ]
11 | }
12 |
13 | module.exports = {
14 | devtool: 'cheap-source-map',
15 | entry: [path.join(__dirname, '../doc/doc.js')],
16 | debug: true,
17 | output: {
18 | path: path.join(__dirname, '../doc-built'),
19 | filename: 'index.js',
20 | publicPath: 'doc-built/'
21 | },
22 | resolve: {
23 | alias: {
24 | component: path.resolve(__dirname, '../component'),
25 | util: path.resolve(__dirname, '../util')
26 | }
27 | },
28 | module: {
29 | preLoaders: [
30 | { test: /\.(js|vue)$/, loader: 'eslint-loader', exclude: /node_modules/ }
31 | ],
32 | loaders: [
33 | { test: /\.js$/, loader: 'babel', exclude: /node_modules/ },
34 | { test: /\.vue/, loader: 'vue' },
35 | { test: /\.scss/, loader: 'style-loader!css-loader!postcss-loader!sass-loader' },
36 | { test: /\.css/, loader: 'style-loader!css-loader' },
37 | { test: /\.doc/, loader: '../demo-loader/loader' }
38 | ]
39 | },
40 | vue: {
41 | postcss
42 | },
43 | postcss,
44 | plugins: [
45 | new webpack.DefinePlugin({
46 | 'process.env': {
47 | NODE_ENV: '"production"'
48 | }
49 | })
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/test/build/karma.conf.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function(config) {
3 | config.set({
4 |
5 | logLevel: config.LOG_DISABLE,
6 |
7 | files: [
8 | // all files ending in "test"
9 | { pattern: 'component/**/*.js', included: false, served: true },
10 | '../test/test.js'
11 | // each file acts as entry point for the webpack configuration
12 | ],
13 |
14 | // frameworks to use
15 | frameworks: ['mocha'],
16 |
17 | preprocessors: {
18 | // only specify one entry point
19 | // and require all tests in there
20 | '../test/test.js': ['webpack'],
21 | 'component/**/*.js': [
22 | 'coverage'
23 | ]
24 | },
25 |
26 | reporters: ['spec', 'coverage'],
27 |
28 | coverageReporter: {
29 | reporters: [
30 | { type: 'lcov', dir: '../coverage/', subdir: '.' }
31 | // { type: 'text-summary', dir: 'coverage/', subdir: '.' },
32 | // { type: 'html', dir: 'coverage/' }
33 | ]
34 | },
35 |
36 | webpack: require('./webpack.config.test.js'),
37 |
38 | // webpack-dev-middleware configuration
39 | webpackMiddleware: {
40 | noInfo: true
41 | },
42 |
43 | plugins: [
44 | require('karma-webpack'),
45 | require('karma-mocha'),
46 | require('karma-coverage'),
47 | require('karma-phantomjs-launcher'),
48 | require('karma-spec-reporter')
49 | ],
50 |
51 | browsers: ['PhantomJS']
52 | })
53 | }
54 |
--------------------------------------------------------------------------------
/src/component/tabs/tab.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
64 |
--------------------------------------------------------------------------------
/example/date-time-picker/base.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
15 |
16 |
21 |
22 |
23 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
38 |
61 |
--------------------------------------------------------------------------------
/src/component/card/card.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
59 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: "airbnb-base",
4 | globals: {
5 | "AMap": true,
6 | "window": true,
7 | "document": true
8 | },
9 | parserOptions: {
10 | // so that 'use strict' is enable
11 | "ecmaFeatures": {
12 | "experimentalObjectRestSpread": true
13 | }
14 | },
15 | // required to lint *.vue files
16 | plugins: [
17 | "html"
18 | ],
19 |
20 | // add your custom rules here
21 | "rules": {
22 | // allow debugger during development
23 | "no-debugger": process.env.NODE_ENV === "production" ? 2 : 0,
24 | "import/no-unresolved": [0],
25 | "import/extensions": [0],
26 | "semi": [2, "never"],
27 | "no-plusplus": [0],
28 | "no-template-curly-in-string": ["off"],
29 | "one-var-declaration-per-line": [0],
30 | "space-infix-ops": [0],
31 | "arrow-parens": [0],
32 | "strict:": [0],
33 | "import/no-extraneous-dependencies": [0],
34 | "no-console": [0],
35 | "no-underscore-dangle": [0],
36 | "prefer-const": [0],
37 | "eol-last": ["off"],
38 | "no-self-assign": [0],
39 | "no-param-reassign": [0],
40 | "no-mixed-operators": [0],
41 | "no-shadow": [1],
42 | "arrow-body-style": [0],
43 | "comma-dangle": [0],
44 | "one-var": [0],
45 | "space-before-function-paren": [0],
46 | "prefer-template": [0],
47 | "no-new": [0],
48 | "consistent-return": [0],
49 | "quote-props": [0],
50 | "array-bracket-spacing": [0],
51 | "no-unused-vars": [1],
52 | "computed-property-spacing": [0],
53 | "no-use-before-define": [0]
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/doc/router.js:
--------------------------------------------------------------------------------
1 | import VueRouter from 'vue-router'
2 | import Vue from 'vue'
3 |
4 | Vue.use(VueRouter)
5 |
6 | import Index from './index.vue'
7 | import DropDown from '../example/drop-down.doc'
8 | import Modal from '../example/modal.doc'
9 | import pagination from '../example/pagination.doc'
10 | import Button from '../example/button.doc'
11 | import Card from '../example/card.doc'
12 | import Navbar from '../example/navbar.doc'
13 | import Menu from '../example/menu.doc'
14 | import Tabs from '../example/tabs.doc'
15 | import Alert from '../example/alert.doc'
16 |
17 | import DateTimePicker from '../example/date-time-picker.doc'
18 |
19 | const router = new VueRouter()
20 |
21 | export const routes = {
22 | '/': {
23 | component: Index,
24 | title: '首页'
25 | },
26 | 'drop-down': {
27 | component: DropDown,
28 | title: '下拉框'
29 | },
30 |
31 | 'pagination': {
32 | component: pagination,
33 | title: '分页'
34 | },
35 |
36 | 'button': {
37 | component: Button,
38 | title: '按钮'
39 | },
40 |
41 | 'card': {
42 | component: Card,
43 | title: '卡片'
44 | },
45 |
46 | 'navbar': {
47 | component: Navbar,
48 | title: 'Navbar'
49 | },
50 |
51 | 'menu': {
52 | component: Menu,
53 | title: 'Menu'
54 | },
55 |
56 | 'tabs': {
57 | component: Tabs,
58 | title: 'Tab'
59 | },
60 |
61 | 'date-time-picker': {
62 | component: DateTimePicker,
63 | title: '日期时间'
64 | },
65 |
66 | 'modal': {
67 | component: Modal,
68 | title: '模态框',
69 | },
70 |
71 | 'alert': {
72 | component: Alert,
73 | title: 'alert'
74 | }
75 | }
76 |
77 | router.map(routes)
78 |
79 | export default router
80 |
--------------------------------------------------------------------------------
/test/build/webpack.config.dev.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const webpack = require('webpack')
3 | const HtmlWebpackPlugin = require('html-webpack-plugin')
4 | const autoprefixer = require('autoprefixer')
5 |
6 | function postcss() {
7 | return [
8 | autoprefixer({
9 | browsers: '> 1%'
10 | })
11 | ]
12 | }
13 |
14 | module.exports = {
15 | devtool: '#cheap-eval-source-map',
16 | entry: [path.join(__dirname, '../doc/doc.js'), 'webpack-hot-middleware/client'],
17 | debug: true,
18 | output: {
19 | path: path.join(__dirname, '../dist'),
20 | filename: 'index.js',
21 | publicPath: '/'
22 | },
23 | resolve: {
24 | alias: {
25 | component: path.resolve(__dirname, '../component'),
26 | util: path.resolve(__dirname, '../util')
27 | }
28 | },
29 | module: {
30 | preLoaders: [
31 | { test: /\.(js|vue)$/, loader: 'eslint-loader', exclude: /node_modules/ }
32 | ],
33 | loaders: [
34 | { test: /\.js$/, loader: 'babel', exclude: /node_modules/ },
35 | { test: /\.vue/, loader: 'vue' },
36 | { test: /\.scss/, loader: 'style-loader!css-loader!postcss-loader!sass-loader' },
37 | { test: /\.css/, loader: 'style-loader!css-loader' },
38 | { test: /\.doc/, loader: '../demo-loader/loader' }
39 | ]
40 | },
41 | vue: {
42 | postcss
43 | },
44 | postcss,
45 | plugins: [
46 | new webpack.DefinePlugin({
47 | 'process.env': {
48 | NODE_ENV: '"development"'
49 | }
50 | }),
51 | new webpack.HotModuleReplacementPlugin(),
52 | new HtmlWebpackPlugin({
53 | template: path.join(__dirname, '../doc/index.html'),
54 | filename: 'index.html'
55 | })
56 | ]
57 | }
58 |
--------------------------------------------------------------------------------
/src/component/tabs/tabs.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
64 |
--------------------------------------------------------------------------------
/test/unit/demo_test.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import chai from 'chai'
3 | import jQuery from 'jquery'
4 | import chaiJquery from 'chai-jquery'
5 | import path from 'path'
6 | import _ from 'lodash'
7 |
8 | chai.use((chai, utils) => {
9 | return chaiJquery(chai, utils, jQuery)
10 | })
11 |
12 | chai.should()
13 | chai.expect
14 |
15 | const demos = require.context('../../example', true, /\.vue$/)
16 |
17 | function getBaseName(dpath) {
18 | let baseName = path.basename(dpath)
19 | return _.lowerCase(_.camelCase(baseName.substr(0, baseName.lastIndexOf('.'))))
20 | }
21 |
22 | function getLasePath(dpath) {
23 | let fullPath = path.dirname(dpath)
24 | return _.lowerCase(_.camelCase(fullPath.substr(fullPath.lastIndexOf('/'), fullPath.length - 1)))
25 | }
26 |
27 | function getTemplates(paths) {
28 | return paths.reduce((result, p) => {
29 | return result + '<' + _.kebabCase(getLasePath(p) + ' ' + getBaseName((p))) + '/>'
30 | }, '')
31 | }
32 |
33 | function getComponents(paths, context) {
34 | return paths.reduce((result, p) => {
35 | result[_.camelCase(getLasePath(p) + ' ' + getBaseName(p))] = context(p)
36 | return result
37 | }, {})
38 | }
39 |
40 | const componentsTemplate = getTemplates(demos.keys())
41 |
42 | let el = $(
43 | `
44 | ${componentsTemplate}
45 |
`
46 | )
47 |
48 | el.appendTo('body')
49 |
50 | const app = new Vue({
51 | el: '#root',
52 | components: getComponents(demos.keys(), demos)
53 | })
54 |
55 | window.app = app
56 | window.Vue = Vue
57 | window.expect = chai.expect
58 |
59 | describe('x-vue', () => {
60 | const testsContext = require.context('./demo_spec', false, /\.js$/)
61 | testsContext.keys().forEach(testsContext)
62 | })
63 |
--------------------------------------------------------------------------------
/src/component/button/button.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
72 |
--------------------------------------------------------------------------------
/src/style/button.styl:
--------------------------------------------------------------------------------
1 |
2 | //
3 | // Buttons
4 | // --------------------------------------------------
5 |
6 | // Base styles
7 | // --------------------------------------------------
8 |
9 | @import "variable";
10 |
11 | .button {
12 | display: inline-block;
13 | margin-bottom: 0; // For input.btn
14 | font-weight: $font-weight-base;
15 | //line-height: $line-height-base;
16 | text-align: center;
17 | vertical-align: middle;
18 | touch-action: manipulation;
19 | cursor: pointer;
20 | background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
21 | border: 1px solid transparent;
22 | white-space: nowrap;
23 | user-select: none;
24 | text-decoration: none;
25 | color: $color-font-default;
26 | background-color: $color-default;
27 | border: 1px solid #eeeeee;
28 | padding: 6px 12px;
29 |
30 | &::-moz-focus-inner {
31 | padding: 0;
32 | border: 0;
33 | }
34 |
35 | &,
36 | &:active,
37 | &.active {
38 | &:focus,
39 | &.focus {
40 | // Default
41 | outline: thin dotted;
42 | // WebKit
43 | outline: 5px auto -webkit-focus-ring-color;
44 | outline-offset: -2px;
45 | }
46 | }
47 |
48 | &:hover,
49 | &:focus,
50 | &.focus {
51 | color: $color-font-default;
52 | text-decoration: none;
53 | }
54 |
55 | &:active,
56 | &.active {
57 | outline: 0;
58 | background-image: none;
59 | box-shadow: inset 0 3px 5px rgba(0,0,0,.125);
60 | }
61 |
62 | &.disabled,
63 | &[disabled],
64 | fieldset[disabled] & {
65 | cursor: default;
66 | opacity: .65;
67 | box-shadow: none;
68 | }
69 |
70 | a& {
71 | &.disabled,
72 | fieldset[disabled] & {
73 | pointer-events: none; // Future-proof disabling of clicks on `` elements
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/src/component/drop-down/drop-down-menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
16 |
17 |
18 |
19 |
71 |
--------------------------------------------------------------------------------
/example/drop-down/base.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
32 |
57 |
--------------------------------------------------------------------------------
/example/drop-down/width.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
show drop down
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
32 |
63 |
--------------------------------------------------------------------------------
/src/component/date-picker/month-picker.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
95 |
--------------------------------------------------------------------------------
/src/component/date-picker/year-picker.vue:
--------------------------------------------------------------------------------
1 |
2 |
30 |
31 |
32 |
105 |
--------------------------------------------------------------------------------
/demo-loader/loader.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var fs = require('fs')
3 | var marked = require('marked')
4 | var loaderUtils = require('loader-utils')
5 |
6 | marked.setOptions({
7 | gfm: true,
8 | tables: true,
9 | breaks: false,
10 | pedantic: false,
11 | sanitize: false,
12 | smartLists: true,
13 | smartypants: false,
14 | highlight: function (code, lang) {
15 | return require('highlight.js').highlight(lang, code).value;
16 | }
17 | })
18 |
19 | module.exports = function (source) {
20 |
21 | if (this.cacheable) this.cacheable()
22 |
23 | var loaderContext = this
24 | var query = loaderUtils.parseQuery(this.query)
25 | var filePath = this.resourcePath
26 | var fileName = path.basename(filePath)
27 | var name = fileName.substr(0, fileName.lastIndexOf('.'))
28 | var docPath = path.join(filePath, '..', name)
29 | var explainPath = path.join(filePath, '..', name, name + '.md')
30 | var docFiles
31 |
32 | if (query.post) {
33 | if (fs.existsSync(filePath + '.cache')) {
34 | // fs.unlinkSync(filePath + '.cache')
35 | }
36 | return source
37 | }
38 |
39 | try {
40 | docFiles = fs.readdirSync(docPath)
41 | } catch(e) {
42 | throw new Error(docPath + ' does not exist')
43 | }
44 |
45 | var html = '', components = '', code, demoFilePath
46 |
47 | // var self = this
48 | this.addContextDependency(docPath)
49 |
50 | docFiles.forEach(function (f, index) {
51 | if (path.extname(f) === '.vue') {
52 | demoFilePath = path.join(docPath, f)
53 | code = fs.readFileSync(demoFilePath, 'utf8')
54 | // self.addDependency(demoFilePath)
55 | html += (
56 | '\n' +
57 | '\n' +
58 | '\n' +
59 | '
\n' +
60 | '\n' +
61 | marked(`\`\`\`html\n ${code} \n\`\`\``) + '\n' +
62 | '
\n' +
63 | '\n'
64 | )
65 | components += 'demo' + index + ':' + ' require(\'./' + name + '/' + f + '\'),'
66 | }
67 | })
68 |
69 | // console.log(explainPath)
70 | if (fs.existsSync(explainPath)) {
71 | // this.addDependency(explainPath)
72 | var explain = fs.readFileSync(explainPath, 'utf8')
73 | html += (
74 | '' +
75 | marked(explain) +
76 | '
'
77 | )
78 | }
79 |
80 | var scripts = ""
85 |
86 | var templates = "\n" +
87 | html + '\n' +
88 | ""
89 |
90 | var finalPath = path.join(filePath, '..', '.' + name + '.doc.cache')
91 |
92 | fs.writeFileSync(finalPath, templates + '\n\n' + scripts, 'utf8')
93 |
94 | function getRequest() {
95 | return loaderUtils.stringifyRequest(loaderContext,
96 | '!!vue!' + finalPath)
97 | }
98 |
99 | return 'module.exports = require(' + getRequest() + ')'
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // button
2 | import XButton from './component/button/button.vue'
3 |
4 | // modal
5 | import XModal from './component/modal/modal.vue'
6 |
7 | // card
8 | import XCard from './component/card/card.vue'
9 | import XCardTitle from './component/card/card-title.vue'
10 | import XCardText from './component/card/card-text.vue'
11 | import XCardLink from './component/card/card-link.vue'
12 | import XCardBlock from './component/card/card-block.vue'
13 | import XCardImage from './component/card/card-image.vue'
14 |
15 | // drop down
16 | import XDropDown from './component/drop-down/drop-down.vue'
17 | import XDropDownMenu from './component/drop-down/drop-down-menu.vue'
18 | import XDropDownMenuDivider from './component/drop-down/drop-down-menu-divider.vue'
19 | import XDropDownItem from './component/drop-down/drop-down-menu-item.vue'
20 |
21 | // tabs
22 | import XTabs from './component/tabs/tabs.vue'
23 | import XTab from './component/tabs/tab.vue'
24 | import XRouterTabs from './component/tabs/router-tabs.vue'
25 |
26 | // date picker
27 | // import XDatePicker from './component/date-picker/date-picker.vue'
28 | // import XDateTimePicker from './component/date-picker/date-time-picker.vue'
29 |
30 | // nav
31 | import XNavBar from './component/navbar/index.vue'
32 | import XNavBarBrand from './component/navbar/navbar-brand.vue'
33 | import XNavItem from './component/navbar/nav-item.vue'
34 | import XNavBarNav from './component/navbar/navbar-nav.vue'
35 | import XNavGroup from './component/navbar/nav-group.vue'
36 |
37 | // pagination
38 | import XPagination from './component/pagination/index.vue'
39 |
40 | // alert
41 | import XAlert from './component/alert/alert.vue'
42 | import XAlertLink from './component/alert/alert-link.vue'
43 | import XAlertHeader from './component/alert/alert-heading.vue'
44 |
45 | // directives
46 | // import DateTimePicker from './component/date-picker/date-time-picker'
47 |
48 | // ueditor
49 | // import Ueditor from './component/ueditor/ueditor.vue'
50 |
51 | export const components = {
52 | XButton,
53 |
54 | XModal,
55 |
56 | XCard,
57 | XCardTitle,
58 | XCardText,
59 | XCardLink,
60 | XCardBlock,
61 | XCardImage,
62 |
63 | XDropDown,
64 | XDropDownMenu,
65 | XDropDownMenuDivider,
66 | XDropDownItem,
67 |
68 | XTabs,
69 | XTab,
70 | XRouterTabs,
71 |
72 | // XDatePicker,
73 | // XDateTimePicker,
74 |
75 | XNavBar,
76 | XNavBarBrand,
77 | XNavItem,
78 | XNavBarNav,
79 | XNavGroup,
80 |
81 | XPagination,
82 |
83 | XAlert,
84 | XAlertLink,
85 | XAlertHeader
86 |
87 | // Ueditor,
88 | }
89 |
90 | // export const directives = {
91 | // DateTimePicker
92 | // }
93 |
94 | export default {
95 |
96 | install(Vue) {
97 | Vue.X_VUE_VERSION = process.env.X_VUE_VERSION
98 | Object.keys(components).forEach((name) => {
99 | Vue.component(name, components[name])
100 | })
101 | // Object.keys(directives).forEach((name) => {
102 | // Vue.directive(name, directives[name])
103 | // })
104 | }
105 |
106 | }
107 |
108 | require('./style/index.styl')
109 | // import '../style/index.styl'
110 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "x-vue",
3 | "version": "0.1.10",
4 | "description": "vue components based on bootstrap",
5 | "main": "source/index.js",
6 | "scripts": {
7 | "dev": "./build/dev.sh",
8 | "start": "node server.js",
9 | "test": "gulp test",
10 | "deploy-doc": "./build/deploy_doc.sh"
11 | },
12 | "keywords": [
13 | "vue",
14 | "x",
15 | "bootstrap"
16 | ],
17 | "files": [
18 | "dist",
19 | "source",
20 | "CHANGELOG.md",
21 | "Readme.md"
22 | ],
23 | "author": "Jokcy ",
24 | "license": "ISC",
25 | "devDependencies": {
26 | "autoprefixer": "^6.3.5",
27 | "babel-eslint": "^6.0.2",
28 | "babel-loader": "^6.2.1",
29 | "babel-plugin-transform-runtime": "^6.4.3",
30 | "babel-preset-es2015": "^6.3.13",
31 | "babel-preset-es2015-rollup": "^1.1.1",
32 | "babel-preset-stage-0": "^6.3.13",
33 | "bootstrap": "^4.0.0-alpha.2",
34 | "bundle-loader": "^0.5.4",
35 | "chai": "^3.5.0",
36 | "chai-jquery": "^2.0.0",
37 | "coveralls": "^2.11.6",
38 | "css-loader": "^0.23.1",
39 | "eslint": "^2.5.3",
40 | "eslint-config-airbnb-base": "^10.0.1",
41 | "eslint-loader": "^1.3.0",
42 | "eslint-plugin-html": "^1.4.0",
43 | "express": "^4.13.4",
44 | "extract-text-webpack-plugin": "^1.0.1",
45 | "file-loader": "^0.8.5",
46 | "gulp": "^3.9.0",
47 | "gulp-autoprefixer": "^3.1.0",
48 | "gulp-babel": "^6.1.2",
49 | "gulp-bump": "^2.1.0",
50 | "gulp-cssmin": "^0.1.7",
51 | "gulp-header": "^1.8.7",
52 | "gulp-load-plugins": "^1.2.4",
53 | "gulp-rename": "^1.2.2",
54 | "gulp-rollup": "^1.8.0",
55 | "gulp-stylus": "^2.5.0",
56 | "gulp-webpack": "^1.5.0",
57 | "highlight.js": "^9.3.0",
58 | "html-webpack-plugin": "^2.22.0",
59 | "istanbul-instrumenter-loader": "^0.2.0",
60 | "jquery": "^2.2.2",
61 | "karma": "^0.13.19",
62 | "karma-coverage": "^0.5.3",
63 | "karma-mocha": "^0.2.1",
64 | "karma-phantomjs-launcher": "^1.0.0",
65 | "karma-spec-reporter": "0.0.23",
66 | "karma-webpack": "^1.7.0",
67 | "lodash": "^4.11.1",
68 | "marked": "^0.3.5",
69 | "mocha": "^2.4.5",
70 | "mocha-lcov-reporter": "^1.0.0",
71 | "mocha-loader": "^0.7.1",
72 | "phantomjs-polyfill": "0.0.1",
73 | "phantomjs-prebuilt": "^2.1.3",
74 | "postcss-loader": "^0.8.2",
75 | "rimraf": "^2.5.2",
76 | "rollup-plugin-vue": "^2.0.0",
77 | "run-sequence": "^1.1.5",
78 | "scriptjs": "^2.5.8",
79 | "scss-loader": "0.0.1",
80 | "style-loader": "^0.13.1",
81 | "stylus": "^0.54.5",
82 | "stylus-loader": "^2.1.1",
83 | "url-loader": "^0.5.7",
84 | "vue": "^1.0.16",
85 | "vue-demo-loader": "^0.1.0",
86 | "vue-hot-reload-api": "^1.3.2",
87 | "vue-html-loader": "^1.1.0",
88 | "vue-loader": "^8.2.3",
89 | "vue-router": "^0.7.13",
90 | "vue-style-loader": "^1.0.0",
91 | "webpack": "^1.13.1",
92 | "webpack-dev-middleware": "^1.5.1",
93 | "webpack-dev-server": "^1.14.1",
94 | "webpack-hot-middleware": "^2.6.4"
95 | },
96 | "dependencies": {
97 | "classnames": "^2.2.5",
98 | "font-awesome": "^4.6.3"
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/component/modal/modal.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
16 |
17 |
18 |
19 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
98 |
99 |
140 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const gulp = require('gulp')
4 | const Server = require('karma').Server
5 | const spawn = require('child_process').spawn
6 | const rimraf = require('rimraf')
7 | const cssmin = require('gulp-cssmin')
8 | const rename = require('gulp-rename')
9 | const stylus = require('gulp-stylus')
10 | const autoprefixer = require('gulp-autoprefixer')
11 | const bump = require('gulp-bump')
12 | const header = require('gulp-header')
13 | const runSequence = require('run-sequence')
14 | const babel = require('gulp-babel')
15 |
16 | const webpack = require('gulp-webpack')
17 |
18 | gulp.task('default', ['test'])
19 |
20 | /* TEST SETUP */
21 | gulp.task('test-watch', ['test'], () => {
22 | gulp.watch(['component/**/*.js', 'test/**/*.js'], ['test'])
23 | })
24 |
25 | gulp.task('test', (done) => {
26 | const server = new Server({
27 | configFile: __dirname + '/build/karma.conf.js',
28 | singleRun: true
29 | }, () => {
30 | done()
31 | })
32 |
33 | server.start()
34 | })
35 |
36 |
37 | gulp.task('copy-stylus', () => {
38 | return gulp.src('src/**/*.stylus')
39 | .pipe(gulp.dest('source'))
40 | })
41 |
42 | // copy vue files
43 | gulp.task('copy-vue', () => {
44 | return gulp.src('src/**/*.vue')
45 | .pipe(gulp.dest('source'))
46 | })
47 |
48 | gulp.task('compile-js', () => {
49 | return gulp.src('src/**/*.js')
50 | .pipe(babel())
51 | .pipe(gulp.dest('source'))
52 | })
53 |
54 | // babel parse
55 | gulp.task('source', (done) => {
56 | rimraf('./source', () => {
57 | runSequence('copy-vue', 'copy-stylus', 'compile-js', () => {
58 | done()
59 | })
60 | })
61 | })
62 |
63 | // publish to npm
64 | gulp.task('npm-publish', (done) => {
65 | spawn('npm', ['publish'], { stdio: 'inherit' }).on('close', done)
66 | })
67 |
68 | // package
69 | gulp.task('package', () => {
70 | return gulp.src('component/index.js')
71 | .pipe(webpack(require('./build/webpack.build')))
72 | .pipe(gulp.dest('dist'))
73 | })
74 |
75 | // package min
76 | gulp.task('package-min', () => {
77 | return gulp.src('component/index.js')
78 | .pipe(webpack(require('./build/webpack.build.min')))
79 | .pipe(gulp.dest('dist'))
80 | })
81 |
82 | // package the css
83 | gulp.task('package-css', () => {
84 | return gulp.src('style/index.styl')
85 | .pipe(stylus())
86 | .pipe(autoprefixer({ browsers: '> 1%' }))
87 | .pipe(rename('x-vue.css'))
88 | .pipe(gulp.dest('dist'))
89 | .pipe(cssmin())
90 | .pipe(rename({ suffix: '.min' }))
91 | .pipe(gulp.dest('dist'))
92 | })
93 |
94 | // clear dist
95 | gulp.task('clear-dist', (done) => {
96 | rimraf('./dist', done)
97 | })
98 |
99 | // bump
100 | gulp.task('bump', () => {
101 | return gulp.src('package.json')
102 | .pipe(bump({ type: 'patch' }))
103 | .pipe(gulp.dest('./'))
104 | })
105 |
106 | gulp.task('add-header', () => {
107 | let pkg = require('./package.json')
108 | let banner = ['/**',
109 | ' * <%= pkg.name %> - <%= pkg.description %>',
110 | ' * @version v<%= pkg.version %>',
111 | ' * @link <%= pkg.homepage %>',
112 | ' * @license <%= pkg.license %>',
113 | ' */',
114 | ''].join('\n')
115 |
116 | return gulp.src(['dist/*.js', 'dist/*.css'])
117 | .pipe(header(banner, { pkg }))
118 | .pipe(gulp.dest('dist/'))
119 | })
120 |
121 | gulp.task('pre-publish', (done) => {
122 | runSequence('clear-dist', 'source', 'bump', 'package', 'package-min', 'add-header', () => {
123 | done()
124 | })
125 | })
126 |
127 | gulp.task('publish', (done) => {
128 | runSequence('npm-publish', () => {
129 | done()
130 | })
131 | })
132 |
133 |
134 | // make doc
135 | gulp.task('build-doc', () => {
136 | return gulp.src('doc/doc.js')
137 | .pipe(webpack(require('./build/webpack.build.doc')))
138 | .pipe(gulp.dest('doc-built'))
139 | })
140 |
--------------------------------------------------------------------------------
/src/component/modal/notification.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
{{icon}}
8 |
{{text}}
9 |
知道了
10 |
11 |
12 |
13 |
14 |
15 |
16 |
63 |
64 |
--------------------------------------------------------------------------------
/src/component/pagination/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
40 |
41 |
42 |
50 |
51 |
162 |
--------------------------------------------------------------------------------
/src/component/date-picker/date-picker.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | |
9 | {{weeks[w]}}
10 | |
11 |
12 |
13 |
14 |
15 | |
16 | {{date.day}}
22 | |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
171 |
--------------------------------------------------------------------------------
/src/component/drop-down/drop-down.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{label}}
9 |
10 |
11 |
12 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
32 |
33 |
166 |
--------------------------------------------------------------------------------
/demo-loader/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "env": {
4 | "browser": true,
5 | "node": true
6 | },
7 |
8 | "rules": {
9 | "accessor-pairs": 2,
10 | "array-bracket-spacing": 0,
11 | "block-scoped-var": 0,
12 | "brace-style": [2, "1tbs", { "allowSingleLine": true }],
13 | "camelcase": 0,
14 | "comma-dangle": [2, "never"],
15 | "comma-spacing": [2, { "before": false, "after": true }],
16 | "comma-style": [2, "last"],
17 | "complexity": 0,
18 | "computed-property-spacing": 0,
19 | "consistent-return": 0,
20 | "consistent-this": 0,
21 | "constructor-super": 2,
22 | "curly": [2, "multi-line"],
23 | "default-case": 0,
24 | "dot-location": [2, "property"],
25 | "dot-notation": 0,
26 | "eol-last": 2,
27 | "eqeqeq": [2, "allow-null"],
28 | "func-names": 0,
29 | "func-style": 0,
30 | "generator-star-spacing": [2, { "before": true, "after": true }],
31 | "guard-for-in": 0,
32 | "handle-callback-err": [2, "^(err|error)$" ],
33 | "indent": [2, 2, { "SwitchCase": 1 }],
34 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
35 | "linebreak-style": 0,
36 | "lines-around-comment": 0,
37 | "max-nested-callbacks": 0,
38 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
39 | "new-parens": 2,
40 | "newline-after-var": 0,
41 | "no-alert": 0,
42 | "no-array-constructor": 2,
43 | "no-caller": 2,
44 | "no-catch-shadow": 0,
45 | "no-cond-assign": 2,
46 | "no-console": 0,
47 | "no-constant-condition": 0,
48 | "no-continue": 0,
49 | "no-control-regex": 2,
50 | "no-debugger": 2,
51 | "no-delete-var": 2,
52 | "no-div-regex": 0,
53 | "no-dupe-args": 2,
54 | "no-dupe-keys": 2,
55 | "no-duplicate-case": 2,
56 | "no-else-return": 0,
57 | "no-empty": 0,
58 | "no-empty-character-class": 2,
59 | "no-empty-label": 2,
60 | "no-eq-null": 0,
61 | "no-eval": 2,
62 | "no-ex-assign": 2,
63 | "no-extend-native": 2,
64 | "no-extra-bind": 2,
65 | "no-extra-boolean-cast": 2,
66 | "no-extra-parens": 0,
67 | "no-extra-semi": 0,
68 | "no-fallthrough": 2,
69 | "no-floating-decimal": 2,
70 | "no-func-assign": 2,
71 | "no-implied-eval": 2,
72 | "no-inline-comments": 0,
73 | "no-inner-declarations": [2, "functions"],
74 | "no-invalid-regexp": 2,
75 | "no-irregular-whitespace": 2,
76 | "no-iterator": 2,
77 | "no-label-var": 2,
78 | "no-labels": 2,
79 | "no-lone-blocks": 2,
80 | "no-lonely-if": 0,
81 | "no-loop-func": 0,
82 | "no-mixed-requires": 0,
83 | "no-mixed-spaces-and-tabs": 2,
84 | "no-multi-spaces": 2,
85 | "no-multi-str": 2,
86 | "no-multiple-empty-lines": [2, { "max": 1 }],
87 | "no-native-reassign": 2,
88 | "no-negated-in-lhs": 2,
89 | "no-nested-ternary": 0,
90 | "no-new": 2,
91 | "no-new-func": 0,
92 | "no-new-object": 2,
93 | "no-new-require": 2,
94 | "no-new-wrappers": 2,
95 | "no-obj-calls": 2,
96 | "no-octal": 2,
97 | "no-octal-escape": 2,
98 | "no-param-reassign": 0,
99 | "no-path-concat": 0,
100 | "no-process-env": 0,
101 | "no-process-exit": 0,
102 | "no-proto": 0,
103 | "no-redeclare": 2,
104 | "no-regex-spaces": 2,
105 | "no-restricted-modules": 0,
106 | "no-return-assign": 2,
107 | "no-script-url": 0,
108 | "no-self-compare": 2,
109 | "no-sequences": 2,
110 | "no-shadow": 0,
111 | "no-shadow-restricted-names": 2,
112 | "no-spaced-func": 2,
113 | "no-sparse-arrays": 2,
114 | "no-sync": 0,
115 | "no-ternary": 0,
116 | "no-this-before-super": 2,
117 | "no-throw-literal": 2,
118 | "no-trailing-spaces": 2,
119 | "no-undef": 2,
120 | "no-undef-init": 2,
121 | "no-undefined": 0,
122 | "no-underscore-dangle": 0,
123 | "no-unexpected-multiline": 2,
124 | "no-unneeded-ternary": 2,
125 | "no-unreachable": 2,
126 | "no-unused-expressions": 0,
127 | "no-unused-vars": [2, { "vars": "all", "args": "none" }],
128 | "no-use-before-define": 0,
129 | "no-var": 0,
130 | "no-void": 0,
131 | "no-warning-comments": 0,
132 | "no-with": 2,
133 | "object-curly-spacing": 0,
134 | "object-shorthand": 0,
135 | "one-var": [2, { "initialized": "never" }],
136 | "operator-assignment": 0,
137 | "operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before" } }],
138 | "padded-blocks": 0,
139 | "prefer-const": 0,
140 | "quote-props": 0,
141 | "quotes": [2, "single", "avoid-escape"],
142 | "radix": 2,
143 | "semi": [2, "never"],
144 | "semi-spacing": 0,
145 | "sort-vars": 0,
146 | "space-after-keywords": [2, "always"],
147 | "space-before-blocks": [2, "always"],
148 | "space-before-function-paren": [2, "always"],
149 | "space-in-parens": [2, "never"],
150 | "space-infix-ops": 2,
151 | "space-return-throw-case": 2,
152 | "space-unary-ops": [2, { "words": true, "nonwords": false }],
153 | "spaced-comment": [2, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!"] }],
154 | "strict": 0,
155 | "use-isnan": 2,
156 | "valid-jsdoc": 0,
157 | "valid-typeof": 2,
158 | "vars-on-top": 0,
159 | "wrap-iife": [2, "any"],
160 | "wrap-regex": 0,
161 | "yoda": [2, "never"]
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/component/date-picker/util.js:
--------------------------------------------------------------------------------
1 | const MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
2 |
3 | export function isLeapYear(year) {
4 | return typeof year === 'number' && (year % 100 === 0 ? year % 400 === 0 : year % 4 === 0)
5 | }
6 |
7 | let testFullDate
8 | let testFullSec = 0
9 | const isLessThen = function (year, month, date, minDate) {
10 | if (minDate === -1) return false
11 | // if (date === 30) debugger
12 | // testFullDate.setFullYear(year)
13 | // testFullDate.setMonth(month)
14 | // testFullDate.setDate(date)
15 | // testFullDate.setHours(23)
16 | // testFullDate.setMinutes(59)
17 | // testFullDate.setSeconds(59)
18 | testFullDate = new Date(year, month, date, 23, 59, 59)
19 |
20 | testFullSec = testFullDate.getTime()
21 |
22 | return testFullSec <= minDate
23 | }
24 |
25 | const isLargerThen = function (year, month, date, maxDate) {
26 | if (maxDate === -1) return false
27 | // if (date === 30) debugger
28 | // testFullDate.setFullYear(year)
29 | // testFullDate.setMonth(month)
30 | // testFullDate.setDate(date)
31 | // testFullDate.setHours(0)
32 | // testFullDate.setMinutes(0)
33 | // testFullDate.setSeconds(0)
34 | testFullDate = new Date(year, month, date, 0, 0, 0)
35 |
36 | testFullSec = testFullDate.getTime()
37 |
38 | return testFullSec >= maxDate
39 | }
40 |
41 | // 获取正常的每个月的日期的数组
42 | export function getNormalDateArray(year, month, today, { maxDate, minDate, valueDate }) {
43 | let todayYear = today.getFullYear()
44 | let todayMonth = today.getMonth()
45 | let todayDate = today.getDate()
46 | let isThisYearMonth = todayYear === year && todayMonth === month
47 |
48 | let length = MONTH_DAYS[month]
49 |
50 | if (length === 28) {
51 | length = isLeapYear(year) ? 29 : 28
52 | }
53 |
54 | let arr = []
55 | for (let i=0; itable{
137 | width : 100%;
138 | text-align: center;
139 |
140 | td{
141 | height: 52px;
142 | }
143 |
144 | .month-item{
145 | display: inline-block;
146 | border-radius: 2px;
147 | padding : 1px 8px;
148 | cursor: pointer;
149 | transition: all .3s;
150 | color: #000000;
151 | font-size: 12px;
152 | &:hover{
153 | background-color: #eee;
154 | text-decoration: none;
155 | }
156 |
157 | &.selected{
158 | background-color: #009ce5;
159 | color: #ffffff;
160 | &.this-month{
161 | color: #ffffff;
162 | border: 1px solid #009ce5;
163 | }
164 | }
165 |
166 | &.disabled{
167 | color: #aeaeae;
168 | &:hover{
169 | cursor: not-allowed;
170 | background-color: transparent;
171 | }
172 | }
173 |
174 | &.this-month{
175 | color: #009ce5;
176 | border: 1px solid #009ce5;
177 | }
178 |
179 | }
180 | }
181 | }
182 |
183 |
184 | // year picker
185 | .x-year-picker{
186 | ul {
187 | margin : 0;
188 | padding : 0;
189 | }
190 | table{
191 | width : 100%;
192 | text-align: center;
193 | }
194 | }
195 | .year-item{
196 | display: inline-block;
197 | float : left;
198 | width : 68px;
199 | height : 52px;
200 | text-align: center;
201 | }
202 | .control-item{
203 | display: block;
204 | float : left;
205 | width : 68px;
206 | height: 52px;
207 | text-align: center;
208 |
209 | .year-picker-item{
210 | color : #999999;
211 | margin-top : 12px;
212 | &:hover{
213 | color : #009ce5;
214 | background-color: transparent;
215 | }
216 | }
217 | }
218 | .year-picker-item{
219 | display: inline-block;
220 | padding : 2px 8px;
221 | margin-top : 15px;
222 | font-size: 12px;
223 | color : #000000;
224 | border-radius: 2px;
225 | &.this-year{
226 | color: #009ce5;
227 | border: 1px solid #009ce5;
228 | }
229 | &.selected{
230 | text-decoration: none;
231 | color : #ffffff;
232 | background-color: #009ce5;
233 | }
234 | &:hover{
235 | text-decoration: none;
236 | color : #ffffff;
237 | background-color: #009ce5;
238 | }
239 | &.disabled{
240 | color: #aeaeae;
241 | &:hover{
242 | cursor: not-allowed;
243 | background-color: transparent;
244 | }
245 | }
246 | }
247 |
248 | .x-time-picker {
249 | //padding: 10px;
250 | }
251 |
252 | .done {
253 | width: 93%;
254 | padding: .1rem .75rem;
255 | margin: 0 auto;
256 | background-color: #009ce5;
257 | border-radius: 3px;
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/src/component/date-picker/time-picker.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
178 |
179 |
224 |
--------------------------------------------------------------------------------
/src/style/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */
2 |
3 | /**
4 | * 1. Change the default font family in all browsers (opinionated).
5 | * 2. Prevent adjustments of font size after orientation changes in IE and iOS.
6 | */
7 |
8 | html {
9 | font-family: sans-serif; /* 1 */
10 | -ms-text-size-adjust: 100%; /* 2 */
11 | -webkit-text-size-adjust: 100%; /* 2 */
12 | }
13 |
14 | /**
15 | * Remove the margin in all browsers (opinionated).
16 | */
17 |
18 | body {
19 | margin: 0;
20 | }
21 |
22 | /* HTML5 display definitions
23 | ========================================================================== */
24 |
25 | /**
26 | * Add the correct display in IE 9-.
27 | * 1. Add the correct display in Edge, IE, and Firefox.
28 | * 2. Add the correct display in IE.
29 | */
30 |
31 | article,
32 | aside,
33 | details, /* 1 */
34 | figcaption,
35 | figure,
36 | footer,
37 | header,
38 | main, /* 2 */
39 | menu,
40 | nav,
41 | section,
42 | summary { /* 1 */
43 | display: block;
44 | }
45 |
46 | /**
47 | * Add the correct display in IE 9-.
48 | */
49 |
50 | audio,
51 | canvas,
52 | progress,
53 | video {
54 | display: inline-block;
55 | }
56 |
57 | /**
58 | * Add the correct display in iOS 4-7.
59 | */
60 |
61 | audio:not([controls]) {
62 | display: none;
63 | height: 0;
64 | }
65 |
66 | /**
67 | * Add the correct vertical alignment in Chrome, Firefox, and Opera.
68 | */
69 |
70 | progress {
71 | vertical-align: baseline;
72 | }
73 |
74 | /**
75 | * Add the correct display in IE 10-.
76 | * 1. Add the correct display in IE.
77 | */
78 |
79 | template, /* 1 */
80 | [hidden] {
81 | display: none;
82 | }
83 |
84 | /* Links
85 | ========================================================================== */
86 |
87 | /**
88 | * Remove the gray background on active links in IE 10.
89 | */
90 |
91 | a {
92 | background-color: transparent;
93 | }
94 |
95 | /**
96 | * Remove the outline on focused links when they are also active or hovered
97 | * in all browsers (opinionated).
98 | */
99 |
100 | a:active,
101 | a:hover {
102 | outline-width: 0;
103 | }
104 |
105 | /* Text-level semantics
106 | ========================================================================== */
107 |
108 | /**
109 | * 1. Remove the bottom border in Firefox 39-.
110 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
111 | */
112 |
113 | abbr[title] {
114 | border-bottom: none; /* 1 */
115 | text-decoration: underline; /* 2 */
116 | text-decoration: underline dotted; /* 2 */
117 | }
118 |
119 | /**
120 | * Prevent the duplicate application of `bolder` by the next rule in Safari 6.
121 | */
122 |
123 | b,
124 | strong {
125 | font-weight: inherit;
126 | }
127 |
128 | /**
129 | * Add the correct font weight in Chrome, Edge, and Safari.
130 | */
131 |
132 | b,
133 | strong {
134 | font-weight: bolder;
135 | }
136 |
137 | /**
138 | * Add the correct font style in Android 4.3-.
139 | */
140 |
141 | dfn {
142 | font-style: italic;
143 | }
144 |
145 | /**
146 | * Correct the font size and margin on `h1` elements within `section` and
147 | * `article` contexts in Chrome, Firefox, and Safari.
148 | */
149 |
150 | h1 {
151 | font-size: 2em;
152 | margin: 0.67em 0;
153 | }
154 |
155 | /**
156 | * Add the correct background and color in IE 9-.
157 | */
158 |
159 | mark {
160 | background-color: #ff0;
161 | color: #000;
162 | }
163 |
164 | /**
165 | * Add the correct font size in all browsers.
166 | */
167 |
168 | small {
169 | font-size: 80%;
170 | }
171 |
172 | /**
173 | * Prevent `sub` and `sup` elements from affecting the line height in
174 | * all browsers.
175 | */
176 |
177 | sub,
178 | sup {
179 | font-size: 75%;
180 | line-height: 0;
181 | position: relative;
182 | vertical-align: baseline;
183 | }
184 |
185 | sub {
186 | bottom: -0.25em;
187 | }
188 |
189 | sup {
190 | top: -0.5em;
191 | }
192 |
193 | /* Embedded content
194 | ========================================================================== */
195 |
196 | /**
197 | * Remove the border on images inside links in IE 10-.
198 | */
199 |
200 | img {
201 | border-style: none;
202 | }
203 |
204 | /**
205 | * Hide the overflow in IE.
206 | */
207 |
208 | svg:not(:root) {
209 | overflow: hidden;
210 | }
211 |
212 | /* Grouping content
213 | ========================================================================== */
214 |
215 | /**
216 | * 1. Correct the inheritance and scaling of font size in all browsers.
217 | * 2. Correct the odd `em` font sizing in all browsers.
218 | */
219 |
220 | code,
221 | kbd,
222 | pre,
223 | samp {
224 | font-family: monospace, monospace; /* 1 */
225 | font-size: 1em; /* 2 */
226 | }
227 |
228 | /**
229 | * Add the correct margin in IE 8.
230 | */
231 |
232 | figure {
233 | margin: 1em 40px;
234 | }
235 |
236 | /**
237 | * 1. Add the correct box sizing in Firefox.
238 | * 2. Show the overflow in Edge and IE.
239 | */
240 |
241 | hr {
242 | box-sizing: content-box; /* 1 */
243 | height: 0; /* 1 */
244 | overflow: visible; /* 2 */
245 | }
246 |
247 | /* Forms
248 | ========================================================================== */
249 |
250 | /**
251 | * Change font properties to `inherit` in all browsers (opinionated).
252 | */
253 |
254 | button,
255 | input,
256 | select,
257 | textarea {
258 | font: inherit;
259 | }
260 |
261 | /**
262 | * Restore the font weight unset by the previous rule.
263 | */
264 |
265 | optgroup {
266 | font-weight: bold;
267 | }
268 |
269 | /**
270 | * Show the overflow in IE.
271 | * 1. Show the overflow in Edge.
272 | * 2. Show the overflow in Edge, Firefox, and IE.
273 | */
274 |
275 | button,
276 | input, /* 1 */
277 | select { /* 2 */
278 | overflow: visible;
279 | }
280 |
281 | /**
282 | * Remove the margin in Safari.
283 | * 1. Remove the margin in Firefox and Safari.
284 | */
285 |
286 | button,
287 | input,
288 | select,
289 | textarea { /* 1 */
290 | margin: 0;
291 | }
292 |
293 | /**
294 | * Remove the inheritence of text transform in Edge, Firefox, and IE.
295 | * 1. Remove the inheritence of text transform in Firefox.
296 | */
297 |
298 | button,
299 | select { /* 1 */
300 | text-transform: none;
301 | }
302 |
303 | /**
304 | * Change the cursor in all browsers (opinionated).
305 | */
306 |
307 | button,
308 | [type="button"],
309 | [type="reset"],
310 | [type="submit"] {
311 | cursor: pointer;
312 | }
313 |
314 | /**
315 | * Restore the default cursor to disabled elements unset by the previous rule.
316 | */
317 |
318 | [disabled] {
319 | cursor: default;
320 | }
321 |
322 | /**
323 | * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
324 | * controls in Android 4.
325 | * 2. Correct the inability to style clickable types in iOS.
326 | */
327 |
328 | button,
329 | html [type="button"], /* 1 */
330 | [type="reset"],
331 | [type="submit"] {
332 | -webkit-appearance: button; /* 2 */
333 | }
334 |
335 | /**
336 | * Remove the inner border and padding in Firefox.
337 | */
338 |
339 | button::-moz-focus-inner,
340 | input::-moz-focus-inner {
341 | border: 0;
342 | padding: 0;
343 | }
344 |
345 | /**
346 | * Restore the focus styles unset by the previous rule.
347 | */
348 |
349 | button:-moz-focusring,
350 | input:-moz-focusring {
351 | outline: 1px dotted ButtonText;
352 | }
353 |
354 | /**
355 | * Change the border, margin, and padding in all browsers (opinionated).
356 | */
357 |
358 | fieldset {
359 | border: 1px solid #c0c0c0;
360 | margin: 0 2px;
361 | padding: 0.35em 0.625em 0.75em;
362 | }
363 |
364 | /**
365 | * 1. Correct the text wrapping in Edge and IE.
366 | * 2. Correct the color inheritance from `fieldset` elements in IE.
367 | * 3. Remove the padding so developers are not caught out when they zero out
368 | * `fieldset` elements in all browsers.
369 | */
370 |
371 | legend {
372 | box-sizing: border-box; /* 1 */
373 | color: inherit; /* 2 */
374 | display: table; /* 1 */
375 | max-width: 100%; /* 1 */
376 | padding: 0; /* 3 */
377 | white-space: normal; /* 1 */
378 | }
379 |
380 | /**
381 | * Remove the default vertical scrollbar in IE.
382 | */
383 |
384 | textarea {
385 | overflow: auto;
386 | }
387 |
388 | /**
389 | * 1. Add the correct box sizing in IE 10-.
390 | * 2. Remove the padding in IE 10-.
391 | */
392 |
393 | [type="checkbox"],
394 | [type="radio"] {
395 | box-sizing: border-box; /* 1 */
396 | padding: 0; /* 2 */
397 | }
398 |
399 | /**
400 | * Correct the cursor style of increment and decrement buttons in Chrome.
401 | */
402 |
403 | [type="number"]::-webkit-inner-spin-button,
404 | [type="number"]::-webkit-outer-spin-button {
405 | height: auto;
406 | }
407 |
408 | /**
409 | * Correct the odd appearance of search inputs in Chrome and Safari.
410 | */
411 |
412 | [type="search"] {
413 | -webkit-appearance: textfield;
414 | }
415 |
416 | /**
417 | * Remove the inner padding and cancel buttons in Chrome on OS X and
418 | * Safari on OS X.
419 | */
420 |
421 | [type="search"]::-webkit-search-cancel-button,
422 | [type="search"]::-webkit-search-decoration {
423 | -webkit-appearance: none;
424 | }
425 |
--------------------------------------------------------------------------------
/src/component/date-picker/date-time-picker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * // 核心功能
3 | * format: YYYY-MM-DD HH:mm:ss
4 | * 如果有DD, 则整个Date picker都显示
5 | * 如果没有根据最近的一个现实picker
6 | * 时间类似
7 | *
8 | * v-date-time-picker:range.start="name"
9 | * argument: range // 这是一个range时间选择
10 | * modifiers: {start: true, end: false} // 代表这是一个range的开始选择
11 | * expression: name // 代表这个range的名字,每个名字的range只能有一个start和end,不然报错
12 | * value: name代表的值
13 | *
14 | * closeOnSelected: Boolean default true
15 | * 是否在选择完了之后关闭选择器
16 | *
17 | * highlightToday: Boolean default true
18 | * 当前日期是否高亮
19 | *
20 | * weekStart: 0-6 代表 周日到周六
21 | *
22 | * method: focus or click
23 | *
24 | * // 非核心功能
25 | * default: 默认时间,在bind中给vm设置这个值
26 | *
27 | * lang: 国际化
28 | */
29 |
30 | import Vue from 'vue'
31 |
32 | import dateTimePicker from './date-time-picker.vue'
33 | import { formatDate, parseDateTime } from './util'
34 |
35 | import EventListener from '../../util/EventListener'
36 | import { getBodyScrollTop } from '../../util/dom'
37 |
38 | const parseDirective = Vue.parsers.directive.parseDirective
39 | const { createAnchor, after, on, off } = Vue.util
40 |
41 | const template = ''
55 |
56 | const body = document.querySelector('body')
57 | const REGEX_FILTER = /[^|]\|[^|]/
58 |
59 | const Component = Vue.extend({
60 | template,
61 | components: {
62 | dateTimePicker
63 | }
64 | })
65 |
66 | const RANGE_CONTROL = new Vue()
67 |
68 | // real directive
69 | export default {
70 |
71 | params: [
72 | 'value',
73 | 'format',
74 | 'default',
75 | 'highlightToday',
76 | 'closeOnSelected',
77 | 'maxDate',
78 | 'minDate',
79 | 'align' // 对齐,left or right
80 | ],
81 |
82 | paramWatchers: {
83 | highlightToday (val) {
84 | this.__vm.highlightToday = !!val
85 | },
86 | minDate (val) {
87 | this.__vm.minDate = parseDateTime(val)
88 | },
89 | maxDate (val) {
90 | this.__vm.maxDate = parseDateTime(val)
91 | }
92 | },
93 |
94 | bind () {
95 | // console.log(this.params)
96 | const el = this.el
97 | let _range = this.modifiers
98 | let _rangeName = this.expression
99 |
100 | // get v-model attr
101 | let raw = el.getAttribute('v-model')
102 | let { model } = this.parseModelRaw(raw)
103 | this.model = model
104 | this.params.format = this.params.format || 'yyyy-MM-dd'
105 | this.isDateEnabled = /yyyy|MM|dd/.test(this.params.format)
106 |
107 | // create date picker Vue instance
108 | this.__vm = this.createVm()
109 | this.setVmValue()
110 |
111 | // create start and end anchor to help insert picker into body end
112 | let startAnchor = createAnchor('date time picker start')
113 | let endAnchor = createAnchor('date time picker end')
114 |
115 | // // insert to body end
116 | after(startAnchor, body.lastChild)
117 | after(endAnchor, startAnchor)
118 |
119 | // 设置range属性
120 | if (_range.start) {
121 | this.isStart = true
122 | } else if (_range.end) {
123 | this.isEnd = true
124 | }
125 |
126 | if ((this.isStart || this.isEnd) && !_rangeName) {
127 | return
128 | }
129 |
130 | if (this.isStart || this.isEnd) {
131 | this.doWithRange()
132 | }
133 |
134 | // watch model, model变化重新设置组件的value
135 | this.watchModel()
136 |
137 | // do mount
138 | this.__vm.$mount()
139 | this.__vm.$before(endAnchor)
140 | this.__vm.$el = this.__vm.$el.childNodes[0]
141 |
142 | // 根据目标节点绑定事件控制控件显示
143 | this.bindEvent()
144 | },
145 |
146 | unbind () {
147 | if (this._removeEventBind) {
148 | this._removeEventBind()
149 | }
150 |
151 | if (this._removeRangeControl) this._removeRangeControl()
152 | },
153 |
154 | /*
155 | * watch this.vm[model], 如果变化则改变this.__vm.value
156 | */
157 | watchModel() {
158 | if (!this.model) return
159 | this.vm.$watch(this.model, () => {
160 | this.setVmValue()
161 | })
162 | },
163 |
164 | /*
165 | * 根据父vm的model的值设置value
166 | */
167 | setVmValue() {
168 | let value = this.vm.$get(this.model || '')
169 | if (!value) {
170 | return
171 | }
172 | let seconds = parseDateTime(value)
173 | if (!isNaN(seconds)) {
174 | this.__vm.value = seconds
175 | }
176 | },
177 |
178 | // bind events to toggle date time picker
179 | bindEvent() {
180 | const focusCb = () => {
181 | // TODO:这样的定位方式存在一些缺陷
182 | // 如果存在局部滚动,在局部滚动的时候就会出现错位
183 | let rect = this.el.getBoundingClientRect()
184 | let bodyScrollTop = getBodyScrollTop()
185 | this.__vm.$set('rect', {
186 | left: rect.left + document.body.scrollLeft,
187 | right: rect.right,
188 | top: rect.top + bodyScrollTop,
189 | bottom: rect.bottom,
190 | width: rect.width || this.el.clientWidth,
191 | height: rect.height || this.el.clientHeight
192 | })
193 | this.__vm.show = true
194 | }
195 |
196 | let self = this
197 |
198 | // important: 使用vm.$mount生成的节点,给vm设置的$el是一个注释节点
199 | // 只有使用nextElementSibling来获取模板生成的节点
200 | const _closeListener = EventListener.listen(window, 'click', (e) => {
201 | // if (self.el &&
202 | // !self.el.contains(e.target) &&
203 | // self.__vm.$el &&
204 | // !self.__vm.$el.contains(e.target)) self.__vm.show = false
205 | if (e.target !== this.el) self.__vm.show = false
206 | })
207 |
208 | const _closeEleListener = EventListener.listen(this.__vm.$el, 'click', (e) => {
209 | e.stopPropagation()
210 | })
211 |
212 | // const _closeTargetListener = EventListener.listen(this.el, 'click', (e) => {
213 | // e.stopPropagation()
214 | // })
215 |
216 | on(this.el, 'focus', focusCb)
217 |
218 | // on(this.el, 'blur', () => {
219 | // this.__vm.show = false
220 | // })
221 |
222 | this._removeEventBind = function () {
223 | off(this.el, 'focus', focusCb)
224 | _closeListener.remove()
225 | _closeEleListener.remove()
226 | // _closeTargetListener.remove()
227 | }
228 | },
229 |
230 | // create date-time-picker Vue instance with init data and components
231 | createVm() {
232 | const _this = this
233 | let vm = new Component({
234 | replace: false,
235 | data: {
236 | show: false,
237 | rect: {},
238 | value: null,
239 | highlightToday: _this.params.highlightToday,
240 | align: _this.params.align,
241 | minDate: parseDateTime(this.params.minDate) || -1,
242 | maxDate: parseDateTime(this.params.maxDate) || -1,
243 | format: _this.params.format,
244 | },
245 | methods: {
246 | onChange (value) {
247 | this.value = parseDateTime(value)
248 | },
249 | onComplete (value) {
250 | value = value || new Date()
251 | // 如果设置了在选择时关闭则设置show为false
252 | if (_this.params.closeOnSelected !== false) {
253 | this.show = false
254 | }
255 | // set value to modle
256 | if (_this.model) {
257 | _this.vm.$set(_this.model, formatDate(value, _this.params.format))
258 | } else {
259 | _this.el.value = formatDate(value, _this.params.format)
260 | }
261 | // 如果有设置range时间的方法,则执行
262 | // 只通过判断是否有该方法判断是否是range
263 | if (_this.setRangeTime) _this.setRangeTime(value)
264 | }
265 | }
266 | })
267 |
268 | return vm
269 | },
270 |
271 | parseModelRaw (raw) {
272 | if (REGEX_FILTER.test(raw)) {
273 | let parsed = parseDirective(raw)
274 | return { model: parsed.expression, filters: parsed.filters }
275 | } else {
276 | return { model: raw }
277 | }
278 | },
279 |
280 | /**
281 | * put this into range control
282 | * listen to range change to control picker to control range
283 | */
284 | doWithRange() {
285 | let rc = RANGE_CONTROL
286 | let rangeName = this.expression
287 | let rangeType = this.isStart ? 'start' : 'end'
288 | let rangeOtherType = this.isStart ? 'end' : 'start'
289 | // debugger
290 | let initModel = this.vm.$get(this.model || '')
291 | let initDate = parseDateTime(initModel)
292 | //
293 | Vue.set(this.__vm, rangeOtherType + 'Date', -1)
294 | // 初始化
295 | if (!rc[rangeName]) {
296 | Vue.set(rc, rangeName, {
297 | start: -1,
298 | end: -1
299 | })
300 | }
301 | // expression start startValue
302 | // 给range中间vue对象中的自己设置初始值
303 | // 等待range所有组件初始化完毕
304 | Vue.nextTick(() => {
305 | Vue.set(rc[rangeName], rangeType, initDate || -1)
306 | })
307 | let unWatchRange = rc.$watch(rangeName + '.' + rangeOtherType, (newVal) => {
308 | // if (newVal[rangeOtherType] !== oldVal[rangeOtherType]) {
309 | // 设置 this.__vm相关的数据
310 | this.__vm[rangeOtherType + 'Date'] = newVal
311 | // }
312 | }, { deep: true })
313 | this.setRangeTime = function (time) {
314 | rc[rangeName][rangeType] = time
315 | }
316 | this._removeRangeControl = function () {
317 | unWatchRange()
318 | if (rc[rangeName]) {
319 | // Vue.delete(rc, rangeName)
320 | rc[rangeName] = null
321 | }
322 | }
323 | }
324 |
325 | }
326 |
--------------------------------------------------------------------------------
/src/component/date-picker/date-time-picker.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
42 |
43 |
49 |
50 |
55 |
56 |
59 |
60 |
61 |
65 |
66 |
69 |
70 |
71 |
72 |
73 |
338 |
--------------------------------------------------------------------------------
/doc/doc.styl:
--------------------------------------------------------------------------------
1 | body{
2 | font-size: 14px;
3 | }
4 | #x-vue-menu{
5 | position : fixed;
6 | width : 260px;
7 | top : 0;
8 | bottom : 0;
9 | //border-right: 1px solid #ddd;
10 | background-color: #efefef;
11 | box-shadow: 2px 0 3px #dadada;
12 |
13 | ul{
14 | list-style: none;
15 | padding : 0;
16 | }
17 |
18 | .menu-item{
19 | height : 40px;
20 | line-height: 40px;
21 | padding : 0 20px;
22 | text-decoration: none;
23 | color: #333;
24 | text-align: right;
25 | display: block;
26 | transition: all .5s;
27 |
28 | &:hover{
29 | background-color: #0b97c4;
30 | color: #ffffff;
31 | }
32 |
33 | }
34 |
35 | }
36 | #x-vue-title{
37 | height : 50px;
38 | background-color: #0b97c4;
39 | color: #ffffff;
40 | padding-right : 20px;
41 | text-align: right;
42 | font-size: 28px;
43 | line-height: 50px;
44 | font-weight: 900;
45 | }
46 | #container{
47 | margin-left: 260px;
48 | padding : 20px;
49 | }
50 |
51 | .x-vue-example-panel{
52 | .card{
53 | max-width: 300px;
54 | }
55 | }
56 |
57 |
58 | // markdown
59 | //@font-face {
60 | // font-family: octicons-link;
61 | // src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff');
62 | //}
63 |
64 | .markdown-body {
65 | -ms-text-size-adjust: 100%;
66 | -webkit-text-size-adjust: 100%;
67 | color: #333;
68 | font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
69 | font-size: 16px;
70 | line-height: 1.6;
71 | word-wrap: break-word;
72 | }
73 |
74 | .markdown-body a {
75 | background-color: transparent;
76 | -webkit-text-decoration-skip: objects;
77 | }
78 |
79 | .markdown-body a:active,
80 | .markdown-body a:hover {
81 | outline-width: 0;
82 | }
83 |
84 | .markdown-body strong {
85 | font-weight: inherit;
86 | }
87 |
88 | .markdown-body strong {
89 | font-weight: bolder;
90 | }
91 |
92 | .markdown-body h1 {
93 | font-size: 2em;
94 | margin: 0.67em 0;
95 | }
96 |
97 | .markdown-body img {
98 | border-style: none;
99 | }
100 |
101 | .markdown-body svg:not(:root) {
102 | overflow: hidden;
103 | }
104 |
105 | .markdown-body code,
106 | .markdown-body kbd,
107 | .markdown-body pre {
108 | font-family: monospace, monospace;
109 | font-size: 1em;
110 | }
111 |
112 | .markdown-body hr {
113 | box-sizing: content-box;
114 | height: 0;
115 | overflow: visible;
116 | }
117 |
118 | .markdown-body input {
119 | font: inherit;
120 | margin: 0;
121 | }
122 |
123 | .markdown-body input {
124 | overflow: visible;
125 | }
126 |
127 | .markdown-body button:-moz-focusring,
128 | .markdown-body [type="button"]:-moz-focusring,
129 | .markdown-body [type="reset"]:-moz-focusring,
130 | .markdown-body [type="submit"]:-moz-focusring {
131 | outline: 1px dotted ButtonText;
132 | }
133 |
134 | .markdown-body [type="checkbox"] {
135 | box-sizing: border-box;
136 | padding: 0;
137 | }
138 |
139 | .markdown-body table {
140 | border-spacing: 0;
141 | border-collapse: collapse;
142 | }
143 |
144 | .markdown-body td,
145 | .markdown-body th {
146 | padding: 0;
147 | }
148 |
149 | .markdown-body * {
150 | box-sizing: border-box;
151 | }
152 |
153 | .markdown-body input {
154 | font: 13px/1.4 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
155 | }
156 |
157 | .markdown-body a {
158 | color: #4078c0;
159 | text-decoration: none;
160 | }
161 |
162 | .markdown-body a:hover,
163 | .markdown-body a:active {
164 | text-decoration: underline;
165 | }
166 |
167 | .markdown-body hr {
168 | height: 0;
169 | margin: 15px 0;
170 | overflow: hidden;
171 | background: transparent;
172 | border: 0;
173 | border-bottom: 1px solid #ddd;
174 | }
175 |
176 | .markdown-body hr::before {
177 | display: table;
178 | content: "";
179 | }
180 |
181 | .markdown-body hr::after {
182 | display: table;
183 | clear: both;
184 | content: "";
185 | }
186 |
187 | .markdown-body h1,
188 | .markdown-body h2,
189 | .markdown-body h3,
190 | .markdown-body h4,
191 | .markdown-body h5,
192 | .markdown-body h6 {
193 | margin-top: 0;
194 | margin-bottom: 0;
195 | line-height: 1.5;
196 | }
197 |
198 | .markdown-body h1 {
199 | font-size: 30px;
200 | }
201 |
202 | .markdown-body h2 {
203 | font-size: 21px;
204 | }
205 |
206 | .markdown-body h3 {
207 | font-size: 16px;
208 | }
209 |
210 | .markdown-body h4 {
211 | font-size: 14px;
212 | }
213 |
214 | .markdown-body h5 {
215 | font-size: 12px;
216 | }
217 |
218 | .markdown-body h6 {
219 | font-size: 11px;
220 | }
221 |
222 | .markdown-body p {
223 | margin-top: 0;
224 | margin-bottom: 10px;
225 | }
226 |
227 | .markdown-body blockquote {
228 | margin: 0;
229 | }
230 |
231 | .markdown-body ul,
232 | .markdown-body ol {
233 | padding-left: 0;
234 | margin-top: 0;
235 | margin-bottom: 0;
236 | }
237 |
238 | .markdown-body ol ol,
239 | .markdown-body ul ol {
240 | list-style-type: lower-roman;
241 | }
242 |
243 | .markdown-body ul ul ol,
244 | .markdown-body ul ol ol,
245 | .markdown-body ol ul ol,
246 | .markdown-body ol ol ol {
247 | list-style-type: lower-alpha;
248 | }
249 |
250 | .markdown-body dd {
251 | margin-left: 0;
252 | }
253 |
254 | .markdown-body code {
255 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
256 | font-size: 12px;
257 | }
258 |
259 | .markdown-body pre {
260 | margin-top: 0;
261 | margin-bottom: 0;
262 | font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
263 | }
264 |
265 | .markdown-body .pl-0 {
266 | padding-left: 0 !important;
267 | }
268 |
269 | .markdown-body .pl-1 {
270 | padding-left: 3px !important;
271 | }
272 |
273 | .markdown-body .pl-2 {
274 | padding-left: 6px !important;
275 | }
276 |
277 | .markdown-body .pl-3 {
278 | padding-left: 12px !important;
279 | }
280 |
281 | .markdown-body .pl-4 {
282 | padding-left: 24px !important;
283 | }
284 |
285 | .markdown-body .pl-5 {
286 | padding-left: 36px !important;
287 | }
288 |
289 | .markdown-body .pl-6 {
290 | padding-left: 48px !important;
291 | }
292 |
293 | .markdown-body .form-select::-ms-expand {
294 | opacity: 0;
295 | }
296 |
297 | .markdown-body:before {
298 | display: table;
299 | content: "";
300 | }
301 |
302 | .markdown-body:after {
303 | display: table;
304 | clear: both;
305 | content: "";
306 | }
307 |
308 | .markdown-body>*:first-child {
309 | margin-top: 0 !important;
310 | }
311 |
312 | .markdown-body>*:last-child {
313 | margin-bottom: 0 !important;
314 | }
315 |
316 | .markdown-body a:not([href]) {
317 | color: inherit;
318 | text-decoration: none;
319 | }
320 |
321 | .markdown-body .anchor {
322 | display: inline-block;
323 | padding-right: 2px;
324 | margin-left: -18px;
325 | }
326 |
327 | .markdown-body .anchor:focus {
328 | outline: none;
329 | }
330 |
331 | .markdown-body h1,
332 | .markdown-body h2,
333 | .markdown-body h3,
334 | .markdown-body h4,
335 | .markdown-body h5,
336 | .markdown-body h6 {
337 | margin-top: 1em;
338 | margin-bottom: 16px;
339 | font-weight: bold;
340 | line-height: 1.4;
341 | }
342 |
343 | .markdown-body h1 .octicon-link,
344 | .markdown-body h2 .octicon-link,
345 | .markdown-body h3 .octicon-link,
346 | .markdown-body h4 .octicon-link,
347 | .markdown-body h5 .octicon-link,
348 | .markdown-body h6 .octicon-link {
349 | color: #000;
350 | vertical-align: middle;
351 | visibility: hidden;
352 | }
353 |
354 | .markdown-body h1:hover .anchor,
355 | .markdown-body h2:hover .anchor,
356 | .markdown-body h3:hover .anchor,
357 | .markdown-body h4:hover .anchor,
358 | .markdown-body h5:hover .anchor,
359 | .markdown-body h6:hover .anchor {
360 | text-decoration: none;
361 | }
362 |
363 | .markdown-body h1:hover .anchor .octicon-link,
364 | .markdown-body h2:hover .anchor .octicon-link,
365 | .markdown-body h3:hover .anchor .octicon-link,
366 | .markdown-body h4:hover .anchor .octicon-link,
367 | .markdown-body h5:hover .anchor .octicon-link,
368 | .markdown-body h6:hover .anchor .octicon-link {
369 | visibility: visible;
370 | }
371 |
372 | .markdown-body h1 {
373 | padding-bottom: 0.3em;
374 | font-size: 2.25em;
375 | line-height: 1.2;
376 | border-bottom: 1px solid #eee;
377 | }
378 |
379 | .markdown-body h1 .anchor {
380 | line-height: 1;
381 | }
382 |
383 | .markdown-body h2 {
384 | padding-bottom: 0.3em;
385 | font-size: 1.75em;
386 | line-height: 1.225;
387 | border-bottom: 1px solid #eee;
388 | }
389 |
390 | .markdown-body h2 .anchor {
391 | line-height: 1;
392 | }
393 |
394 | .markdown-body h3 {
395 | font-size: 1.5em;
396 | line-height: 1.43;
397 | }
398 |
399 | .markdown-body h3 .anchor {
400 | line-height: 1.2;
401 | }
402 |
403 | .markdown-body h4 {
404 | font-size: 1.25em;
405 | }
406 |
407 | .markdown-body h4 .anchor {
408 | line-height: 1.2;
409 | }
410 |
411 | .markdown-body h5 {
412 | font-size: 1em;
413 | }
414 |
415 | .markdown-body h5 .anchor {
416 | line-height: 1.1;
417 | }
418 |
419 | .markdown-body h6 {
420 | font-size: 1em;
421 | color: #777;
422 | }
423 |
424 | .markdown-body h6 .anchor {
425 | line-height: 1.1;
426 | }
427 |
428 | .markdown-body p,
429 | .markdown-body blockquote,
430 | .markdown-body ul,
431 | .markdown-body ol,
432 | .markdown-body dl,
433 | .markdown-body table,
434 | .markdown-body pre {
435 | margin-top: 0;
436 | margin-bottom: 16px;
437 | }
438 |
439 | .markdown-body hr {
440 | height: 4px;
441 | padding: 0;
442 | margin: 16px 0;
443 | background-color: #e7e7e7;
444 | border: 0 none;
445 | }
446 |
447 | .markdown-body ul,
448 | .markdown-body ol {
449 | padding-left: 2em;
450 | }
451 |
452 | .markdown-body ul ul,
453 | .markdown-body ul ol,
454 | .markdown-body ol ol,
455 | .markdown-body ol ul {
456 | margin-top: 0;
457 | margin-bottom: 0;
458 | }
459 |
460 | .markdown-body li>p {
461 | margin-top: 16px;
462 | }
463 |
464 | .markdown-body dl {
465 | padding: 0;
466 | }
467 |
468 | .markdown-body dl dt {
469 | padding: 0;
470 | margin-top: 16px;
471 | font-size: 1em;
472 | font-style: italic;
473 | font-weight: bold;
474 | }
475 |
476 | .markdown-body dl dd {
477 | padding: 0 16px;
478 | margin-bottom: 16px;
479 | }
480 |
481 | .markdown-body blockquote {
482 | padding: 0 15px;
483 | color: #777;
484 | border-left: 4px solid #ddd;
485 | }
486 |
487 | .markdown-body blockquote>:first-child {
488 | margin-top: 0;
489 | }
490 |
491 | .markdown-body blockquote>:last-child {
492 | margin-bottom: 0;
493 | }
494 |
495 | .markdown-body table {
496 | display: block;
497 | width: 100%;
498 | overflow: auto;
499 | word-break: normal;
500 | word-break: keep-all;
501 | }
502 |
503 | .markdown-body table th {
504 | font-weight: bold;
505 | }
506 |
507 | .markdown-body table th,
508 | .markdown-body table td {
509 | padding: 6px 13px;
510 | border: 1px solid #ddd;
511 | }
512 |
513 | .markdown-body table tr {
514 | background-color: #fff;
515 | border-top: 1px solid #ccc;
516 | }
517 |
518 | .markdown-body table tr:nth-child(2n) {
519 | background-color: #f8f8f8;
520 | }
521 |
522 | .markdown-body img {
523 | max-width: 100%;
524 | box-sizing: content-box;
525 | background-color: #fff;
526 | }
527 |
528 | .markdown-body code {
529 | padding: 0;
530 | padding-top: 0.2em;
531 | padding-bottom: 0.2em;
532 | margin: 0;
533 | font-size: 85%;
534 | background-color: rgba(0,0,0,0.04);
535 | border-radius: 3px;
536 | }
537 |
538 | .markdown-body code:before,
539 | .markdown-body code:after {
540 | letter-spacing: -0.2em;
541 | content: "\00a0";
542 | }
543 |
544 | .markdown-body pre>code {
545 | padding: 0;
546 | margin: 0;
547 | font-size: 100%;
548 | word-break: normal;
549 | white-space: pre;
550 | background: transparent;
551 | border: 0;
552 | }
553 |
554 | .markdown-body .highlight {
555 | margin-bottom: 16px;
556 | }
557 |
558 | .markdown-body .highlight pre,
559 | .markdown-body pre {
560 | padding: 16px;
561 | overflow: auto;
562 | font-size: 85%;
563 | line-height: 1.45;
564 | background-color: #f7f7f7;
565 | border-radius: 3px;
566 | }
567 |
568 | .markdown-body .highlight pre {
569 | margin-bottom: 0;
570 | word-break: normal;
571 | }
572 |
573 | .markdown-body pre {
574 | word-wrap: normal;
575 | }
576 |
577 | .markdown-body pre code {
578 | display: inline;
579 | max-width: initial;
580 | padding: 0;
581 | margin: 0;
582 | overflow: initial;
583 | line-height: inherit;
584 | word-wrap: normal;
585 | background-color: transparent;
586 | border: 0;
587 | }
588 |
589 | .markdown-body pre code:before,
590 | .markdown-body pre code:after {
591 | content: normal;
592 | }
593 |
594 | .markdown-body kbd {
595 | display: inline-block;
596 | padding: 3px 5px;
597 | font-size: 11px;
598 | line-height: 10px;
599 | color: #555;
600 | vertical-align: middle;
601 | background-color: #fcfcfc;
602 | border: solid 1px #ccc;
603 | border-bottom-color: #bbb;
604 | border-radius: 3px;
605 | box-shadow: inset 0 -1px 0 #bbb;
606 | }
607 |
608 | .markdown-body .pl-c {
609 | color: #969896;
610 | }
611 |
612 | .markdown-body .pl-c1,
613 | .markdown-body .pl-s .pl-v {
614 | color: #0086b3;
615 | }
616 |
617 | .markdown-body .pl-e,
618 | .markdown-body .pl-en {
619 | color: #795da3;
620 | }
621 |
622 | .markdown-body .pl-s .pl-s1,
623 | .markdown-body .pl-smi {
624 | color: #333;
625 | }
626 |
627 | .markdown-body .pl-ent {
628 | color: #63a35c;
629 | }
630 |
631 | .markdown-body .pl-k {
632 | color: #a71d5d;
633 | }
634 |
635 | .markdown-body .pl-pds,
636 | .markdown-body .pl-s,
637 | .markdown-body .pl-s .pl-pse .pl-s1,
638 | .markdown-body .pl-sr,
639 | .markdown-body .pl-sr .pl-cce,
640 | .markdown-body .pl-sr .pl-sra,
641 | .markdown-body .pl-sr .pl-sre {
642 | color: #183691;
643 | }
644 |
645 | .markdown-body .pl-v {
646 | color: #ed6a43;
647 | }
648 |
649 | .markdown-body .pl-id {
650 | color: #b52a1d;
651 | }
652 |
653 | .markdown-body .pl-ii {
654 | background-color: #b52a1d;
655 | color: #f8f8f8;
656 | }
657 |
658 | .markdown-body .pl-sr .pl-cce {
659 | color: #63a35c;
660 | font-weight: bold;
661 | }
662 |
663 | .markdown-body .pl-ml {
664 | color: #693a17;
665 | }
666 |
667 | .markdown-body .pl-mh,
668 | .markdown-body .pl-mh .pl-en,
669 | .markdown-body .pl-ms {
670 | color: #1d3e81;
671 | font-weight: bold;
672 | }
673 |
674 | .markdown-body .pl-mq {
675 | color: #008080;
676 | }
677 |
678 | .markdown-body .pl-mi {
679 | color: #333;
680 | font-style: italic;
681 | }
682 |
683 | .markdown-body .pl-mb {
684 | color: #333;
685 | font-weight: bold;
686 | }
687 |
688 | .markdown-body .pl-md {
689 | background-color: #ffecec;
690 | color: #bd2c00;
691 | }
692 |
693 | .markdown-body .pl-mi1 {
694 | background-color: #eaffea;
695 | color: #55a532;
696 | }
697 |
698 | .markdown-body .pl-mdr {
699 | color: #795da3;
700 | font-weight: bold;
701 | }
702 |
703 | .markdown-body .pl-mo {
704 | color: #1d3e81;
705 | }
706 |
707 | .markdown-body kbd {
708 | display: inline-block;
709 | padding: 3px 5px;
710 | font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
711 | line-height: 10px;
712 | color: #555;
713 | vertical-align: middle;
714 | background-color: #fcfcfc;
715 | border: solid 1px #ccc;
716 | border-bottom-color: #bbb;
717 | border-radius: 3px;
718 | box-shadow: inset 0 -1px 0 #bbb;
719 | }
720 |
721 | .markdown-body .full-commit .btn-outline:not(:disabled):hover {
722 | color: #4078c0;
723 | border: 1px solid #4078c0;
724 | }
725 |
726 | .markdown-body :checked+.radio-label {
727 | position: relative;
728 | z-index: 1;
729 | border-color: #4078c0;
730 | }
731 |
732 | .markdown-body .octicon {
733 | display: inline-block;
734 | vertical-align: text-top;
735 | fill: currentColor;
736 | }
737 |
738 | .markdown-body .task-list-item {
739 | list-style-type: none;
740 | }
741 |
742 | .markdown-body .task-list-item+.task-list-item {
743 | margin-top: 3px;
744 | }
745 |
746 | .markdown-body .task-list-item input {
747 | margin: 0 0.2em 0.25em -1.6em;
748 | vertical-align: middle;
749 | }
750 |
751 | .markdown-body hr {
752 | border-bottom-color: #eee;
753 | }
754 |
755 |
--------------------------------------------------------------------------------