├── .eslintignore ├── .eslintrc ├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── .postcssrc ├── README.md ├── babel.config.js ├── build ├── rollup.config.base.js ├── rollup.config.browser.js ├── rollup.config.es.js └── rollup.config.umd.js ├── dist └── .gitkeep ├── docs-src ├── .babelrc ├── App.vue ├── assets │ └── logo.png ├── components │ └── MyTab.vue ├── demo-routes.js ├── helpers.js ├── main.js ├── router.js ├── store.js └── views │ ├── About.vue │ ├── Home.vue │ └── demos │ ├── Button.vue │ ├── ButtonGroup.vue │ ├── Colors.vue │ ├── Disable.vue │ ├── Dropdown.vue │ ├── Icon.vue │ ├── Input.vue │ ├── Loading.vue │ ├── Modal.vue │ ├── Select.vue │ ├── Switch.vue │ ├── Tabs.vue │ ├── Tooltip.vue │ └── TypeAhead.vue ├── docs ├── .nojekyll ├── css │ └── app.7d07430f.css ├── index.html ├── js │ ├── app.94ab3425.js │ ├── app.94ab3425.js.map │ ├── chunk-vendors.28127d79.js │ └── chunk-vendors.28127d79.js.map └── logo.png ├── package.json ├── public ├── .nojekyll ├── index.html └── logo.png ├── src ├── components │ ├── VueButton.vue │ ├── VueDisable.vue │ ├── VueDropdown.vue │ ├── VueDropdownButton.vue │ ├── VueFormField.vue │ ├── VueGroup.vue │ ├── VueGroupButton.vue │ ├── VueIcon.js │ ├── VueInput.vue │ ├── VueLoadingBar.js │ ├── VueLoadingIndicator.js │ ├── VueModal.vue │ ├── VueSelect.vue │ ├── VueSelectButton.vue │ ├── VueSwitch.vue │ ├── VueTab.vue │ ├── VueTabs.vue │ └── VueTypeAhead.vue ├── icons.js ├── index.js ├── mixins │ ├── CoupledChild.js │ ├── CoupledParent.js │ ├── DisableScroll.js │ ├── DisabledChild.js │ └── DisabledParent.js └── style │ ├── animation.styl │ ├── base.styl │ ├── colors.styl │ ├── imports.styl │ ├── md-colors.styl │ ├── mixins.styl │ ├── tooltip.styl │ └── vars.styl ├── vue.config.js └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "plugin:vue/essential", 5 | "@vue/standard" 6 | ], 7 | "rules": { 8 | "comma-dangle": ["error", "always-multiline"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: Akryum 2 | open_collective: vuejs 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | 4 | # local env files 5 | .env.local 6 | .env.*.local 7 | 8 | # Log files 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | 21 | /dist 22 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | docs/ 2 | docs-src/ 3 | public/ 4 | .babelrc 5 | .eslintrc 6 | .postcssrc 7 | -------------------------------------------------------------------------------- /.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "autoprefixer": {}, 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue UI Framework 2 | 3 | [![npm](https://img.shields.io/npm/v/@vue/ui.svg)](https://www.npmjs.com/package/@vue/ui) 4 | [![vue2](https://img.shields.io/badge/vue-2.5.13-brightgreen.svg)](https://vuejs.org/) 5 | 6 | This is a collection of components and styles meant to be used across all official Vue.js apps. 7 | 8 | ## Installation 9 | 10 | Install the `@vue/ui` package: 11 | 12 | ``` 13 | npm i -S @vue/ui 14 | ``` 15 | 16 | Install the Vue plugin: 17 | 18 | ```js 19 | import Vue from 'vue' 20 | import VueUi from '@vue/ui' 21 | 22 | Vue.use(VueUi) 23 | ``` 24 | 25 | Import the CSS: 26 | 27 | ```js 28 | import '@vue/ui/dist/vue-ui.css' 29 | ``` 30 | 31 | **Documentation is Work In Progress** 32 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'presets': [ 3 | '@vue/babel-preset-jsx', 4 | [ 5 | '@babel/env', { 6 | 'modules': false, 7 | }, 8 | ], 9 | ], 10 | } 11 | -------------------------------------------------------------------------------- /build/rollup.config.base.js: -------------------------------------------------------------------------------- 1 | import { babel } from '@rollup/plugin-babel' 2 | import resolve from '@rollup/plugin-node-resolve' 3 | import vue from 'rollup-plugin-vue' 4 | import cjs from '@rollup/plugin-commonjs' 5 | import replace from '@rollup/plugin-replace' 6 | import requireContext from 'rollup-plugin-require-context' 7 | import { string } from 'rollup-plugin-string' 8 | import fs from 'fs-extra' 9 | import CleanCSS from 'clean-css' 10 | import autoprefixer from 'autoprefixer' 11 | import css from 'rollup-plugin-css-only' 12 | 13 | const config = require('../package.json') 14 | 15 | export default { 16 | input: 'src/index.js', 17 | plugins: [ 18 | resolve({ 19 | mainFields: ['module', 'jsnext', 'main', 'browser'], 20 | }), 21 | string({ 22 | include: '**/*.svg', 23 | }), 24 | vue({ 25 | css: false, 26 | style: { 27 | postcssPlugins: [autoprefixer], 28 | }, 29 | }), 30 | babel({ 31 | exclude: 'node_modules/**', 32 | presets: [ 33 | '@vue/babel-preset-jsx', 34 | [ 35 | '@babel/env', { 36 | 'modules': false, 37 | }, 38 | ], 39 | ], 40 | }), 41 | css({ 42 | output: styles => { 43 | fs.ensureDirSync('dist') 44 | fs.writeFileSync('dist/vue-ui.css', new CleanCSS().minify(styles).styles) 45 | }, 46 | }), 47 | cjs({ 48 | exclude: 'src/**', 49 | }), 50 | requireContext(), 51 | replace({ 52 | VERSION: JSON.stringify(config.version), 53 | }), 54 | ], 55 | watch: { 56 | include: 'src/**', 57 | }, 58 | external: [ 59 | 'vue', 60 | ], 61 | } 62 | -------------------------------------------------------------------------------- /build/rollup.config.browser.js: -------------------------------------------------------------------------------- 1 | import base from './rollup.config.base' 2 | import { terser } from 'rollup-plugin-terser' 3 | 4 | const config = Object.assign({}, base, { 5 | output: { 6 | exports: 'named', 7 | name: 'VueUi', 8 | file: 'dist/vue-ui.min.js', 9 | format: 'iife', 10 | sourcemap: true, 11 | globals: { 12 | vue: 'Vue', 13 | }, 14 | }, 15 | }) 16 | 17 | config.plugins.push(terser()) 18 | 19 | export default config 20 | -------------------------------------------------------------------------------- /build/rollup.config.es.js: -------------------------------------------------------------------------------- 1 | import base from './rollup.config.base' 2 | 3 | const config = Object.assign({}, base, { 4 | output: { 5 | name: 'vue-ui', 6 | file: 'dist/vue-ui.esm.js', 7 | format: 'es', 8 | sourcemap: true, 9 | }, 10 | external: [ 11 | ...base.external, 12 | 'focus-visible', 13 | 'v-tooltip', 14 | 'vue-resize', 15 | ], 16 | }) 17 | 18 | export default config 19 | -------------------------------------------------------------------------------- /build/rollup.config.umd.js: -------------------------------------------------------------------------------- 1 | import base from './rollup.config.base' 2 | 3 | const config = Object.assign({}, base, { 4 | output: { 5 | exports: 'named', 6 | name: 'vue-ui', 7 | file: 'dist/vue-ui.umd.js', 8 | format: 'umd', 9 | sourcemap: true, 10 | }, 11 | }) 12 | 13 | export default config 14 | -------------------------------------------------------------------------------- /dist/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/ui/63f67359862e9ef8d5e679172e4aa01f922271be/dist/.gitkeep -------------------------------------------------------------------------------- /docs-src/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@vue/app" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /docs-src/App.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 30 | 31 | 81 | -------------------------------------------------------------------------------- /docs-src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/ui/63f67359862e9ef8d5e679172e4aa01f922271be/docs-src/assets/logo.png -------------------------------------------------------------------------------- /docs-src/components/MyTab.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /docs-src/demo-routes.js: -------------------------------------------------------------------------------- 1 | const nameReg = /([a-z0-9]+)\./i 2 | const demos = require.context('./views/demos', true, /[a-z0-9]+\.(jsx?|vue)$/i) 3 | 4 | export default demos.keys().map(key => { 5 | const name = key.match(nameReg)[1] 6 | return { 7 | path: `${name.toLowerCase()}`, 8 | name: `demo-${name.toLowerCase()}`, 9 | component: demos(key).default, 10 | meta: { 11 | label: name, 12 | }, 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /docs-src/helpers.js: -------------------------------------------------------------------------------- 1 | export function versionCompare (v1, v2, options) { 2 | const lexicographical = options && options.lexicographical 3 | const zeroExtend = options && options.zeroExtend 4 | let v1parts = v1.split('.') 5 | let v2parts = v2.split('.') 6 | 7 | function isValidPart (x) { 8 | return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x) 9 | } 10 | 11 | if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) { 12 | return NaN 13 | } 14 | 15 | if (zeroExtend) { 16 | while (v1parts.length < v2parts.length) v1parts.push('0') 17 | while (v2parts.length < v1parts.length) v2parts.push('0') 18 | } 19 | 20 | if (!lexicographical) { 21 | v1parts = v1parts.map(Number) 22 | v2parts = v2parts.map(Number) 23 | } 24 | 25 | for (let i = 0; i < v1parts.length; ++i) { 26 | if (v2parts.length === i) { 27 | return 1 28 | } 29 | 30 | if (v1parts[i] === v2parts[i]) { 31 | 32 | } else if (v1parts[i] > v2parts[i]) { 33 | return 1 34 | } else { 35 | return -1 36 | } 37 | } 38 | 39 | if (v1parts.length !== v2parts.length) { 40 | return -1 41 | } 42 | 43 | return 0 44 | } 45 | -------------------------------------------------------------------------------- /docs-src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | import VueUiFramework from '../' 6 | import '../dist/vue-ui.css' 7 | 8 | Vue.use(VueUiFramework, /* { 9 | vtooltip: { 10 | themes: { 11 | tooltip: { 12 | delay: 2000, 13 | }, 14 | }, 15 | }, 16 | } */) 17 | 18 | Vue.config.productionTip = false 19 | 20 | Vue.prototype.log = (...args) => { 21 | console.log(...args) 22 | } 23 | 24 | new Vue({ 25 | router, 26 | store, 27 | ...App, 28 | }).$mount('#app') 29 | -------------------------------------------------------------------------------- /docs-src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Home from './views/Home.vue' 4 | import About from './views/About.vue' 5 | import demos from './demo-routes' 6 | 7 | Vue.use(Router) 8 | 9 | export default new Router({ 10 | routes: [ 11 | { 12 | path: '/', 13 | name: 'home', 14 | component: Home, 15 | }, 16 | { 17 | path: '/about', 18 | name: 'about', 19 | component: About, 20 | }, 21 | { 22 | path: '/demo', 23 | component: Home, 24 | children: demos, 25 | }, 26 | ], 27 | }) 28 | -------------------------------------------------------------------------------- /docs-src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | theme: 'default', 9 | }, 10 | mutations: { 11 | 'SWITCH_THEME': (state, value) => { 12 | state.theme = value 13 | localStorage.setItem('vue-ui:theme', value) 14 | const el = document.getElementsByTagName('html')[0] 15 | if (value !== 'default') { 16 | el.classList.add('vue-ui-dark-mode') 17 | } else { 18 | el.classList.remove('vue-ui-dark-mode') 19 | } 20 | if (value !== 'high-contrast') { 21 | el.classList.remove('vue-ui-high-contrast') 22 | } else { 23 | el.classList.add('vue-ui-high-contrast') 24 | } 25 | }, 26 | }, 27 | actions: { 28 | 29 | }, 30 | }) 31 | -------------------------------------------------------------------------------- /docs-src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs-src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 33 | 34 | 69 | -------------------------------------------------------------------------------- /docs-src/views/demos/ButtonGroup.vue: -------------------------------------------------------------------------------- 1 | 441 | 442 | 465 | 466 | 475 | -------------------------------------------------------------------------------- /docs-src/views/demos/Colors.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 52 | -------------------------------------------------------------------------------- /docs-src/views/demos/Disable.vue: -------------------------------------------------------------------------------- 1 | 98 | 99 | 112 | 113 | 125 | -------------------------------------------------------------------------------- /docs-src/views/demos/Dropdown.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 82 | -------------------------------------------------------------------------------- /docs-src/views/demos/Icon.vue: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /docs-src/views/demos/Input.vue: -------------------------------------------------------------------------------- 1 | 95 | 96 | 118 | -------------------------------------------------------------------------------- /docs-src/views/demos/Loading.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 69 | 70 | -------------------------------------------------------------------------------- /docs-src/views/demos/Modal.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 42 | -------------------------------------------------------------------------------- /docs-src/views/demos/Select.vue: -------------------------------------------------------------------------------- 1 | 52 | 53 | 62 | 63 | 69 | -------------------------------------------------------------------------------- /docs-src/views/demos/Switch.vue: -------------------------------------------------------------------------------- 1 | 64 | 65 | 74 | -------------------------------------------------------------------------------- /docs-src/views/demos/Tabs.vue: -------------------------------------------------------------------------------- 1 | 80 | 81 | 96 | 97 | 101 | -------------------------------------------------------------------------------- /docs-src/views/demos/Tooltip.vue: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /docs-src/views/demos/TypeAhead.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 80 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/ui/63f67359862e9ef8d5e679172e4aa01f922271be/docs/.nojekyll -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | Vue UI Framework
-------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/ui/63f67359862e9ef8d5e679172e4aa01f922271be/docs/logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vue/ui", 3 | "description": "UI components used in the vuejs organization apps", 4 | "version": "0.12.5", 5 | "author": { 6 | "name": "Guillaume Chau", 7 | "email": "guillaume.b.chau@gmail.com" 8 | }, 9 | "keywords": [ 10 | "vue", 11 | "vuejs" 12 | ], 13 | "license": "MIT", 14 | "main": "dist/vue-ui.umd.js", 15 | "module": "dist/vue-ui.esm.js", 16 | "unpkg": "dist/vue-ui.min.js", 17 | "scripts": { 18 | "demo:serve": "vue-cli-service serve", 19 | "demo:build": "vue-cli-service build", 20 | "demo:lint": "vue-cli-service lint", 21 | "lint": "eslint --ext .js,.vue src/", 22 | "dev": "nodemon --exec 'npm run build:es' --watch src -e js,vue,styl", 23 | "build": "npm run build:browser && npm run build:es && npm run build:umd", 24 | "build:browser": "rollup --config build/rollup.config.browser.js", 25 | "build:es": "rollup --config build/rollup.config.es.js", 26 | "build:umd": "rollup --config build/rollup.config.umd.js", 27 | "prepublishOnly": "yarn run lint && yarn run build" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "git+https://github.com/vuejs/ui.git" 32 | }, 33 | "bugs": { 34 | "url": "https://github.com/vuejs/ui/issues" 35 | }, 36 | "homepage": "https://github.com/vuejs/ui#readme", 37 | "publishConfig": { 38 | "access": "public" 39 | }, 40 | "dependencies": { 41 | "focus-visible": "^5.2.0", 42 | "v-tooltip": "^3.0.0-alpha.20", 43 | "vue-resize": "^1.0.0" 44 | }, 45 | "devDependencies": { 46 | "@akryum/md-icons-svg": "^1.0.1", 47 | "@babel/core": "^7.12.10", 48 | "@babel/plugin-transform-runtime": "^7.4.0", 49 | "@babel/preset-env": "^7.4.2", 50 | "@rollup/plugin-babel": "^5.2.2", 51 | "@rollup/plugin-commonjs": "^11.0.2", 52 | "@rollup/plugin-node-resolve": "^7.1.1", 53 | "@rollup/plugin-replace": "^2.3.1", 54 | "@vue/babel-helper-vue-jsx-merge-props": "^1.2.1", 55 | "@vue/babel-preset-jsx": "^1.2.4", 56 | "@vue/cli-plugin-babel": "^3.5.1", 57 | "@vue/cli-plugin-eslint": "^3.5.1", 58 | "@vue/cli-service": "^3.5.1", 59 | "@vue/eslint-config-standard": "^4.0.0", 60 | "babel-eslint": "^10.0.1", 61 | "clean-css": "^4.1.8", 62 | "core-js": "^2.0.0", 63 | "cross-env": "^5.1.3", 64 | "fs-extra": "^9.1.0", 65 | "nodemon": "^1.17.5", 66 | "raw-loader": "^2.0.0", 67 | "rollup": "^2.38.2", 68 | "rollup-plugin-css-only": "^3.1.0", 69 | "rollup-plugin-require-context": "^0.0.2", 70 | "rollup-plugin-string": "^3.0.0", 71 | "rollup-plugin-terser": "^7.0.2", 72 | "rollup-plugin-vue": "^4", 73 | "stylus": "^0.54.5", 74 | "stylus-loader": "^3.0.1", 75 | "vue": "^2.6.10", 76 | "vue-router": "^3.0.1", 77 | "vue-template-compiler": "^2.6.10", 78 | "vuex": "^3.0.1" 79 | }, 80 | "peerDependencies": { 81 | "vue": "^2.5.13" 82 | }, 83 | "resolutions": { 84 | "upath": "1.1.0" 85 | }, 86 | "browserslist": [ 87 | "> 10%", 88 | "last 2 versions" 89 | ] 90 | } 91 | -------------------------------------------------------------------------------- /public/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/ui/63f67359862e9ef8d5e679172e4aa01f922271be/public/.nojekyll -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Vue UI Framework 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/ui/63f67359862e9ef8d5e679172e4aa01f922271be/public/logo.png -------------------------------------------------------------------------------- /src/components/VueButton.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 134 | 135 | 333 | -------------------------------------------------------------------------------- /src/components/VueDisable.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 44 | -------------------------------------------------------------------------------- /src/components/VueDropdown.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 159 | 160 | 198 | -------------------------------------------------------------------------------- /src/components/VueDropdownButton.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 26 | 27 | 38 | -------------------------------------------------------------------------------- /src/components/VueFormField.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 102 | 103 | 142 | -------------------------------------------------------------------------------- /src/components/VueGroup.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 121 | 122 | 220 | -------------------------------------------------------------------------------- /src/components/VueGroupButton.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 63 | 64 | 165 | -------------------------------------------------------------------------------- /src/components/VueIcon.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'VueIcon', 3 | 4 | functional: true, 5 | 6 | props: { 7 | icon: { 8 | type: String, 9 | required: true, 10 | }, 11 | }, 12 | 13 | render (h, { props, data }) { 14 | return
18 | 19 | 20 | 21 |
22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /src/components/VueInput.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 224 | 225 | 433 | -------------------------------------------------------------------------------- /src/components/VueLoadingBar.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'VueLoadingBar', 3 | 4 | functional: true, 5 | 6 | props: { 7 | value: { 8 | type: Number, 9 | default: 0, 10 | }, 11 | 12 | unknown: { 13 | type: Boolean, 14 | default: false, 15 | }, 16 | }, 17 | 18 | render (h, { props, data }) { 19 | data.class = [ 20 | data.class, 21 | { 22 | unknown: props.unknown, 23 | }, 24 | ] 25 | return
29 |
33 |
34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /src/components/VueLoadingIndicator.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'VueLoadingIndicator', 3 | 4 | functional: true, 5 | 6 | render (h, { data, children }) { 7 | return
8 |
9 | {children} 10 |
11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /src/components/VueModal.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 93 | 94 | 213 | -------------------------------------------------------------------------------- /src/components/VueSelect.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 126 | 127 | 139 | -------------------------------------------------------------------------------- /src/components/VueSelectButton.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 49 | 50 | 56 | -------------------------------------------------------------------------------- /src/components/VueSwitch.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 77 | 78 | 203 | -------------------------------------------------------------------------------- /src/components/VueTab.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 95 | 96 | 102 | -------------------------------------------------------------------------------- /src/components/VueTabs.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 171 | 172 | 216 | -------------------------------------------------------------------------------- /src/components/VueTypeAhead.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 235 | 236 | 246 | -------------------------------------------------------------------------------- /src/icons.js: -------------------------------------------------------------------------------- 1 | const icons = require.context('../node_modules/@akryum/md-icons-svg/svg/', true, /materialicons\/24px\.svg$/) 2 | 3 | export default { 4 | install (Vue) { 5 | const sprites = [''] 6 | let spriteIndex = 0 7 | // Load all the SVG symbols 8 | icons.keys().forEach((key, index) => { 9 | let result = icons(key) 10 | const [, iconName] = /(\w+)\/materialicons/.exec(key) 11 | const [, content] = /(.*)<\/svg>/.exec(result) 12 | result = `${content}` 13 | sprites[spriteIndex] += result 14 | if ((index + 1) % 40 === 0) { 15 | sprites.push('') 16 | spriteIndex++ 17 | } 18 | }) 19 | for (const html of sprites) { 20 | const iconsWrapper = document.createElement('div') 21 | iconsWrapper.style.display = 'none' 22 | iconsWrapper.innerHTML = html 23 | document.body.insertBefore(iconsWrapper, document.body.firstChild) 24 | } 25 | }, 26 | } 27 | 28 | export function generateHtmlIcon (icon) { 29 | return `
` 30 | } 31 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import VueIcons from './icons' 2 | import VTooltip from 'v-tooltip' 3 | import VueResize from 'vue-resize' 4 | import 'focus-visible' 5 | 6 | import 'vue-resize/dist/vue-resize.css' 7 | import 'v-tooltip/dist/v-tooltip.css' 8 | 9 | import VueButton from './components/VueButton.vue' 10 | import VueDisable from './components/VueDisable.vue' 11 | import VueDropdown from './components/VueDropdown.vue' 12 | import VueDropdownButton from './components/VueDropdownButton.vue' 13 | import VueFormField from './components/VueFormField.vue' 14 | import VueGroup from './components/VueGroup.vue' 15 | import VueGroupButton from './components/VueGroupButton.vue' 16 | import VueIcon from './components/VueIcon' 17 | import VueInput from './components/VueInput.vue' 18 | import VueLoadingBar from './components/VueLoadingBar' 19 | import VueLoadingIndicator from './components/VueLoadingIndicator' 20 | import VueModal from './components/VueModal.vue' 21 | import VueSelect from './components/VueSelect.vue' 22 | import VueSelectButton from './components/VueSelectButton.vue' 23 | import VueSwitch from './components/VueSwitch.vue' 24 | import VueTab from './components/VueTab.vue' 25 | import VueTabs from './components/VueTabs.vue' 26 | import VueTypeAhead from './components/VueTypeAhead.vue' 27 | 28 | // Exported mixins 29 | export { default as CoupledChild } from './mixins/CoupledChild' 30 | export { default as CoupledParent } from './mixins/CoupledParent' 31 | export { default as DisabledChild } from './mixins/DisabledChild' 32 | export { default as DisableScroll } from './mixins/DisableScroll' 33 | 34 | // Exported utils 35 | export { generateHtmlIcon } from './icons' 36 | 37 | export function install (Vue, options = {}) { 38 | Vue.use(VueIcons) 39 | 40 | Vue.use(VTooltip, mergeOptions({ 41 | bondary: document.body, 42 | themes: { 43 | tooltip: { 44 | delay: { 45 | show: 1000, 46 | hide: 800, 47 | }, 48 | instantMove: true, 49 | }, 50 | dropdown: { 51 | handleResize: false, 52 | }, 53 | }, 54 | }, options.vtooltip)) 55 | 56 | Vue.use(VueResize) 57 | 58 | Vue.component('VueButton', VueButton) 59 | Vue.component('VueDisable', VueDisable) 60 | Vue.component('VueDropdown', VueDropdown) 61 | Vue.component('VueDropdownButton', VueDropdownButton) 62 | Vue.component('VueFormField', VueFormField) 63 | Vue.component('VueGroup', VueGroup) 64 | Vue.component('VueGroupButton', VueGroupButton) 65 | Vue.component('VueIcon', VueIcon) 66 | Vue.component('VueInput', VueInput) 67 | Vue.component('VueLoadingBar', VueLoadingBar) 68 | Vue.component('VueLoadingIndicator', VueLoadingIndicator) 69 | Vue.component('VueModal', VueModal) 70 | Vue.component('VueSelect', VueSelect) 71 | Vue.component('VueSelectButton', VueSelectButton) 72 | Vue.component('VueSwitch', VueSwitch) 73 | Vue.component('VueTab', VueTab) 74 | Vue.component('VueTabs', VueTabs) 75 | Vue.component('VueTypeAhead', VueTypeAhead) 76 | } 77 | 78 | const plugin = { 79 | // eslint-disable-next-line no-undef 80 | version: VERSION, 81 | install, 82 | } 83 | 84 | export default plugin 85 | 86 | function mergeOptions (to, from) { 87 | for (const key in from) { 88 | if (to[key] && from[key] && typeof to[key] === 'object' && typeof from[key] === 'object') { 89 | mergeOptions(to[key], from[key]) 90 | } else { 91 | to[key] = from[key] 92 | } 93 | } 94 | return to 95 | } 96 | 97 | // Auto-install 98 | let GlobalVue = null 99 | if (typeof window !== 'undefined') { 100 | GlobalVue = window.Vue 101 | } else if (typeof global !== 'undefined') { 102 | GlobalVue = global.Vue 103 | } 104 | if (GlobalVue) { 105 | GlobalVue.use(plugin) 106 | } 107 | -------------------------------------------------------------------------------- /src/mixins/CoupledChild.js: -------------------------------------------------------------------------------- 1 | /** 2 | * (Use with the CoupleParent mixin) 3 | * This mixin should be used on children components of a component implementing the CoupledParent mixin. 4 | * @param {string} name Name of the injection 5 | */ 6 | export default function (name) { 7 | // @vue/component 8 | return { 9 | inject: [ 10 | name, 11 | ], 12 | 13 | computed: { 14 | active () { 15 | return this[name].activeChild === this.$_couplingProxy 16 | }, 17 | }, 18 | 19 | created () { 20 | const proxy = this.$_couplingProxy = {} 21 | for (const key in this.$data) { 22 | if (key.charAt(0) === '$' || key.charAt(0) === '_') continue 23 | Object.defineProperty(proxy, key, { 24 | enumerable: true, 25 | configurable: false, 26 | get: () => this.$data[key], 27 | }) 28 | } 29 | for (const key in this.$props) { 30 | if (key.charAt(0) === '$' || key.charAt(0) === '_') continue 31 | Object.defineProperty(proxy, key, { 32 | enumerable: true, 33 | configurable: false, 34 | get: () => this.$props[key], 35 | }) 36 | } 37 | Object.defineProperty(proxy, '$slots', { 38 | enumerable: false, 39 | configurable: false, 40 | get: () => this.$slots, 41 | }) 42 | this[name].$_addCoupledChild(proxy) 43 | }, 44 | 45 | beforeDestroy () { 46 | this[name].$_removeCoupledChild(this.$_couplingProxy) 47 | }, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/mixins/CoupledParent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * (Use with the CoupledChild mixin) 3 | * Mixin allowing the automatic collection of children while preserving the virtual dom children order at all times. 4 | * Useful for creating tabs-style component, when we need to replicate the order of the children to display 5 | * a group of button (tab strip). 6 | * @param {string} name Name of the injection 7 | */ 8 | export default function (name) { 9 | // @vue/component 10 | return { 11 | provide () { 12 | const proxy = {} 13 | Object.defineProperty(proxy, 'activeChild', { 14 | get: () => this.activeChild, 15 | }) 16 | proxy.$_addCoupledChild = this.$_addCoupledChild.bind(this) 17 | proxy.$_removeCoupledChild = this.$_removeCoupledChild.bind(this) 18 | return { 19 | [name]: proxy, 20 | } 21 | }, 22 | 23 | props: { 24 | childIndex: { 25 | default: 0, 26 | }, 27 | }, 28 | 29 | data () { 30 | return { 31 | children: [], 32 | activeChildIndex: parseInt(this.childIndex) || 0, 33 | } 34 | }, 35 | 36 | computed: { 37 | activeChild () { 38 | if (this.activeChildIndex < this.children.length) { 39 | return this.children[this.activeChildIndex] 40 | } 41 | }, 42 | }, 43 | 44 | watch: { 45 | childIndex (val) { 46 | this.activateChild(parseInt(val) || 0, true) 47 | }, 48 | }, 49 | 50 | methods: { 51 | /** 52 | * Activates a child. 53 | * @param {number} index Index of child to activate 54 | * @param {boolean} external Indicates if the activation comes from an external source (like props) 55 | */ 56 | activateChild (index, external = false) { 57 | const oldIndex = this.activeChildIndex 58 | if (index < 0) { 59 | index = 0 60 | } else if (index >= this.children.length) { 61 | index = this.children.length - 1 62 | } 63 | this.activeChildIndex = index 64 | this.$emit('update:childIndex', index) 65 | this.childActivated(index, oldIndex, external) 66 | }, 67 | 68 | /** 69 | * Hook called when a child is activated. 70 | * @param {number} index Index of the activated child 71 | * @param {number} oldIndex Index of the previously activated child 72 | * @param {boolean} external Indicates if the activation comes from an external source (like props) 73 | */ 74 | childActivated (index, oldIndex, external) { 75 | // Override this in component 76 | }, 77 | 78 | /** 79 | * Add a child component while preserving its order in the children list. 80 | * @param {object} proxyVm Vue instance 81 | */ 82 | $_addCoupledChild (proxyVm) { 83 | // Guard 84 | if (this.$slots && this.$slots.default) { 85 | // We need to wait for the instances creation 86 | this.$nextTick(() => { 87 | // We need to get the components in the slot 88 | const childComponents = this.$slots.default.reduce((list, vnode) => { 89 | const coupledChild = findCoupledChild(vnode) 90 | if (coupledChild) { 91 | list.push(coupledChild.$_couplingProxy) 92 | } 93 | return list 94 | }, []) 95 | // List has the child component in the right order 96 | // We can now register the child component in the right place 97 | const index = childComponents.indexOf(proxyVm) 98 | // Add child 99 | if (index !== -1) { 100 | this.children.splice(index, 0, proxyVm) 101 | // Hook 102 | this.$_updateChildren('add', index, proxyVm) 103 | } 104 | }) 105 | } 106 | }, 107 | 108 | /** 109 | * Removes a child component. Automatically activates the next remaining component. 110 | * @param {object} proxyVm Vue instance 111 | */ 112 | $_removeCoupledChild (proxyVm) { 113 | const index = this.children.indexOf(proxyVm) 114 | // Remove child 115 | if (index !== -1) { 116 | this.children.splice(index, 1) 117 | } 118 | // Hook 119 | this.$_updateChildren('remove', index, proxyVm) 120 | }, 121 | 122 | /** 123 | * Hook called when an operation is processed. It will intelligently activate a child if needed. 124 | * @param {string} operation Name of the operation. Can be 'add' or 'remove' 125 | * @param {number} index Index of the related child. 126 | * @param {object} proxyVm Related child Vue instance 127 | */ 128 | $_updateChildren (operation, index, proxyVm) { 129 | if (operation === 'add') { 130 | // If the child was added before the currently active one, 131 | // we need to move the selection to the right 132 | if (index <= this.activeChildIndex) { 133 | this.activateChild(this.activeChildIndex + 1) 134 | } 135 | // Default when there is only one child 136 | if (this.children.length === 1) { 137 | this.activateChild(0) 138 | } 139 | } else if (operation === 'remove') { 140 | // If we remove a child before the currently active one, 141 | // we need to move the selection to the left 142 | if (index <= this.activeChildIndex) { 143 | this.activateChild(this.activeChildIndex - 1) 144 | } 145 | } 146 | }, 147 | }, 148 | } 149 | } 150 | 151 | function findCoupledChild (vnode) { 152 | const vm = vnode.child 153 | if (vm) { 154 | if (vm.$_couplingProxy) { 155 | return vm 156 | } else { 157 | return findCoupledChildInChildren([...vm.$children]) 158 | } 159 | } 160 | } 161 | 162 | // Breadth-first search 163 | function findCoupledChildInChildren (queue) { 164 | let child 165 | while ((child = queue.shift())) { 166 | if (child.$_couplingProxy) { 167 | return child 168 | } else { 169 | queue.push(...child.$children) 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/mixins/DisableScroll.js: -------------------------------------------------------------------------------- 1 | let count = 0 2 | 3 | function getScrollingElements () { 4 | return document.querySelectorAll('.vue-ui-disable-scroll, body') 5 | } 6 | 7 | function updateScroll () { 8 | if (count === 0) { 9 | getScrollingElements().forEach(el => el.classList.remove('vue-ui-no-scroll')) 10 | } else if (count === 1) { 11 | getScrollingElements().forEach(el => el.classList.add('vue-ui-no-scroll')) 12 | } 13 | } 14 | 15 | export default { 16 | mounted () { 17 | count++ 18 | updateScroll() 19 | }, 20 | 21 | beforeDestroy () { 22 | count-- 23 | updateScroll() 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /src/mixins/DisabledChild.js: -------------------------------------------------------------------------------- 1 | /** 2 | * (Use with the DisabledParent mixin) 3 | * This mixin should be implemented on all components that can be disabled. 4 | */ 5 | // @vue/component 6 | export default { 7 | inject: { 8 | VueDisableMixin: { 9 | default: null, 10 | }, 11 | }, 12 | 13 | props: { 14 | disabled: { 15 | type: Boolean, 16 | default: false, 17 | }, 18 | }, 19 | 20 | computed: { 21 | finalDisabled () { 22 | return this.disabled || (this.VueDisableMixin && this.VueDisableMixin.data.value) 23 | }, 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /src/mixins/DisabledParent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * (Use with the DisabledChild mixin) 3 | * Allow disabling an entire tree of components implementing the DisabledChild mixin. 4 | */ 5 | // @vue/component 6 | export default { 7 | provide () { 8 | return { 9 | VueDisableMixin: { 10 | data: this.injectedDisableData, 11 | }, 12 | } 13 | }, 14 | 15 | props: { 16 | disabled: { 17 | type: Boolean, 18 | default: false, 19 | }, 20 | }, 21 | 22 | data () { 23 | return { 24 | injectedDisableData: { 25 | value: this.disabled, 26 | }, 27 | } 28 | }, 29 | 30 | watch: { 31 | disabled (value, oldValue) { 32 | if (value !== oldValue) this.injectedDisableData.value = value 33 | }, 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /src/style/animation.styl: -------------------------------------------------------------------------------- 1 | // Focus 2 | 3 | @keyframes vue-ui-focus 4 | $color = $vue-ui-accent-500 5 | 0% 6 | border-color $color 7 | box-shadow 0 0 20px rgba($color, 2) 8 | 100% 9 | border-color rgba($color, .6) 10 | box-shadow 0 0 4px rgba($color, .5) 11 | 12 | @keyframes vue-ui-focus-dark 13 | $color = $vue-ui-accent-300 14 | 0% 15 | border-color $color 16 | box-shadow 0 0 20px rgba($color, 2) 17 | 100% 18 | border-color rgba($color, .6) 19 | box-shadow 0 0 4px rgba($color, .5) 20 | 21 | // Slide 22 | 23 | vue-ui-slide($direction, $offset) 24 | if $direction == bottom 25 | $transform = "translateY(%s)" % $offset 26 | else if $direction == top 27 | $transform = "translateY(-%s)" % $offset 28 | else if $direction == left 29 | $transform = "translateX(-%s)" % $offset 30 | else if $direction == right 31 | $transform = "translateX(%s)" % $offset 32 | @keyframes vue-ui-slide-from-{$direction} 33 | 0% 34 | transform $transform 35 | 100% 36 | transform none 37 | @keyframes vue-ui-slide-to-{$direction} 38 | 0% 39 | transform none 40 | 100% 41 | transform $transform 42 | 43 | $offset = 6px 44 | vue-ui-slide(bottom, $offset) 45 | vue-ui-slide(top, $offset) 46 | vue-ui-slide(left, $offset) 47 | vue-ui-slide(right, $offset) 48 | 49 | // Fade 50 | 51 | .vue-ui-fade-enter-active, 52 | .vue-ui-fade-leave-active 53 | transition opacity .15s linear 54 | 55 | .vue-ui-fade-enter, 56 | .vue-ui-fade-leave-to 57 | opacity 0 58 | -------------------------------------------------------------------------------- /src/style/base.styl: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700,700i') 2 | 3 | @import "./imports" 4 | @import "./animation" 5 | @import "./tooltip" 6 | 7 | html 8 | background $vue-ui-white 9 | 10 | body 11 | font-size 16px 12 | font-family 'Roboto', 'Avenir', Helvetica, Arial, sans-serif 13 | -webkit-font-smoothing antialiased 14 | -moz-osx-font-smoothing grayscale 15 | color $vue-ui-gray-800 16 | margin 0 17 | 18 | .vue-ui-dark-mode 19 | color $vue-ui-white 20 | background $vue-ui-black 21 | body 22 | color @color 23 | 24 | .vue-ui-high-contrast 25 | background black 26 | 27 | hr 28 | border none 29 | height 1px 30 | background $vue-ui-primary-100 31 | 32 | a 33 | color $vue-ui-primary-500 34 | text-decoration none 35 | .vue-ui-icon 36 | svg 37 | fill @color 38 | 39 | h1, h2, h3, h4, h5, h6 40 | font-weight 300 41 | margin 24px 0 8px 42 | &:first-child 43 | margin-top 0 44 | 45 | h1 46 | font-size 42px 47 | 48 | h2 49 | font-size 32px 50 | 51 | h3 52 | font-size 26px 53 | 54 | h4 55 | font-size 22px 56 | 57 | h5 58 | font-size 18px 59 | 60 | h6 61 | font-size 16px 62 | 63 | p 64 | margin 0 0 8px 65 | 66 | ul 67 | margin 4px 0 68 | 69 | .vue-ui-no-scroll 70 | overflow hidden 71 | 72 | .vue-ui-spacer 73 | flex auto 1 1 !important 74 | width 0 75 | height 0 76 | 77 | .vue-ui-empty 78 | color rgba($vue-ui-gray-800, .5) 79 | padding 24px 80 | text-align center 81 | box-sizing border-box 82 | .vue-ui-icon 83 | svg 84 | fill @color 85 | .vue-ui-dark-mode & 86 | color rgba($vue-ui-white, .5) 87 | 88 | .vue-ui-text 89 | &.banner 90 | padding 12px 91 | display flex 92 | align-items center 93 | border-radius $br 94 | > .vue-ui-icon 95 | flex auto 0 0 96 | &:first-child 97 | margin-right 10px 98 | &.primary 99 | vue-ui-text-colors($vue-ui-primary-500) 100 | &.accent 101 | vue-ui-text-colors($vue-ui-accent-500) 102 | &.danger 103 | vue-ui-text-colors($vue-ui-danger-500) 104 | &.warning 105 | vue-ui-text-colors($vue-ui-warning-500) 106 | &.info 107 | vue-ui-text-colors($vue-ui-info-500) 108 | &.success 109 | vue-ui-text-colors($vue-ui-primary-500) 110 | 111 | .vue-ui-grid 112 | display grid 113 | &.default-gap 114 | grid-gap 12px 115 | &.big-gap 116 | grid-gap 24px 117 | for n in (1..10) 118 | &.col-{n} 119 | grid-template-columns repeat(n, 1fr) 120 | 121 | .span-{n} 122 | grid-column span n 123 | 124 | ::-webkit-scrollbar 125 | width 10px 126 | height @width 127 | ::-webkit-scrollbar-track-piece 128 | background transparent 129 | ::-webkit-scrollbar-track:hover 130 | background rgba($vue-ui-gray-600, .05) 131 | .vue-ui-dark-mode & 132 | background rgba($vue-ui-gray-600, .1) 133 | ::-webkit-scrollbar-thumb 134 | background-color $vue-ui-gray-300 135 | border 3px solid transparent 136 | background-clip padding-box 137 | border-radius 5px 138 | &:hover 139 | background-color $vue-ui-gray-600 140 | .vue-ui-dark-mode & 141 | background-color $vue-ui-gray-800 142 | &:hover 143 | background-color $vue-ui-gray-500 144 | 145 | .vue-ui-dark-mode 146 | scrollbar-color $vue-ui-gray-800 $vue-ui-black 147 | 148 | .vue-ui-high-contrast 149 | :focus 150 | outline cyan 2px solid !important 151 | 152 | // Icon 153 | 154 | .vue-ui-icon 155 | display inline-block 156 | width 18px 157 | height @width 158 | vertical-align bottom 159 | svg 160 | width 100% 161 | height 100% 162 | fill $vue-ui-gray-800 163 | pointer-events none 164 | 165 | .vue-ui-dark-mode & 166 | svg 167 | fill $vue-ui-white 168 | 169 | &.primary 170 | svg 171 | fill $vue-ui-primary-500 172 | &.accent 173 | svg 174 | fill $vue-ui-accent-500 175 | &.danger 176 | svg 177 | fill $vue-ui-danger-500 178 | &.warning 179 | svg 180 | fill $vue-ui-warning-500 181 | &.info 182 | svg 183 | fill $vue-ui-info-500 184 | &.success 185 | svg 186 | fill $vue-ui-primary-500 187 | 188 | &.top 189 | position relative 190 | top -.06rem 191 | 192 | // Size 193 | &.small 194 | width 12px 195 | height @width 196 | &.medium 197 | width 20px 198 | height @width 199 | &.big 200 | width 24px 201 | height @width 202 | &.large 203 | width 32px 204 | height @width 205 | &.huge 206 | width 42px 207 | height @width 208 | &.gigantic 209 | width 64px 210 | height @width 211 | 212 | // Loading bar 213 | 214 | colors($foreground, $background) 215 | background $background 216 | .bar 217 | background $foreground 218 | 219 | .vue-ui-loading-bar 220 | height 3px 221 | position relative 222 | 223 | .bar 224 | height 100% 225 | 226 | colors($vue-ui-gray-800, $vue-ui-primary-100) 227 | .vue-ui-dark-mode & 228 | colors($vue-ui-gray-600, $vue-ui-gray-800) 229 | 230 | &.primary 231 | colors($vue-ui-primary-500, $vue-ui-primary-100) 232 | .vue-ui-dark-mode & 233 | colors($vue-ui-primary-500, $vue-ui-gray-800) 234 | 235 | &.accent 236 | colors($vue-ui-accent-500, $vue-ui-primary-100) 237 | .vue-ui-dark-mode & 238 | colors($vue-ui-accent-300, $vue-ui-gray-800) 239 | 240 | &.unknown 241 | .bar 242 | position absolute 243 | top 0 244 | animation bar-animation .8s infinite linear 245 | 246 | &.ghost 247 | height 0 248 | z-index 300 249 | background transparent 250 | .bar 251 | height 3px 252 | 253 | @keyframes bar-animation 254 | 0% 255 | left 0 256 | right 100% 257 | 50% 258 | left 0 259 | right 0 260 | 100% 261 | left 100% 262 | right 0 263 | 264 | // Loading indicator 265 | 266 | colors($color) 267 | border-color rgba($color, .1) 268 | border-right-color $color 269 | 270 | .vue-ui-loading-indicator 271 | display flex 272 | &.inline 273 | display inline-flex 274 | flex-direction column 275 | box-center() 276 | 277 | > .animation 278 | animation rotating .7s linear infinite 279 | width 16px 280 | height @width 281 | border-radius 50% 282 | border transparent 2px solid 283 | colors($vue-ui-gray-800) 284 | .vue-ui-dark-mode & 285 | colors($vue-ui-gray-600) 286 | &.primary 287 | > .animation 288 | colors($vue-ui-primary-500) 289 | &.accent 290 | > .animation 291 | colors($vue-ui-accent-500) 292 | .vue-ui-dark-mode & 293 | colors($vue-ui-accent-300) 294 | &.small 295 | > .animation 296 | width 10px 297 | height @width 298 | &.big 299 | > .animation 300 | width 24px 301 | height @width 302 | border-width 3px 303 | 304 | .vue-ui-high-contrast & 305 | > .animation 306 | border-width 4px 307 | 308 | &.overlay 309 | position absolute 310 | top 0 311 | bottom 0 312 | left 0 313 | right 0 314 | z-index 1 315 | > .animation 316 | margin-bottom 32px 317 | &:not(.transparent) 318 | background rgba($vue-ui-white, .95) 319 | .vue-ui-dark-mode & 320 | background rgba($vue-ui-gray-900, .95) 321 | &.fixed 322 | position fixed 323 | 324 | @keyframes rotating 325 | 0% 326 | transform rotate(0) 327 | 100% 328 | transform rotate(360deg) -------------------------------------------------------------------------------- /src/style/colors.styl: -------------------------------------------------------------------------------- 1 | $vue-ui-white = #ffffff 2 | $vue-ui-black = #0b1015 3 | // Gray 4 | $vue-ui-gray-900 = #1d2935 5 | $vue-ui-gray-800 = #2c3e50 6 | $vue-ui-gray-700 = #3e5770 7 | $vue-ui-gray-600 = #4f6f7f 8 | $vue-ui-gray-500 = #809fae 9 | $vue-ui-gray-400 = #93b0be 10 | $vue-ui-gray-300 = #b6c6ce 11 | $vue-ui-gray-200 = #c8d3d9 12 | $vue-ui-gray-100 = #e0e5e7 13 | // Primary 14 | $vue-ui-primary-900 = #034124 15 | $vue-ui-primary-800 = #085e37 16 | $vue-ui-primary-700 = #13794a 17 | $vue-ui-primary-600 = #299f69 18 | $vue-ui-primary-500 = #42b983 19 | $vue-ui-primary-400 = #56cd96 20 | $vue-ui-primary-300 = #89deb7 21 | $vue-ui-primary-200 = #abeacd 22 | $vue-ui-primary-100 = #e0f8ed 23 | // Accent 24 | $vue-ui-accent-900 = #350066 25 | $vue-ui-accent-800 = #4f0098 26 | $vue-ui-accent-700 = #6806c1 27 | $vue-ui-accent-600 = #8929e3 28 | $vue-ui-accent-500 = #a44cf6 29 | $vue-ui-accent-400 = #b96dff 30 | $vue-ui-accent-300 = #c88eff 31 | $vue-ui-accent-200 = #d7adff 32 | $vue-ui-accent-100 = #e6ccff 33 | // Danger 34 | $vue-ui-danger-900 = #500000 35 | $vue-ui-danger-800 = #850505 36 | $vue-ui-danger-700 = #ac0d0d 37 | $vue-ui-danger-600 = #cd1b1b 38 | $vue-ui-danger-500 = #e83030 39 | $vue-ui-danger-400 = #f44747 40 | $vue-ui-danger-300 = #ff6565 41 | $vue-ui-danger-200 = #ff9494 42 | $vue-ui-danger-100 = #ffcaca 43 | // Warning 44 | $vue-ui-warning-900 = #702200 45 | $vue-ui-warning-800 = #943800 46 | $vue-ui-warning-700 = #b54d01 47 | $vue-ui-warning-600 = #c85900 48 | $vue-ui-warning-500 = #ea6e00 49 | $vue-ui-warning-400 = #ff8915 50 | $vue-ui-warning-300 = #ffa733 51 | $vue-ui-warning-200 = #ffc45e 52 | $vue-ui-warning-100 = #ffe6b0 53 | // Info 54 | $vue-ui-info-900 = #004576 55 | $vue-ui-info-800 = #006294 56 | $vue-ui-info-700 = #007db1 57 | $vue-ui-info-600 = #0098c4 58 | $vue-ui-info-500 = #03c2e6 59 | $vue-ui-info-400 = #74e0ed 60 | $vue-ui-info-300 = #9ae6ef 61 | $vue-ui-info-200 = #bceef1 62 | $vue-ui-info-100 = #e3f5f6 63 | 64 | // Legacy 65 | $vue-ui-color-light = #fff 66 | $vue-ui-color-light-neutral = #e4f5ef 67 | $vue-ui-color-dark = #2c3e50 68 | $vue-ui-color-dark-neutral = #4f6f7f 69 | $vue-ui-color-darker = #1d2935 70 | $vue-ui-color-almost-black = #0b1015 71 | $vue-ui-color-primary = #42b983 72 | $vue-ui-color-accent = #6806c1 73 | $vue-ui-color-accent-light = lighten($vue-ui-color-accent, 60%) 74 | $vue-ui-color-danger = #e83030 75 | $vue-ui-color-warning = #ea6e00 76 | $vue-ui-color-info = #03c2e6 77 | $vue-ui-color-success = #42b983 78 | -------------------------------------------------------------------------------- /src/style/imports.styl: -------------------------------------------------------------------------------- 1 | @import "./md-colors" 2 | @import "./colors" 3 | @import "./vars" 4 | @import "./mixins" 5 | -------------------------------------------------------------------------------- /src/style/md-colors.styl: -------------------------------------------------------------------------------- 1 | $md-red =#f44336; 2 | $md-red-50 =#ffebee; 3 | $md-red-100 =#ffcdd2; 4 | $md-red-200 =#ef9a9a; 5 | $md-red-300 =#e57373; 6 | $md-red-400 =#ef5350; 7 | $md-red-500 =#f44336; 8 | $md-red-600 =#e53935; 9 | $md-red-700 =#d32f2f; 10 | $md-red-800 =#c62828; 11 | $md-red-900 =#b71c1c; 12 | $md-red-a100 =#ff8a80; 13 | $md-red-a200 =#ff5252; 14 | $md-red-a400 =#ff1744; 15 | $md-red-a700 =#d50000; 16 | 17 | $md-pink =#e91e63; 18 | $md-pink-50 =#fce4ec; 19 | $md-pink-100 =#f8bbd0; 20 | $md-pink-200 =#f48fb1; 21 | $md-pink-300 =#f06292; 22 | $md-pink-400 =#ec407a; 23 | $md-pink-500 =#e91e63; 24 | $md-pink-600 =#d81b60; 25 | $md-pink-700 =#c2185b; 26 | $md-pink-800 =#ad1457; 27 | $md-pink-900 =#880e4f; 28 | $md-pink-a100 =#ff80ab; 29 | $md-pink-a200 =#ff4081; 30 | $md-pink-a400 =#f50057; 31 | $md-pink-a700 =#c51162; 32 | 33 | $md-purple =#9c27b0; 34 | $md-purple-50 =#f3e5f5; 35 | $md-purple-100 =#e1bee7; 36 | $md-purple-200 =#ce93d8; 37 | $md-purple-300 =#ba68c8; 38 | $md-purple-400 =#ab47bc; 39 | $md-purple-500 =#9c27b0; 40 | $md-purple-600 =#8e24aa; 41 | $md-purple-700 =#7b1fa2; 42 | $md-purple-800 =#6a1b9a; 43 | $md-purple-900 =#4a148c; 44 | $md-purple-a100 =#ea80fc; 45 | $md-purple-a200 =#e040fb; 46 | $md-purple-a400 =#d500f9; 47 | $md-purple-a700 =#aa00ff; 48 | 49 | $md-deep-purple =#673ab7; 50 | $md-deep-purple-50 =#ede7f6; 51 | $md-deep-purple-100 =#d1c4e9; 52 | $md-deep-purple-200 =#b39ddb; 53 | $md-deep-purple-300 =#9575cd; 54 | $md-deep-purple-400 =#7e57c2; 55 | $md-deep-purple-500 =#673ab7; 56 | $md-deep-purple-600 =#5e35b1; 57 | $md-deep-purple-700 =#512da8; 58 | $md-deep-purple-800 =#4527a0; 59 | $md-deep-purple-900 =#311b92; 60 | $md-deep-purple-a100 =#b388ff; 61 | $md-deep-purple-a200 =#7c4dff; 62 | $md-deep-purple-a400 =#651fff; 63 | $md-deep-purple-a700 =#6200ea; 64 | 65 | $md-indigo =#3f51b5; 66 | $md-indigo-50 =#e8eaf6; 67 | $md-indigo-100 =#c5cae9; 68 | $md-indigo-200 =#9fa8da; 69 | $md-indigo-300 =#7986cb; 70 | $md-indigo-400 =#5c6bc0; 71 | $md-indigo-500 =#3f51b5; 72 | $md-indigo-600 =#3949ab; 73 | $md-indigo-700 =#303f9f; 74 | $md-indigo-800 =#283593; 75 | $md-indigo-900 =#1a237e; 76 | $md-indigo-a100 =#8c9eff; 77 | $md-indigo-a200 =#536dfe; 78 | $md-indigo-a400 =#3d5afe; 79 | $md-indigo-a700 =#304ffe; 80 | 81 | $md-blue =#2196f3; 82 | $md-blue-50 =#e3f2fd; 83 | $md-blue-100 =#bbdefb; 84 | $md-blue-200 =#90caf9; 85 | $md-blue-300 =#64b5f6; 86 | $md-blue-400 =#42a5f5; 87 | $md-blue-500 =#2196f3; 88 | $md-blue-600 =#1e88e5; 89 | $md-blue-700 =#1976d2; 90 | $md-blue-800 =#1565c0; 91 | $md-blue-900 =#0d47a1; 92 | $md-blue-a100 =#82b1ff; 93 | $md-blue-a200 =#448aff; 94 | $md-blue-a400 =#2979ff; 95 | $md-blue-a700 =#2962ff; 96 | 97 | $md-light-blue =#03a9f4; 98 | $md-light-blue-50 =#e1f5fe; 99 | $md-light-blue-100 =#b3e5fc; 100 | $md-light-blue-200 =#81d4fa; 101 | $md-light-blue-300 =#4fc3f7; 102 | $md-light-blue-400 =#29b6f6; 103 | $md-light-blue-500 =#03a9f4; 104 | $md-light-blue-600 =#039be5; 105 | $md-light-blue-700 =#0288d1; 106 | $md-light-blue-800 =#0277bd; 107 | $md-light-blue-900 =#01579b; 108 | $md-light-blue-a100 =#80d8ff; 109 | $md-light-blue-a200 =#40c4ff; 110 | $md-light-blue-a400 =#00b0ff; 111 | $md-light-blue-a700 =#0091ea; 112 | 113 | $md-cyan =#00bcd4; 114 | $md-cyan-50 =#e0f7fa; 115 | $md-cyan-100 =#b2ebf2; 116 | $md-cyan-200 =#80deea; 117 | $md-cyan-300 =#4dd0e1; 118 | $md-cyan-400 =#26c6da; 119 | $md-cyan-500 =#00bcd4; 120 | $md-cyan-600 =#00acc1; 121 | $md-cyan-700 =#0097a7; 122 | $md-cyan-800 =#00838f; 123 | $md-cyan-900 =#006064; 124 | $md-cyan-a100 =#84ffff; 125 | $md-cyan-a200 =#18ffff; 126 | $md-cyan-a400 =#00e5ff; 127 | $md-cyan-a700 =#00b8d4; 128 | 129 | $md-teal =#009688; 130 | $md-teal-50 =#e0f2f1; 131 | $md-teal-100 =#b2dfdb; 132 | $md-teal-200 =#80cbc4; 133 | $md-teal-300 =#4db6ac; 134 | $md-teal-400 =#26a69a; 135 | $md-teal-500 =#009688; 136 | $md-teal-600 =#00897b; 137 | $md-teal-700 =#00796b; 138 | $md-teal-800 =#00695c; 139 | $md-teal-900 =#004d40; 140 | $md-teal-a100 =#a7ffeb; 141 | $md-teal-a200 =#64ffda; 142 | $md-teal-a400 =#1de9b6; 143 | $md-teal-a700 =#00bfa5; 144 | 145 | $md-green =#4caf50; 146 | $md-green-50 =#e8f5e9; 147 | $md-green-100 =#c8e6c9; 148 | $md-green-200 =#a5d6a7; 149 | $md-green-300 =#81c784; 150 | $md-green-400 =#66bb6a; 151 | $md-green-500 =#4caf50; 152 | $md-green-600 =#43a047; 153 | $md-green-700 =#388e3c; 154 | $md-green-800 =#2e7d32; 155 | $md-green-900 =#1b5e20; 156 | $md-green-a100 =#b9f6ca; 157 | $md-green-a200 =#69f0ae; 158 | $md-green-a400 =#00e676; 159 | $md-green-a700 =#00c853; 160 | 161 | $md-light-green =#8bc34a; 162 | $md-light-green-50 =#f1f8e9; 163 | $md-light-green-100 =#dcedc8; 164 | $md-light-green-200 =#c5e1a5; 165 | $md-light-green-300 =#aed581; 166 | $md-light-green-400 =#9ccc65; 167 | $md-light-green-500 =#8bc34a; 168 | $md-light-green-600 =#7cb342; 169 | $md-light-green-700 =#689f38; 170 | $md-light-green-800 =#558b2f; 171 | $md-light-green-900 =#33691e; 172 | $md-light-green-a100 =#ccff90; 173 | $md-light-green-a200 =#b2ff59; 174 | $md-light-green-a400 =#76ff03; 175 | $md-light-green-a700 =#64dd17; 176 | 177 | $md-lime =#cddc39; 178 | $md-lime-50 =#f9fbe7; 179 | $md-lime-100 =#f0f4c3; 180 | $md-lime-200 =#e6ee9c; 181 | $md-lime-300 =#dce775; 182 | $md-lime-400 =#d4e157; 183 | $md-lime-500 =#cddc39; 184 | $md-lime-600 =#c0ca33; 185 | $md-lime-700 =#afb42b; 186 | $md-lime-800 =#9e9d24; 187 | $md-lime-900 =#827717; 188 | $md-lime-a100 =#f4ff81; 189 | $md-lime-a200 =#eeff41; 190 | $md-lime-a400 =#c6ff00; 191 | $md-lime-a700 =#aeea00; 192 | 193 | $md-yellow =#ffeb3b; 194 | $md-yellow-50 =#fffde7; 195 | $md-yellow-100 =#fff9c4; 196 | $md-yellow-200 =#fff59d; 197 | $md-yellow-300 =#fff176; 198 | $md-yellow-400 =#ffee58; 199 | $md-yellow-500 =#ffeb3b; 200 | $md-yellow-600 =#fdd835; 201 | $md-yellow-700 =#fbc02d; 202 | $md-yellow-800 =#f9a825; 203 | $md-yellow-900 =#f57f17; 204 | $md-yellow-a100 =#ffff8d; 205 | $md-yellow-a200 =#ffff00; 206 | $md-yellow-a400 =#ffea00; 207 | $md-yellow-a700 =#ffd600; 208 | 209 | $md-amber =#ffc107; 210 | $md-amber-50 =#fff8e1; 211 | $md-amber-100 =#ffecb3; 212 | $md-amber-200 =#ffe082; 213 | $md-amber-300 =#ffd54f; 214 | $md-amber-400 =#ffca28; 215 | $md-amber-500 =#ffc107; 216 | $md-amber-600 =#ffb300; 217 | $md-amber-700 =#ffa000; 218 | $md-amber-800 =#ff8f00; 219 | $md-amber-900 =#ff6f00; 220 | $md-amber-a100 =#ffe57f; 221 | $md-amber-a200 =#ffd740; 222 | $md-amber-a400 =#ffc400; 223 | $md-amber-a700 =#ffab00; 224 | 225 | $md-orange =#ff9800; 226 | $md-orange-50 =#fff3e0; 227 | $md-orange-100 =#ffe0b2; 228 | $md-orange-200 =#ffcc80; 229 | $md-orange-300 =#ffb74d; 230 | $md-orange-400 =#ffa726; 231 | $md-orange-500 =#ff9800; 232 | $md-orange-600 =#fb8c00; 233 | $md-orange-700 =#f57c00; 234 | $md-orange-800 =#ef6c00; 235 | $md-orange-900 =#e65100; 236 | $md-orange-a100 =#ffd180; 237 | $md-orange-a200 =#ffab40; 238 | $md-orange-a400 =#ff9100; 239 | $md-orange-a700 =#ff6d00; 240 | 241 | $md-deep-orange =#ff5722; 242 | $md-deep-orange-50 =#fbe9e7; 243 | $md-deep-orange-100 =#ffccbc; 244 | $md-deep-orange-200 =#ffab91; 245 | $md-deep-orange-300 =#ff8a65; 246 | $md-deep-orange-400 =#ff7043; 247 | $md-deep-orange-500 =#ff5722; 248 | $md-deep-orange-600 =#f4511e; 249 | $md-deep-orange-700 =#e64a19; 250 | $md-deep-orange-800 =#d84315; 251 | $md-deep-orange-900 =#bf360c; 252 | $md-deep-orange-a100 =#ff9e80; 253 | $md-deep-orange-a200 =#ff6e40; 254 | $md-deep-orange-a400 =#ff3d00; 255 | $md-deep-orange-a700 =#dd2c00; 256 | 257 | $md-brown =#795548; 258 | $md-brown-50 =#efebe9; 259 | $md-brown-100 =#d7ccc8; 260 | $md-brown-200 =#bcaaa4; 261 | $md-brown-300 =#a1887f; 262 | $md-brown-400 =#8d6e63; 263 | $md-brown-500 =#795548; 264 | $md-brown-600 =#6d4c41; 265 | $md-brown-700 =#5d4037; 266 | $md-brown-800 =#4e342e; 267 | $md-brown-900 =#3e2723; 268 | 269 | $md-grey =#9e9e9e; 270 | $md-grey-50 =#fafafa; 271 | $md-grey-100 =#f5f5f5; 272 | $md-grey-200 =#eeeeee; 273 | $md-grey-300 =#e0e0e0; 274 | $md-grey-400 =#bdbdbd; 275 | $md-grey-500 =#9e9e9e; 276 | $md-grey-600 =#757575; 277 | $md-grey-700 =#616161; 278 | $md-grey-800 =#424242; 279 | $md-grey-900 =#212121; 280 | 281 | $md-blue-grey =#607d8b; 282 | $md-blue-grey-50 =#eceff1; 283 | $md-blue-grey-100 =#cfd8dc; 284 | $md-blue-grey-200 =#b0bec5; 285 | $md-blue-grey-300 =#90a4ae; 286 | $md-blue-grey-400 =#78909c; 287 | $md-blue-grey-500 =#607d8b; 288 | $md-blue-grey-600 =#546e7a; 289 | $md-blue-grey-700 =#455a64; 290 | $md-blue-grey-800 =#37474f; 291 | $md-blue-grey-900 =#263238; 292 | 293 | $md-black =#000000; 294 | $md-white =#ffffff; 295 | -------------------------------------------------------------------------------- /src/style/mixins.styl: -------------------------------------------------------------------------------- 1 | ellipsis() { 2 | overflow: hidden; 3 | -ms-text-overflow: ellipsis; 4 | text-overflow: ellipsis; 5 | white-space: nowrap; 6 | } 7 | 8 | bounds($distance) { 9 | top: $distance; 10 | bottom: $distance; 11 | right: $distance; 12 | left: $distance; 13 | } 14 | 15 | overlay() { 16 | position: absolute; 17 | bounds(0); 18 | } 19 | 20 | flex-box() { 21 | display: flex; 22 | 23 | & > * { 24 | flex: auto 0 0; 25 | } 26 | } 27 | 28 | h-box() { 29 | flex-box(); 30 | flex-direction: row; 31 | } 32 | 33 | v-box() { 34 | flex-box(); 35 | flex-direction: column; 36 | } 37 | 38 | flex-control() { 39 | width: 0 !important; 40 | } 41 | 42 | box-center() { 43 | align-items: center; 44 | justify-content: center; 45 | } 46 | 47 | space-between-x($margin) { 48 | margin-right: $margin; 49 | 50 | &:last-child { 51 | margin-right: 0; 52 | } 53 | } 54 | 55 | space-between-y($margin) { 56 | margin-bottom: $margin; 57 | 58 | &:last-child { 59 | margin-bottom: 0; 60 | } 61 | } 62 | 63 | // Disable noisy browser styles 64 | disable-focus-styles() 65 | outline none 66 | -webkit-tap-highlight-color rgba(255, 255, 255, 0) 67 | &::-moz-focus-inner 68 | border 0 69 | 70 | // Buttons 71 | 72 | button-colors($foreground, $background) 73 | color $foreground 74 | background $background 75 | &:not(.ghost) 76 | &:hover, 77 | .vue-ui-dropdown.open .dropdown-trigger & 78 | background lighten($background, 25%) 79 | .vue-ui-dark-mode .vue-ui-dropdown.open .dropdown-trigger & 80 | background $vue-ui-gray-600 81 | color $vue-ui-white 82 | > .content 83 | > .button-icon 84 | svg 85 | fill $vue-ui-white 86 | 87 | &:hover 88 | .vue-ui-dark-mode .popover & 89 | background $vue-ui-gray-800 !important 90 | &:active 91 | background darken($background, 8%) 92 | > .content 93 | > .button-icon 94 | svg 95 | fill $foreground 96 | > .vue-ui-loading-indicator, 97 | > .content > .loading-secondary 98 | .animation 99 | border-right-color $foreground 100 | > .content > .tag-wrapper > .tag 101 | background $foreground 102 | color $background 103 | if $background is transparent 104 | color $vue-ui-white 105 | .vue-ui-dark-mode & 106 | color $vue-ui-gray-800 !important 107 | .vue-ui-high-contrast & 108 | background black !important 109 | color white !important 110 | &::before 111 | background $background 112 | 113 | &.vue-ui-dropdown-button 114 | background transparent 115 | &:not(:hover) 116 | color $vue-ui-gray-800 117 | .vue-ui-dark-mode & 118 | color $vue-ui-white !important 119 | > .content 120 | > .button-icon 121 | svg 122 | fill @color 123 | .vue-ui-dark-mode & 124 | fill $vue-ui-white !important 125 | 126 | button-transitions() 127 | transition background .1s, color .1s 128 | > .content 129 | > .button-icon 130 | svg 131 | transition fill .1s 132 | 133 | // Vue text 134 | 135 | vue-ui-text-colors($c) 136 | color $c 137 | .vue-ui-icon 138 | svg 139 | fill $c !important 140 | &.banner 141 | background lighten($c, 90%) 142 | .vue-ui-dark-mode & 143 | background darken($c, 60%) 144 | -------------------------------------------------------------------------------- /src/style/tooltip.styl: -------------------------------------------------------------------------------- 1 | .v-popper--theme-tooltip 2 | $background = $vue-ui-gray-800 3 | $dark-background = $vue-ui-white 4 | $color = $vue-ui-white 5 | $dark-color = $vue-ui-gray-800 6 | 7 | font-size 14px 8 | 9 | .v-popper__inner 10 | background $background 11 | color $color 12 | 13 | .v-popper__arrow 14 | border-color $background 15 | 16 | .vue-ui-dark-mode & 17 | .v-popper__inner 18 | background $dark-background 19 | color $dark-color 20 | 21 | .v-popper__arrow 22 | border-color $dark-background 23 | 24 | .v-popper--theme-dropdown 25 | $background = $vue-ui-white 26 | $dark-background = $vue-ui-gray-900 27 | $color = $vue-ui-gray-800 28 | $dark-color = $vue-ui-white 29 | 30 | .v-popper__inner 31 | background $background 32 | color $color 33 | padding 4px 0 34 | box-shadow 0 0 3px rgba(black, .05), 0 10px 30px rgba(black, .1) 35 | 36 | .v-popper__arrow 37 | border-color $background 38 | 39 | .vue-ui-dark-mode & 40 | .v-popper__inner 41 | background $dark-background 42 | color $dark-color 43 | 44 | .v-popper__arrow 45 | border-color $dark-background 46 | 47 | &[data-popper-placement^='top'] 48 | .v-popper__arrow 49 | filter drop-shadow(0 3px 3px rgba(black, .15)) 50 | &[data-popper-placement^='bottom'] 51 | .v-popper__arrow 52 | filter drop-shadow(0 -3px 3px rgba(black, .15)) 53 | &[data-popper-placement^='left'] 54 | .v-popper__arrow 55 | filter drop-shadow(3px 0 3px rgba(black, .15)) 56 | &[data-popper-placement^='right'] 57 | .v-popper__arrow 58 | filter drop-shadow(-3px 0 3px rgba(black, .15)) 59 | 60 | // Animation 61 | &.v-popper__popper--show-to, 62 | &.v-popper__popper--hide-to 63 | > .v-popper__wrapper 64 | transition transform .12s ease-out 65 | 66 | &.v-popper__popper--show-from, 67 | &.v-popper__popper--hide-to 68 | &[data-popper-placement^='top'] 69 | > .v-popper__wrapper 70 | transform translateY(6px) 71 | &[data-popper-placement^='bottom'] 72 | > .v-popper__wrapper 73 | transform translateY(-6px) 74 | &[data-popper-placement^='left'] 75 | > .v-popper__wrapper 76 | transform translateX(6px) 77 | &[data-popper-placement^='right'] 78 | > .v-popper__wrapper 79 | transform translateX(-6px) -------------------------------------------------------------------------------- /src/style/vars.styl: -------------------------------------------------------------------------------- 1 | $br = 3px 2 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | lintOnSave: false, 5 | 6 | outputDir: './docs', 7 | publicPath: './', 8 | 9 | configureWebpack: { 10 | entry: { 11 | app: path.resolve(__dirname, './docs-src/main.js'), 12 | }, 13 | resolve: { 14 | alias: { 15 | '@style': path.resolve(__dirname, './src/style/imports.styl'), 16 | '@': path.resolve(__dirname, './docs-src'), 17 | }, 18 | }, 19 | }, 20 | 21 | chainWebpack: config => { 22 | config.module 23 | .rule('js') 24 | .include 25 | .add(path.resolve(__dirname, './docs-src')) 26 | 27 | config.module 28 | .rule('vue') 29 | .use('vue-loader') 30 | .loader('vue-loader') 31 | .tap(options => { 32 | options.compilerOptions.preserveWhitespace = true 33 | return options 34 | }) 35 | }, 36 | } 37 | --------------------------------------------------------------------------------