├── .gitignore ├── README.md ├── deploy-docs.sh ├── docs ├── README.md ├── SUMMARY.md ├── backend.md ├── commands.md ├── e2e.md ├── env.md ├── linter.md ├── pre-processors.md ├── prerender.md ├── proxy.md ├── static.md ├── structure.md └── unit.md ├── meta.js ├── package.json └── template ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── README.md ├── build ├── build.js ├── check-versions.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── webpack.base.conf.js ├── webpack.bundle.conf.js ├── webpack.dev.conf.js └── webpack.docs.conf.js ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── docs ├── assets │ ├── _functions.sass │ ├── base │ │ ├── _animations.sass │ │ ├── _functions.sass │ │ ├── _global.sass │ │ ├── _media.sass │ │ ├── _mixins.sass │ │ ├── _typo.sass │ │ ├── _z-stack.scss │ │ └── normalize.scss │ ├── components │ │ ├── _avatars.sass │ │ ├── _breadcrumbs.sass │ │ ├── _buttons.sass │ │ ├── _dropdown.sass │ │ ├── _flex_grid.sass │ │ ├── _grid.sass │ │ ├── _inputs.sass │ │ ├── _lists.sass │ │ ├── _mobile_nav.sass │ │ ├── _offcanvas.sass │ │ ├── _panels.sass │ │ ├── _table.sass │ │ └── _tabs.sass │ ├── github.svg │ ├── layout │ │ └── _topbar.sass │ ├── logo.png │ ├── main.sass │ ├── multiselect.sass │ ├── prism.scss │ └── utils │ │ ├── _utils.sass │ │ └── _visibility.sass ├── docs.scss ├── index.pug ├── main.js └── partials │ ├── _footer.pug │ ├── _getting-started.pug │ ├── _nav.pug │ ├── _start.pug │ ├── api │ ├── _events.pug │ ├── _props.pug │ └── _slots.pug │ └── examples │ └── _section.pug ├── index.html ├── package.json ├── src ├── MyComponent.vue └── index.js ├── static ├── .gitkeep ├── monterail-logo.png ├── prism.js └── vue-logo.png └── test ├── e2e ├── custom-assertions │ └── elementCount.js ├── nightwatch.conf.js ├── runner.js └── specs │ └── test.js └── unit ├── .eslintrc ├── index.js ├── karma.conf.js └── specs └── Hello.spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | docs/_book 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-component-template 2 | 3 | > A full-featured Webpack setup with hot-reload, lint-on-save, unit testing & css extraction for open source Vue components. 4 | 5 | > Based on the official vue-webpack-boilerplate template 6 | 7 | > This template is Vue 2.0 compatible. 8 | 9 | ## Documentation 10 | 11 | - [For this template](http://vuejs-templates.github.io/webpack): common questions specific to this template are answered and each part is described in greater detail 12 | - [For Vue 2.0](http://vuejs.org/guide/): general information about how to work with Vue, not specific to this template 13 | 14 | ## Usage 15 | 16 | This is a project template for [vue-cli](https://github.com/vuejs/vue-cli). **It is recommended to use npm 3+ for a more efficient dependency tree.** 17 | 18 | ``` bash 19 | $ npm install -g vue-cli 20 | $ vue init monterail/vue-component-template my-project 21 | $ cd my-project 22 | $ npm install 23 | $ npm run dev 24 | ``` 25 | 26 | ## What's Included 27 | 28 | - `npm run dev`: first-in-class development experience. 29 | - Webpack + `vue-loader` for single file Vue components. 30 | - State preserving hot-reload 31 | - State preserving compilation error overlay 32 | - Lint-on-save with ESLint 33 | - Source maps 34 | 35 | - `npm run bundle`: Create UMD bundle. 36 | 37 | - `npm run docs`: Create docs inside `/gh-pages` ready to be published 38 | 39 | - `npm run unit`: Unit tests run in PhantomJS with [Karma](http://karma-runner.github.io/0.13/index.html) + [Mocha](http://mochajs.org/) + [karma-webpack](https://github.com/webpack/karma-webpack). 40 | - Supports ES2015 in test files. 41 | - Supports all webpack loaders. 42 | - Easy mock injection. 43 | 44 | - `npm run e2e`: End-to-end tests with [Nightwatch](http://nightwatchjs.org/). 45 | - Run tests in multiple browsers in parallel. 46 | - Works with one command out of the box: 47 | - Selenium and chromedriver dependencies automatically handled. 48 | - Automatically spawns the Selenium server. 49 | -------------------------------------------------------------------------------- /deploy-docs.sh: -------------------------------------------------------------------------------- 1 | cd docs 2 | rm -rf _book 3 | gitbook build 4 | cd _book 5 | git init 6 | git add -A 7 | git commit -m 'update book' 8 | git push -f git@github.com:vuejs-templates/webpack.git master:gh-pages 9 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This boilerplate is targeted towards large, serious projects and assumes you are somewhat familiar with Webpack and `vue-loader`. Make sure to also read [`vue-loader`'s documentation](http://vuejs.github.io/vue-loader/index.html) for common workflow recipes. 4 | 5 | If you just want to try out `vue-loader` or whip out a quick prototype, use the [webpack-simple](https://github.com/vuejs-templates/webpack-simple) template instead. 6 | 7 | ## Quickstart 8 | 9 | To use this template, scaffold a project with [vue-cli](https://github.com/vuejs/vue-cli). **It is recommended to use npm 3+ for a more efficient dependency tree.** 10 | 11 | ``` bash 12 | $ npm install -g vue-cli 13 | $ vue init webpack my-project 14 | $ cd my-project 15 | $ npm install 16 | $ npm run dev 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Project Structure](structure.md) 4 | - [Build Commands](commands.md) 5 | - [Linter Configuration](linter.md) 6 | - [Pre-Processors](pre-processors.md) 7 | - [Handling Static Assets](static.md) 8 | - [Environment Variables](env.md) 9 | - [Integrate with Backend Framework](backend.md) 10 | - [API Proxying During Development](proxy.md) 11 | - [Unit Testing](unit.md) 12 | - [End-to-end Testing](e2e.md) 13 | - [Prerendering for SEO](prerender.md) 14 | -------------------------------------------------------------------------------- /docs/backend.md: -------------------------------------------------------------------------------- 1 | # Integrating with Backend Framework 2 | 3 | If you are building a purely-static app (one that is deployed separately from the backend API), then you probably don't even need to edit `config/index.js`. However, if you want to integrate this template with an existing backend framework, e.g. Rails/Django/Laravel, which comes with their own project structures, you can edit `config/index.js` to directly generate front-end assets into your backend project. 4 | 5 | Let's take a look at the default `config/index.js`: 6 | 7 | ``` js 8 | var path = require('path') 9 | 10 | module.exports = { 11 | build: { 12 | index: path.resolve(__dirname, 'dist/index.html'), 13 | assetsRoot: path.resolve(__dirname, 'dist'), 14 | assetsSubDirectory: 'static', 15 | assetsPublicPath: '/', 16 | productionSourceMap: true 17 | }, 18 | dev: { 19 | port: 8080, 20 | proxyTable: {} 21 | } 22 | } 23 | ``` 24 | 25 | Inside the `build` section, we have the following options: 26 | 27 | ### `build.index` 28 | 29 | > Must be an absolute path on your local file system. 30 | 31 | This is where the `index.html` (with injected asset URLs) will be generated. 32 | 33 | If you are using this template with a backend-framework, you can edit `index.html` accordingly and point this path to a view file rendered by your backend app, e.g. `app/views/layouts/application.html.erb` for a Rails app, or `resources/views/index.blade.php` for a Laravel app. 34 | 35 | ### `build.assetsRoot` 36 | 37 | > Must be an absolute path on your local file system. 38 | 39 | This should point to the root directory that contains all the static assets for your app. For example, `public/` for both Rails/Laravel. 40 | 41 | ### `build.assetsSubDirectory` 42 | 43 | Nest webpack-generated assets under this directory in `build.assetsRoot`, so that they are not mixed with other files you may have in `build.assetsRoot`. For example, if `build.assetsRoot` is `/path/to/dist`, and `build.assetsSubDirectory` is `static`, then all Webpack assets will be generated in `path/to/dist/static`. 44 | 45 | This directory will be cleaned before each build, so it should only contain assets generated by the build. 46 | 47 | Files inside `static/` will be copied into this directory as-is during build. This means if you change this prefix, all your absolute URLs referencing files in `static/` will also need to be changed. See [Handling Static Assets](static.md) for more details. 48 | 49 | ### `build.assetsPublicPath` 50 | 51 | This should be the URL path where your `build.assetsRoot` will be served from over HTTP. In most cases, this will be root (`/`). Only change this if your backend framework serves static assets with a path prefix. Internally, this is passed to Webpack as `output.publicPath`. 52 | 53 | ### `build.productionSourceMap` 54 | 55 | Whether to generate source maps for production build. 56 | 57 | ### `dev.port` 58 | 59 | Specify the port for the dev server to listen to. 60 | 61 | ### `dev.proxyTable` 62 | 63 | Define proxy rules for the dev server. See [API Proxying During Development](proxy.md) for more details. 64 | -------------------------------------------------------------------------------- /docs/commands.md: -------------------------------------------------------------------------------- 1 | # Build Commands 2 | 3 | All build commands are executed via [NPM Scripts](https://docs.npmjs.com/misc/scripts). 4 | 5 | ### `npm run dev` 6 | 7 | > Starts a Node.js local development server. See [API Proxying During Development](proxy.md) for more details. 8 | 9 | - Webpack + `vue-loader` for single file Vue components. 10 | - State preserving hot-reload 11 | - State preserving compilation error overlay 12 | - Lint-on-save with ESLint 13 | - Source maps 14 | 15 | ### `npm run build` 16 | 17 | > Build assets for production. See [Integrating with Backend Framework](backend.md) for more details. 18 | 19 | - JavaScript minified with [UglifyJS](https://github.com/mishoo/UglifyJS2). 20 | - HTML minified with [html-minifier](https://github.com/kangax/html-minifier). 21 | - CSS across all components extracted into a single file and minified with [cssnano](https://github.com/ben-eb/cssnano). 22 | - All static assets compiled with version hashes for efficient long-term caching, and a production `index.html` is auto-generated with proper URLs to these generated assets. 23 | - Also see [deployment notes](#how-do-i-deploy-built-assets-with-my-backend-framework). 24 | 25 | ### `npm run unit` 26 | 27 | > Run unit tests in PhantomJS with [Karma](http://karma-runner.github.io/0.13/index.html). See [Unit Testing](unit.md) for more details. 28 | 29 | - Supports ES2015 in test files. 30 | - Supports all webpack loaders. 31 | - Easy [mock injection](http://vuejs.github.io/vue-loader/en/workflow/testing-with-mocks.html). 32 | 33 | ### `npm run e2e` 34 | 35 | > Run end-to-end tests with [Nightwatch](http://nightwatchjs.org/). See [End-to-end Testing](e2e.md) for more details. 36 | 37 | - Run tests in multiple browsers in parallel. 38 | - Works with one command out of the box: 39 | - Selenium and chromedriver dependencies automatically handled. 40 | - Automatically spawns the Selenium server. 41 | -------------------------------------------------------------------------------- /docs/e2e.md: -------------------------------------------------------------------------------- 1 | # End-to-end Testing 2 | 3 | This boilerplate uses [Nightwatch.js](http://nightwatchjs.org) for e2e tests. Nightwatch.js is a highly integrated e2e test runner built on top of Selenium. This boilerplate comes with Selenium server and chromedriver binaries pre-configured for you, so you don't have to mess with these yourself. 4 | 5 | Let's take a look at the files in the `test/e2e` directory: 6 | 7 | - `runner.js` 8 | 9 | A Node.js script that starts the dev server, and then launches Nightwatch to run tests against it. This is the script that will run when you run `npm run e2e`. 10 | 11 | - `nightwatch.conf.js` 12 | 13 | Nightwatch configuration file. See [Nightwatch's docs on configuration](http://nightwatchjs.org/guide#settings-file) for more details. 14 | 15 | - `custom-assertions/` 16 | 17 | Custom assertions that can be used in Nightwatch tests. See [Nightwatch's docs on writing custom assertions](http://nightwatchjs.org/guide#writing-custom-assertions) for more details. 18 | 19 | - `specs/` 20 | 21 | You actual tests! See [Nightwatch's docs on writing tests](http://nightwatchjs.org/guide#writing-tests) and [API reference](http://nightwatchjs.org/api) for more details. 22 | 23 | ### Running Tests in More Browsers 24 | 25 | To configure which browsers to run the tests in, add an entry under "test_settings" in [`test/e2e/nightwatch.conf.js`](https://github.com/vuejs-templates/webpack/blob/master/template/test/e2e/nightwatch.conf.js#L17-L39) , and also the `--env` flag in [`test/e2e/runner.js`](https://github.com/vuejs-templates/webpack/blob/master/template/test/e2e/runner.js#L15). If you wish to configure remote testing on services like SauceLabs, you can either make the Nightwatch config conditional based on environment variables, or use a separate config file altogether. Consult [Nightwatch's docs on Selenium](http://nightwatchjs.org/guide#selenium-settings) for more details. 26 | -------------------------------------------------------------------------------- /docs/env.md: -------------------------------------------------------------------------------- 1 | # Environment Variables 2 | 3 | Sometimes it is practical to have different config values according to the environment that the application is running in. 4 | 5 | As an example: 6 | 7 | ```js 8 | // config/prod.env.js 9 | module.exports = { 10 | NODE_ENV: '"production"', 11 | DEBUG_MODE: false, 12 | API_KEY: '"..."' // this is shared between all environments 13 | } 14 | 15 | // config/dev.env.js 16 | module.exports = merge(prodEnv, { 17 | NODE_ENV: '"development"', 18 | DEBUG_MODE: true // this overrides the DEBUG_MODE value of prod.env 19 | }) 20 | 21 | // config/test.env.js 22 | module.exports = merge(devEnv, { 23 | NODE_ENV: '"testing"' 24 | }) 25 | ``` 26 | 27 | > **Note:** string variables need to be wrapped into single and double quotes `'"..."'` 28 | 29 | So, the environment variables are: 30 | - Production 31 | - NODE_ENV = 'production', 32 | - DEBUG_MODE = false, 33 | - API_KEY = '...' 34 | - Development 35 | - NODE_ENV = 'development', 36 | - DEBUG_MODE = true, 37 | - API_KEY = '...' 38 | - Testing 39 | - NODE_ENV = 'testing', 40 | - DEBUG_MODE = true, 41 | - API_KEY = '...' 42 | 43 | As we can see, `test.env` inherits the `dev.env` and the `dev.env` inherits the `prod.env`. 44 | 45 | ### Usage 46 | 47 | It is simple to use the environment variables in your code. For example: 48 | 49 | ```js 50 | Vue.config.debug = process.env.DEBUG_MODE 51 | ``` -------------------------------------------------------------------------------- /docs/linter.md: -------------------------------------------------------------------------------- 1 | # Linter Configuration 2 | 3 | This boilerplate uses [ESLint](http://eslint.org/) as the linter, and uses the [Standard](https://github.com/feross/standard/blob/master/RULES.md) preset with some small customizations. 4 | 5 | If you are not happy with the default linting rules, you have several options: 6 | 7 | 1. Overwrite individual rules in `.eslintrc.js`. For example, you can add the following rule to enforce semicolons instead of omitting them: 8 | 9 | ``` js 10 | "semi": [2, "always"] 11 | ``` 12 | 13 | 2. Pick a different ESLint preset when generating the project, for example [eslint-config-airbnb](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb). 14 | 15 | 3. Pick "none" for ESLint preset when generating the project and define your own rules. See [ESLint documentation](http://eslint.org/docs/rules/) for more details. 16 | -------------------------------------------------------------------------------- /docs/pre-processors.md: -------------------------------------------------------------------------------- 1 | # Pre-Processors 2 | 3 | This boilerplate has pre-configured CSS extraction for most popular CSS pre-processors including LESS, SASS, Stylus, and PostCSS. To use a pre-processor, all you need to do is installing the appropriate webpack loader for it. For example, to use SASS: 4 | 5 | ``` bash 6 | npm install sass-loader node-sass --save-dev 7 | ``` 8 | 9 | Note you also need to install `node-sass` because `sass-loader` depends on it as a peer dependency. 10 | 11 | ### Using Pre-Processors inside Components 12 | 13 | Once installed, you can use the pre-processors inside your `*.vue` components using the `lang` attribute on ` 19 | ``` 20 | 21 | ### A note on SASS syntax 22 | 23 | - `lang="scss"` corresponds to the CSS-superset syntax (with curly braces and semicolones). 24 | - `lang="sass"` corresponds to the indentation-based syntax. 25 | 26 | ### PostCSS 27 | 28 | Styles in `*.vue` files are piped through PostCSS by default, so you don't need to use a specific loader for it. You can simply add PostCSS plugins you want to use in `build/webpack.base.conf.js` under the `vue` block: 29 | 30 | ``` js 31 | // build/webpack.base.conf.js 32 | module.exports = { 33 | // ... 34 | vue: { 35 | postcss: [/* your plugins */] 36 | } 37 | } 38 | ``` 39 | 40 | See [vue-loader's related documentation](http://vuejs.github.io/vue-loader/en/features/postcss.html) for more details. 41 | 42 | ### Standalone CSS Files 43 | 44 | To ensure consistent extraction and processing, it is recommended to import global, standalone style files from your root `App.vue` component, for example: 45 | 46 | ``` html 47 | 48 | 49 | ``` 50 | 51 | Note you should probably only do this for the styles written by yourself for your application. For existing libraries e.g. Bootstrap or Semantic UI, you can place them inside `/static` and reference them directly in `index.html`. This avoids extra build time and also is better for browser caching. (See [Static Asset Handling](static.md)) 52 | -------------------------------------------------------------------------------- /docs/prerender.md: -------------------------------------------------------------------------------- 1 | # Prerendering for SEO 2 | 3 | If you want to prerender routes that will not significantly change once pushed to production, use this Webpack plugin: [prerender-spa-plugin](https://www.npmjs.com/package/prerender-spa-plugin), which has been tested for use with Vue. For pages that _do_ frequently change, [Prerender.io](https://prerender.io/) and [Netlify](https://www.netlify.com/pricing) both offer plans for regularly re-prerendering your content for search engines. 4 | 5 | ## Using `prerender-spa-plugin` 6 | 7 | 1. Install it as a dev dependency: 8 | 9 | ```bash 10 | npm install --save-dev prerender-spa-plugin 11 | ``` 12 | 13 | 2. Require it in **build/webpack.prod.conf.js**: 14 | 15 | ```js 16 | // This line should go at the top of the file where other 'imports' live in 17 | var PrerenderSpaPlugin = require('prerender-spa-plugin') 18 | ``` 19 | 20 | 3. Configure it in the `plugins` array (also in **build/webpack.prod.conf.js**): 21 | 22 | ```js 23 | new PrerenderSpaPlugin( 24 | // Path to compiled app 25 | path.join(__dirname, '../dist'), 26 | // List of endpoints you wish to prerender 27 | [ '/' ] 28 | ) 29 | ``` 30 | 31 | If you also wanted to prerender `/about` and `/contact`, then that array would be `[ '/', '/about', '/contact' ]`. 32 | -------------------------------------------------------------------------------- /docs/proxy.md: -------------------------------------------------------------------------------- 1 | # API Proxying During Development 2 | 3 | When integrating this boilerplate with an existing backend, a common need is to access the backend API when using the dev server. To achieve that, we can run the dev server and the API backend side-by-side (or remotely), and let the dev server proxy all API requests to the actual backend. 4 | 5 | To configure the proxy rules, edit `dev.proxyTable` option in `config/index.js`. The dev server is using [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) for proxying, so you should refer to its docs for detailed usage. But here's a simple example: 6 | 7 | ``` js 8 | // config/index.js 9 | module.exports = { 10 | // ... 11 | dev: { 12 | proxyTable: { 13 | // proxy all requests starting with /api to jsonplaceholder 14 | '/api': { 15 | target: 'http://jsonplaceholder.typicode.com', 16 | changeOrigin: true, 17 | pathRewrite: { 18 | '^/api': '' 19 | } 20 | } 21 | } 22 | } 23 | } 24 | ``` 25 | 26 | The above example will proxy the request `/api/posts/1` to `http://jsonplaceholder.typicode.com/posts/1`. 27 | -------------------------------------------------------------------------------- /docs/static.md: -------------------------------------------------------------------------------- 1 | # Handing Static Assets 2 | 3 | You will notice in the project structure we have two directories for static assets: `src/assets` and `static/`. What is the difference between them? 4 | 5 | ### Webpacked Assets 6 | 7 | To answer this question, we first need to understand how Webpack deals with static assets. In `*.vue` components, all your templates and CSS are parsed by `vue-html-loader` and `css-loader` to look for asset URLs. For example, in `` and `background: url(./logo.png)`, `"./logo.png"` is a relative asset path and will be **resolved by Webpack as a module dependency**. 8 | 9 | Because `logo.png` is not JavaScript, when treated as a module dependency, we need to use `url-loader` and `file-loader` to process it. This boilerplate has already configured these loaders for you, so you basically get features such as filename fingerprinting and conditional base64 inlining for free, while being able to use relative/module paths without worrying about deployment. 10 | 11 | Since these assets may be inlined/copied/renamed during build, they are essentially part of your source code. This is why it is recommended to place Webpack-processed static assets inside `/src`, along side other source files. In fact, you don't even have to put them all in `/src/assets`: you can organize them based on the module/component using them. For example, you can put each component in its own directory, with its static assets right next to it. 12 | 13 | ### Asset Resolving Rules 14 | 15 | - **Relative URLs**, e.g. `./assets/logo.png` will be interpreted as a module dependency. They will be replaced with an auto-generated URL based on your Webpack output configuration. 16 | 17 | - **Non-prefixed URLs**, e.g. `assets/logo.png` will be treated the same as the relative URLs and translated into `./assets/logo.png`. 18 | 19 | - **URLs prefixed with `~`** are treated as a module request, similar to `require('some-module/image.png')`. You need to use this prefix if you want to leverage Webpack's module resolving configurations. For example if you have a resolve alias for `assets`, you need to use `` to ensure that alias is respected. 20 | 21 | - **Root-relative URLs**, e.g. `/assets/logo.png` are not processed at all. 22 | 23 | ### Getting Asset Paths in JavaScript 24 | 25 | In order for Webpack to return the correct asset paths, you need to use `require('./relative/path/to/file.jpg')`, which will get processed by `file-loader` and returns the resolved URL. For example: 26 | 27 | ``` js 28 | computed: { 29 | background () { 30 | return require('./bgs/' + this.id + '.jpg') 31 | } 32 | } 33 | ``` 34 | 35 | **Note the above example will include every image under `./bgs/` in the final build.** This is because Webpack cannot guess which of them will be used at runtime, so it includes them all. 36 | 37 | ### "Real" Static Assets 38 | 39 | In comparison, files in `static/` are not processed by Webpack at all: they are directly copied to their final destination as-is, with the same filename. You must reference these files using absolute paths, which is determined by joining `build.assetsPublicPath` and `build.assetsSubDirectory` in `config.js`. 40 | 41 | As an example, with the following default values: 42 | 43 | ``` js 44 | // config.js 45 | module.exports = { 46 | // ... 47 | build: { 48 | assetsPublicPath: '/', 49 | assetsSubDirectory: 'static' 50 | } 51 | } 52 | ``` 53 | 54 | Any file placed in `static/` should be referenced using the absolute URL `/static/[filename]`. If you change `assetSubDirectory` to `assets`, then these URLs will need to be changed to `/assets/[filename]`. 55 | 56 | We will learn more about the config file in the section about [backend integration](backend.md). 57 | -------------------------------------------------------------------------------- /docs/structure.md: -------------------------------------------------------------------------------- 1 | # Project Structure 2 | 3 | ``` bash 4 | . 5 | ├── build/ # webpack config files 6 | │ └── ... 7 | ├── config/ 8 | │   ├── index.js # main project config 9 | │ └── ... 10 | ├── src/ 11 | │   ├── main.js # app entry file 12 | │   ├── App.vue # main app component 13 | │   ├── components/ # ui components 14 | │   │   └── ... 15 | │   └── assets/ # module assets (processed by webpack) 16 | │      └── ... 17 | ├── static/ # pure static assets (directly copied) 18 | ├── test/ 19 | │ └── unit/ # unit tests 20 | │ │   ├── specs/ # test spec files 21 | │ │   ├── index.js # test build entry file 22 | │ │   └── karma.conf.js # test runner config file 23 | │ └── e2e/ # e2e tests 24 | │ │   ├── specs/ # test spec files 25 | │ │   ├── custom-assertions/ # custom assertions for e2e tests 26 | │ │   ├── runner.js # test runner script 27 | │ │   └── nightwatch.conf.js # test runner config file 28 | ├── .babelrc # babel config 29 | ├── .editorconfig.js # editor config 30 | ├── .eslintrc.js # eslint config 31 | ├── index.html # index.html template 32 | └── package.json # build scripts and dependencies 33 | ``` 34 | 35 | ### `build/` 36 | 37 | This directory holds the actual configurations for both the development server and the production webpack build. Normally you don't need to touch these files unless you want to customize Webpack loaders, in which case you should probably look at `build/webpack.base.conf.js`. 38 | 39 | ### `config/index.js` 40 | 41 | This is the main configuration file that exposes some of the most common configuration options for the build setup. See [API Proxying During Development](proxy.md) and [Integrating with Backend Framework](backend.md) for more details. 42 | 43 | ### `src/` 44 | 45 | This is where most of your application code will live in. How to structure everything inside this directory is largely up to you; if you are using Vuex, you can consult the [recommendations for Vuex applications](http://vuex.vuejs.org/en/structure.html). 46 | 47 | ### `static/` 48 | 49 | This directory is an escape hatch for static assets that you do not want to process with Webpack. They will be directly copied into the same directory where webpack-built assets are generated. 50 | 51 | See [Handling Static Assets](static.md) for more details. 52 | 53 | ### `test/unit` 54 | 55 | Contains unit test related files. See [Unit Testing](unit.md) for more details. 56 | 57 | ### `test/e2e` 58 | 59 | Contains e2e test related files. See [End-to-end Testing](e2e.md) for more details. 60 | 61 | ### `index.html` 62 | 63 | This is the **template** `index.html` for our single page application. During development and builds, Webpack will generate assets, and the URLs for those generated assets will be automatically injected into this template to render the final HTML. 64 | 65 | ### `package.json` 66 | 67 | The NPM package meta file that contains all the build dependencies and [build commands](commands.md). 68 | -------------------------------------------------------------------------------- /docs/unit.md: -------------------------------------------------------------------------------- 1 | # Unit Testing 2 | 3 | An overview of the tools used by this boilerplate for unit testing: 4 | 5 | - [Karma](http://karma-runner.github.io/0.13/index.html): the test runner that launches browsers, runs the tests and reports the results to us. 6 | - [karma-webpack](https://github.com/webpack/karma-webpack): the plugin for Karma that bundles our tests using Webpack. 7 | - [Mocha](https://mochajs.org/): the test framework that we write test specs with. 8 | - [Chai](http://chaijs.com/): test assertion library that provides better assertion syntax. 9 | - [Sinon](http://sinonjs.org/): test utility library that provides spies, stubs and mocks. 10 | 11 | Chai and Sinon are integrated using [karma-sinon-chai](https://github.com/kmees/karma-sinon-chai), so all Chai interfaces (`should`, `expect`, `assert`) and `sinon` are globally available in test files. 12 | 13 | And the files: 14 | 15 | - `index.js` 16 | 17 | This is the entry file used by `karma-webpack` to bundle all the test code and source code (for coverage purposes). You can ignore it for the most part. 18 | 19 | - `specs/` 20 | 21 | This directory is where you write your actual tests. You can use full ES2015 and all supported Webpack loaders in your tests. 22 | 23 | - `karma.conf.js` 24 | 25 | This is the Karma configuration file. See [Karma docs](http://karma-runner.github.io/0.13/index.html) for more details. 26 | 27 | ## Running Tests in More Browsers 28 | 29 | You can run the tests in multiple real browsers by installing more [karma launchers](http://karma-runner.github.io/0.13/config/browsers.html) and adjusting the `browsers` field in `test/unit/karma.conf.js`. 30 | 31 | ## Mocking Dependencies 32 | 33 | This boilerplate comes with [inject-loader](https://github.com/plasticine/inject-loader) installed by default. For usage with `*.vue` components, see [vue-loader docs on testing with mocks](http://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html). 34 | -------------------------------------------------------------------------------- /meta.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "helpers": { 3 | "if_or": function (v1, v2, options) { 4 | if (v1 || v2) { 5 | return options.fn(this); 6 | } 7 | 8 | return options.inverse(this); 9 | } 10 | }, 11 | "prompts": { 12 | "name": { 13 | "type": "string", 14 | "required": true, 15 | "message": "Project name" 16 | }, 17 | "description": { 18 | "type": "string", 19 | "required": false, 20 | "message": "Project description", 21 | "default": "A Vue.js project" 22 | }, 23 | "author": { 24 | "type": "string", 25 | "message": "Author" 26 | }, 27 | "build": { 28 | "type": "list", 29 | "message": "Vue build", 30 | "choices": [ 31 | { 32 | "name": "Runtime + Compiler: recommended for most users", 33 | "value": "standalone", 34 | "short": "standalone" 35 | }, 36 | { 37 | "name": "Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .vue files - render functions are required elsewhere", 38 | "value": "runtime", 39 | "short": "runtime" 40 | } 41 | ] 42 | }, 43 | "lint": { 44 | "type": "confirm", 45 | "message": "Use ESLint to lint your code?" 46 | }, 47 | "lintConfig": { 48 | "when": "lint", 49 | "type": "list", 50 | "message": "Pick an ESLint preset", 51 | "choices": [ 52 | { 53 | "name": "Standard (https://github.com/feross/standard)", 54 | "value": "standard", 55 | "short": "Standard" 56 | }, 57 | { 58 | "name": "AirBNB (https://github.com/airbnb/javascript)", 59 | "value": "airbnb", 60 | "short": "AirBNB" 61 | }, 62 | { 63 | "name": "none (configure it yourself)", 64 | "value": "none", 65 | "short": "none" 66 | } 67 | ] 68 | }, 69 | "unit": { 70 | "type": "confirm", 71 | "message": "Setup unit tests with Karma + Mocha?" 72 | }, 73 | "e2e": { 74 | "type": "confirm", 75 | "message": "Setup e2e tests with Nightwatch?" 76 | } 77 | }, 78 | "filters": { 79 | ".eslintrc.js": "lint", 80 | ".eslintignore": "lint", 81 | "config/test.env.js": "unit || e2e", 82 | "test/unit/**/*": "unit", 83 | "test/e2e/**/*": "e2e" 84 | }, 85 | "completeMessage": "To get started:\n\n cd {{destDirName}}\n npm install\n npm run dev\n\nDocumentation can be found at https://vuejs-templates.github.io/webpack" 86 | }; 87 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cli-template-webpack", 3 | "version": "2.0.0", 4 | "license": "MIT", 5 | "description": "A full-featured Webpack setup with hot-reload, lint-on-save, unit testing & css extraction.", 6 | "scripts": { 7 | "docs": "cd docs && gitbook serve", 8 | "deploy-docs": "bash ./deploy-docs.sh" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /template/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /template/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /template/.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /template/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | {{#if_eq lintConfig "standard"}} 8 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 9 | extends: 'standard', 10 | {{/if_eq}} 11 | {{#if_eq lintConfig "airbnb"}} 12 | extends: 'airbnb-base', 13 | {{/if_eq}} 14 | // required to lint *.vue files 15 | plugins: [ 16 | 'html' 17 | ], 18 | {{#if_eq lintConfig "airbnb"}} 19 | // check if imports actually resolve 20 | 'settings': { 21 | 'import/resolver': { 22 | 'webpack': { 23 | 'config': 'build/webpack.base.conf.js' 24 | } 25 | } 26 | }, 27 | {{/if_eq}} 28 | // add your custom rules here 29 | 'rules': { 30 | {{#if_eq lintConfig "standard"}} 31 | // allow paren-less arrow functions 32 | 'arrow-parens': 0, 33 | // allow async-await 34 | 'generator-star-spacing': 0, 35 | {{/if_eq}} 36 | {{#if_eq lintConfig "airbnb"}} 37 | // don't require .vue extension when importing 38 | 'import/extensions': ['error', 'always', { 39 | 'js': 'never', 40 | 'vue': 'never' 41 | }], 42 | {{/if_eq}} 43 | // allow debugger during development 44 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /template/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | {{#unit}} 6 | test/unit/coverage 7 | {{/unit}} 8 | {{#e2e}} 9 | test/e2e/reports 10 | selenium-debug.log 11 | {{/e2e}} 12 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # {{ name }} 2 | 3 | > {{ description }} 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # create UMD bundle. 15 | npm run bundle 16 | 17 | # Create docs inside /gh-pages ready to be published 18 | npm run docs 19 | 20 | {{#unit}} 21 | # run unit tests 22 | npm run unit 23 | {{/unit}} 24 | {{#e2e}} 25 | 26 | # run e2e tests 27 | npm run e2e 28 | {{/e2e}} 29 | {{#if_or unit e2e}} 30 | 31 | # run all tests 32 | npm test 33 | {{/if_or}} 34 | ``` 35 | 36 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 37 | -------------------------------------------------------------------------------- /template/build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('./check-versions')() 3 | require('shelljs/global') 4 | env.NODE_ENV = 'production' 5 | 6 | var path = require('path') 7 | var config = require('../config') 8 | var ora = require('ora') 9 | var webpack = require('webpack') 10 | var webpackConfig = require('./webpack.docs.conf') 11 | 12 | console.log( 13 | ' Tip:\n' + 14 | ' Built files are meant to be served over an HTTP server.\n' + 15 | ' Opening index.html over file:// won\'t work.\n' 16 | ) 17 | 18 | var spinner = ora('building for production...') 19 | spinner.start() 20 | 21 | var assetsPath = path.join(config.docs.assetsRoot, config.docs.assetsSubDirectory) 22 | rm('-rf', assetsPath) 23 | mkdir('-p', assetsPath) 24 | cp('-R', 'static/*', assetsPath) 25 | 26 | webpack(webpackConfig, function (err, stats) { 27 | spinner.stop() 28 | if (err) throw err 29 | process.stdout.write(stats.toString({ 30 | colors: true, 31 | modules: false, 32 | children: false, 33 | chunks: false, 34 | chunkModules: false 35 | }) + '\n') 36 | }) 37 | -------------------------------------------------------------------------------- /template/build/check-versions.js: -------------------------------------------------------------------------------- 1 | var semver = require('semver') 2 | var chalk = require('chalk') 3 | var packageConfig = require('../package.json') 4 | var exec = function (cmd) { 5 | return require('child_process') 6 | .execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | }, 15 | { 16 | name: 'npm', 17 | currentVersion: exec('npm --version'), 18 | versionRequirement: packageConfig.engines.npm 19 | } 20 | ] 21 | 22 | module.exports = function () { 23 | var warnings = [] 24 | for (var i = 0; i < versionRequirements.length; i++) { 25 | var mod = versionRequirements[i] 26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 27 | warnings.push(mod.name + ': ' + 28 | chalk.red(mod.currentVersion) + ' should be ' + 29 | chalk.green(mod.versionRequirement) 30 | ) 31 | } 32 | } 33 | 34 | if (warnings.length) { 35 | console.log('') 36 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 37 | console.log() 38 | for (var i = 0; i < warnings.length; i++) { 39 | var warning = warnings[i] 40 | console.log(' ' + warning) 41 | } 42 | console.log() 43 | process.exit(1) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /template/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /template/build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | var config = require('../config') 3 | if (!process.env.NODE_ENV) process.env.NODE_ENV = config.dev.env 4 | var path = require('path') 5 | var express = require('express') 6 | var webpack = require('webpack') 7 | var opn = require('opn') 8 | var proxyMiddleware = require('http-proxy-middleware') 9 | var webpackConfig = {{#if_or unit e2e}}process.env.NODE_ENV === 'testing' 10 | ? require('./webpack.prod.conf') 11 | : {{/if_or}}require('./webpack.dev.conf') 12 | 13 | // default port where dev server listens for incoming traffic 14 | var port = process.env.PORT || config.dev.port 15 | // Define HTTP proxies to your custom API backend 16 | // https://github.com/chimurai/http-proxy-middleware 17 | var proxyTable = config.dev.proxyTable 18 | 19 | var app = express() 20 | var compiler = webpack(webpackConfig) 21 | 22 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 23 | publicPath: webpackConfig.output.publicPath, 24 | stats: { 25 | colors: true, 26 | chunks: false 27 | } 28 | }) 29 | 30 | var hotMiddleware = require('webpack-hot-middleware')(compiler) 31 | // force page reload when html-webpack-plugin template changes 32 | compiler.plugin('compilation', function (compilation) { 33 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 34 | hotMiddleware.publish({ action: 'reload' }) 35 | cb() 36 | }) 37 | }) 38 | 39 | // proxy api requests 40 | Object.keys(proxyTable).forEach(function (context) { 41 | var options = proxyTable[context] 42 | if (typeof options === 'string') { 43 | options = { target: options } 44 | } 45 | app.use(proxyMiddleware(context, options)) 46 | }) 47 | 48 | // handle fallback for HTML5 history API 49 | app.use(require('connect-history-api-fallback')()) 50 | 51 | // serve webpack bundle output 52 | app.use(devMiddleware) 53 | 54 | // enable hot-reload and state-preserving 55 | // compilation error display 56 | app.use(hotMiddleware) 57 | 58 | // serve pure static assets 59 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 60 | app.use(staticPath, express.static('./static')) 61 | 62 | module.exports = app.listen(port, function (err) { 63 | if (err) { 64 | console.log(err) 65 | return 66 | } 67 | var uri = 'http://localhost:' + port 68 | console.log('Listening at ' + uri + '\n') 69 | 70 | // when env is testing, don't need open it 71 | if (process.env.NODE_ENV !== 'testing') { 72 | opn(uri) 73 | } 74 | }) 75 | -------------------------------------------------------------------------------- /template/build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.docs.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | // generate loader string to be used with extract text plugin 15 | function generateLoaders (loaders) { 16 | var sourceLoader = loaders.map(function (loader) { 17 | var extraParamChar 18 | if (/\?/.test(loader)) { 19 | loader = loader.replace(/\?/, '-loader?') 20 | extraParamChar = '&' 21 | } else { 22 | loader = loader + '-loader' 23 | extraParamChar = '?' 24 | } 25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 26 | }).join('!') 27 | 28 | // Extract CSS when that option is specified 29 | // (which is the case during production docs) 30 | if (options.extract) { 31 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 32 | } else { 33 | return ['vue-style-loader', sourceLoader].join('!') 34 | } 35 | } 36 | 37 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html 38 | return { 39 | css: generateLoaders(['css']), 40 | postcss: generateLoaders(['css']), 41 | less: generateLoaders(['css', 'less']), 42 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 43 | scss: generateLoaders(['css', 'sass']), 44 | stylus: generateLoaders(['css', 'stylus']), 45 | styl: generateLoaders(['css', 'stylus']) 46 | } 47 | } 48 | 49 | // Generate loaders for standalone style files (outside of .vue) 50 | exports.styleLoaders = function (options) { 51 | var output = [] 52 | var loaders = exports.cssLoaders(options) 53 | for (var extension in loaders) { 54 | var loader = loaders[extension] 55 | output.push({ 56 | test: new RegExp('\\.' + extension + '$'), 57 | loader: loader 58 | }) 59 | } 60 | return output 61 | } 62 | -------------------------------------------------------------------------------- /template/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var projectRoot = path.resolve(__dirname, '../') 5 | 6 | var env = process.env.NODE_ENV 7 | // check env & config/index.js to decide weither to enable CSS Sourcemaps for the 8 | // various preprocessor loaders added to vue-loader at the end of this file 9 | var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap) 10 | var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap) 11 | var useCssSourceMap = cssSourceMapDev || cssSourceMapProd 12 | 13 | module.exports = { 14 | entry: { 15 | app: './docs/main.js' 16 | }, 17 | output: { 18 | path: config.docs.assetsRoot, 19 | publicPath: process.env.NODE_ENV === 'production' ? config.docs.assetsPublicPath : config.dev.assetsPublicPath, 20 | filename: '[name].js' 21 | }, 22 | resolve: { 23 | extensions: ['', '.js', '.vue'], 24 | fallback: [path.join(__dirname, '../node_modules')], 25 | alias: { 26 | {{#if_eq build "standalone"}} 27 | 'vue$': 'vue/dist/vue', 28 | {{/if_eq}} 29 | 'src': path.resolve(__dirname, '../src'), 30 | 'assets': path.resolve(__dirname, '../src/assets'), 31 | 'components': path.resolve(__dirname, '../src/components') 32 | } 33 | }, 34 | resolveLoader: { 35 | fallback: [path.join(__dirname, '../node_modules')] 36 | }, 37 | module: { 38 | {{#lint}} 39 | preLoaders: [ 40 | { 41 | test: /\.vue$/, 42 | loader: 'eslint', 43 | include: projectRoot, 44 | exclude: /node_modules/ 45 | }, 46 | { 47 | test: /\.js$/, 48 | loader: 'eslint', 49 | include: projectRoot, 50 | exclude: /node_modules/ 51 | } 52 | ], 53 | {{/lint}} 54 | loaders: [ 55 | { 56 | test: /\.vue$/, 57 | loader: 'vue' 58 | }, 59 | { 60 | test: /\.js$/, 61 | loader: 'babel', 62 | include: projectRoot, 63 | exclude: /node_modules/ 64 | }, 65 | { 66 | test: /\.json$/, 67 | loader: 'json' 68 | }, 69 | { 70 | test: /\.pug$/, 71 | loader: 'pug' 72 | }, 73 | { 74 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 75 | loader: 'url', 76 | query: { 77 | limit: 10000, 78 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 79 | } 80 | }, 81 | { 82 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 83 | loader: 'url', 84 | query: { 85 | limit: 10000, 86 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 87 | } 88 | } 89 | ] 90 | }, 91 | {{#lint}} 92 | eslint: { 93 | formatter: require('eslint-friendly-formatter') 94 | }, 95 | {{/lint}} 96 | vue: { 97 | loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }), 98 | postcss: [ 99 | require('autoprefixer')({ 100 | browsers: ['last 2 versions'] 101 | }) 102 | ] 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /template/build/webpack.bundle.conf.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const CopyWebpackPlugin = require('copy-webpack-plugin') 3 | const base = require('./webpack.base.conf') 4 | const config = require('../config') 5 | 6 | base.entry = { 7 | lib: './src/index.js' 8 | } 9 | 10 | base.output = { 11 | path: config.bundle.assetsRoot, 12 | publicPath: config.bundle.assetsPublicPath, 13 | filename: '{{ name }}.min.js', 14 | library: '{{ name }}', 15 | libraryTarget: 'umd' 16 | } 17 | 18 | var webpackConfig = Object.assign({}, base) 19 | 20 | webpackConfig.plugins = (webpackConfig.plugins || []).concat([ 21 | new webpack.DefinePlugin({ 22 | 'process.env': { 23 | NODE_ENV: '"production"' 24 | } 25 | }), 26 | new webpack.optimize.UglifyJsPlugin({ 27 | compress: { warnings: false } 28 | }), 29 | new webpack.optimize.OccurenceOrderPlugin(), 30 | new CopyWebpackPlugin([ 31 | { from: './src/' } 32 | ], { 33 | ignore: ['.DS_Store', 'index.js'] 34 | }) 35 | ]) 36 | 37 | module.exports = webpackConfig 38 | -------------------------------------------------------------------------------- /template/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var webpack = require('webpack') 3 | var merge = require('webpack-merge') 4 | var utils = require('./utils') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | 8 | // add hot-reload related code to entry chunks 9 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 10 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 11 | }) 12 | 13 | module.exports = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 16 | }, 17 | // eval-source-map is faster for development 18 | devtool: '#eval-source-map', 19 | plugins: [ 20 | new webpack.DefinePlugin({ 21 | 'process.env': config.dev.env 22 | }), 23 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 24 | new webpack.optimize.OccurenceOrderPlugin(), 25 | new webpack.HotModuleReplacementPlugin(), 26 | new webpack.NoErrorsPlugin(), 27 | // https://github.com/ampedandwired/html-webpack-plugin 28 | new HtmlWebpackPlugin({ 29 | filename: 'index.html', 30 | template: 'docs/index.pug', 31 | inject: true 32 | }) 33 | ] 34 | }) 35 | -------------------------------------------------------------------------------- /template/build/webpack.docs.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var env = {{#if_or unit e2e}}process.env.NODE_ENV === 'testing' 10 | ? require('../config/test.env') 11 | : {{/if_or}}config.docs.env 12 | 13 | var webpackConfig = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.docs.productionSourceMap, extract: true }) 16 | }, 17 | devtool: config.docs.productionSourceMap ? '#source-map' : false, 18 | output: { 19 | path: config.docs.assetsRoot, 20 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 21 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 22 | }, 23 | vue: { 24 | loaders: utils.cssLoaders({ 25 | sourceMap: config.docs.productionSourceMap, 26 | extract: true 27 | }) 28 | }, 29 | plugins: [ 30 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 31 | new webpack.DefinePlugin({ 32 | 'process.env': env 33 | }), 34 | new webpack.optimize.UglifyJsPlugin({ 35 | compress: { 36 | warnings: false 37 | } 38 | }), 39 | new webpack.optimize.OccurenceOrderPlugin(), 40 | // extract css into its own file 41 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 42 | // generate dist index.html with correct asset hash for caching. 43 | // you can customize output by editing /index.html 44 | // see https://github.com/ampedandwired/html-webpack-plugin 45 | new HtmlWebpackPlugin({ 46 | filename: {{#if_or unit e2e}}process.env.NODE_ENV === 'testing' 47 | ? 'index.html' 48 | : {{/if_or}}config.docs.index, 49 | template: 'docs/index.html', 50 | inject: true, 51 | minify: { 52 | removeComments: true, 53 | collapseWhitespace: true, 54 | removeAttributeQuotes: true 55 | // more options: 56 | // https://github.com/kangax/html-minifier#options-quick-reference 57 | }, 58 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 59 | chunksSortMode: 'dependency' 60 | }), 61 | // split vendor js into its own file 62 | new webpack.optimize.CommonsChunkPlugin({ 63 | name: 'vendor', 64 | minChunks: function (module, count) { 65 | // any required modules inside node_modules are extracted to vendor 66 | return ( 67 | module.resource && 68 | /\.js$/.test(module.resource) && 69 | module.resource.indexOf( 70 | path.join(__dirname, '../node_modules') 71 | ) === 0 72 | ) 73 | } 74 | }), 75 | // extract webpack runtime and module manifest to its own file in order to 76 | // prevent vendor hash from being updated whenever app bundle is updated 77 | new webpack.optimize.CommonsChunkPlugin({ 78 | name: 'manifest', 79 | chunks: ['vendor'] 80 | }) 81 | ] 82 | }) 83 | 84 | module.exports = webpackConfig 85 | -------------------------------------------------------------------------------- /template/config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /template/config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | dev: { 6 | env: require('./dev.env'), 7 | port: 8080, 8 | assetsSubDirectory: 'static', 9 | assetsPublicPath: '/', 10 | proxyTable: {}, 11 | // CSS Sourcemaps off by default because relative paths are "buggy" 12 | // with this option, according to the CSS-Loader README 13 | // (https://github.com/webpack/css-loader#sourcemaps) 14 | // In our experience, they generally work as expected, 15 | // just be aware of this issue when enabling this option. 16 | cssSourceMap: false 17 | }, 18 | bundle: { 19 | env: require('./prod.env'), 20 | assetsRoot: path.resolve(__dirname, '../dist'), 21 | assetsPublicPath: '/' 22 | }, 23 | docs: { 24 | env: require('./prod.env'), 25 | index: path.resolve(__dirname, '../gh-pages/index.html'), 26 | assetsRoot: path.resolve(__dirname, '../gh-pages'), 27 | assetsSubDirectory: 'static', 28 | assetsPublicPath: '', 29 | productionSourceMap: true 30 | }, 31 | } 32 | -------------------------------------------------------------------------------- /template/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /template/config/test.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var devEnv = require('./dev.env') 3 | 4 | module.exports = merge(devEnv, { 5 | NODE_ENV: '"testing"' 6 | }) 7 | -------------------------------------------------------------------------------- /template/docs/assets/_functions.sass: -------------------------------------------------------------------------------- 1 | @function no-unit($value) 2 | @return $value / ($value * 0 + 1) 3 | 4 | @function to-rem($rem, $base-size: 16px) 5 | $rem: no-unit($rem) / no-unit($base-size) * 1rem 6 | @if ($rem == 0rem) 7 | $rem: 0 8 | @return $rem 9 | 10 | @function rem($values) 11 | $values-list: length($values) 12 | 13 | @if $values-list == 1 14 | @return to-rem($values) 15 | 16 | $rem-list: () 17 | 18 | @for $i from 1 through $values-list 19 | $rem-list: append($rem-list, to-rem(nth($values, $i))) 20 | 21 | @return $rem-list 22 | 23 | @mixin spinner($size: 16px, $color: #333, $border-width: 2px) 24 | width: rem($size) 25 | 26 | &:before, 27 | &:after 28 | position: absolute 29 | content: '' 30 | top: 50% 31 | left: 50% 32 | margin: rem($size / -2 0 0 $size / -2) 33 | width: rem($size) 34 | height: rem($size) 35 | border-radius: 100% 36 | border-color: $color transparent transparent 37 | border-style: solid 38 | border-width: $border-width 39 | box-shadow: 0 0 0 1px transparent 40 | 41 | &:before 42 | animation: spinning 1.8s cubic-bezier(0.41, 0.26, 0.2, 0.62) 43 | animation-iteration-count: infinite 44 | 45 | &:after 46 | animation: spinning 1.8s cubic-bezier(0.51, 0.09, 0.21, 0.8) 47 | animation-iteration-count: infinite 48 | 49 | @keyframes spinning 50 | 0% 51 | transform: rotate3d(0, 0, 1, 0) 52 | 100% 53 | transform: rotate3d(0, 0, 1, 720deg) 54 | -------------------------------------------------------------------------------- /template/docs/assets/base/_animations.sass: -------------------------------------------------------------------------------- 1 | @keyframes spinning 2 | 0% 3 | transform: rotate3d(0, 0, 1, 0) 4 | 100% 5 | transform: rotate3d(0, 0, 1, 720deg) 6 | -------------------------------------------------------------------------------- /template/docs/assets/base/_functions.sass: -------------------------------------------------------------------------------- 1 | @function no-unit($value) 2 | @return $value / ($value * 0 + 1) 3 | 4 | @function to-rem($rem, $base-size: $global-font-size) 5 | $rem: no-unit($rem) / no-unit($base-size) * 1rem 6 | @if ($rem == 0rem) 7 | $rem: 0 8 | @return $rem 9 | 10 | @function rem($values) 11 | $values-list: length($values) 12 | 13 | @if $values-list == 1 14 | @return to-rem($values) 15 | 16 | $rem-list: () 17 | 18 | @for $i from 1 through $values-list 19 | $rem-list: append($rem-list, to-rem(nth($values, $i))) 20 | 21 | @return $rem-list 22 | -------------------------------------------------------------------------------- /template/docs/assets/base/_global.sass: -------------------------------------------------------------------------------- 1 | $primary-color: #41B883 2 | 3 | $secondary-color: #374853 4 | $secondary-lighten-color: #939EA5 5 | $tertiary-color: #F3F3F3 6 | $quaternary-color: #bbb 7 | 8 | $bright-grey-color: #E8E8E8 9 | 10 | $error-color: #f04124 11 | $success-color: #43AC6A 12 | $alert-color: #f08a24 13 | $info-color: #5fadd6 14 | 15 | $global-radius: 5px 16 | 17 | // z-index stack concept 18 | // Please go to utils/_z-stack.scss for easy config 19 | // .sass syntax lacks multiline list declarations ;( 20 | 21 | 22 | // global 23 | $global-font-size: 16px 24 | $global-font: 'Lato', sans-serif 25 | $global-font-secondary: 'Dosis', sans-serif 26 | $global-font-weight-light: 300 27 | $global-font-weight: 300 28 | $global-font-weight-bold: 700 29 | $global-font-weight-black: 700 30 | $global-font-color: $secondary-color 31 | $global-font-inverted: #fff 32 | $global-background: #fff 33 | $global-support-background: #fafafa 34 | $global-grid-columns: 12 35 | $global-page-width: 1400px 36 | $global-gutter: 40px 37 | $global-v-gutter: 30px 38 | $global-topbar-height: 70px 39 | -------------------------------------------------------------------------------- /template/docs/assets/base/_media.sass: -------------------------------------------------------------------------------- 1 | $screen: "only screen" !default 2 | 3 | $small: 640px 4 | $medium: 1024px 5 | $large: 1440px 6 | $xlarge: 1920px 7 | 8 | $landscape: "#{$screen} and (orientation: landscape)" 9 | $portrait: "#{$screen} and (orientation: portrait)" 10 | 11 | $small-up: $screen !default 12 | $small-only: "#{$screen} and (max-width: #{$small})" !default 13 | 14 | $medium-up: "#{$screen} and (min-width: #{$small})" !default 15 | $medium-only: "#{$screen} and (min-width: #{$small}) and (max-width: #{$medium})" !default 16 | 17 | $large-up: "#{$screen} and (min-width: #{$medium})" !default 18 | $large-only: "#{$screen} and (min-width: #{$medium}) and (max-width: #{$large})" !default 19 | 20 | $xlarge-up: "#{$screen} and (min-width: #{$large})" !default 21 | $xlarge-only: "#{$screen} and (min-width: #{$large}) and (max-width: #{$xlarge})" !default 22 | 23 | $xxlarge-up: "#{$screen} and (min-width: #{$xlarge})" !default 24 | -------------------------------------------------------------------------------- /template/docs/assets/base/_mixins.sass: -------------------------------------------------------------------------------- 1 | @mixin clearfix 2 | &:before, 3 | &:after 4 | content: "" 5 | display: table 6 | &:after 7 | clear: both 8 | 9 | @mixin spinner($size: 16px, $color: #333, $border-width: 2px) 10 | width: rem($size) 11 | 12 | &:before, 13 | &:after 14 | position: absolute 15 | content: '' 16 | top: 50% 17 | left: 50% 18 | margin: rem($size / -2 0 0 $size / -2) 19 | width: rem($size) 20 | height: rem($size) 21 | border-radius: 100% 22 | border-color: $color transparent transparent 23 | border-style: solid 24 | border-width: $border-width 25 | box-shadow: 0 0 0 1px transparent 26 | 27 | &:before 28 | animation: spinning 2.4s cubic-bezier(0.41, 0.26, 0.2, 0.62) 29 | animation-iteration-count: infinite 30 | 31 | &:after 32 | animation: spinning 2.4s cubic-bezier(0.51, 0.09, 0.21, 0.8) 33 | animation-iteration-count: infinite 34 | -------------------------------------------------------------------------------- /template/docs/assets/base/_typo.sass: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Lato:700,300) 2 | @import url('https://fonts.googleapis.com/css?family=Dosis:400') 3 | 4 | // config 5 | $header-line-height: 1.2 6 | $header-color: $secondary-color 7 | 8 | $header-h1-family: $global-font-secondary 9 | $header-h1-size-ratio-lg: 2.5 // 48px 10 | $header-h1-size-ratio-md: 2.5 // 40px 11 | $header-h1-size-ratio-sm: 2 // 32px 12 | $header-h1-weight: $global-font-weight-bold 13 | 14 | $header-h2-family: $global-font-secondary 15 | $header-h2-size-ratio-lg: 1.8 // 36px 16 | $header-h2-size-ratio-md: 1.8 // 32px 17 | $header-h2-size-ratio-sm: 1.625 // 26px 18 | $header-h2-weight: $global-font-weight-bold 19 | 20 | $header-h3-family: $global-font-secondary 21 | $header-h3-size-ratio-lg: 1.5 // 28px 22 | $header-h3-size-ratio-md: 1.5 // 24px 23 | $header-h3-size-ratio-sm: 1.375 // 22px 24 | $header-h3-weight: $global-font-weight-bold 25 | 26 | $header-h4-family: $global-font 27 | $header-h4-size-ratio-sm: 1.375 28 | $header-h4-size-ratio-md: 1.375 29 | $header-h4-size-ratio-lg: 1.125 30 | $header-h4-weight: $global-font-weight-light 31 | 32 | $paragraph-family: $global-font 33 | $paragraph-font-size-ratio-lg: 1.125 // 18px 34 | $paragraph-font-size-ratio-md: 1.125 // 18px 35 | $paragraph-font-size-ratio-sm: 1 // 16px 36 | $paragraph-font-weight: $global-font-weight 37 | $paragraph-line-height: 1.8 38 | $paragraph-color: $secondary-color 39 | 40 | $hr-margin: 30px 41 | $hr-border: 1px solid $bright-grey-color 42 | 43 | $blockquote-family: $global-font-secondary 44 | $blockqoute-cite-family: $global-font 45 | $blockquote-font-size: 16px 46 | $blockquote-line-height: 1.8 47 | $blockquote-color: $secondary-lighten-color 48 | $blockquote-padding: 5px 20px 49 | $blockquote-border: 1px solid $bright-grey-color 50 | 51 | $label-font-size: 14px 52 | 53 | body 54 | color: $global-font-color 55 | font-size: $global-font-size 56 | 57 | *::selection, 58 | background: $primary-color 59 | color: #fff 60 | 61 | .typo__h1, 62 | .typo__h2, 63 | .typo__h3, 64 | .typo__h4, 65 | .typo__h5 66 | margin-top: 0 67 | margin-bottom: rem($global-font-size) 68 | color: $header-color 69 | line-height: $header-line-height 70 | 71 | .typo__h1 72 | font: 73 | family: $header-h1-family 74 | weight: $header-h1-weight 75 | size: rem($header-h1-size-ratio-sm * $global-font-size) 76 | margin-bottom: rem(40px) 77 | 78 | @media #{$medium-up} 79 | font-size: rem($header-h1-size-ratio-md * $global-font-size) 80 | 81 | @media #{$large-up} 82 | font-size: rem($header-h1-size-ratio-lg * $global-font-size) 83 | 84 | .typo__h2 85 | font: 86 | family: $header-h2-family 87 | weight: $header-h2-weight 88 | size: rem($header-h2-size-ratio-sm * $global-font-size) 89 | padding-top: rem(60px) 90 | 91 | @media #{$medium-up} 92 | font-size: rem($header-h2-size-ratio-md * $global-font-size) 93 | 94 | @media #{$large-up} 95 | font-size: rem($header-h2-size-ratio-lg * $global-font-size) 96 | 97 | .typo__h3 98 | font: 99 | family: $header-h3-family 100 | weight: $header-h3-weight 101 | size: rem($header-h3-size-ratio-sm * $global-font-size) 102 | 103 | @media #{$medium-up} 104 | font-size: rem($header-h3-size-ratio-md * $global-font-size) 105 | 106 | @media #{$large-up} 107 | font-size: rem($header-h3-size-ratio-lg * $global-font-size) 108 | 109 | .typo__h4 110 | font: 111 | family: $header-h4-family 112 | weight: $header-h4-weight 113 | size: rem($header-h4-size-ratio-sm * $global-font-size) 114 | 115 | @media #{$medium-up} 116 | font-size: rem($header-h4-size-ratio-md * $global-font-size) 117 | 118 | @media #{$large-up} 119 | font-size: rem($header-h4-size-ratio-lg * $global-font-size) 120 | 121 | .typo__p 122 | margin-top: 0 123 | margin-bottom: rem($paragraph-font-size-ratio-sm * $global-font-size) 124 | line-height: $paragraph-line-height 125 | font: 126 | family: $paragraph-family 127 | weight: $paragraph-font-weight 128 | size: rem($paragraph-font-size-ratio-sm * $global-font-size) 129 | 130 | @media #{$medium-up} 131 | font-size: rem($paragraph-font-size-ratio-md * $global-font-size) 132 | 133 | @media #{$large-up} 134 | font-size: rem($paragraph-font-size-ratio-lg * $global-font-size) 135 | 136 | .typo__blockquote 137 | font: 138 | family: $blockquote-family 139 | size: rem($blockquote-font-size) 140 | color: $blockquote-color 141 | margin: 0px 142 | border-left: $blockquote-border 143 | padding: rem($blockquote-padding) 144 | line-height: $blockquote-line-height 145 | text-align: left 146 | 147 | cite 148 | font: 149 | size: rem($blockquote-font-size - 2px) 150 | weight: $global-font-weight-bold 151 | family: $blockqoute-cite-family 152 | style: normal 153 | margin-top: 6px 154 | display: block 155 | color: $secondary-color 156 | 157 | &:before 158 | content: "\2014 \0020" 159 | 160 | .typo__hr 161 | border: none 162 | border-bottom: $hr-border 163 | margin: rem($hr-margin) 0 164 | outline: none 165 | 166 | .typo__link 167 | color: $primary-color 168 | text-decoration: none 169 | font-weight: 700 170 | 171 | .typo__label 172 | font-family: $global-font 173 | font-weight: $global-font-weight 174 | font-size: rem($label-font-size) 175 | color: $quaternary-color 176 | margin: rem(20px) 0 rem(10px) 177 | display: block 178 | 179 | .typo__text 180 | font-family: $global-font 181 | font-size: rem($label-font-size + 2px) 182 | display: block 183 | margin: 0 184 | line-height: 1.4 185 | 186 | .typo--bold, strong 187 | font-weight: $global-font-weight-bold 188 | 189 | kbd 190 | color: $primary-color 191 | padding: 3px 5px 192 | border-radius: 4px 193 | background: $tertiary-color 194 | -------------------------------------------------------------------------------- /template/docs/assets/base/_z-stack.scss: -------------------------------------------------------------------------------- 1 | $z-index-list: 2 | modal, 3 | modal-bg, 4 | mobile-trigger, 5 | panel, 6 | topbar, 7 | mobile, 8 | notify, 9 | sidebar, 10 | dropdown, 11 | content, 12 | offcanvas; 13 | 14 | @function z-index($element, $stack: $z-index-list, $step: 100) { 15 | $z-index-value: (length($stack) - index($stack, $element)) * $step + $step; 16 | @return $z-index-value; 17 | } 18 | -------------------------------------------------------------------------------- /template/docs/assets/base/normalize.scss: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; /* 1 */ 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; /* 2 */ 361 | box-sizing: content-box; 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | border: 0; /* 1 */ 392 | padding: 0; /* 2 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } 428 | -------------------------------------------------------------------------------- /template/docs/assets/components/_avatars.sass: -------------------------------------------------------------------------------- 1 | $avatar-size: 120px 2 | $avatar-size-small: 60px 3 | 4 | .avatar 5 | display: inline-block 6 | vertical-align: middle 7 | max-width: 100% 8 | max-height: rem($avatar-size) 9 | border-radius: $global-radius 10 | margin-bottom: rem(10px) 11 | margin-top: rem(10px) 12 | 13 | & + & 14 | margin-left: rem(12px) 15 | 16 | &--small 17 | max-height: rem($avatar-size-small) 18 | 19 | &--round 20 | border-radius: 100% 21 | 22 | .avatar__description 23 | margin-left: rem(10px) 24 | vertical-align: middle 25 | display: inline-block 26 | -------------------------------------------------------------------------------- /template/docs/assets/components/_breadcrumbs.sass: -------------------------------------------------------------------------------- 1 | .breadcrumbs 2 | font: 3 | size: rem(12px) 4 | weight: $global-font-weight 5 | line-height: rem(20px) 6 | text-transform: uppercase 7 | color: $secondary-color 8 | margin: rem($global-v-gutter) 0 9 | 10 | a.breadcrumbs__element 11 | color: $primary-color 12 | text-decoration: none 13 | 14 | &:after 15 | content: "/" 16 | margin: rem(0 5px) 17 | 18 | .breadcrumbs__element 19 | display: inline-block 20 | 21 | &:last-child 22 | font-weight: $global-font-weight-black 23 | -------------------------------------------------------------------------------- /template/docs/assets/components/_buttons.sass: -------------------------------------------------------------------------------- 1 | // config 2 | $button-height-xlarge: 60px 3 | $button-height-large: 50px 4 | $button-height: 40px 5 | $button-height-small: 30px 6 | $button-padding-xlarge: 14px 50px 15px 7 | $button-padding-large: 11px 40px 13px 8 | $button-padding: 8px 30px 10px 9 | $button-padding-small: 6px 20px 6px 10 | $button-size-xlarge: 18px 11 | $button-size-large: 16px 12 | $button-size: 14px 13 | $button-size-small: 12px 14 | $button-hollow-border: 1px 15 | $button-background: $primary-color 16 | $button-color: $global-font-inverted 17 | $button-font-weight: $global-font-weight-bold 18 | $button-border-radius: $global-radius 19 | $button-border: 3px 20 | 21 | @mixin button-variant($name, $color) 22 | .button--#{$name} 23 | background: $color 24 | border-bottom: $button-border solid darken($color, 20%) 25 | 26 | &:hover, 27 | &:focus 28 | background: darken($color, 10%) 29 | cursor: pointer 30 | 31 | .button 32 | font: 33 | family: $global-font 34 | size: rem($button-size) 35 | weight: $global-font-weight 36 | color: $button-color 37 | min-height: rem($button-height) 38 | line-height: 1.4 39 | padding: rem($button-padding) 40 | box-sizing: border-box 41 | position: relative 42 | display: inline-block 43 | background: $button-background 44 | border: none 45 | border-radius: $button-border-radius 46 | z-index: 1 47 | overflow: hidden 48 | outline: none 49 | vertical-align: middle 50 | transition: 0.1s background ease, 0.1s border-color ease, 0.1s color ease 51 | border-bottom: $button-border solid darken($primary-color, 20%) 52 | text-decoration: none 53 | 54 | &:hover, 55 | &:focus 56 | background: darken($button-background, 10%) 57 | cursor: pointer 58 | 59 | &:active 60 | background: darken($button-background, 20%) 61 | 62 | &:focus 63 | outline: none 64 | 65 | &--small 66 | padding: rem($button-padding-small) 67 | font-size: rem($button-size-small) 68 | min-height: rem($button-height-small) 69 | 70 | &--xlarge 71 | padding: rem($button-padding-xlarge) 72 | font-size: rem($button-size-xlarge) 73 | min-height: rem($button-height-xlarge) 74 | 75 | &--large 76 | padding: rem($button-padding-large) 77 | font-size: rem($button-size-large) 78 | min-height: rem($button-height-large) 79 | 80 | &--fake 81 | background: none 82 | color: $secondary-color 83 | border-color: transparent 84 | 85 | &:hover, &:focus 86 | background: rgba(#000, 0.05) 87 | 88 | &--hollow 89 | background: none 90 | color: $secondary-color 91 | border: $button-hollow-border solid darken($bright-grey-color, 25%) 92 | 93 | &:hover, 94 | &:focus 95 | background: rgba(#000, 0.05) 96 | color: darken($secondary-color, 80%) 97 | border: $button-hollow-border solid darken($bright-grey-color, 80%) 98 | cursor: pointer 99 | 100 | &--expanded 101 | width: 100% 102 | 103 | +button-variant('secondary', $secondary-color) 104 | +button-variant('success', $success-color) 105 | +button-variant('error', $alert-color) 106 | +button-variant('info', $info-color) 107 | 108 | .button__group 109 | margin-bottom: $grid-gutter-width / 2 110 | width: 100% 111 | 112 | .button 113 | display: inline-block 114 | margin: 115 | right: 0 116 | bottom: 0 117 | border-radius: 0 118 | 119 | &:first-child 120 | border-top-left-radius: $button-border-radius 121 | border-bottom-left-radius: $button-border-radius 122 | 123 | &:last-child 124 | border-top-right-radius: $button-border-radius 125 | border-bottom-right-radius: $button-border-radius 126 | 127 | $button-group-count: 3 128 | 129 | @for $i from 1 through $button-group-count 130 | 131 | .button__group--#{$i} 132 | 133 | .button 134 | width: 100% / $i 135 | -------------------------------------------------------------------------------- /template/docs/assets/components/_dropdown.sass: -------------------------------------------------------------------------------- 1 | // config 2 | $dropdown-height: 40px 3 | $dropdown-font: $global-font 4 | $dropdown-font-size: 14px 5 | $dropdown-line-height: 16px 6 | $dropdown-font-weight: $global-font-weight 7 | $dropdown-background: $global-background 8 | $dropdown-hover-bg: $global-support-background 9 | $dropdown-border: $bright-grey-color 10 | $dropdown-border-radius: $global-radius 11 | $dropdown-padding: ($dropdown-height - $dropdown-line-height) / 2 12 | 13 | .dropdown 14 | box-sizing: content-box 15 | 16 | * 17 | box-sizing: border-box 18 | 19 | display: block 20 | position: relative 21 | background: $dropdown-background 22 | width: 100% 23 | height: rem($dropdown-height) 24 | text-align: left 25 | font: 26 | family: $dropdown-font 27 | size: rem($dropdown-font-size) 28 | weight: $dropdown-font-weight 29 | 30 | &:hover, 31 | &--active 32 | z-index: z-index(dropdown) 33 | 34 | .dropdown__current, 35 | .dropdown__input 36 | border-bottom-left-radius: 0 37 | border-bottom-right-radius: 0 38 | 39 | .dropdown__list 40 | display: block 41 | 42 | .dropdown__input 43 | margin-bottom: 0 44 | 45 | .dropdown--disabled 46 | background: darken($dropdown-background, 7%) 47 | pointer-events: none 48 | 49 | .dropdown__current, 50 | .dropdown__select 51 | background: darken($dropdown-background, 7%) 52 | color: darken($dropdown-background, 35%) 53 | 54 | .dropdown__list 55 | display: none 56 | position: relative 57 | list-style: none 58 | padding: 0 59 | margin: 0 60 | background: $dropdown-background 61 | border: 1px solid $dropdown-border 62 | border-top: none 63 | 64 | .dropdown__option 65 | display: block 66 | padding: rem($dropdown-padding) 67 | min-height: rem($dropdown-height) 68 | line-height: rem(16px) 69 | color: $global-font-color 70 | font-weight: 300 71 | text-decoration: none 72 | text-transform: none 73 | vertical-align: middle 74 | 75 | &:hover, &:focus 76 | background: $dropdown-hover-bg 77 | 78 | .dropdown__icon 79 | margin-right: rem(8px) 80 | 81 | .dropdown__img 82 | display: inline-block 83 | margin-right: rem(6px) 84 | vertical-align: middle 85 | max-height: rem(18px) 86 | max-width: rem($dropdown-height) 87 | 88 | .dropdown__option--disabled 89 | background: darken($dropdown-background, 7%) 90 | color: darken($dropdown-background, 35%) 91 | cursor: text 92 | pointer-events: none 93 | 94 | &:visited 95 | color: darken($dropdown-background, 35%) 96 | 97 | &:hover, 98 | &:focus 99 | background: darken($dropdown-hover-bg, 3%) 100 | 101 | .dropdown__current 102 | line-height: rem($dropdown-line-height) 103 | min-height: rem($dropdown-height) 104 | box-sizing: border-box 105 | display: block 106 | overflow: hidden 107 | padding: rem($dropdown-padding) 108 | padding-right: 30px 109 | white-space: nowrap 110 | margin: 0 111 | color: $global-font-color 112 | text-decoration: none 113 | border-radius: $dropdown-border-radius 114 | border: 1px solid $dropdown-border 115 | cursor: pointer 116 | 117 | .dropdown__select 118 | line-height: rem(16px) 119 | display: block 120 | position: absolute 121 | box-sizing: border-box 122 | width: rem($dropdown-height) 123 | height: 100% 124 | right: rem(1px) 125 | top: rem(1px) 126 | padding: rem(4px 8px) 127 | margin: 0 128 | color: $global-font-color 129 | text-decoration: none 130 | border-left: 1px solid $dropdown-border 131 | text-align: center 132 | background: $dropdown-background 133 | cursor: pointer 134 | 135 | &:before 136 | position: absolute 137 | right: 15px 138 | top: $dropdown-height / 2 - 8 139 | color: #999 140 | margin-top: rem(4px) 141 | border-style: solid 142 | border-width: 5px 5px 0 5px 143 | border-color: #999999 transparent transparent transparent 144 | content: "" 145 | -------------------------------------------------------------------------------- /template/docs/assets/components/_flex_grid.sass: -------------------------------------------------------------------------------- 1 | =calc-flex-columns($class, $i: 1) 2 | @for $i from 1 through $flex-columns 3 | .flex__unit--#{$class}-#{$i} 4 | width: percentage($i / $flex-columns) 5 | flex: 0 0 percentage($i / $flex-columns) 6 | 7 | // config 8 | $flex-columns: $global-grid-columns 9 | $flex-gutter-width: $global-gutter 10 | $flex-max-width: $global-page-width 11 | $flex-equal-height-columns: true 12 | 13 | .flex__column, 14 | .flex__columns 15 | flex: 0 0 auto 16 | width: 100% 17 | padding: 0 ($flex-gutter-width/2) 18 | 19 | .flex__column--top 20 | align-self: flex-start 21 | 22 | .flex__column--middle 23 | align-self: center 24 | 25 | .flex__column--bottom 26 | align-self: flex-end 27 | 28 | .flex__row 29 | display: flex 30 | flex-wrap: wrap 31 | margin: 0 auto 32 | max-width: $flex-max-width 33 | 34 | @if $flex-equal-height-columns 35 | align-items: stretch 36 | @else 37 | align-items: flex-start 38 | 39 | .flex__row 40 | margin: 0 ($flex-gutter-width/-2) 41 | max-width: none 42 | 43 | &.flex__row--collapse 44 | 45 | & > .flex__column 46 | padding-left: 0 47 | padding-right: 0 48 | 49 | .flex__row--centered 50 | justify-content: center 51 | 52 | .flex__row--top 53 | align-items: flex-start 54 | 55 | .flex__row--middle 56 | align-items: center 57 | 58 | .flex__row--bottom 59 | align-items: flex-end 60 | 61 | .flex__row--stretch 62 | align-items: stretch 63 | 64 | +calc-flex-columns(sm) 65 | 66 | @media #{$medium-up} 67 | +calc-flex-columns(md) 68 | 69 | @media #{$large-up} 70 | +calc-flex-columns(lg) 71 | -------------------------------------------------------------------------------- /template/docs/assets/components/_grid.sass: -------------------------------------------------------------------------------- 1 | =calc-grid-columns($class, $i: 1) 2 | @for $i from 1 through $grid-columns 3 | .grid__unit--#{$class}-#{$i} 4 | width: percentage($i / $grid-columns) 5 | 6 | .grid__push--#{$class}-#{$i} 7 | left: percentage($i / $grid-columns) 8 | right: auto 9 | 10 | .grid__pull--#{$class}-#{$i} 11 | right: percentage($i / $grid-columns) 12 | left: auto 13 | 14 | .grid__offset--#{$class}-#{$i} 15 | margin-left: percentage($i / $grid-columns) 16 | 17 | .blocks--#{$class}-#{$i} .blocks__element 18 | width: calc(#{percentage(1 / ($grid-columns / ($grid-columns / $i)))} - #{$grid-gutter-width / 2}) 19 | 20 | // config 21 | $grid-columns: $global-grid-columns 22 | $grid-gutter-width: $global-gutter 23 | $grid-max-width: $global-page-width 24 | 25 | html, body 26 | font-size: 100% 27 | height: 100% 28 | 29 | html 30 | overflow-y: auto 31 | box-sizing: border-box 32 | 33 | *, *:before, *:after 34 | box-sizing: inherit 35 | 36 | .grid__column, 37 | .grid__columns 38 | box-sizing: border-box 39 | display: inline-block 40 | font-size: 1rem 41 | margin: 0 42 | text-align: left 43 | vertical-align: top 44 | width: 100% 45 | position: relative 46 | padding: 0 ($grid-gutter-width/2) 47 | 48 | .grid__column--centered 49 | display: block 50 | margin: 0 auto 51 | 52 | .grid__row--middle 53 | .grid__column, 54 | .grid__columns 55 | vertical-align: middle 56 | 57 | .grid__row--bottom 58 | .grid__column, 59 | .grid__columns 60 | vertical-align: bottom 61 | 62 | .grid__row 63 | +clearfix 64 | 65 | display: block 66 | font-size: 0 67 | margin: 0 auto 68 | box-sizing: border-box 69 | padding: 0 70 | text-align: left 71 | max-width: $grid-max-width 72 | 73 | .grid__row 74 | margin: 0 ($grid-gutter-width/-2) 75 | 76 | 77 | &.grid__row--collapse 78 | 79 | & > .grid__column 80 | padding-left: 0 81 | padding-right: 0 82 | 83 | .grid__row--full 84 | max-width: 100% 85 | 86 | .grid__row--centered 87 | text-align: center 88 | 89 | .grid__push--small-reset 90 | left: auto !important 91 | right: auto !important 92 | 93 | .blocks 94 | margin: 0 $grid-gutter-width / -4 95 | 96 | .blocks__element 97 | position: relative 98 | float: left 99 | box-sizing: border-box 100 | transition: background .2s ease 101 | margin: $grid-gutter-width/4 102 | 103 | 104 | +calc-grid-columns(sm) 105 | 106 | @media #{$medium-up} 107 | 108 | html, body 109 | overflow-x: initial 110 | 111 | .grid__push--md-reset 112 | left: auto 113 | right: auto 114 | 115 | +calc-grid-columns(md) 116 | 117 | @media #{$large-up} 118 | 119 | .grid__push--lg-reset 120 | left: auto 121 | right: auto 122 | 123 | +calc-grid-columns(lg) 124 | -------------------------------------------------------------------------------- /template/docs/assets/components/_inputs.sass: -------------------------------------------------------------------------------- 1 | // config 2 | $input-font: $global-font 3 | $input-font-color: $secondary-color 4 | $input-font-weight: $global-font-weight 5 | $input-font-size: 14px 6 | $input-height: 40px 7 | $input-border-width: 1px 8 | $input-border-color: $bright-grey-color 9 | $input-border: $input-border-width solid $input-border-color 10 | $input-label-left-margin: 14px 11 | $input-padding: 0 13px 12 | $input-margin-bottom: $global-font-size * 2 13 | $input-label-color: lighten($input-font-color, 10%) 14 | $input-label-size: 13px 15 | $input-background: $global-background 16 | $input-radius: $global-radius 17 | $input-select-font-size: 14px 18 | $input-select-background: $global-background 19 | $input-message-font-size: 12px 20 | $input-message-margin: 5px 21 | 22 | $input-addon-weight: 700 23 | 24 | .form 25 | position: relative 26 | 27 | .form__input, 28 | .form__textarea 29 | position: relative 30 | margin: 31 | bottom: rem($input-margin-bottom) 32 | 33 | .form__input, 34 | .form__textarea 35 | font: 36 | family: $input-font 37 | size: rem($input-font-size) 38 | weight: $input-font-weight 39 | color: $global-font-color 40 | line-height: rem($input-height - 2*$input-border-width) 41 | min-height: rem($input-height - 2*$input-border-width) 42 | position: relative 43 | border: $input-border 44 | border-radius: $input-radius 45 | background: $input-background 46 | padding: rem($input-padding) 47 | width: 100% 48 | transition: border .1s ease 49 | box-sizing: border-box 50 | 51 | &:hover 52 | border-color: darken($input-border-color, 10%) 53 | 54 | &:focus 55 | border-color: darken($input-border-color, 25%) 56 | outline: none 57 | 58 | &--with-left-icon 59 | padding-left: rem(45px) 60 | 61 | &--with-right-icon 62 | padding-right: rem(45px) 63 | 64 | .form__icon 65 | position: absolute 66 | pointer-events: none 67 | top: -1px 68 | height: rem($input-height) 69 | line-height: rem($input-height) 70 | 71 | &--right 72 | right: rem(15px) 73 | 74 | &--left 75 | left: rem(13px) 76 | 77 | .form__textarea 78 | max-width: 100% 79 | min-height: rem(82px) 80 | resize: none 81 | line-height: 1.4 82 | padding-top: $input-height / 4 83 | 84 | .form__label 85 | font-size: rem($input-label-size) 86 | color: $input-label-color 87 | margin: 88 | bottom: rem(5px) 89 | left: rem($input-label-left-margin) 90 | display: block 91 | font-family: $global-font 92 | 93 | .form__label--inline 94 | @extend .form__label 95 | 96 | display: inline-block 97 | margin-right: rem($grid-gutter-width / 2) 98 | margin-left: rem($grid-gutter-width / 5) 99 | 100 | .form-group 101 | margin-bottom: rem($input-margin-bottom) 102 | 103 | .form__input, 104 | .form__textarea 105 | margin-bottom: 0 106 | 107 | .form-group--merged 108 | font-size: 0 109 | display: table 110 | width: 100% 111 | border-collapse: separate 112 | 113 | .form__label 114 | display: table-caption 115 | 116 | .form-group__input, 117 | .form-group__addon, 118 | .form-group__button 119 | display: table-cell 120 | vertical-align: middle 121 | margin: 0 122 | white-space: nowrap 123 | 124 | .form-group__addon:first-child, 125 | .form-group__input:first-child, 126 | .form-group__button:first-child .button 127 | border-top-right-radius: 0 128 | border-bottom-right-radius: 0 129 | margin-right: -1px 130 | 131 | .form-group__addon:last-child, 132 | .form-group__input:last-child, 133 | .form-group__button:last-child .button 134 | border-top-left-radius: 0 135 | border-bottom-left-radius: 0 136 | margin-left: -1px 137 | 138 | .form-group__input:not(:first-child):not(:last-child), 139 | .form-group__addon:not(:first-child):not(:last-child), 140 | .form-group__button:not(:first-child):not(:last-child) .button 141 | border-radius: 0 142 | 143 | .form-group__button:not(:first-child):not(:last-child) .button 144 | margin-left: -1px 145 | margin-right: -1px 146 | 147 | .form-group__addon:first-child 148 | border-right: none 149 | 150 | .form-group__addon:last-child 151 | border-left: none 152 | 153 | .form-group__addon 154 | background: $tertiary-color 155 | border: $input-border 156 | border-radius: $input-radius 157 | height: rem($input-height - 2*$input-border-width) 158 | line-height: rem($input-height - 2*$input-border-width) 159 | width: 1% 160 | padding: $input-padding 161 | font: 162 | size: $input-font-size 163 | text-align: center 164 | 165 | .form-group__button 166 | width: 1% 167 | 168 | .button 169 | margin: 0 170 | padding-right: rem(20px) 171 | padding-left: rem(20px) 172 | 173 | .form-group__message 174 | font-size: rem($input-message-font-size) 175 | line-height: 1 176 | display: none 177 | margin: 178 | left: $input-label-left-margin 179 | top: rem(($input-margin-bottom * -1) + $input-message-margin) 180 | // Magic now :) 181 | bottom: rem(($input-margin-bottom) - ($input-message-font-size + $input-message-margin)) 182 | 183 | .form-group--alert, 184 | .form-group--error 185 | animation: 186 | name: shakeError 187 | fill-mode: forward 188 | duration: .6s 189 | timing-function: ease-in-out 190 | 191 | .form-group--success 192 | .form__label 193 | color: $success-color 194 | 195 | .form-group__addon 196 | color: white 197 | border-color: lighten($success-color, 20%) 198 | background: lighten($success-color, 20%) 199 | 200 | input, 201 | textarea, 202 | input:focus, 203 | input:hover 204 | border-color: lighten($success-color, 20%) 205 | 206 | & + .form-group__message 207 | display: block 208 | color: lighten($success-color, 15%) 209 | 210 | .form-group--error 211 | .form__label 212 | color: $error-color 213 | 214 | .form-group__addon 215 | color: white 216 | border-color: lighten($error-color, 20%) 217 | background: lighten($error-color, 20%) 218 | 219 | input, 220 | textarea, 221 | input:focus, 222 | input:hover 223 | border-color: lighten($error-color, 20%) 224 | 225 | & + .form-group__message 226 | display: block 227 | color: lighten($error-color, 15%) 228 | 229 | .form-group--alert 230 | .form__label 231 | color: $alert-color 232 | 233 | .form-group__addon 234 | color: white 235 | border-color: lighten($alert-color, 20%) 236 | background: lighten($alert-color, 20%) 237 | 238 | input, 239 | textarea, 240 | input:focus, 241 | input:hover 242 | border-color: lighten($alert-color, 20%) 243 | 244 | & + .form-group__message 245 | display: block 246 | color: lighten($alert-color, 15%) 247 | 248 | @keyframes shakeError 249 | $shake-distance: rem(6px) 250 | 0% 251 | transform: translateX(0) 252 | 253 | 15% 254 | transform: translateX($shake-distance) 255 | 256 | 30% 257 | transform: translateX(-$shake-distance) 258 | 259 | 45% 260 | transform: translateX($shake-distance) 261 | 262 | 60% 263 | transform: translateX(-$shake-distance) 264 | 265 | 75% 266 | transform: translateX($shake-distance) 267 | 268 | 90% 269 | transform: translateX(-$shake-distance) 270 | 271 | 100% 272 | transform: translateX(0) 273 | -------------------------------------------------------------------------------- /template/docs/assets/components/_lists.sass: -------------------------------------------------------------------------------- 1 | .list 2 | font: 3 | family: $global-font 4 | size: rem(16px) 5 | color: $secondary-color 6 | letter-spacing: 0.4px 7 | line-height: 32px 8 | list-style: none 9 | 10 | .list--sticky 11 | position: fixed 12 | top: 0 13 | 14 | .list__heading 15 | font: 16 | family: $global-font-secondary 17 | size: rem(14px) 18 | weight: $global-font-weight-bold 19 | line-height: rem(30px) 20 | color: $primary-color 21 | text-transform: uppercase 22 | letter-spacing: 0.4px 23 | margin: rem($global-v-gutter 0 10px) 24 | 25 | .list__link 26 | color: $secondary-color 27 | text-decoration: none 28 | display: block 29 | padding: rem(0 10px) 30 | margin-left: rem(-10px) 31 | border-radius: 5px 32 | 33 | &--active 34 | background: $tertiary-color 35 | 36 | &--disabled 37 | color: $secondary-lighten-color 38 | pointer-events: none 39 | 40 | .list__dl 41 | font-family: $global-font 42 | font-weight: $global-font-weight 43 | 44 | .list__dt 45 | font-size: rem(14px) 46 | margin-bottom: rem(10px) 47 | color: $quaternary-color 48 | 49 | .list__dd 50 | font-size: rem($global-font-size) 51 | margin-left: 0 52 | margin-bottom: rem(20px) 53 | line-height: 1.4 54 | 55 | .list__ul, 56 | .list__ol 57 | margin: rem(0 0 0 30px) 58 | padding: 0 59 | line-height: 1.8 60 | font-weight: $global-font-weight 61 | 62 | .list__ul 63 | list-style: square 64 | -------------------------------------------------------------------------------- /template/docs/assets/components/_mobile_nav.sass: -------------------------------------------------------------------------------- 1 | @import ../base/global 2 | 3 | // config 4 | $mobile-trigger-width: 55px 5 | $mobile-trigger-height: 50px 6 | $mobile-tab-height: 70px 7 | $mobile-tab-bg: $primary-color 8 | $mobile-tab-font-size: 20px 9 | $mobile-nav-bg: rgba(darken($secondary-color, 10%), .95) 10 | $mobile-link-height: 70px 11 | $mobile-link-font-size: 16px 12 | $mobile-link-color: $global-font-inverted 13 | $mobile-link-border: $global-font-color 14 | $mobile-link-bg: $primary-color 15 | 16 | =mobile-tabs-count($i: 3) 17 | .mobile__tabs--#{$i} 18 | .mobile__tab 19 | width: percentage(1 / $i) 20 | 21 | 22 | @media #{$small-only} 23 | .mobile__block-overflow 24 | overflow: hidden 25 | 26 | .mobile 27 | z-index: z-index(mobile) 28 | position: fixed 29 | height: 100% 30 | width: 100% 31 | top: 0 32 | left: 0 33 | background: $mobile-nav-bg 34 | transform: translateY(-100%) 35 | transition: transform .3s ease 36 | 37 | @media #{$large-up} 38 | display: none 39 | 40 | .mobile__trigger 41 | z-index: z-index(mobile-trigger) 42 | display: inline-block 43 | border: none 44 | width: rem(55px) 45 | height: rem(50px) 46 | margin-left: rem(-15px) 47 | cursor: pointer 48 | position: relative 49 | line-height: 100% 50 | background: none 51 | vertical-align: middle 52 | 53 | span 54 | position: absolute 55 | top: rem(23px) 56 | left: rem(15px) 57 | right: rem(15px) 58 | display: block 59 | height: rem(3px) 60 | background: $secondary-color 61 | transition: transform .3s ease, top .1s ease 62 | 63 | &:before, 64 | &:after 65 | content: "" 66 | position: absolute 67 | display: block 68 | left: 0 69 | width: 100% 70 | background: $secondary-color 71 | height: 100% 72 | transition: transform .3s ease, top .2s ease 73 | transform-origin: 50% 50% 74 | 75 | &:before 76 | top: rem(-7px) 77 | 78 | &:after 79 | top: rem(7px) 80 | 81 | &:hover 82 | 83 | span:before 84 | top: rem(-9px) 85 | 86 | span:after 87 | top: rem(9px) 88 | 89 | .mobile--show, 90 | .offcanvas--right 91 | 92 | .mobile__trigger 93 | 94 | span 95 | background: transparent 96 | 97 | span:before, span:after 98 | 99 | top: 0 100 | 101 | span:before 102 | transform: rotate3d(0,0,1,45deg) 103 | 104 | span:after 105 | transform: rotate3d(0,0,1,-45deg) 106 | 107 | .mobile 108 | transform: translateY(0) 109 | 110 | li 111 | opacity: 1 112 | transform: translateX(0) 113 | 114 | .mobile__panel 115 | position: relative 116 | display: block 117 | height: 100% 118 | 119 | .mobile__tabs 120 | position: absolute 121 | bottom: 0 122 | left: 0 123 | width: 100% 124 | height: rem($mobile-tab-height) 125 | border-top: 1px solid darken($mobile-tab-bg, 10%) 126 | font-size: 0 127 | vertical-align: middle 128 | 129 | +mobile-tabs-count(3) 130 | 131 | .mobile__tab 132 | box-sizing: border-box 133 | font-size: rem($mobile-tab-font-size) 134 | text-align: center 135 | display: inline-block 136 | color: #fff 137 | background: $mobile-tab-bg 138 | height: 100% 139 | vertical-align: middle 140 | padding: rem(16px) 141 | border-right: 1px solid darken($mobile-tab-bg, 10%) 142 | 143 | &:last-child 144 | border-right: none 145 | 146 | &:hover 147 | color: #fff 148 | background: darken($mobile-tab-bg, 10%) 149 | 150 | small 151 | display: block 152 | font-size: 60% 153 | margin-top: rem(5px) 154 | 155 | i 156 | top: rem(-10px) 157 | 158 | .mobile__nav 159 | position: absolute 160 | height: calc(100% - #{rem($mobile-tab-height)} - #{rem(20px)} - #{rem($global-topbar-height)}) 161 | width: 100% 162 | top: rem($global-topbar-height) 163 | overflow-y: scroll 164 | left: 0 165 | padding: 0 166 | margin: 0 167 | font-weight: $global-font-weight 168 | text-transform: uppercase 169 | 170 | .mobile__option 171 | box-sizing: border-box 172 | display: inline-block 173 | width: 100% 174 | position: relative 175 | text-align: center 176 | vertical-align: middle 177 | 178 | .mobile__link 179 | display: block 180 | width: 100% 181 | line-height: rem($mobile-link-height) 182 | font-size: rem($mobile-link-font-size) 183 | letter-spacing: 1px 184 | cursor: pointer 185 | color: $mobile-link-color 186 | // background: $mobile-link-bg 187 | border-bottom: 1px solid $mobile-link-border 188 | -------------------------------------------------------------------------------- /template/docs/assets/components/_offcanvas.sass: -------------------------------------------------------------------------------- 1 | $offcanvas-position: absolute 2 | $offcanvas-background: $tertiary-color 3 | $offcanvas-width: 250px 4 | 5 | .topbar 6 | transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) 7 | 8 | .offcanvas 9 | position: relative 10 | min-height: 100% 11 | 12 | .offcanvas__content 13 | z-index: z-index(offcanvas) 14 | position: $offcanvas-position 15 | background: $offcanvas-background 16 | width: calc(100% - 60px) 17 | height: 100% 18 | overflow: auto 19 | 20 | @media #{$medium-up} 21 | width: rem($offcanvas-width) 22 | 23 | .offcanvas__wrapper 24 | background: $global-background 25 | position: relative 26 | z-index: z-index(content) 27 | transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) 28 | box-shadow: -2px 0 15px rgba(0, 0, 0, 0.1) 29 | 30 | .offcanvas--right, 31 | .offcanvas--left 32 | 33 | .offcanvas 34 | overflow: hidden 35 | 36 | .offcanvas--right 37 | 38 | .offcanvas__wrapper, 39 | .topbar 40 | transform: translate3d(calc(100% - 60px), 0, 0) 41 | 42 | @media #{$medium-up} 43 | transform: translate3d(rem($offcanvas-width), 0, 0) 44 | 45 | .offcanvas--left 46 | 47 | .offcanvas 48 | overflow: hidden 49 | 50 | .topbar, 51 | .offcanvas__wrapper 52 | transform: translate3d(calc(-100% + 60px), 0, 0) 53 | 54 | @media #{$medium-up} 55 | transform: translate3d(rem(-$offcanvas-width), 0, 0) 56 | -------------------------------------------------------------------------------- /template/docs/assets/components/_panels.sass: -------------------------------------------------------------------------------- 1 | $panel-position: fixed 2 | $panel-background: $global-background 3 | $panel-size: 30% 4 | $panel-header-height: $global-topbar-height 5 | 6 | @mixin panel($name: panel, $side: right, $size: $panel-size, $position: fixed) 7 | .#{$name} 8 | @extend %panel 9 | 10 | position: $panel-position 11 | 12 | @if $side == right 13 | top: 0 14 | right: 0 15 | transform: translate3d(100%, 0, 0) 16 | box-shadow: -2px 0 10px rgba(0,0,0,0.1) 17 | width: calc(100% - 60px) 18 | min-height: 100% 19 | height: 100% 20 | 21 | @media #{$medium-up} 22 | width: $panel-size 23 | 24 | @if $side == left 25 | top: 0 26 | left: 0 27 | transform: translate3d(-100%, 0, 0) 28 | box-shadow: 2px 0 10px rgba(0,0,0,0.1) 29 | width: calc(100% - 60px) 30 | min-height: 100% 31 | height: 100% 32 | 33 | @media #{$medium-up} 34 | width: $panel-size 35 | 36 | @if $side == top 37 | top: 0 38 | left: 0 39 | right: 0 40 | transform: translate3d(0, -100%, 0) 41 | box-shadow: 0 2px 10px rgba(0,0,0,0.1) 42 | height: calc(100% - 200px) 43 | 44 | @media #{$medium-up} 45 | height: $panel-size 46 | 47 | @if $side == bottom 48 | bottom: 0 49 | left: 0 50 | right: 0 51 | transform: translate3d(0, 100%, 0) 52 | box-shadow: 0 -2px 10px rgba(0,0,0,0.1) 53 | height: calc(100% - 200px) 54 | 55 | @media #{$medium-up} 56 | height: $panel-size 57 | 58 | .#{$name}--active 59 | 60 | .#{$name} 61 | transform: translate3d(0, 0, 0) 62 | 63 | +panel(panel, right) 64 | 65 | %panel 66 | overflow: auto 67 | z-index: z-index(panel) 68 | background: $panel-background 69 | transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) 70 | 71 | .panel__header 72 | @extend .typo__h4 73 | 74 | line-height: rem($panel-header-height) 75 | display: block 76 | text-align: center 77 | margin-bottom: rem($global-v-gutter) 78 | border-bottom: $hr-border 79 | 80 | 81 | // TODO: Needs refactor 82 | .panel__close 83 | display: block 84 | cursor: pointer 85 | position: absolute 86 | transition: opacity .2s ease 87 | padding: 0 88 | background: none 89 | border: none 90 | z-index: 2 91 | transform: translate3d(0, 0, 0) 92 | top: rem($global-v-gutter) 93 | left: rem($global-gutter / 2) 94 | line-height: 1 95 | 96 | &:before 97 | content: "\d7" 98 | font-size: rem(20px) 99 | color: $secondary-color 100 | display: block 101 | z-index: 2 102 | transform: scale(1.6) 103 | transition: transform 0.3s cubic-bezier(0.51, -0.15, 0.48, 1.24), color 0.2s ease-in-out 104 | 105 | &:after 106 | content: "" 107 | z-index: -1 108 | position: absolute 109 | border-radius: 100% 110 | transform: scale(0) 111 | display: block 112 | background: $secondary-color 113 | transition: transform .2s cubic-bezier(0.54, -0.46, 0.36, 1.79) 114 | top: rem(-8px) 115 | left: rem(-9px) 116 | height: rem(32px) 117 | width: rem(32px) 118 | 119 | &:hover, &:focus 120 | 121 | &:before 122 | color: $global-background 123 | transform: scale(1) 124 | 125 | &:after 126 | transform: scale(1) 127 | -------------------------------------------------------------------------------- /template/docs/assets/components/_table.sass: -------------------------------------------------------------------------------- 1 | @import ../base/global 2 | 3 | // config 4 | $table-border: darken($tertiary-color, 5%) 5 | $table-font-size: 16px 6 | $table-padding: 14px 16px 7 | $table-bg: $global-support-background 8 | $table-even-bg: $global-background 9 | 10 | =table-row-variant($name, $color, $hover-modifier) 11 | .table__tr--#{$name} 12 | border-left: rem(4px) solid $color 13 | 14 | &:hover 15 | background: lighten($color, $hover-modifier) 16 | 17 | .table 18 | font: 19 | family: $global-font 20 | size: rem($table-font-size) 21 | weight: $global-font-weight 22 | margin-bottom: rem(40px) 23 | line-height: 1.4 24 | 25 | .table__tr 26 | border-bottom: 1px solid $table-border 27 | box-sizing: border-box 28 | border-left: rem(4px) solid transparent 29 | 30 | &:nth-child(even) 31 | background: #fafafa 32 | 33 | &:hover 34 | background: #f4f4f4 35 | 36 | +table-row-variant(primary, $primary-color, 48%) 37 | 38 | .table__td, 39 | .table__th 40 | padding: rem($table-padding) 41 | 42 | .table__th 43 | border-bottom: 1px solid #ccc 44 | 45 | .table__container 46 | overflow-x: auto 47 | 48 | .table--full-size 49 | width: 100% 50 | 51 | .table--fixed 52 | table-layout: fixed 53 | -------------------------------------------------------------------------------- /template/docs/assets/components/_tabs.sass: -------------------------------------------------------------------------------- 1 | @import ../base/global 2 | 3 | // config 4 | $tabs-bg: $global-background 5 | $tabs-bg-active: $global-background 6 | $tabs-font-size: 16px 7 | $tabs-height: 40px 8 | $tabs-link-weight: $global-font-weight 9 | $tabs-border: $tertiary-color 10 | $tabs-padding: 0 20px 11 | $tabs-width: 3px 12 | 13 | %tabs 14 | display: flex 15 | align-items: stretch 16 | min-height: rem($tabs-height) 17 | 18 | %tabs__link 19 | display: block 20 | padding: rem($tabs-padding) 21 | font: 22 | family: $global-font 23 | size: rem($tabs-font-size) 24 | weight: $tabs-link-weight 25 | text-decoration: none 26 | cursor: pointer 27 | line-height: rem($tabs-height) 28 | color: $secondary-lighten-color 29 | transition: color .2s ease 30 | 31 | %tabs__link--active 32 | font-weight: $global-font-weight-bold 33 | color: $secondary-color 34 | 35 | =tabs($name: tabs, $style: row, $inverted-content-side: false, $line-side: bottom) 36 | @if $style == column 37 | @if $inverted-content-side 38 | $line-side: left 39 | @else 40 | $line-side: right 41 | @else 42 | @if $inverted-content-side 43 | $line-side: top 44 | @else 45 | $line-side: bottom 46 | 47 | .#{$name} 48 | @extend %tabs 49 | 50 | flex-direction: $style 51 | border-#{$line-side}: $tabs-width solid $bright-grey-color 52 | margin-#{$line-side}: -$tabs-width 53 | 54 | .#{$name}__link 55 | @extend %tabs__link 56 | 57 | border-#{$line-side}: $tabs-width solid $bright-grey-color 58 | margin-#{$line-side}: -$tabs-width 59 | 60 | &:hover, 61 | &:focus 62 | color: $global-font-color 63 | 64 | .#{$name}__link--active 65 | @extend %tabs__link--active 66 | 67 | border-color: $primary-color 68 | 69 | +tabs(tabs, row) 70 | 71 | +tabs(vertical-tabs, column, false) 72 | -------------------------------------------------------------------------------- /template/docs/assets/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Fill 50 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /template/docs/assets/layout/_topbar.sass: -------------------------------------------------------------------------------- 1 | $topbar-bg: $global-support-background 2 | $topbar-bg-hover: $global-background 3 | $topbar-color: $secondary-color 4 | $topbar-border: $tertiary-color 5 | $topbar-link-underline: $primary-color 6 | 7 | $topbar-font-weight: $global-font-weight 8 | $topbar-font: $global-font 9 | $topbar-font-size: 14px 10 | $topbar-height: $global-topbar-height 11 | $topbar-dropdown-font-size: 14px 12 | 13 | .topbar--sticky 14 | 15 | .offcanvas__wrapper, 16 | .content 17 | padding-top: rem($topbar-height) 18 | 19 | .topbar 20 | position: fixed 21 | top: 0 22 | left: 0 23 | right: 0 24 | z-index: z-index(topbar) 25 | 26 | 27 | .topbar 28 | background: $topbar-bg 29 | width: 100% 30 | display: block 31 | box-sizing: content-box 32 | height: rem($topbar-height) 33 | color: $topbar-color 34 | line-height: rem($topbar-height) 35 | font-family: $topbar-font 36 | padding: 0 37 | border-bottom: 1px solid $topbar-border 38 | box-shadow: 0 1px 3px rgba(#000, 0.1) 39 | 40 | .topbar__logo, 41 | .topbar__link 42 | position: relative 43 | 44 | 45 | .topbar__logo 46 | font-weight: 700 47 | font-size: rem(16px) 48 | height: rem($topbar-height) 49 | vertical-align: middle 50 | text-decoration: none 51 | color: $topbar-color 52 | 53 | &:visited 54 | color: $topbar-color 55 | 56 | small 57 | font-weight: $global-font-weight 58 | margin-left: 5px 59 | 60 | img, svg 61 | max-height: rem($topbar-height - 15px) 62 | padding: 0 5px 5px 0 63 | display: inline-block 64 | vertical-align: middle 65 | 66 | .topbar__nav 67 | list-style: none 68 | float: left 69 | font-size: rem($topbar-font-size) 70 | font-weight: $topbar-font-weight 71 | margin: 0 72 | padding: 0 73 | height: rem($topbar-height) 74 | font-size: rem(0) 75 | 76 | .topbar__option 77 | display: inline-block 78 | font-size: rem($topbar-font-size) 79 | height: 100% 80 | vertical-align: top 81 | text-transform: uppercase 82 | 83 | 84 | .topbar__option--has-dropdown 85 | 86 | .topbar__link:before 87 | content: "" 88 | width: 0 89 | height: 0 90 | border-style: solid 91 | border-width: rem(5px 5px 0 5px) 92 | border-color: $topbar-color transparent transparent transparent 93 | display: inline-block 94 | margin-right: rem($grid-gutter-width / 5) 95 | padding-bottom: rem(2px) 96 | 97 | 98 | .topbar__separator 99 | display: inline-block 100 | border-left: 1px solid $topbar-border 101 | height: 100% 102 | vertical-align: top 103 | 104 | .topbar__link 105 | display: block 106 | font-size: rem($topbar-font-size) 107 | padding: 0 rem($topbar-font-size * 1.5) 108 | color: $topbar-color 109 | text-decoration: none 110 | transition: background .1s ease 111 | 112 | &:hover, 113 | &:visited 114 | color: $topbar-color 115 | 116 | &:hover, &:focus 117 | outline: none 118 | background: $topbar-bg-hover 119 | 120 | .topbar__right 121 | float: right 122 | 123 | .topbar__left 124 | float: left 125 | 126 | 127 | // dropdown extension 128 | .topbar__option 129 | .dropdown 130 | height: 100% 131 | width: auto 132 | background: none 133 | 134 | .topbar__link:after, 135 | .user:after 136 | content: "" 137 | position: absolute 138 | bottom: rem(-1px) 139 | left: 0 140 | width: 0 141 | height: rem(2px) 142 | background: $primary-color 143 | transition: width .15s ease 144 | 145 | &:hover 146 | .topbar__link:after, 147 | .user:after 148 | width: 100% 149 | 150 | 151 | .dropdown__current 152 | height: 100% 153 | 154 | .dropdown__list 155 | position: absolute 156 | margin-left: rem(-1px) 157 | margin-top: rem(1px) 158 | min-width: 100% 159 | white-space: nowrap 160 | 161 | .dropdown__option 162 | line-height: rem($topbar-height / 2) 163 | border-bottom: 1px solid $tertiary-color 164 | font-size: rem($topbar-dropdown-font-size) 165 | padding-left: rem($topbar-font-size * 1.5) 166 | padding-right: rem($topbar-font-size * 1.5) 167 | -------------------------------------------------------------------------------- /template/docs/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monterail/vue-component-template/10a6c1bf1996c7248d997425a98c656f689940ec/template/docs/assets/logo.png -------------------------------------------------------------------------------- /template/docs/assets/main.sass: -------------------------------------------------------------------------------- 1 | // BASE 2 | @import base/mixins 3 | @import base/z-stack 4 | @import base/normalize 5 | @import base/animations 6 | @import base/global 7 | @import base/functions 8 | @import base/media 9 | @import base/typo 10 | 11 | // COMPONENTS 12 | 13 | @import components/grid 14 | @import components/table 15 | @import components/buttons 16 | @import components/inputs 17 | @import components/lists 18 | 19 | // TODO: OVERRIDING UTILS (which has to be loaded last to reduce the use of !important) 20 | @import utils/visibility 21 | @import utils/utils 22 | -------------------------------------------------------------------------------- /template/docs/assets/multiselect.sass: -------------------------------------------------------------------------------- 1 | .multiselect__spinner 2 | position: absolute 3 | right: 1px 4 | top: 1px 5 | width: 3rem 6 | height: 2.1875rem 7 | background: #fff 8 | display: block 9 | 10 | &:before, 11 | &:after 12 | position: absolute 13 | content: '' 14 | top: 50% 15 | left: 50% 16 | margin: 0.875rem 0 0 0.875rem 17 | width: 1rem 18 | height: 1rem 19 | border-radius: 100% 20 | border-color: #41B883 transparent transparent 21 | border-style: solid 22 | border-width: 2px 23 | box-shadow: 0 0 0 1px transparent 24 | 25 | &:before 26 | animation: spinning 2.4s cubic-bezier(0.41, 0.26, 0.2, 0.62) 27 | animation-iteration-count: infinite 28 | 29 | &:after 30 | animation: spinning 2.4s cubic-bezier(0.51, 0.09, 0.21, 0.8) 31 | animation-iteration-count: infinite 32 | 33 | .multiselect__loading-transition 34 | transition: opacity 0.4s ease-in-out 35 | opacity: 1 36 | 37 | .multiselect__loading-enter, 38 | .multiselect__loading-leave 39 | opacity: 0 40 | 41 | .multiselect, 42 | .multiselect__input, 43 | .multiselect__single 44 | font: 45 | family: inherit 46 | size: 0.875rem 47 | weight: lighter 48 | 49 | .multiselect 50 | box-sizing: content-box 51 | 52 | * 53 | box-sizing: border-box 54 | 55 | display: block 56 | position: relative 57 | width: 100% 58 | min-height: 2.5rem 59 | text-align: left 60 | color: #35495E 61 | 62 | &:focus 63 | outline: none 64 | 65 | &--active 66 | z-index: 50 67 | 68 | .multiselect__current, 69 | .multiselect__input, 70 | .multiselect__tags 71 | border-bottom-left-radius: 0 72 | border-bottom-right-radius: 0 73 | 74 | .multiselect__select 75 | transform: rotateZ(180deg) 76 | 77 | .multiselect__input, 78 | .multiselect__single 79 | position: relative 80 | display: inline-block 81 | min-height: 1.25rem 82 | line-height: 1.25rem 83 | border: none 84 | border-radius: 0.3125rem 85 | background: #fff 86 | padding: 1px 0 0 0.3125rem 87 | width: auto 88 | transition: border .1s ease 89 | box-sizing: border-box 90 | margin-bottom: 0.5rem 91 | 92 | &:hover 93 | border-color: darken(#E8E8E8, 10%) 94 | 95 | &:focus 96 | border-color: darken(#E8E8E8, 25%) 97 | outline: none 98 | 99 | .multiselect__single 100 | padding-left: 0.375rem 101 | margin-bottom: 0.5rem 102 | 103 | .multiselect__tags 104 | min-height: 2.5rem 105 | display: block 106 | padding: 0.5rem 2.5rem 0 0.5rem 107 | border-radius: 0.3125rem 108 | border: 1px solid #E8E8E8 109 | background: #fff 110 | 111 | .multiselect__tag 112 | position: relative 113 | display: inline-block 114 | padding: 0.25rem 1.625rem 0.25rem 0.625rem 115 | border-radius: 0.3125rem 116 | margin-right: 0.625rem 117 | color: #fff 118 | line-height: 1 119 | background: #41B883 120 | margin-bottom: 0.5rem 121 | 122 | .multiselect__tag-icon 123 | cursor: pointer 124 | margin-left: 7px 125 | position: absolute 126 | right: 0 127 | top: 0 128 | bottom: 0 129 | font: 130 | weight: 700 131 | style: initial 132 | width: 1.375rem 133 | text-align: center 134 | line-height: 1.375rem 135 | transition: all 0.2s ease 136 | border-radius: 0.3125rem 137 | 138 | &:after 139 | content: "\00D7" 140 | color: darken(#41B883, 20%) 141 | font-size: 0.875rem 142 | 143 | &:focus, &:hover 144 | background: darken(#41B883, 8%) 145 | 146 | &:after 147 | color: white 148 | 149 | .multiselect__current 150 | line-height: 1rem 151 | min-height: 2.5rem 152 | box-sizing: border-box 153 | display: block 154 | overflow: hidden 155 | padding: 0.5rem 0.75rem 0 156 | padding-right: 1.875rem 157 | white-space: nowrap 158 | margin: 0 159 | text-decoration: none 160 | border-radius: 0.3125rem 161 | border: 1px solid #E8E8E8 162 | cursor: pointer 163 | 164 | .multiselect__select 165 | line-height: 1rem 166 | display: block 167 | position: absolute 168 | box-sizing: border-box 169 | width: 2.5rem 170 | height: 2.375rem 171 | right: 1px 172 | top: 1px 173 | padding: 0.25rem 0.5rem 174 | margin: 0 175 | text-decoration: none 176 | text-align: center 177 | cursor: pointer 178 | transition: transform 0.2s ease 179 | 180 | &:before 181 | position: relative 182 | right: 0 183 | top: 65% 184 | color: #999 185 | margin-top: 0.25rem 186 | border-style: solid 187 | border-width: 0.3125rem 0.3125rem 0 0.3125rem 188 | border-color: #999999 transparent transparent transparent 189 | content: "" 190 | 191 | .multiselect__placeholder 192 | color: #ADADAD 193 | display: inline-block 194 | margin-bottom: 0.625rem 195 | padding-top: 0.125rem 196 | 197 | .multiselect--active & 198 | display: none 199 | 200 | .multiselect__content 201 | position: absolute 202 | list-style: none 203 | display: block 204 | background: #fff 205 | width: 100% 206 | max-height: 15rem 207 | overflow: auto 208 | padding: 0 209 | margin: 0 210 | border: 1px solid #E8E8E8 211 | border-top: none 212 | border-bottom-left-radius: 0.3125rem 213 | border-bottom-right-radius: 0.3125rem 214 | z-index: 50 215 | 216 | &::webkit-scrollbar 217 | display: none 218 | 219 | .multiselect__option 220 | display: block 221 | padding: 0.75rem 222 | min-height: 2.5rem 223 | line-height: 1rem 224 | font-weight: 300 225 | text-decoration: none 226 | text-transform: none 227 | vertical-align: middle 228 | position: relative 229 | cursor: pointer 230 | 231 | &:after 232 | top: 0 233 | right: 0 234 | position: absolute 235 | line-height: 2.5rem 236 | padding-right: 0.75rem 237 | padding-left: 1.25rem 238 | 239 | &--highlight 240 | background: #41B883 241 | outline: none 242 | color: white 243 | 244 | &:after 245 | content: attr(data-select) 246 | color: white 247 | 248 | &--selected 249 | background: #F3F3F3 250 | color: #35495E 251 | font-weight: bold 252 | 253 | &:after 254 | content: attr(data-selected) 255 | font-weight: 300 256 | color: darken(#F3F3F3, 20%) 257 | 258 | .multiselect__option--selected.multiselect__option--highlight 259 | background: #FF6A6A 260 | color: #fff 261 | font-weight: lighter 262 | 263 | &:after 264 | content: attr(data-deselect) 265 | color: #fff 266 | 267 | .multiselect--disabled 268 | background: darken(#fff, 7%) 269 | pointer-events: none 270 | 271 | .multiselect__current, 272 | .multiselect__select 273 | background: darken(#fff, 7%) 274 | color: darken(#fff, 35%) 275 | 276 | .multiselect__option--disabled 277 | background: darken(#fff, 7%) 278 | color: darken(#fff, 35%) 279 | cursor: text 280 | pointer-events: none 281 | 282 | &:visited 283 | color: darken(#fff, 35%) 284 | 285 | &:hover, 286 | &:focus 287 | background: darken(#41B883, 3%) 288 | 289 | .multiselect-transition 290 | transition: all .3s ease 291 | 292 | .multiselect-enter, .multiselect-leave 293 | opacity: 0 294 | max-height: 0 !important 295 | -------------------------------------------------------------------------------- /template/docs/assets/prism.scss: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+coffeescript+css-extras+git+jade+sass+scss&plugins=show-language+remove-initial-line-feed */ 2 | /** 3 | * prism.js default theme for JavaScript, CSS and HTML 4 | * Based on dabblet (http://dabblet.com) 5 | * @author Lea Verou 6 | */ 7 | 8 | code[class*="language-"], 9 | pre[class*="language-"] { 10 | color: black; 11 | text-shadow: 0 1px white; 12 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 13 | direction: ltr; 14 | text-align: left; 15 | white-space: pre; 16 | word-spacing: normal; 17 | word-break: normal; 18 | word-wrap: normal; 19 | line-height: 1.5; 20 | 21 | -moz-tab-size: 4; 22 | -o-tab-size: 4; 23 | tab-size: 4; 24 | 25 | -webkit-hyphens: none; 26 | -moz-hyphens: none; 27 | -ms-hyphens: none; 28 | hyphens: none; 29 | } 30 | 31 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 32 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { 33 | text-shadow: none; 34 | background: #b3d4fc; 35 | } 36 | 37 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, 38 | code[class*="language-"]::selection, code[class*="language-"] ::selection { 39 | text-shadow: none; 40 | background: #b3d4fc; 41 | } 42 | 43 | @media print { 44 | code[class*="language-"], 45 | pre[class*="language-"] { 46 | text-shadow: none; 47 | } 48 | } 49 | 50 | /* Code blocks */ 51 | pre[class*="language-"] { 52 | padding: 1.3em 1em; 53 | margin: 0 0 20px 0; 54 | overflow: auto; 55 | } 56 | 57 | :not(pre) > code[class*="language-"], 58 | pre[class*="language-"] { 59 | background: #F3F5F6; 60 | } 61 | 62 | /* Inline code */ 63 | :not(pre) > code[class*="language-"] { 64 | padding: .1em; 65 | border-radius: .3em; 66 | white-space: normal; 67 | } 68 | 69 | .token.comment, 70 | .token.prolog, 71 | .token.doctype, 72 | .token.cdata { 73 | color: slategray; 74 | } 75 | 76 | .token.punctuation { 77 | color: #999; 78 | } 79 | 80 | .namespace { 81 | opacity: .7; 82 | } 83 | 84 | .token.property, 85 | .token.tag, 86 | .token.boolean, 87 | .token.number, 88 | .token.constant, 89 | .token.symbol, 90 | .token.deleted { 91 | color: #905; 92 | } 93 | 94 | .token.selector, 95 | .token.attr-name, 96 | .token.string, 97 | .token.char, 98 | .token.builtin, 99 | .token.inserted { 100 | color: #690; 101 | } 102 | 103 | .token.operator, 104 | .token.entity, 105 | .token.url, 106 | .language-css .token.string, 107 | .style .token.string { 108 | color: #a67f59; 109 | background: hsla(0, 0%, 100%, .5); 110 | } 111 | 112 | .token.atrule, 113 | .token.attr-value, 114 | .token.keyword { 115 | color: #07a; 116 | } 117 | 118 | .token.function { 119 | color: #DD4A68; 120 | } 121 | 122 | .token.regex, 123 | .token.important, 124 | .token.variable { 125 | color: #e90; 126 | } 127 | 128 | .token.important, 129 | .token.bold { 130 | font-weight: bold; 131 | } 132 | .token.italic { 133 | font-style: italic; 134 | } 135 | 136 | .token.entity { 137 | cursor: help; 138 | } 139 | 140 | div.prism-show-language { 141 | position: relative; 142 | } 143 | 144 | div.prism-show-language > div.prism-show-language-label[data-language] { 145 | color: black; 146 | background-color: #CFCFCF; 147 | opacity: 0.5; 148 | display: inline-block; 149 | position: absolute; 150 | bottom: auto; 151 | left: auto; 152 | top: 0; 153 | right: 0; 154 | width: auto; 155 | height: auto; 156 | font-size: 0.9em; 157 | border-radius: 0 0 0 5px; 158 | padding: 0.1em 0.5em; 159 | text-shadow: none; 160 | z-index: 1; 161 | -webkit-box-shadow: none; 162 | -moz-box-shadow: none; 163 | box-shadow: none; 164 | -webkit-transform: none; 165 | -moz-transform: none; 166 | -ms-transform: none; 167 | -o-transform: none; 168 | transform: none; 169 | } 170 | -------------------------------------------------------------------------------- /template/docs/assets/utils/_utils.sass: -------------------------------------------------------------------------------- 1 | .utils--center 2 | text-align: center 3 | 4 | .utils--right 5 | text-align: right 6 | -------------------------------------------------------------------------------- /template/docs/assets/utils/_visibility.sass: -------------------------------------------------------------------------------- 1 | @media #{$small-only} 2 | .small--hidden 3 | display: none !important 4 | 5 | @media #{$medium-only} 6 | .medium--hidden 7 | display: none !important 8 | 9 | @media #{$medium-up} 10 | .medium-up--hidden 11 | display: none !important 12 | 13 | @media #{$large-only} 14 | .large--hidden 15 | display: none !important 16 | 17 | @media #{$large-up} 18 | .large-up--hidden 19 | display: none !important 20 | 21 | @media #{$xlarge-only} 22 | .xlarge--hidden 23 | display: none !important 24 | -------------------------------------------------------------------------------- /template/docs/docs.scss: -------------------------------------------------------------------------------- 1 | @import './assets/main'; 2 | @import './assets/prism'; 3 | 4 | .invalid { 5 | .typo__label { 6 | color: $error-color; 7 | } 8 | .multiselect__tags { 9 | border-color: $error-color !important; 10 | } 11 | } 12 | 13 | body { 14 | background: #fff; 15 | color: #35495E; 16 | font-family: 'Lato', Helvetica, sans-serif; 17 | text-decoration: none; 18 | } 19 | 20 | .start { 21 | text-align: center; 22 | display: block; 23 | background: linear-gradient(to left bottom, #8cc1f7 0%, #9cffd3 100%); 24 | 25 | .typo__h1 { 26 | padding-top: rem(40px); 27 | position: relative; 28 | } 29 | 30 | .typo__h3 { 31 | padding: rem(20px 0) 32 | } 33 | 34 | @media #{$medium-up} { 35 | min-height: 100vh; 36 | } 37 | 38 | .button { 39 | margin-bottom: rem(24px); 40 | } 41 | } 42 | 43 | .start__list { 44 | padding-top: rem(30px) 45 | } 46 | 47 | .docs { 48 | text-align: left; 49 | padding-top: rem(60px) 50 | } 51 | 52 | .center-vertically { 53 | position: relative; 54 | 55 | @media #{$medium-up} { 56 | position: absolute; 57 | height: 600px; 58 | left: 0; 59 | right: 0; 60 | top: 50%; 61 | transform: translateY(-50%); 62 | } 63 | } 64 | 65 | .multiselect-example__container { 66 | margin: 0 auto 60px; 67 | } 68 | 69 | .button { 70 | margin: rem(0 10px) 71 | } 72 | 73 | .logo { 74 | height: rem(70px); 75 | margin-right: rem(20px); 76 | vertical-align: middle; 77 | display: inline-block; 78 | } 79 | 80 | .monterail-logo { 81 | width: 100px; 82 | height: 100px; 83 | margin-bottom: rem(30px) 84 | } 85 | 86 | .monterail-link { 87 | color: #D20C03 88 | } 89 | 90 | .button--github { 91 | padding-left: rem(60px); 92 | 93 | &:before { 94 | content: url('./assets/github.svg'); 95 | left: rem(25px); 96 | position: absolute; 97 | } 98 | } 99 | 100 | .version { 101 | position: absolute; 102 | bottom: rem(-7px); 103 | font-size: rem(20px); 104 | color: $secondary-color; 105 | transform: translateX(-100%); 106 | } 107 | -------------------------------------------------------------------------------- /template/docs/index.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang="en") 3 | head 4 | meta(charset='utf-8') 5 | meta(name='viewport', content='width=device-width,initial-scale=1,maximum-scale=1') 6 | title {{ name }} | A Vue.js library 7 | link(rel='icon', href='static/vue-logo.png', type='image/x-icon') 8 | meta(name='description', content='{{ description }}') 9 | meta(property='og:title', content='{{ name }} | A Vue.js library.') 10 | meta(property='og:site_name', content='{{ name }} | A Vue.js library.') 11 | meta(property='og:url', content='http://monterail.github.io/vue-multiselect') 12 | meta(property='og:description', content='{{ description }}') 13 | meta(property='og:image', content='http://monterail.github.io/vue-multiselect/static/vue-logo.png') 14 | meta(property='twitter:image', content='http://monterail.github.io/vue-multiselect/static/vue-logo.png') 15 | meta(property='twitter:title', content='{{ name }} | A Vue.js library.') 16 | meta(property='twitter:description', content='{{ description }}') 17 | body 18 | #app 19 | include ./partials/_start 20 | 21 | .grid__row.docs 22 | .grid__columns.grid__unit--sm-3.small--hidden 23 | include ./partials/_nav 24 | .grid__columns.grid__unit--sm-12.grid__unit--md-9 25 | include ./partials/_getting-started 26 | 27 | hr.typo__hr 28 | h1.typo__h1 Examples 29 | 30 | hr.typo__hr 31 | include ./partials/examples/_section 32 | 33 | include ./partials/api/_props 34 | include ./partials/api/_events 35 | include ./partials/api/_slots 36 | 37 | include ./partials/_footer 38 | 39 | script(src='static/prism.js') 40 | -------------------------------------------------------------------------------- /template/docs/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | require('./docs.scss') 4 | 5 | function throttle (callback, limit) { 6 | var wait = false 7 | return function () { 8 | if (!wait) { 9 | callback.call() 10 | wait = true 11 | setTimeout(function () { 12 | wait = false 13 | }, limit) 14 | } 15 | } 16 | } 17 | 18 | const SL = ', 100%, 85%' 19 | 20 | /* eslint-disable no-new */ 21 | new Vue({ 22 | el: '#app', 23 | data () { 24 | return { 25 | isNavSticky: false, 26 | firstColor: Math.floor(Math.random() * 255), 27 | secondColor: Math.floor(Math.random() * 255) 28 | } 29 | }, 30 | computed: { 31 | gradient () { 32 | return { 33 | background: `linear-gradient(to left bottom, hsl(${this.firstColor + SL}) 0%, hsl(${this.secondColor + SL}) 100%)` 34 | } 35 | } 36 | }, 37 | methods: { 38 | adjustNav () { 39 | this.isNavSticky = window.scrollY > window.innerHeight 40 | } 41 | }, 42 | mounted () { 43 | this.adjustNav() 44 | window.addEventListener('scroll', throttle(this.adjustNav, 50)) 45 | } 46 | }) 47 | -------------------------------------------------------------------------------- /template/docs/partials/_footer.pug: -------------------------------------------------------------------------------- 1 | section.utils--center 2 | h4.typo__h4 3 | | Created by {{ author }} 4 | strong 5 | a.typo__link(href='https://twitter.com/', target='_BLANK') 6 | | {{ author }} twitter handle 7 | h4.typo__h4 8 | | With love from 9 | strong 10 | a.typo__link.monterail-link(href='http://monterail.com', target='_BLANK') Monterail 11 | a(href='http://monterail.com', target='_BLANK') 12 | img.monterail-logo(src='static/monterail-logo.png') 13 | -------------------------------------------------------------------------------- /template/docs/partials/_getting-started.pug: -------------------------------------------------------------------------------- 1 | .grid__row 2 | .grid__column 3 | section.docs#getting-started 4 | h1.typo__h1 Getting started 5 | hr.typo__hr 6 | 7 | .grid__row 8 | .grid__column 9 | h2.typo__h2 Installation 10 | pre.language-bash 11 | code. 12 | npm install {{ name }} --save 13 | 14 | .grid__column 15 | h2.typo__h2 Basic usage 16 | pre.language-jade 17 | code. 18 | multiselect( 19 | v-model="selected", 20 | :options="options" 21 | ) 22 | pre.language-javascript 23 | code. 24 | import {{ name }} from '{{ name }}' 25 | export default { 26 | components: { {{ name }} } 27 | } 28 | 29 | .grid__row 30 | .grid__column 31 | h2.typo__h2 Package content 32 | 33 | .grid__column.grid__unit--md-5 34 | p.typo__p 35 | | {{ description }} 36 | -------------------------------------------------------------------------------- /template/docs/partials/_nav.pug: -------------------------------------------------------------------------------- 1 | mixin nav-element(componentName, href) 2 | li.list__element 3 | a.link.list__link(href="##{href}")= componentName 4 | 5 | ul.list( 6 | :class="{ 'list--sticky': isNavSticky }" 7 | ) 8 | li.list__heading Setup 9 | +nav-element('Getting Started', 'getting-started') 10 | 11 | li.list__heading Examples 12 | +nav-element('Section', 'section') 13 | 14 | li.list__heading API 15 | +nav-element('Props', 'props') 16 | +nav-element('Events', 'events') 17 | +nav-element('Slots', 'slots') 18 | -------------------------------------------------------------------------------- /template/docs/partials/_start.pug: -------------------------------------------------------------------------------- 1 | section.start( 2 | :style="gradient" 3 | ) 4 | .center-vertically 5 | h1.typo__h1 6 | img.logo(src="./static/vue-logo.png") 7 | | {{ name }} 8 | small.version (version here) 9 | h3.typo__h3 {{ Description }} 10 | = ' for ' 11 | a.typo__link(href="http://vuejs.org" target="_BLANK") Vue.js 12 | 13 | .grid__row.grid__row--centered 14 | .grid__column.grid__unit--md-6 15 | .multiselect-example__container 16 | .grid__row.start__list 17 | .grid__column.grid__unit--md-6.list 18 | ul.list__ul 19 | li.typo__li Perks here 20 | li.typo__li And here 21 | li.typo__li: a.typo__link(href="#search") And here with a link 22 | .grid__column.grid__unit--md-6.list 23 | ul.list__ul 24 | li.typo__li Perks here 25 | li.typo__li And here 26 | li.typo__li: a.typo__link(href="#search") And here with a link 27 | 28 | .grid__row.grid__row--centered 29 | .grid__column.utils--center 30 | a.button.button--large.button--secondary.button--github(href="https://github.com/monterail" target="_BLANK") View on GitHub 31 | a.button.button--large(href="#getting-started") Getting started & examples 32 | -------------------------------------------------------------------------------- /template/docs/partials/api/_events.pug: -------------------------------------------------------------------------------- 1 | h2.typo__h2#events Events 2 | .grid__row 3 | .table__container 4 | table.table.table--full-size 5 | thead 6 | tr.table__tr 7 | th.table__th(width="150") Name 8 | th.table__th(width="100") Attributes 9 | th.table__th(width="150") Listen to 10 | th.table__th(width="250") Description 11 | tbody 12 | tr.table__tr 13 | td.table__td: strong Input 14 | td.table__td: kbd (value, id) 15 | td.table__td: kbd @input 16 | td.table__td 17 | | Emitted after 18 | = " " 19 | kbd this.value 20 | | changes 21 | -------------------------------------------------------------------------------- /template/docs/partials/api/_props.pug: -------------------------------------------------------------------------------- 1 | h2.typo__h2#props Props 2 | .grid__row 3 | .table__container 4 | table.table.table--full-size.table--fixed 5 | thead 6 | tr.table__tr 7 | th.table__th(width="100") Name 8 | th.table__th(width="80") Type 9 | th.table__th(width="180") Default 10 | th.table__th(width="200") Description 11 | tbody 12 | tr.table__tr 13 | td.table__td: strong Id 14 | td.table__td Integer||String 15 | td.table__td 16 | td.table__td. 17 | Used to identify the component in events. 18 | -------------------------------------------------------------------------------- /template/docs/partials/api/_slots.pug: -------------------------------------------------------------------------------- 1 | h2.typo__h2#slots Slots 2 | .grid__row 3 | .table__container 4 | table.table.table--full-size.table--fixed 5 | thead 6 | tr.table__tr 7 | th.table__th(width="200") Name 8 | th.table__th Description 9 | tbody 10 | tr.table__tr 11 | td.table__td: strong MaxElements 12 | td.table__td 13 | | Shows when the maximum options have been selected. 14 | -------------------------------------------------------------------------------- /template/docs/partials/examples/_section.pug: -------------------------------------------------------------------------------- 1 | h2.typo__h2#tagging Section 2 | p.typo__p 3 | | Section description 4 | .grid__row 5 | .grid__column.grid__unit--md-5 6 | label.typo__label Section 7 | | Code here 8 | 9 | .grid__column.grid__unit--md-7 10 | label.typo__label Code sample 11 | pre.language-jade 12 | code. 13 | multiselect( 14 | :options="taggingOptions", 15 | v-model="taggingSelected", 16 | :multiple="true", 17 | :searchable="searchable", 18 | :taggable="true", 19 | @tag="addTag", 20 | tag-placeholder="Add this as new tag" 21 | placeholder="Type to search or add tag" 22 | label="name" 23 | track-by="code" 24 | ) 25 | span(slot="noResult"). 26 | Oops! No elements found. Consider changing the search query. 27 | 28 | pre.language-javascript 29 | code. 30 | addTag (newTag) { 31 | const tag = { 32 | name: newTag, 33 | // Just for example needs as we use Array of Objects that should have other properties filled. 34 | // For primitive values you can simply push the tag into options and selected arrays. 35 | code: newTag.substring(0, 2) + Math.floor((Math.random() * 10000000)) 36 | } 37 | this.taggingOptions.push(tag) 38 | this.taggingSelected.push(tag) 39 | } 40 | -------------------------------------------------------------------------------- /template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ name }} 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{ name }}", 3 | "version": "1.0.0", 4 | "description": "{{ description }}", 5 | "author": "{{ author }}", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "bundle": "webpack --config build/webpack.bundle.conf.js", 10 | "docs": "rm -rf gh-pages && mkdir gh-pages && node build/build.js"{{#unit}}, 11 | "unit": "karma start test/unit/karma.conf.js --single-run"{{/unit}}{{#e2e}}, 12 | "e2e": "node test/e2e/runner.js"{{/e2e}}{{#if_or unit e2e}}, 13 | "test": "{{#unit}}npm run unit{{/unit}}{{#unit}}{{#e2e}} && {{/e2e}}{{/unit}}{{#e2e}}npm run e2e{{/e2e}}"{{/if_or}}{{#lint}}, 14 | "lint": "eslint --ext .js,.vue src{{#unit}} test/unit/specs{{/unit}}{{#e2e}} test/e2e/specs{{/e2e}}"{{/lint}} 15 | }, 16 | "devDependencies": { 17 | "autoprefixer": "^6.4.0", 18 | "babel-core": "^6.0.0", 19 | {{#lint}} 20 | "babel-eslint": "^7.0.0", 21 | {{/lint}} 22 | "babel-loader": "^6.0.0", 23 | "babel-plugin-transform-runtime": "^6.0.0", 24 | "babel-preset-es2015": "^6.0.0", 25 | "babel-preset-stage-2": "^6.0.0", 26 | "babel-register": "^6.0.0", 27 | "chalk": "^1.1.3", 28 | "connect-history-api-fallback": "^1.1.0", 29 | "copy-webpack-plugin": "^4.0.0", 30 | "css-loader": "^0.25.0", 31 | {{#lint}} 32 | "eslint": "^3.7.1", 33 | "eslint-friendly-formatter": "^2.0.5", 34 | "eslint-loader": "^1.5.0", 35 | "eslint-plugin-html": "^1.3.0", 36 | {{#if_eq lintConfig "standard"}} 37 | "eslint-config-standard": "^6.1.0", 38 | "eslint-plugin-promise": "^2.0.1", 39 | "eslint-plugin-standard": "^2.0.1", 40 | {{/if_eq}} 41 | {{#if_eq lintConfig "airbnb"}} 42 | "eslint-config-airbnb-base": "^8.0.0", 43 | "eslint-import-resolver-webpack": "^0.6.0", 44 | "eslint-plugin-import": "^1.16.0", 45 | {{/if_eq}} 46 | {{/lint}} 47 | "eventsource-polyfill": "^0.9.6", 48 | "express": "^4.13.3", 49 | "extract-text-webpack-plugin": "^1.0.1", 50 | "file-loader": "^0.9.0", 51 | "function-bind": "^1.0.2", 52 | "html-webpack-plugin": "^2.8.1", 53 | "http-proxy-middleware": "^0.17.2", 54 | "json-loader": "^0.5.4", 55 | {{#unit}} 56 | "karma": "^1.3.0", 57 | "karma-coverage": "^1.1.1", 58 | "karma-mocha": "^1.2.0", 59 | "karma-phantomjs-launcher": "^1.0.0", 60 | "karma-sinon-chai": "^1.2.0", 61 | "karma-sourcemap-loader": "^0.3.7", 62 | "karma-spec-reporter": "0.0.26", 63 | "karma-webpack": "^1.7.0", 64 | "lolex": "^1.4.0", 65 | "mocha": "^3.1.0", 66 | "chai": "^3.5.0", 67 | "sinon": "^1.17.3", 68 | "sinon-chai": "^2.8.0", 69 | "inject-loader": "^2.0.1", 70 | "isparta-loader": "^2.0.0", 71 | "phantomjs-prebuilt": "^2.1.3", 72 | {{/unit}} 73 | {{#e2e}} 74 | "chromedriver": "^2.21.2", 75 | "cross-spawn": "^4.0.2", 76 | "nightwatch": "^0.9.8", 77 | "selenium-server": "2.53.1", 78 | {{/e2e}} 79 | "node-sass": "^3.4.2", 80 | "sass-loader": "^3.2.0", 81 | "semver": "^5.3.0", 82 | "opn": "^4.0.2", 83 | "ora": "^0.3.0", 84 | "pug": "2.0.0-beta6", 85 | "pug-loader": "^2.3.0", 86 | "shelljs": "^0.7.4", 87 | "url-loader": "^0.5.7", 88 | "vue": "^2.0.4", 89 | "vue-loader": "^9.4.0", 90 | "vue-style-loader": "^1.0.0", 91 | "webpack": "^1.13.2", 92 | "webpack-dev-middleware": "^1.8.3", 93 | "webpack-hot-middleware": "^2.12.2", 94 | "webpack-merge": "^0.14.1" 95 | }, 96 | "engines": { 97 | "node": ">= 4.0.0", 98 | "npm": ">= 3.0.0" 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /template/src/MyComponent.vue: -------------------------------------------------------------------------------- 1 | export default { 2 | data () { 3 | return { 4 | msg: 'Hi!' 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /template/src/index.js: -------------------------------------------------------------------------------- 1 | import MyComponent from './MyComponent' 2 | 3 | export default MyComponent 4 | 5 | export { MyComponent } 6 | -------------------------------------------------------------------------------- /template/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monterail/vue-component-template/10a6c1bf1996c7248d997425a98c656f689940ec/template/static/.gitkeep -------------------------------------------------------------------------------- /template/static/monterail-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monterail/vue-component-template/10a6c1bf1996c7248d997425a98c656f689940ec/template/static/monterail-logo.png -------------------------------------------------------------------------------- /template/static/prism.js: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+coffeescript+css-extras+git+jade+sass+scss&plugins=show-language+remove-initial-line-feed */ 2 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=_self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),P=[p,1];b&&P.push(b);var A=new a(i,g?t.tokenize(m,g):m,h);P.push(A),w&&P.push(w),Array.prototype.splice.apply(r,P)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var l={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}t.hooks.run("wrap",l);var o="";for(var s in l.attributes)o+=(o?" ":"")+s+'="'+(l.attributes[s]||"")+'"';return"<"+l.tag+' class="'+l.classes.join(" ")+'" '+o+">"+l.content+""},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code,l=n.immediateClose;_self.postMessage(t.highlight(r,t.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); 3 | Prism.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=.$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup; 4 | Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/()[\w\W]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag)); 5 | Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}; 6 | Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),Prism.languages.insertBefore("javascript","class-name",{"template-string":{pattern:/`(?:\\`|\\?[^`])*`/,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript"}}),Prism.languages.js=Prism.languages.javascript; 7 | !function(e){var n=/#(?!\{).+/,t={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:n,string:[/'(?:\\?[^\\])*?'/,{pattern:/"(?:\\?[^\\])*?"/,inside:{interpolation:t}}],keyword:/\b(and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:n,interpolation:t}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\?[\s\S])*?`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},rest:e.languages.javascript}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,alias:"string"},{pattern:/"""[\s\S]*?"""/,alias:"string",inside:{interpolation:t}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/})}(Prism); 8 | Prism.languages.css.selector={pattern:/[^\{\}\s][^\{\}]*(?=\s*\{)/,inside:{"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+(?:\(.*\))?/,"class":/\.[-:\.\w]+/,id:/#[-:\.\w]+/}},Prism.languages.insertBefore("css","function",{hexcode:/#[\da-f]{3,6}/i,entity:/\\[\da-f]{1,8}/i,number:/[\d%\.]+/}); 9 | Prism.languages.git={comment:/^#.*/m,deleted:/^[-–].*/m,inserted:/^\+.*/m,string:/("|')(\\?.)*?\1/m,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s(--|-)\w+/m}},coord:/^@@.*@@$/m,commit_sha1:/^commit \w{40}$/m}; 10 | !function(e){e.languages.jade={comment:{pattern:/(^([\t ]*))\/\/.*((?:\r?\n|\r)\2[\t ]+.+)*/m,lookbehind:!0},"multiline-script":{pattern:/(^([\t ]*)script\b.*\.[\t ]*)((?:\r?\n|\r(?!\n))(?:\2[\t ]+.+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0,inside:{rest:e.languages.javascript}},filter:{pattern:/(^([\t ]*)):.+((?:\r?\n|\r(?!\n))(?:\2[\t ]+.+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0,inside:{"filter-name":{pattern:/^:[\w-]+/,alias:"variable"}}},"multiline-plain-text":{pattern:/(^([\t ]*)[\w\-#.]+\.[\t ]*)((?:\r?\n|\r(?!\n))(?:\2[\t ]+.+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0},markup:{pattern:/(^[\t ]*)<.+/m,lookbehind:!0,inside:{rest:e.languages.markup}},doctype:{pattern:/((?:^|\n)[\t ]*)doctype(?: .+)?/,lookbehind:!0},"flow-control":{pattern:/(^[\t ]*)(?:if|unless|else|case|when|default|each|while)\b(?: .+)?/m,lookbehind:!0,inside:{each:{pattern:/^each .+? in\b/,inside:{keyword:/\b(?:each|in)\b/,punctuation:/,/}},branch:{pattern:/^(?:if|unless|else|case|when|default|while)\b/,alias:"keyword"},rest:e.languages.javascript}},keyword:{pattern:/(^[\t ]*)(?:block|extends|include|append|prepend)\b.+/m,lookbehind:!0},mixin:[{pattern:/(^[\t ]*)mixin .+/m,lookbehind:!0,inside:{keyword:/^mixin/,"function":/\w+(?=\s*\(|\s*$)/,punctuation:/[(),.]/}},{pattern:/(^[\t ]*)\+.+/m,lookbehind:!0,inside:{name:{pattern:/^\+\w+/,alias:"function"},rest:e.languages.javascript}}],script:{pattern:/(^[\t ]*script(?:(?:&[^(]+)?\([^)]+\))*[\t ]+).+/m,lookbehind:!0,inside:{rest:e.languages.javascript}},"plain-text":{pattern:/(^[\t ]*(?!-)[\w\-#.]*[\w\-](?:(?:&[^(]+)?\([^)]+\))*\/?[\t ]+).+/m,lookbehind:!0},tag:{pattern:/(^[\t ]*)(?!-)[\w\-#.]*[\w\-](?:(?:&[^(]+)?\([^)]+\))*\/?:?/m,lookbehind:!0,inside:{attributes:[{pattern:/&[^(]+\([^)]+\)/,inside:{rest:e.languages.javascript}},{pattern:/\([^)]+\)/,inside:{"attr-value":{pattern:/(=\s*)(?:\{[^}]*\}|[^,)\r\n]+)/,lookbehind:!0,inside:{rest:e.languages.javascript}},"attr-name":/[\w-]+(?=\s*!?=|\s*[,)])/,punctuation:/[!=(),]+/}}],punctuation:/:/}},code:[{pattern:/(^[\t ]*(?:-|!?=)).+/m,lookbehind:!0,inside:{rest:e.languages.javascript}}],punctuation:/[.\-!=|]+/};for(var t="(^([\\t ]*)):{{filter_name}}((?:\\r?\\n|\\r(?!\\n))(?:\\2[\\t ]+.+|\\s*?(?=\\r?\\n|\\r)))+",n=[{filter:"atpl",language:"twig"},{filter:"coffee",language:"coffeescript"},"ejs","handlebars","hogan","less","livescript","markdown","mustache","plates",{filter:"sass",language:"scss"},"stylus","swig"],a={},i=0,r=n.length;r>i;i++){var s=n[i];s="string"==typeof s?{filter:s,language:s}:s,e.languages[s.language]&&(a["filter-"+s.filter]={pattern:RegExp(t.replace("{{filter_name}}",s.filter),"m"),lookbehind:!0,inside:{"filter-name":{pattern:/^:[\w-]+/,alias:"variable"},rest:e.languages[s.language]}})}e.languages.insertBefore("jade","filter",a)}(Prism); 11 | !function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t]+.+)*/m,lookbehind:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,inside:{atrule:/(?:@[\w-]+|[+=])/m}}}),delete e.languages.sass.atrule;var a=/((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i,t=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|or|not)\b/,{pattern:/(\s+)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,inside:{punctuation:/:/,variable:a,operator:t}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s]+.*)/m,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:a,operator:t,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,delete e.languages.sass.selector,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/([ \t]*)\S(?:,?[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,?[^,\r\n]+)*)*/,lookbehind:!0}})}(Prism); 12 | Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\w\W]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-]+(?:\([^()]+\)|[^(])*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)*url(?=\()/i,selector:{pattern:/(?=\S)[^@;\{\}\(\)]?([^@;\{\}\(\)]|&|#\{\$[-_\w]+\})+(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/m,inside:{placeholder:/%[-_\w]+/}}}),Prism.languages.insertBefore("scss","atrule",{keyword:[/@(?:if|else(?: if)?|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)/i,{pattern:/( +)(?:from|through)(?= )/,lookbehind:!0}]}),Prism.languages.insertBefore("scss","property",{variable:/\$[-_\w]+|#\{\$[-_\w]+\}/}),Prism.languages.insertBefore("scss","function",{placeholder:{pattern:/%[-_\w]+/,alias:"selector"},statement:/\B!(?:default|optional)\b/i,"boolean":/\b(?:true|false)\b/,"null":/\bnull\b/,operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|or|not)(?=\s)/,lookbehind:!0}}),Prism.languages.scss.atrule.inside.rest=Prism.util.clone(Prism.languages.scss); 13 | !function(){if("undefined"!=typeof self&&self.Prism&&self.document){var e={css:"CSS",clike:"C-like",javascript:"JavaScript",abap:"ABAP",actionscript:"ActionScript",apacheconf:"Apache Configuration",apl:"APL",applescript:"AppleScript",asciidoc:"AsciiDoc",aspnet:"ASP.NET (C#)",autoit:"AutoIt",autohotkey:"AutoHotkey",basic:"BASIC",csharp:"C#",cpp:"C++",coffeescript:"CoffeeScript","css-extras":"CSS Extras",fsharp:"F#",glsl:"GLSL",http:"HTTP",inform7:"Inform 7",latex:"LaTeX",lolcode:"LOLCODE",matlab:"MATLAB",mel:"MEL",nasm:"NASM",nginx:"nginx",nsis:"NSIS",objectivec:"Objective-C",ocaml:"OCaml",parigp:"PARI/GP",php:"PHP","php-extras":"PHP Extras",powershell:"PowerShell",jsx:"React JSX",rest:"reST (reStructuredText)",sas:"SAS",sass:"Sass (Sass)",scss:"Sass (Scss)",sql:"SQL",typescript:"TypeScript",vhdl:"VHDL",vim:"vim",wiki:"Wiki markup",yaml:"YAML"};Prism.hooks.add("before-highlight",function(a){var s=a.element.parentNode;if(s&&/pre/i.test(s.nodeName)){var t=e[a.language]||a.language.substring(0,1).toUpperCase()+a.language.substring(1);s.setAttribute("data-language",t);var i,r,l=s.previousSibling;l&&/\s*\bprism-show-language\b\s*/.test(l.className)&&l.firstChild&&/\s*\bprism-show-language-label\b\s*/.test(l.firstChild.className)?(r=l.firstChild,r.getAttribute("data-language")!==t&&(r.setAttribute("data-language",t),r.innerHTML=t)):(i=document.createElement("div"),r=document.createElement("div"),r.className="prism-show-language-label",r.setAttribute("data-language",t),r.innerHTML=t,i.className="prism-show-language",i.appendChild(r),s.parentNode.insertBefore(i,s))}})}}(); 14 | !function(){"undefined"!=typeof self&&self.Prism&&self.document&&Prism.hooks.add("before-highlight",function(e){if(e.code){var s=e.element.parentNode,n=/\s*\bkeep-initial-line-feed\b\s*/;!s||"pre"!==s.nodeName.toLowerCase()||n.test(s.className)||n.test(e.element.className)||(e.code=e.code.replace(/^(?:\r?\n|\r)/,""))}})}(); 15 | -------------------------------------------------------------------------------- /template/static/vue-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monterail/vue-component-template/10a6c1bf1996c7248d997425a98c656f689940ec/template/static/vue-logo.png -------------------------------------------------------------------------------- /template/test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // the name of the method is the filename. 3 | // can be used in tests like this: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // for how to write custom assertions see 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | exports.assertion = function (selector, count) { 10 | this.message = 'Testing if element <' + selector + '> has count: ' + count{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 11 | this.expected = count{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 12 | this.pass = function (val) { 13 | return val === this.expected{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 14 | } 15 | this.value = function (res) { 16 | return res.value{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 17 | } 18 | this.command = function (cb) { 19 | var self = this{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 22 | }, [selector], function (res) { 23 | cb.call(self, res){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 24 | }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /template/test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/guide#settings-file 5 | module.exports = { 6 | "src_folders": ["test/e2e/specs"], 7 | "output_folder": "test/e2e/reports", 8 | "custom_assertions_path": ["test/e2e/custom-assertions"], 9 | 10 | "selenium": { 11 | "start_process": true, 12 | "server_path": "node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.1.jar", 13 | "host": "127.0.0.1", 14 | "port": 4444, 15 | "cli_args": { 16 | "webdriver.chrome.driver": require('chromedriver').path 17 | } 18 | }, 19 | 20 | "test_settings": { 21 | "default": { 22 | "selenium_port": 4444, 23 | "selenium_host": "localhost", 24 | "silent": true, 25 | "globals": { 26 | "devServerURL": "http://localhost:" + (process.env.PORT || config.dev.port) 27 | } 28 | }, 29 | 30 | "chrome": { 31 | "desiredCapabilities": { 32 | "browserName": "chrome", 33 | "javascriptEnabled": true, 34 | "acceptSslCerts": true 35 | } 36 | }, 37 | 38 | "firefox": { 39 | "desiredCapabilities": { 40 | "browserName": "firefox", 41 | "javascriptEnabled": true, 42 | "acceptSslCerts": true 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /template/test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing'{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 3 | var server = require('../../build/dev-server.js'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 4 | 5 | // 2. run the nightwatch test suite against it 6 | // to run in additional browsers: 7 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 8 | // 2. add it to the --env flag below 9 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 10 | // For more information on Nightwatch's config file, see 11 | // http://nightwatchjs.org/guide#settings-file 12 | var opts = process.argv.slice(2){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 13 | if (opts.indexOf('--config') === -1) { 14 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 15 | } 16 | if (opts.indexOf('--env') === -1) { 17 | opts = opts.concat(['--env', 'chrome']){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 18 | } 19 | 20 | var spawn = require('cross-spawn'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 21 | var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 22 | 23 | runner.on('exit', function (code) { 24 | server.close(){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 25 | process.exit(code){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 26 | }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 27 | 28 | runner.on('error', function (err) { 29 | server.close(){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 30 | throw err{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 31 | }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 32 | -------------------------------------------------------------------------------- /template/test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function {{#if_eq lintConfig "airbnb"}}test{{/if_eq}}(browser) { 6 | // automatically uses dev Server port from /config.index.js 7 | // default: http://localhost:8080 8 | // see nightwatch.conf.js 9 | const devServer = browser.globals.devServerURL{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 10 | 11 | browser 12 | .url(devServer) 13 | .waitForElementVisible('#app', 5000) 14 | .end(){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 15 | }{{#if_eq lintConfig "airbnb"}},{{/if_eq}} 16 | }{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 17 | -------------------------------------------------------------------------------- /template/test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /template/test/unit/index.js: -------------------------------------------------------------------------------- 1 | // Polyfill fn.bind() for PhantomJS 2 | /* eslint-disable no-extend-native */ 3 | Function.prototype.bind = require('function-bind'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 4 | 5 | // require all test files (files that ends with .spec.js) 6 | const testsContext = require.context('./specs', true, /\.spec$/){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 7 | testsContext.keys().forEach(testsContext){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 13 | srcContext.keys().forEach(srcContext){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 14 | -------------------------------------------------------------------------------- /template/test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var path = require('path'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 7 | var merge = require('webpack-merge'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 8 | var baseConfig = require('../../build/webpack.base.conf'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 9 | var utils = require('../../build/utils'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 10 | var webpack = require('webpack'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 11 | var projectRoot = path.resolve(__dirname, '../../'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 12 | 13 | var webpackConfig = merge(baseConfig, { 14 | // use inline sourcemap for karma-sourcemap-loader 15 | module: { 16 | loaders: utils.styleLoaders() 17 | }, 18 | devtool: '#inline-source-map', 19 | vue: { 20 | loaders: { 21 | js: 'isparta' 22 | } 23 | }, 24 | plugins: [ 25 | new webpack.DefinePlugin({ 26 | 'process.env': require('../../config/test.env') 27 | }) 28 | ] 29 | }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 30 | 31 | // no need for app entry during tests 32 | delete webpackConfig.entry{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 33 | 34 | // make sure isparta loader is applied before eslint 35 | webpackConfig.module.preLoaders = webpackConfig.module.preLoaders || []{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 36 | webpackConfig.module.preLoaders.unshift({ 37 | test: /\.js$/, 38 | loader: 'isparta', 39 | include: path.resolve(projectRoot, 'src'){{#if_eq lintConfig "airbnb"}},{{/if_eq}} 40 | }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 41 | 42 | // only apply babel for test files when using isparta 43 | webpackConfig.module.loaders.some(function (loader, i) { 44 | if (loader.loader === 'babel') { 45 | loader.include = path.resolve(projectRoot, 'test/unit'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 46 | return true{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 47 | } 48 | }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 49 | 50 | module.exports = function (config) { 51 | config.set({ 52 | // to run in additional browsers: 53 | // 1. install corresponding karma launcher 54 | // http://karma-runner.github.io/0.13/config/browsers.html 55 | // 2. add it to the `browsers` array below. 56 | browsers: ['PhantomJS'], 57 | frameworks: ['mocha', 'sinon-chai'], 58 | reporters: ['spec', 'coverage'], 59 | files: ['./index.js'], 60 | preprocessors: { 61 | './index.js': ['webpack', 'sourcemap'] 62 | }, 63 | webpack: webpackConfig, 64 | webpackMiddleware: { 65 | noInfo: true{{#if_eq lintConfig "airbnb"}},{{/if_eq}} 66 | }, 67 | coverageReporter: { 68 | dir: './coverage', 69 | reporters: [ 70 | { type: 'lcov', subdir: '.' }, 71 | { type: 'text-summary' }{{#if_eq lintConfig "airbnb"}},{{/if_eq}} 72 | ] 73 | }{{#if_eq lintConfig "airbnb"}},{{/if_eq}} 74 | }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 75 | }{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 76 | -------------------------------------------------------------------------------- /template/test/unit/specs/Hello.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 2 | import MyComponent from 'src/MyComponent'{{#if_eq lintConfig "airbnb"}};{{/if_eq}} 3 | 4 | describe('MyComponent.vue', () => { 5 | it('should have msg data set to Hi!', () => { 6 | const vm = new Vue({ 7 | el: document.createElement('div'), 8 | render: (h) => h(MyComponent){{#if_eq lintConfig "airbnb"}},{{/if_eq}} 9 | }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 10 | expect(vm.$children[0].msg) 11 | .to.equal('Hi!'){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 12 | }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 13 | }){{#if_eq lintConfig "airbnb"}};{{/if_eq}} 14 | --------------------------------------------------------------------------------