Commit 3be931bc authored by Radu Florin's avatar Radu Florin

First commit

parents
{
"presets": [
[
"env",
{
"modules": false
}
],
"stage-2"
],
"plugins": ["transform-runtime"],
"comments": false,
"env": {
"test": {
"plugins": [ "istanbul" ]
}
}
}
node_modules/
dist/
.git/
.dockerignore
.gitattributes
.gitignore
Dockerfile
README.md
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
build/*.js
config/*.js
// http://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
env: {
browser: true,
},
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: 'standard',
// required to lint *.vue files
plugins: [
'html'
],
// add your custom rules here
'rules': {
'comma-dangle': 'off',
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
'no-multiple-empty-lines': 0,
'no-mixed-operators': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
}
.DS_Store
node_modules/
dist/
npm-debug.log
package-lock.json
/yarn-error.log
.idea/
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
"plugins": {
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {}
}
}
FROM node:8
WORKDIR /app
COPY . /app
EXPOSE 8080
RUN npm install http-server -g
RUN npm install && npm run build
CMD http-server ./dist
MIT License
Copyright (c) 2017 Dream Support LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Vuestic Admin Dashboard
Responsive admin dashboard template built with [Vue.js](https://vuejs.org) and [Bootstrap 4](https://v4-alpha.getbootstrap.com). Developed by [Epicmax](http://epicmax.co). Designed by [Vasili Savitski](https://xxsavitski.myportfolio.com/)
<p align="center">
<a href="http://vuestic.epicmax.co" target="_blank">
<img src="http://i.imgur.com/pMuJVVc.png" align="center" width="888px"/>
</a>
</p>
## Demo
Check it out [live](http://vuestic.epicmax.co)!
## Prerequisites:
- [Node.js](https://nodejs.org/en/) (at least 4.x, 8.x recommended)
- npm version 3+ and [Git](https://git-scm.com/).
- [vuestic-installer](https://github.com/epicmaxco/vuestic-installer) `npm install vuestic-installer -g`.
## Browser Support
* Latest Chrome, Firefox, Safari, Edge, IE11+
## Installation
``` bash
# create new project via vuestic-installer command.
$ vuestic myproject
or
# clone the repo
$ git clone https://github.com/epicmaxco/vuestic-admin.git myproject
# go into app's directory and install dependencies:
$ cd myproject
$ npm install
# serve with hot reload at localhost:8080.
$ npm run dev
# build for production with minification
$ npm run build
# build for production and view the bundle analyzer report.
$ npm run build --report
```
## Documentation
Got stuck? Check out our [documentation](https://github.com/epicmaxco/vuestic-admin/wiki) 🤓
## Features
* Vue.js
* Bootstrap 4
* Webpack
* Responsive layout
* Charts (Chart.js)
* Maps (Google, Leaflet, amMap)
* Progress bars
* Material forms with beautiful validation
* 4 Form wizard types
* Static tables and datatables
* Login/signup pages templates
* Medium editor
* Toasts, tooltips, popovers,
* i18n
* and many more!
## How can I support developers?
- Star our GitHub repo :star:
- Create pull requests, submit bugs, suggest new features or documentation updates :wrench:
- Follow us on [Twitter](https://twitter.com/epicmaxco) :feet:
- Like our page on [Facebook](https://www.facebook.com/epicmaxco) :thumbsup:
## Can I hire you guys?
Yes! Visit [our homepage](http://epicmax.co/) or simply leave us a message to [hello@epicmax.co](mailto:hello@epicmax.co). We will be happy to work with you!
## License
[MIT](https://github.com/epicmaxco/vuestic-admin/blob/master/LICENSE) license.
'use strict'
require('./check-versions')()
process.env.NODE_ENV = 'production'
const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')
const spinner = ora('building for production...')
spinner.start()
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, function (err, stats) {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'))
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
))
})
})
'use strict'
const chalk = require('chalk')
const semver = require('semver')
const packageConfig = require('../package.json')
const shell = require('shelljs')
function exec (cmd) {
return require('child_process').execSync(cmd).toString().trim()
}
const versionRequirements = [
{
name: 'node',
currentVersion: semver.clean(process.version),
versionRequirement: packageConfig.engines.node
}
]
if (shell.which('npm')) {
versionRequirements.push({
name: 'npm',
currentVersion: exec('npm --version'),
versionRequirement: packageConfig.engines.npm
})
}
module.exports = function () {
const warnings = []
for (let i = 0; i < versionRequirements.length; i++) {
const mod = versionRequirements[i]
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
warnings.push(mod.name + ': ' +
chalk.red(mod.currentVersion) + ' should be ' +
chalk.green(mod.versionRequirement)
)
}
}
if (warnings.length) {
console.log('')
console.log(chalk.yellow('To use this template, you must update following to modules:'))
console.log()
for (let i = 0; i < warnings.length; i++) {
const warning = warnings[i]
console.log(' ' + warning)
}
console.log()
process.exit(1)
}
}
/* eslint-disable */
'use strict'
require('eventsource-polyfill')
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
hotClient.subscribe(function (event) {
if (event.action === 'reload') {
window.location.reload()
}
})
'use strict'
require('./check-versions')()
const config = require('../config')
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
}
const opn = require('opn')
const path = require('path')
const express = require('express')
const webpack = require('webpack')
const proxyMiddleware = require('http-proxy-middleware')
const webpackConfig = require('./webpack.dev.conf')
// default port where dev server listens for incoming traffic
const port = process.env.PORT || config.dev.port
// automatically open browser, if not set will be false
const autoOpenBrowser = !!config.dev.autoOpenBrowser
// Define HTTP proxies to your custom API backend
// https://github.com/chimurai/http-proxy-middleware
const proxyTable = config.dev.proxyTable
const app = express()
const compiler = webpack(webpackConfig)
const devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
quiet: true
})
const hotMiddleware = require('webpack-hot-middleware')(compiler, {
log: false,
heartbeat: 2000
})
// force page reload when html-webpack-plugin template changes
// currently disabled until this is resolved:
// https://github.com/jantimon/html-webpack-plugin/issues/680
// compiler.plugin('compilation', function (compilation) {
// compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
// hotMiddleware.publish({ action: 'reload' })
// cb()
// })
// })
// enable hot-reload and state-preserving
// compilation error display
app.use(hotMiddleware)
// load the favicon
app.use('/favicon.ico', express.static(__dirname + '/../favicon.ico'));
// proxy api requests
Object.keys(proxyTable).forEach(function (context) {
let options = proxyTable[context]
if (typeof options === 'string') {
options = { target: options }
}
app.use(proxyMiddleware(options.filter || context, options))
})
// handle fallback for HTML5 history API
app.use(require('connect-history-api-fallback')())
// serve webpack bundle output
app.use(devMiddleware)
// serve pure static assets
const staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
app.use(staticPath, express.static('./static'))
const uri = 'http://localhost:' + port
var _resolve
var _reject
var readyPromise = new Promise((resolve, reject) => {
_resolve = resolve
_reject = reject
})
var server
var portfinder = require('portfinder')
portfinder.basePort = port
console.log('> Starting dev server...')
devMiddleware.waitUntilValid(() => {
portfinder.getPort((err, port) => {
if (err) {
_reject(err)
}
process.env.PORT = port
var uri = 'http://localhost:' + port
console.log('> Listening at ' + uri + '\n')
// when env is testing, don't need open it
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
opn(uri)
}
server = app.listen(port)
_resolve()
})
})
module.exports = {
ready: readyPromise,
close: () => {
server.close()
}
}
'use strict'
const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
exports.assetsPath = function (_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory
return path.posix.join(assetsSubDirectory, _path)
}
exports.cssLoaders = function (options) {
options = options || {}
const cssLoader = {
loader: 'css-loader',
options: {
minimize: process.env.NODE_ENV === 'production',
sourceMap: options.sourceMap
}
}
// generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
const loaders = [cssLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
const output = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
}
return output
}
'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
module.exports = {
loaders: utils.cssLoaders({
sourceMap: isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap,
extract: isProduction
}),
transformToRequire: {
video: 'src',
source: 'src',
img: 'src',
image: 'xlink:href'
}
}
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'src': resolve('src'),
'assets': resolve('src/assets'),
'components': resolve('src/components'),
'services': resolve('src/services'),
'directives': resolve('src/directives'),
'vuestic-mixins': resolve('src/vuestic-theme/vuestic-mixins'),
'vuestic-components': resolve('src/vuestic-theme/vuestic-components'),
'vuestic-directives': resolve('src/vuestic-theme/vuestic-directives'),
'vuestic-theme': resolve('src/vuestic-theme'),
'data': resolve('src/data'),
'vuex-store': resolve('src/store')
}
},
module: {
rules: [
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter')
}
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
}
}
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})
module.exports = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
},
// cheap-module-eval-source-map is faster for development
devtool: '#cheap-module-eval-source-map',
plugins: [
new webpack.DefinePlugin({
'process.env': config.dev.env
}),
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
new FriendlyErrorsPlugin()
]
})
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const env = config.build.env
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true
})
},
devtool: config.build.productionSourceMap ? '#source-map' : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
// UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css')
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true
}
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
}),
// keep module.id stable when vender modules does not change
new webpack.HashedModuleIdsPlugin(),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
]),
// copy favicon
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../favicon.ico'),
to: config.build.assetsRoot
}
])
]
})
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240,
minRatio: 0.8
})
)
}
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
})
'use strict'
const path = require('path')
module.exports = {
build: {
env: require('./prod.env'),
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
productionSourceMap: true,
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
},
dev: {
env: require('./dev.env'),
port: process.env.PORT || 8080,
autoOpenBrowser: true,
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// CSS Sourcemaps off by default because relative paths are "buggy"
// with this option, according to the CSS-Loader README
// (https://github.com/webpack/css-loader#sourcemaps)
// In our experience, they generally work as expected,
// just be aware of this issue when enabling this option.
cssSourceMap: false
}
}
'use strict'
module.exports = {
NODE_ENV: '"production"'
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Vuestic Admin</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
{
"name": "vuestic-admin",
"version": "1.6.0",
"description": "Vue.js admin template",
"author": "smartapant <smartapant@gmail.com>",
"private": false,
"scripts": {
"dev": "node build/dev-server.js",
"build": "node build/build.js",
"lint": "eslint --ext .js,.vue src"
},
"repository": {
"type": "git",
"url": "https://github.com/epicmaxco/vuestic-admin.git"
},
"license": "MIT",
"dependencies": {
"amcharts3": "github:amcharts/amcharts3",
"ammap3": "github:amcharts/ammap3",
"awesome-bootstrap-checkbox": "1.0.0-alpha.5",
"axios": "^0.18.0",
"babel-polyfill": "^6.26.0",
"bootstrap": "^4.0.0",
"chart.js": "^2.6.0",
"detect-browser": "^1.7.1",
"element-resize-detector": "^1.1.12",
"epic-spinners": "^1.0.1",
"flag-icon-css": "^2.9.0",
"font-awesome": "^4.7.0",
"gemini-scrollbar": "^1.5.1",
"google-maps": "^3.3.0",
"ionicons": "^3.0.0",
"kewler": "^1.0.8",
"leaflet-map": "^0.2.1",
"medium-editor": "^5.23.3",
"normalize.css": "7.0.0",
"v-tooltip": "^2.0.0-rc.30",
"vee-validate": "2.0.0-rc.7",
"vue": "2.5.2",
"vue-axios": "^2.1.1",
"vue-bulma-expanding": "0.0.1",
"vue-chartjs": "^2.8.1",
"vue-router": "^3.0.1",
"vue-slider-component": "2.3.3",
"vue-toasted": "^1.1.24",
"vue-yandex-maps": "^0.7.9",
"vue2-circle-progress": "^1.0.3",
"vuetable-2": "1.7.5",
"vuex": "^3.0.1",
"vuex-i18n": "^1.7.0",
"vuex-router-sync": "5.0.0"
},
"devDependencies": {
"autoprefixer": "7.1.2",
"babel-core": "6.22.1",
"babel-eslint": "7.1.1",
"babel-loader": "7.1.1",
"babel-plugin-transform-runtime": "6.22.0",
"babel-preset-env": "1.6.1",
"babel-preset-es2015": "6.24.1",
"babel-preset-stage-2": "6.22.0",
"babel-register": "6.22.0",
"chalk": "2.3.0",
"connect-history-api-fallback": "1.3.0",
"copy-webpack-plugin": "4.0.1",
"css-loader": "0.28.0",
"es6-promise": "^4.2.4",
"eslint": "3.19.0",
"eslint-config-standard": "10.2.1",
"eslint-friendly-formatter": "3.0.0",
"eslint-loader": "1.7.1",
"eslint-plugin-html": "3.0.0",
"eslint-plugin-import": "2.7.0",
"eslint-plugin-node": "5.2.0",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "3.0.1",
"eventsource-polyfill": "0.9.6",
"express": "4.14.1",
"extract-text-webpack-plugin": "3.0.0",
"file-loader": "1.1.4",
"friendly-errors-webpack-plugin": "1.6.1",
"html-webpack-plugin": "2.30.1",
"http-proxy-middleware": "0.17.3",
"node-sass": "4.7.1",
"opn": "5.1.0",
"optimize-css-assets-webpack-plugin": "3.2.0",
"ora": "1.2.0",
"portfinder": "1.0.13",
"rimraf": "2.6.0",
"sass-loader": "6.0.6",
"semver": "5.3.0",
"shelljs": "0.7.6",
"url-loader": "0.5.8",
"vue-component-tree": "^2.2.1",
"vue-flatpickr-component": "^7.0.1",
"vue-loader": "13.3.0",
"vue-style-loader": "3.0.1",
"vue-template-compiler": "2.5.2",
"webpack": "3.6.0",
"webpack-bundle-analyzer": "2.9.0",
"webpack-dev-middleware": "1.12.0",
"webpack-hot-middleware": "2.18.2",
"webpack-merge": "4.1.0"
},
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
<template>
<div id="app" class="app">
<layout v-if="isAuth"/>
<auth-layout v-else></auth-layout>
</div>
</template>
<script>
import Layout from 'components/layout/Layout'
import AuthLayout from 'components/layout/AuthLayout'
import store from './store'
import VuesticPreLoader from 'vuestic-components/vuestic-preloader/VuesticPreLoader.vue'
export default {
name: 'app',
components: {
VuesticPreLoader,
AuthLayout,
Layout
},
store,
vuex: {
getters: {
auth: ({ auth }) => auth.auth,
route: ({ route }) => route
}
},
computed: {
isAuth () {
let stateItem = localStorage.getItem('access_token')
store.dispatch('LOGIN', { access_token: stateItem })
if (stateItem) {
this.$router.push('/')
} else {
this.$router.push('/auth/login')
}
return stateItem != null
}
}
}
</script>
<style lang="scss">
@import "sass/main";
body {
height: 100%;
#app {
height: 100%;
}
}
</style>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 20" style="enable-background:new 0 0 24 20;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
</style>
<path class="st0" d="M23,11h-6c-0.6,0-1-0.4-1-1c0-0.6,0.4-1,1-1h6c0.6,0,1,0.4,1,1C24,10.6,23.6,11,23,11z M23,2H1C0.4,2,0,1.6,0,1
c0-0.6,0.4-1,1-1h22c0.6,0,1,0.4,1,1C24,1.6,23.6,2,23,2z M1,9h6c0.6,0,1,0.4,1,1c0,0.6-0.4,1-1,1H1c-0.6,0-1-0.4-1-1
C0,9.4,0.4,9,1,9z M1,18h4c0.6,0,1,0.4,1,1s-0.4,1-1,1H1c-0.6,0-1-0.4-1-1S0.4,18,1,18z M9.8,15.3l1.2,1.2V10c0-0.6,0.4-1,1-1
c0.6,0,1,0.4,1,1v6.5l1.2-1.2c0.4-0.4,1.1-0.4,1.5,0c0.4,0.4,0.4,1.1,0,1.5l-2.9,2.9C12.6,19.9,12.3,20,12,20c0,0-0.1,0-0.1,0
c0,0,0,0,0,0c-0.2,0-0.5-0.1-0.7-0.3l-2.9-2.9c-0.4-0.4-0.4-1.1,0-1.5C8.7,14.9,9.4,14.9,9.8,15.3z M19,18h4c0.6,0,1,0.4,1,1
s-0.4,1-1,1h-4c-0.6,0-1-0.4-1-1S18.4,18,19,18z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 20" style="enable-background:new 0 0 24 20;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
</style>
<path class="st0" d="M23,11h-4c-0.6,0-1-0.4-1-1c0-0.6,0.4-1,1-1h4c0.6,0,1,0.4,1,1C24,10.6,23.6,11,23,11z M23,2H1C0.4,2,0,1.6,0,1
c0-0.6,0.4-1,1-1h22c0.6,0,1,0.4,1,1C24,1.6,23.6,2,23,2z M1,9h4c0.6,0,1,0.4,1,1c0,0.6-0.4,1-1,1H1c-0.6,0-1-0.4-1-1
C0,9.4,0.4,9,1,9z M1,18h6c0.6,0,1,0.4,1,1c0,0.6-0.4,1-1,1H1c-0.6,0-1-0.4-1-1C0,18.4,0.4,18,1,18z M11.3,9.3
C11.3,9.3,11.3,9.3,11.3,9.3C11.5,9.1,11.7,9,12,9c0.1,0,0.3,0,0.4,0.1c0.1,0,0.1,0,0.1,0.1c0,0,0,0,0.1,0c0.1,0,0.1,0.1,0.2,0.1
l2.9,2.9c0.4,0.4,0.4,1.1,0,1.5c-0.4,0.4-1.1,0.4-1.5,0L13,12.5V19c0,0.6-0.4,1-1,1c-0.6,0-1-0.4-1-1v-6.5l-1.2,1.2
c-0.4,0.4-1.1,0.4-1.5,0c-0.4-0.4-0.4-1.1,0-1.5L11.3,9.3z M17,18h6c0.6,0,1,0.4,1,1c0,0.6-0.4,1-1,1h-6c-0.6,0-1-0.4-1-1
C16,18.4,16.4,18,17,18z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56.02 50.34"><defs><style>.cls-1{fill:#4ae387;}.cls-2{fill:#34495e;}</style></defs><title>overview_icon_4</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M38.23,16.17a10,10,0,1,0-17.67,6.42V47.5l7.33-5,8,5V22.58A10,10,0,0,0,38.23,16.17Z"/><path class="cls-2" d="M28.23,0a13.15,13.15,0,0,0-9.17,22.6V50.34l8.87-6,9.46,5.92V22.6A13.15,13.15,0,0,0,28.23,0ZM34.4,44.79l-6.54-4.08-5.8,4V24.79a13.11,13.11,0,0,0,12.33,0ZM28.23,23.33A10.17,10.17,0,1,1,38.4,13.17,10.18,10.18,0,0,1,28.23,23.33Z"/><path class="cls-2" d="M28.23,5.67a7.5,7.5,0,1,0,7.5,7.5A7.51,7.51,0,0,0,28.23,5.67Zm0,12a4.5,4.5,0,1,1,4.5-4.5A4.5,4.5,0,0,1,28.23,17.67Z"/><polygon class="cls-2" points="9.51 15.11 0 24.61 9.51 34.12 11.63 32 4.24 24.61 11.63 17.23 9.51 15.11"/><polygon class="cls-2" points="46.52 15.11 44.39 17.23 51.78 24.61 44.39 32 46.52 34.12 56.02 24.61 46.52 15.11"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 44.99 51.04"><defs><style>.cls-1{fill:#4ae387;}.cls-2{fill:none;stroke:#34495e;stroke-miterlimit:10;stroke-width:3px;}.cls-3{fill:#34495e;}</style></defs><title>overview_icon_2</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M1.08,28.21C1.08,13.62,8.38,6.29,19,6.29S37,13.69,37,28.21,29.66,50.54,19,50.54,1.08,42.8,1.08,28.21Zm23.56,0c0-11.3-2.58-16.9-5.62-16.9s-5.62,5.6-5.62,16.9S16,41.66,19,41.66,24.65,39.51,24.65,28.21Z"/><line class="cls-2" x1="39.83" y1="47.62" x2="39.83" y2="50.96"/><path class="cls-3" d="M18.73,9.64c-4.9,0-6.9,4.54-6.9,15.66,0,11.29,2.06,16.1,6.9,16.1s6.9-4.81,6.9-16.1C25.63,14.17,23.63,9.64,18.73,9.64Zm0,28.76c-1.07,0-3.9,0-3.9-13.1,0-12.66,2.64-12.66,3.9-12.66s3.9,0,3.9,12.66C22.63,38.4,19.8,38.4,18.73,38.4Z"/><path class="cls-3" d="M42.9,43.74A3.76,3.76,0,0,1,40.17,45c-1.95,0-3.24-1.57-3.24-4.4s1.53-4.35,3.29-4.35a3.67,3.67,0,0,1,2.5,1.11l2.08-2.55A6.8,6.8,0,0,0,41.33,33V31h-3v2.12a7.09,7.09,0,0,0-1.64.63,43.71,43.71,0,0,0,.77-8.41c0-15.84-7-25.3-18.73-25.3S0,9.46,0,25.3,7.18,51,18.73,51A16.4,16.4,0,0,0,33.12,43.1,6.77,6.77,0,0,0,40,48.46a6.35,6.35,0,0,0,5-2.22ZM18.73,48C8.88,48,3,39.54,3,25.3S8.73,3,18.73,3s15.73,8.13,15.73,22.3S28.58,48,18.73,48Z"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50.98 47.66"><defs><style>.cls-1{fill:#4ae387;}.cls-2{fill:#34495e;}</style></defs><title>overview_icon_5</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M6,19C11,12.66,26.33,3,46.33,6c-3.67,17-8.67,26-8.67,26s-7,14-19.67-3.67C5.67,26.33,9,22.33,6,19Z"/><path class="cls-2" d="M48.33.49l-.77,0c-11.22-1.88-30.21,1.46-39,9-3.38,2.89-5,6.11-4.69,9.59a11.06,11.06,0,0,0,4.77,8,11,11,0,0,0,6.24,1.82q.53,0,1.09,0A55.51,55.51,0,0,0,13.2,39.21C9.48,33.07,2.35,30.83,0,30.83v3c.12,0,12.18,1.95,12.5,13.54h0c0,.1,0,.19,0,.29h3a50.57,50.57,0,0,1,3.12-17.21c2.48,5.09,6.36,8,10.91,8.13,5.3.07,10.1-3.85,11.91-9.81.94-3.12,1.88-6.37,2.78-9.51C46.32,11.9,48.31,5,49.62,2.76L51,.49ZM10.28,24.61a8.06,8.06,0,0,1-3.45-5.73c-.19-2.47,1-4.85,3.65-7.08,5.9-5,17.25-8.12,27-8.7-8.35,4-15.7,12.31-20.23,22.51l-.38.1h0A8.82,8.82,0,0,1,10.28,24.61Zm31-6.18c-.9,3.13-1.82,6.37-2.76,9.47-1.4,4.62-4.95,7.69-8.86,7.69h-.13c-4-.07-7.45-3.43-9.33-9.09C25.83,14.27,35.67,4.94,45.92,3.65,44.6,7,43.06,12.39,41.33,18.42Z"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 47.5 49"><defs><style>.cls-1{fill:#4ae387;}.cls-2{fill:#34495e;}</style></defs><title>overview_icon_3</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><polygon class="cls-1" points="37 26 37 7 11 7 11 18 3 18 3 46 11 46 15 46 30 46 37 46 45 46 45 26 37 26"/><path class="cls-2" d="M40,19V0H8V11H0V49H47.5V19ZM3,46V14H8V46Zm34,0H11V3H37Zm7.5,0H40V22h4.5Z"/><circle class="cls-2" cx="24" cy="41" r="2.67"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56.99 55"><defs><style>.cls-1{fill:#4ae387;}.cls-2{fill:#34495e;}</style></defs><title>overview_icon_6</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><rect class="cls-1" x="10.31" y="30.5" width="37.33" height="23"/><path class="cls-2" d="M57,41.18l-7.85-16V24H8.81v1.11L0,41.11l2.63,1.45L8.81,31.33V55H49.15V32L54.3,42.5ZM46.15,52H11.81V27H46.15Z"/><polygon class="cls-2" points="35.3 1.8 32.9 0 28.12 6.39 26.16 4.63 24.16 6.87 28.56 10.8 35.3 1.8"/><polygon class="cls-2" points="22.3 12.46 19.9 10.67 15.12 17.05 13.16 15.3 11.16 17.54 15.56 21.47 22.3 12.46"/><polygon class="cls-2" points="38.89 21.14 45.64 12.13 43.23 10.33 38.45 16.72 36.49 14.97 34.49 17.2 38.89 21.14"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 55.05 47.8"><defs><style>.cls-1{fill:#4ae387;}.cls-2{fill:#34495e;}</style></defs><title>overview_icon_1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><polygon class="cls-1" points="27.75 21.19 18.48 6.18 4.78 6.18 27.75 42.92 50.89 6.18 36.13 6.18 27.75 21.19"/><path class="cls-2" d="M33.08,0,27.44,9.76,21.84,0H0L27.43,47.8,55,0ZM27.43,15.77,34.81,3h4.6l-12,20.72L15.55,3h4.55ZM5.18,3h6.91L27.43,29.73,42.88,3h7L27.44,41.78Z"/></g></g></svg>
\ No newline at end of file
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 129 15.4" style="enable-background:new 0 0 129 15.4;" xml:space="preserve">
<style type="text/css">
.st0{fill:#4AE387;}
</style>
<g>
<path class="st0" d="M0,0.5h3.7l2.9,6.9l2.9-6.9h3.7L6.8,15.4H6.4L0,0.5z"/>
<path class="st0" d="M22.2,0.5h3.5v9c0,1.9,0.9,2.6,2.1,2.6c1.3,0,2.2-0.7,2.2-2.6v-9h3.5V10c0,3.4-2.5,5.3-5.7,5.3
c-3.3,0-5.6-2-5.6-5.3V0.5z"/>
<path class="st0" d="M43.9,0.5h9.5v3.1h-6v2.6H53v3.1h-5.5v2.6h6.3v3h-9.8V0.5z"/>
<path class="st0" d="M66.7,10.7c0,0.8,0.7,1.5,1.5,1.5c0.9,0,1.4-0.5,1.4-1.2c0-1.1-1.4-1.4-2.6-1.8c-2.4-0.9-3.8-2-3.8-4.5
c0-2.5,2.2-4.7,4.9-4.7c3.2,0,4.7,2,4.9,4.7h-3.3c0-0.8-0.5-1.5-1.5-1.5c-0.8,0-1.5,0.5-1.5,1.4c0,1.1,1.3,1.3,2.5,1.6
C71.8,7,73,8.4,73,10.7c0,2.5-2.2,4.7-4.9,4.7c-3.1,0-4.9-2.1-4.9-4.7H66.7z"/>
<path class="st0" d="M85.4,3.6h-3.2V0.5h10v3.1H89v11.3h-3.6V3.6z"/>
<path class="st0" d="M101.5,0.5h3.5v14.4h-3.5V0.5z"/>
<path class="st0" d="M122.8,0c2.7,0,4.6,1,6.2,2.6l-2.4,2.3c-1-1-2.3-1.6-3.7-1.6c-2.6,0-4.2,1.9-4.2,4.3s1.7,4.3,4.2,4.3
c1.4,0,2.7-0.6,3.7-1.6l2.4,2.3c-1.4,1.5-3.4,2.6-6.1,2.6c-4.6,0-7.8-3.4-7.8-7.7S118.2,0,122.8,0z"/>
</g>
</svg>
import axios from 'axios'
const API_URL = process.env.API_URL || 'http://localhost:3000/api/v1'
export default axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.token
}
})
import Vue from 'vue'
import VueAxios from 'vue-axios'
import axios from './axios'
Vue.use(VueAxios, axios)
<template>
<div class="login">
<form id="loginForm">
<h2>{{'auth.welcome' | translate}}</h2>
<div class="form-group">
<div class="input-group">
<input type="text" id="email" required="required" v-model="email" />
<label class="control-label" for="email">{{'auth.email' | translate}}</label><i class="bar"></i>
</div>
</div>
<div class="form-group">
<div class="input-group">
<input type="password" id="password" required="required" v-model="password" />
<label class="control-label" for="password">{{'auth.password' | translate}}</label><i class="bar"></i>
</div>
</div>
<div class="d-flex flex-column flex-lg-row align-items-center justify-content-between down-container">
<button class="btn btn-primary" type="submit" v-on:click="showAlert(email, password)">
{{'auth.login' | translate}}
</button>
</div>
</form>
</div>
</template>
<script>
import store from '@/store'
import router from '@/router'
let authService = require('@/services/auth')
export default {
name: 'login',
store,
router,
vuex: {
getters: {
auth: ({ auth }) => auth.auth,
route: ({ route }) => route
}
},
data () {
return {
email: '',
password: ''
}
},
methods: {
showAlert: (email, password) => {
if (email && password) {
authService.default.requestToken(email, password, store, router)
}
}
}
}
</script>
<style lang="scss">
@import '../../../sass/variables';
@import '~bootstrap/scss/mixins/breakpoints';
@import "~bootstrap/scss/functions";
@import '~bootstrap/scss/variables';
.login {
@include media-breakpoint-down(md) {
width: 100%;
padding-right: 2rem;
padding-left: 2rem;
.down-container {
.link {
margin-top: 2relogim;
}
}
}
h2 {
text-align: center;
}
width: 21.375rem;
.down-container {
margin-top: 3.125rem;
}
}
</style>
<template>
<div class="signup">
<h2>{{'auth.createNewAccount' | translate}}</h2>
<form method="post" action="/auth/signup" name="signup">
<div class="form-group">
<div class="input-group">
<input type="text" id="email" required="required"/>
<label class="control-label" for="email">{{'auth.email' | translate}}</label><i class="bar"></i>
</div>
</div>
<div class="form-group">
<div class="input-group">
<input type="password" id="password" required="required"/>
<label class="control-label" for="password">{{'auth.password' | translate}}</label><i class="bar"></i>
</div>
</div>
<vuestic-checkbox
:id="'checkbox1'"
v-model="checkboxOneModel">
<template slot="label">{{'auth.agree' | translate}}
<router-link to="">{{'auth.termsOfUse' | translate}}</router-link>
</template>
</vuestic-checkbox>
<div class="d-flex flex-column flex-lg-row align-items-center justify-content-between down-container">
<button class="btn btn-primary" type="submit">
{{'auth.signUp' | translate}}
</button>
<router-link class='link' :to="{name: 'Login'}">{{'auth.alreadyJoined' | translate}}</router-link>
</div>
</form>
</div>
</template>
<script>
export default {
name: 'signup',
data () {
return {
checkboxOneModel: true
}
}
}
</script>
<style lang="scss">
@import '../../../sass/variables';
@import '~bootstrap/scss/mixins/breakpoints';
@import "~bootstrap/scss/functions";
@import '~bootstrap/scss/variables';
.signup {
@include media-breakpoint-down(md) {
width: 100%;
padding-right: 2rem;
padding-left: 2rem;
.down-container {
.link {
margin-top: 2rem;
}
}
}
h2 {
text-align: center;
}
width: 21.375rem;
.down-container {
margin-top: 2.6875rem;
}
}
</style>
<template>
<div class="dashboard">
<dashboard-info-widgets></dashboard-info-widgets>
<vuestic-widget class="no-padding no-v-padding">
<vuestic-tabs
:names="[$t('dashboard.dataVisualization'), $t('dashboard.usersAndMembers'), $t('dashboard.setupProfile'), $t('dashboard.features')]"
ref="tabs">
<div :slot="$t('dashboard.dataVisualization')">
<data-visualisation-tab></data-visualisation-tab>
</div>
<div :slot="$t('dashboard.usersAndMembers')">
<users-members-tab></users-members-tab>
</div>
<div :slot="$t('dashboard.setupProfile')">
<setup-profile-tab></setup-profile-tab>
</div>
<div :slot="$t('dashboard.features')">
<features-tab></features-tab>
</div>
</vuestic-tabs>
</vuestic-widget>
<dashboard-bottom-widgets></dashboard-bottom-widgets>
</div>
</template>
<script>
import DashboardInfoWidgets from './DashboardInfoWidgets'
import UsersMembersTab from './users-and-members-tab/UsersMembersTab.vue'
import SetupProfileTab from './setup-profile-tab/SetupProfileTab.vue'
import FeaturesTab from './features-tab/FeaturesTab.vue'
import DataVisualisationTab from './data-visualisation-tab/DataVisualisation.vue'
import DashboardBottomWidgets from './DashboardBottomWidgets.vue'
export default {
name: 'dashboard',
components: {
DataVisualisationTab,
DashboardInfoWidgets,
UsersMembersTab,
SetupProfileTab,
FeaturesTab,
DashboardBottomWidgets
},
methods: {
launchEpicmaxToast () {
this.showToast(`Let's work together!`, {
icon: 'fa-star-o',
position: 'top-right',
duration: Infinity,
action: {
text: 'Hire us',
href: 'http://epicmax.co/#/contact',
class: 'vuestic-toasted-link'
}
})
}
}
}
</script>
<style lang="scss" scoped>
@import "../../sass/_variables.scss";
</style>
<template>
<div class="row bottom-widgets">
<div class="col-md-6 d-flex">
<vuestic-widget class="no-h-padding no-v-padding">
<vuestic-feed :initialPosts="posts"></vuestic-feed>
</vuestic-widget>
</div>
<div class="col-md-6 d-flex">
<vuestic-widget class="business-posts">
<vuestic-social-news class="vuestic-social-news" :news="news" :url="'http://instagram.com/smartapant'"></vuestic-social-news>
</vuestic-widget>
</div>
</div>
</template>
<script>
export default {
name: 'dashboard-bottom-widgets',
data () {
return {
posts: [
{
name: 'Irina Myatelskaya',
text: 'joined the network',
photoURL: 'http://i.imgur.com/VuTDC8u.png'
},
{
name: 'Andrei Hrabouski',
text: 'has just started a live video',
photoURL: 'http://i.imgur.com/W3mGrmW.png'
},
{
name: 'Evan You',
text: 'joined the network',
photoURL: 'http://i.imgur.com/D7DOGBH.jpg'
}
],
news: [
{
photoURL: 'http://i.imgur.com/PiTDDcA.png'
},
{
photoURL: 'http://i.imgur.com/M6GugaM.png'
},
{
photoURL: 'http://i.imgur.com/vEy3fRU.png'
},
{
photoURL: 'http://i.imgur.com/Xrywphx.png'
},
{
photoURL: 'http://i.imgur.com/dqVtQGY.png'
},
{
photoURL: 'http://i.imgur.com/qP7rTCy.png'
},
{
photoURL: 'http://i.imgur.com/6YLsM43.png'
},
{
photoURL: 'http://i.imgur.com/9PAOx55.png'
},
{
photoURL: 'http://i.imgur.com/mVpc04D.png'
},
{
photoURL: 'http://i.imgur.com/WdbTSLn.png'
},
{
photoURL: 'http://i.imgur.com/ZXRIHfk.png'
}
]
}
}
}
</script>
<style lang="scss" scoped>
.bottom-widgets {
> div[class^='col'] {
& > div {
width: 100%;
}
}
}
</style>
<template>
<div class="row dashboard-info-widgets">
<div class="col-md-6 col-xl-3">
<vuestic-widget class="info-widget">
<div class="info-widget-inner">
<div class="stats">
<div class="stats-number">
<i class="ion ion-md-arrow-up text-primary stats-icon"></i>
59
</div>
<div class="stats-title">{{'dashboard.elements' | translate}}</div>
</div>
</div>
</vuestic-widget>
</div>
<div class="col-md-6 col-xl-3">
<vuestic-widget class="info-widget">
<div class="info-widget-inner">
<div class="stats">
<div class="stats-number">
<i class="ion ion-md-arrow-down text-danger stats-icon"></i>
12
</div>
<div class="stats-title">{{'dashboard.versions' | translate}}</div>
</div>
</div>
</vuestic-widget>
</div>
<div class="col-md-6 col-xl-3">
<vuestic-widget class="info-widget brand-danger">
<div class="info-widget-inner">
<div class="info-widget-inner has-chart">
<div class="stats">
<div class="stats-number">
425
</div>
<div class="stats-title">Commits</div>
</div>
<div class="chart-container">
<vuestic-progress-bar type="circle" ref="circleProgress" :colorName="'white'" :backgroundColorName="'danger'"
:startColorName="'danger'"></vuestic-progress-bar>
</div>
</div>
</div>
</vuestic-widget>
</div>
<div class="col-md-6 col-xl-3">
<vuestic-widget class="info-widget brand-info">
<div class="info-widget-inner">
<div class="stats">
<div class="stats-number">
<i class="ion ion-md-people stats-icon icon-wide"></i>
5
</div>
<div class="stats-title">{{'dashboard.teamMembers' | translate}}</div>
</div>
</div>
</vuestic-widget>
</div>
</div>
</template>
<script>
export default {
name: 'dashboard-info-widgets',
mounted () {
this.$refs.circleProgress.$data.value = 70
}
}
</script>
<style lang="scss" scoped>
@import "../../sass/_variables.scss";
.stats-number, .stats-title {
line-height: 1;
}
.info-widget-inner {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
position: relative;
width: 100%;
&.has-chart {
justify-content: space-between;
}
.stats {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
}
}
.stats-number {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
font-size: 2.625rem;
margin-bottom: 0.5rem;
.stats-icon {
font-size: 1.5625rem;
position: absolute;
top: 0.625rem;
left: -1.25rem;
&.icon-wide {
left: -1.875rem;
}
}
}
</style>
<template>
<div class="data-visualisation-tab dashboard-tab">
<div class="row">
<div class="col-md-6">
<div class="chart-container">
<vuestic-chart v-bind:data="donutChartData" type="donut"></vuestic-chart>
</div>
</div>
<div class="col-md-6">
<vuestic-data-table
:apiMode="apiMode"
:tableData="tableData"
:tableFields="tableFields"
:itemsPerPage="itemsPerPage"
:onEachSide="onEachSide"
:sortFunctions="sortFunctions"
:dataModeFilterableFields="dataModeFilterableFields"
/>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import BadgeColumn from 'components/tables/BadgeColumn.vue'
import TableData from './TableData'
import DonutChartData from './DonutChartData'
import FieldsDef from './fields-definition'
Vue.component('badge-column', BadgeColumn)
export default {
name: 'data-visualisation-tab',
data () {
return {
donutChartData: DonutChartData,
apiMode: false,
sortFunctions: FieldsDef.sortFunctions,
tableData: TableData,
onEachSide: 1,
tableFields: FieldsDef.tableFields,
dataModeFilterableFields: ['name'],
itemsPerPage: [
{
value: 5
},
{
value: 6
}
],
}
}
}
</script>
<style lang="scss" scoped>
@import "../../../sass/_variables.scss";
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins/breakpoints";
.chart-container {
padding: 0 2rem;
height: 24rem;
}
</style>
import store from 'vuex-store'
let palette = store.getters.palette
export default {
labels: ['North America', 'South America', 'Australia'],
datasets: [{
label: 'Population (millions)',
backgroundColor: [palette.info, palette.warning, palette.primary],
data: [3000, 6000, 1500]
}]
}
This diff is collapsed.
export default {
tableFields: [
{
name: '__component:badge-column',
title: '',
dataClass: 'text-center'
},
{
name: 'name',
title: 'user',
sortField: 'name'
},
{
name: 'salary',
title: 'score'
}
],
sortFunctions: {
'name': function (item1, item2) {
return item1 >= item2 ? 1 : -1
}
}
}
<template>
<div class="overview-tab dashboard-tab">
<div class="d-flex overview-row flex-row w-100 justify-content-sm-around justify-content-xs-start">
<div class="overview-col">
<div class="overview-item">
<div class="overview-icon-container">
<i class="i-vuestic-vue"></i>
</div>
Built with Vue.js framework
</div>
<div class="overview-item">
<div class="overview-icon-container">
<i class="i-vuestic-free"></i>
</div>
Absolutely free for everyone
</div>
<div class="overview-item">
<div class="overview-icon-container">
<i class="i-vuestic-fresh"></i>
</div>
Fresh and crisp design
</div>
</div>
<div class="overview-col">
<div class="overview-item">
<div class="overview-icon-container">
<i class="i-vuestic-responsive"></i>
</div>
Responsive and optimized for mobile
</div>
<div class="overview-item">
<div class="overview-icon-container">
<i class="i-vuestic-rich"></i>
</div>
Tons of useful components
</div>
<div class="overview-item">
<div class="overview-icon-container">
<i class="i-vuestic-clean-code"></i>
</div>
Completely jQuery free
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'features-tab'
}
</script>
<style lang="scss" scoped>
@import "../../../sass/_variables.scss";
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins/breakpoints";
.overview-item {
display: flex;
align-items: center;
height: 55px;
margin-bottom: 3rem;
padding-right: 1rem;
font-size: 1.25rem;
font-weight: bold;
.overview-icon-container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
min-width: 85px;
max-width: 85px;
height: 100%;
}
}
.overview-row {
@include media-breakpoint-down(xs) {
flex-wrap: wrap;
}
}
.overview-col:first-child {
margin-left: 2rem;
@include media-breakpoint-down(md) {
margin-left: 0;
}
}
.explore-btn {
margin-top: 6rem;
margin-bottom: 1rem;
}
</style>
<template>
<div class="setup-profile-tab dashboard-tab">
<vuestic-wizard
:steps="steps"
wizard-layout="vertical"
:wizard-type="wizardType">
<div slot="page1" class="form-wizard-tab-content">
<h4>Type your name</h4>
<p>Zebras communicate with facial expressions and sounds. They make loud braying or barking sounds and
soft snorting sounds. The position of their ears, how wide open their eyes are, and whether they show
their teeth all send a signal. For example, ears flat back means trouble, or "you better follow orders!"</p>
<div class="form-group with-icon-right" :class="{'has-error': errors.has('name'), 'valid': isFormFieldValid('name')}">
<div class="input-group">
<input
type="text"
name="name"
v-model="name"
v-validate="'required'"
required="required"/>
<i class="fa fa-exclamation-triangle error-icon icon-right input-icon"></i>
<i class="fa fa-check valid-icon icon-right input-icon"></i>
<label class="control-label">Name</label><i class="bar"></i>
<small v-show="errors.has('name')" class="help text-danger">{{ errors.first('name') }}</small>
</div>
</div>
</div>
<div slot="page2" class="form-wizard-tab-content">
<h4>Select your country</h4>
<p>Zebras communicate with facial expressions and sounds. They make loud braying or barking sounds and
soft snorting sounds. The position of their ears, how wide open their eyes are, and whether they show
their teeth all send a signal. For example, ears flat back means trouble, or "you better follow orders!"</p>
<vuestic-simple-select
label="Select country"
v-model="selectedCountry"
name="country"
:required="true"
ref="selectedCountrySelect"
v-bind:options="countriesList">
</vuestic-simple-select>
</div>
<div slot="page3" class="form-wizard-tab-content">
<h4>Confirm selection</h4>
<p>
Zebras communicate with facial expressions and sounds. They make loud braying or barking sounds and
soft snorting sounds. The position of their ears, how wide open their eyes are, and whether they show
their teeth all send a signal. For example, ears flat back means trouble, or "you better follow orders!"
</p>
</div>
<div slot="wizardCompleted" class="form-wizard-tab-content wizard-completed-tab">
<h4>Wizard completed!</h4>
<p>
Zebras communicate with facial expressions and sounds. They make loud braying or barking sounds and
soft snorting sounds. The position of their ears, how wide open their eyes are, and whether they show
their teeth all send a signal. For example, ears flat back means trouble, or "you better follow orders!"
</p>
</div>
</vuestic-wizard>
</div>
</template>
<script>
import CountriesList from 'data/CountriesList'
export default {
name: 'setup-profile-tab',
props: {
wizardType: {
default: 'rich'
}
},
data () {
return {
steps: [
{
label: 'Step 1. Name',
slot: 'page1',
onNext: () => {
this.validateFormField('name')
},
isValid: () => {
return this.isFormFieldValid('name')
}
},
{
label: 'Step 2. Country',
slot: 'page2',
onNext: () => {
this.$refs.selectedCountrySelect.validate()
},
isValid: () => {
return this.$refs.selectedCountrySelect.isValid()
}
},
{
label: 'Step 3. Confirm',
slot: 'page3'
}
],
name: '',
selectedCountry: '',
countriesList: CountriesList
}
},
methods: {
isFormFieldValid (field) {
let isValid = false
if (this.formFields[field]) {
isValid = this.formFields[field].validated && this.formFields[field].valid
}
return isValid
},
validateFormField (fieldName) {
this.$validator.validate(fieldName, this[fieldName])
}
}
}
</script>
<style lang="scss" scoped>
@import "../../../sass/_variables.scss";
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins/breakpoints";
.form-group {
min-width: 200px;
max-width: 360px;
width: 80%;
}
.wizard-completed-tab {
@include media-breakpoint-up(md) {
margin-top: -$tab-content-pt;
}
}
</style>
<template>
<div class="users-members-tab dashboard-tab">
<div class="row">
<div class="col-md-3 d-flex justify-content-center align-items-center">
<vuestic-profile-card :name="'Veronique Lee'" :location="'Malaga, Spain'" photoSource="http://i.imgur.com/NLrdqsk.png"
:social="{twitter: 'twitter.com', facebook: 'facebook.com',
instagram: 'instagram.com'}">
</vuestic-profile-card>
</div>
<div class="col-md-9 d-flex">
<vuestic-chat v-model="chatMessages"></vuestic-chat>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'users-members-tab',
data () {
return {
chatMessages: [
{
text: 'Hello! So glad you liked my work. Do you want me to shoot you?',
yours: false
},
{
text: 'Yeah, that would be cool. Maybe this Sunday at 3 pm?',
yours: true
},
{
text: 'Sounds great! See you later!',
yours: false
},
{
text: 'Should I bring a lightbox with me?',
yours: true
},
{
text: 'No, thanks. There is no need. Can we set up a meeting earlier?',
yours: false
},
{
text: 'I\'m working on Vuestic, so let\'s meet at 3pm. Thanks!',
yours: true
}
]
}
}
}
</script>
<style lang="scss" scoped>
@import "../../../sass/_variables.scss";
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins/breakpoints";
.vuestic-profile-card {
margin-left: 1rem;
@include media-breakpoint-up(md) {
margin-top: -$tab-content-pt;
}
@include media-breakpoint-down(md) {
margin-bottom: $tab-content-pt;
margin-left: 0;
}
}
</style>
<template>
<div class="extra">
<vuestic-widget :headerText="'extra.tabs.title' | translate" class="no-v-padding">
<vuestic-tabs class="tabs" :names="[$t('extra.tabs.maps'), $t('extra.tabs.setupProfile'), $t('extra.tabs.overview')]">
<div :slot="'extra.tabs.overview' | translate" class="d-flex justify-content-center">
<overview-tab></overview-tab>
</div>
<div :slot="'extra.tabs.maps' | translate" class="maps-tab">
<leaflet-map></leaflet-map>
</div>
<div :slot="'extra.tabs.setupProfile' | translate" class="d-flex justify-content-center">
<setup-profile-tab wizardType="simple"></setup-profile-tab>
</div>
</vuestic-tabs>
</vuestic-widget>
<div class="row">
<div class="col-md-4 d-flex">
<vuestic-widget :headerText="$t('extra.profileCard')" class="profile-card-widget">
<vuestic-profile-card :name="'Veronique Lee'" :location="'Malaga, Spain'" photoSource="http://i.imgur.com/NLrdqsk.png"
:social="{twitter: 'twitter.com', facebook: 'facebook.com',
instagram: 'instagram.com'}">
</vuestic-profile-card>
</vuestic-widget>
</div>
<div class="col-md-8 d-flex">
<vuestic-widget :headerText="$t('extra.chat')" class="chat-widget">
<vuestic-chat v-model="chatMessages"></vuestic-chat>
</vuestic-widget>
</div>
</div>
<div class="row bottom-widgets">
<div class="col-md-6 d-flex">
<vuestic-widget class="no-h-padding no-v-padding">
<vuestic-feed :initialPosts="posts"></vuestic-feed>
</vuestic-widget>
</div>
<div class="col-md-6 d-flex">
<vuestic-widget class="business-posts">
<vuestic-social-news :news="news" :url="'http://instagram.com/smartapant'"></vuestic-social-news>
</vuestic-widget>
</div>
</div>
</div>
</template>
<script>
import OverviewTab from 'components/dashboard/features-tab/FeaturesTab.vue'
import SetupProfileTab from 'components/dashboard/setup-profile-tab/SetupProfileTab.vue'
import LeafletMap from 'components/maps/leaflet-maps/LeafletMap.vue'
export default {
name: 'extra',
components: {
LeafletMap,
SetupProfileTab,
OverviewTab
},
data () {
return {
chatMessages: [
{
text: 'Hello! So glad you liked my work. Do you want me to shoot you?',
yours: false
},
{
text: 'Yeah, that would be cool. Maybe this Sunday at 3 pm?',
yours: true
},
{
text: 'Sounds great! See you later!',
yours: false
},
{
text: 'Should I bring a lightbox with me?',
yours: true
},
{
text: 'No, thanks. There is no need. Can we set up a meeting earlier?',
yours: false
},
{
text: 'I\'m working on Vuestic, so let\'s meet at 3pm. Thanks!',
yours: true
}
],
posts: [
{
name: 'Irina Myatelskaya',
text: 'joined the network',
photoURL: 'http://i.imgur.com/VuTDC8u.png'
},
{
name: 'Andrei Hrabouski',
text: 'has just started a live video',
photoURL: 'http://i.imgur.com/W3mGrmW.png'
},
{
name: 'Evan You',
text: 'joined the network',
photoURL: 'http://i.imgur.com/D7DOGBH.jpg'
}
],
news: [
{
photoURL: 'http://i.imgur.com/PiTDDcA.png'
},
{
photoURL: 'http://i.imgur.com/M6GugaM.png'
},
{
photoURL: 'http://i.imgur.com/vEy3fRU.png'
},
{
photoURL: 'http://i.imgur.com/Xrywphx.png'
},
{
photoURL: 'http://i.imgur.com/dqVtQGY.png'
},
{
photoURL: 'http://i.imgur.com/qP7rTCy.png'
},
{
photoURL: 'http://i.imgur.com/6YLsM43.png'
},
{
photoURL: 'http://i.imgur.com/9PAOx55.png'
},
{
photoURL: 'http://i.imgur.com/mVpc04D.png'
},
{
photoURL: 'http://i.imgur.com/WdbTSLn.png'
},
{
photoURL: 'http://i.imgur.com/ZXRIHfk.png'
}
]
}
}
}
</script>
<style lang="scss" scoped>
.tabs {
.overview-tab {
.explore-row {
display: none !important;
}
}
.maps-tab {
height: 500px;
}
}
.profile-card-widget, .chat-widget {
width: 100%;
.widget-body {
display: flex;
justify-content: center;
align-items: center;
& > div {
width: 100%;
}
}
}
.bottom-widgets {
> div[class^='col'] {
& > div {
width: 100%;
}
}
}
</style>
This diff is collapsed.
This diff is collapsed.
<template>
<div class="medium-editor">
<div class="row">
<div class="col-md-12">
<vuestic-widget :headerText="'forms.mediumEditor.title' | translate">
<vuestic-medium-editor @initialized="handleEditorInitialization" :editor-options="editorOptions">
<h1>Girl, no you don’t</h1>
<p>
<i>Every time a straight girl tells me “I wish I was a lesbian”, I want to light myself on fire.</i>
</p>
<p>
Picture it. Walk with me for a second.
</p>
<p>
You enter into your favorite local bar looking <b class="default-selection">good</b> as hell, but you know the only heads you want to turn — spicy & stylish alpha bitches — are heavily
fixated on the D. The hot girl talks to you, but she only wants to be your best friend. Her nonthreatening and attentive best friend. Receiver of sexy
selfies, listener of stories. Meanwhile, you attract unwanted attention from straight men, pudgy and greasy moths to your emotionally distant flame.
</p>
<h3>
The only place you can go out and feel desired is a <i>lesbian</i> party. There is a reason lesbian bars no longer exist. Women aren’t taught to approach each
other. We’re taught to cross our arms and judge. You worry about the shape of your eyebrows now? The stage of your roots? You haven’t felt fully judged
until you’ve been in a room full of scowling women who want to fuck each other.
</h3>
<p>
For years, your friends, family members, and medical professionals will doubt your continued homosexual confessions. They will tell you that you “haven’t
met the right man.” Sex with women is fine. That’s allowed. You can be “experimental,” a titillating object of the male gaze. You can be fluid. But you
want to partner with a woman? No no. You must be mistaken. You tend to believe them, because you’ve been conditioned to disbelieve yourself, to instead
defer to the voices of others.
</p>
<p>
You will experience years of confusion about your sexuality, because you haven’t been taught to prioritize your own sexual desire. None of your female
friends orgasm anyway. And if they do, it’s definitely not from penetration. Everyone’s a little in love with their best friend, right? Maybe you just
haven’t met the right man.
</p>
<p>
The word “crazy” continues to come up whenever you discuss your love life, because mainstream society still associates lesbian love with mental
instability. If you’re femme-presenting, you will hear wildly homophobic statements in your presence. You will hear people opine about single brothers,
cousins, uncles who are “obviously gay,” which doesn’t bother you. But then you’ll hear them mention their unhinged friend, about whom they express a
performative concern, tinged with excitement: “She went to rehab and then she dated a woman…. That’s just Crazy Carrie for you!”
</p>
<p>
A family member to tell you that your your “alarming lifestyle” has required them to seek therapy. Your mom will tell you that she “supports you no
matter what” but that it would be “much easier for everyone if you dated a man.” Your love life will become a burden, something that frightens people.
You will go to the Deep South for the holidays and your Grandmother will quite literally scream when you confirm her suspicions that you do, in fact,
have a girlfriend...
</p>
<p>
Read full article on <a href="https://medium.com/@dorn.anna/girl-no-you-dont-2e21e826c62c">Medium</a>
</p>
</vuestic-medium-editor>
</vuestic-widget>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'medium-editor',
data () {
return {
editor: {},
editorOptions: {
buttonLabels: 'fontawesome',
autoLink: true,
toolbar: {
buttons: [
'bold',
'italic',
'underline',
'anchor',
'h1',
'h2',
'h3'
]
}
}
}
},
methods: {
handleEditorInitialization (editor) {
this.editor = editor
this.$nextTick(() => {
this.highlightSampleText()
})
},
highlightSampleText () {
let sampleText = document.getElementsByClassName('default-selection')[0]
this.editor.selectElement(sampleText)
}
}
}
</script>
<style lang="scss">
</style>
<template>
<div class="auth-layout">
<div class="nav d-lg-none"><router-link class="i-vuestic" :to="{path: '/auth/login'}"></router-link></div>
<div class="main row">
<div class="auth-content col-lg-6 col-12">
<router-view></router-view>
</div>
<div class="auth-wallpaper col-6 d-none d-lg-flex">
<div class="oblique"></div>
<router-link class="i-vuestic" :to="{path: '/auth/login'}"></router-link>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'AuthLayout'
}
</script>
<style lang="scss">
@import '../../sass/variables';
@import '~bootstrap/scss/mixins/breakpoints';
@import "~bootstrap/scss/functions";
@import '~bootstrap/scss/variables';
.auth-layout {
height: 100vh;
margin: 0;
.nav {
display: flex;
align-items: center;
justify-content: center;
height: $top-mobile-nav-height;
background-color: $top-nav-bg;
.i-vuestic {
height: $auth-mobile-nav-ivuestic-h;
width: 100%;
}
}
.main {
margin: 0;
height: 100%;
.auth-content {
padding: 0;
display: flex;
align-items: center;
justify-content: center;
background-color: white;
}
.auth-wallpaper {
background-color: $top-nav-bg;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
.i-vuestic {
z-index: 2;
height: $auth-wallpaper-ivuestic-h;
width: 100%;
}
.oblique {
position: absolute;
background-color: $auth-wallpaper-oblique-line;
left: calc(50% - 27%/2);
transform: rotate(15deg);
width: 27%;
height: 115%;
}
}
}
@include media-breakpoint-down(md) {
.main {
height: $auth-mobile-main-h;
.auth-content {
align-items: flex-start;
padding-top: $auth-content-padding-t;
}
}
}
}
</style>
<template>
<div class="layout" :class="classObject" v-resize>
<navbar></navbar>
<sidebar></sidebar>
<div class="content-wrap" id="content-wrap">
<main id="content" class="content" role="main">
<vuestic-breadcrumbs :breadcrumbs="breadcrumbs"/>
<vuestic-pre-loader v-show="isLoading" ref="preLoader" class="pre-loader"></vuestic-pre-loader>
<router-view v-show="!isLoading"></router-view>
</main>
</div>
<div class="made-by-footer">
©2018. Made by&nbsp;<a href="https://tourpaq.com/" target="_blank">Tourpaq ApS </a>
</div>
</div>
</template>
<script>
import {mapGetters} from 'vuex'
import Navbar from './navbar/Navbar'
import Sidebar from './sidebar/Sidebar'
import Resize from 'directives/ResizeHandler'
export default {
name: 'layout',
components: {
Navbar,
Sidebar
},
directives: {
resize: Resize
},
props: {
fixed: {
type: Boolean,
default: false,
}
},
computed: {
...mapGetters([
'sidebarOpened',
'toggleWithoutAnimation',
'isLoading'
]),
classObject: function () {
return {
'layout-fixed': this.fixed,
'sidebar-hidden': !this.toggleWithoutAnimation && !this.sidebarOpened,
'sidebar-hidden sidebar-hidden_without-animation': this.toggleWithoutAnimation && !this.sidebarOpened
}
},
breadcrumbs () {
return this.$store.getters.breadcrumbs(this.$route.name)
},
}
}
</script>
<style lang="scss">
@import "../../sass/_variables.scss";
@import "~bootstrap/scss/mixins/breakpoints";
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
.layout {
&-fixed {
.content-wrap {
padding-right: $layout-padding-right;
padding-top: $sidebar-top;
@include media-breakpoint-down(md) {
padding: $content-mobile-wrap-fixed-layout;
margin-left: 0;
}
}
}
}
.content-wrap {
margin-left: $content-wrap-ml;
transition: margin-left 0.3s ease;
padding-right: $layout-padding-right;
padding-top: $layout-padding;
padding-bottom: $content-wrap-pb;
.pre-loader {
position: absolute;
left: $vuestic-preloader-left;
top: $vuestic-preloader-top;
}
.sidebar-hidden & {
margin-left: $sidebar-left;
}
@include media-breakpoint-down(md) {
padding: $content-mobile-wrap;
margin-left: 0;
.sidebar-hidden & {
margin-left: 0;
padding-top: $content-mobile-wrap-sb-top;
}
}
}
.made-by-footer {
padding-top:25px;
position: absolute;
bottom: 0;
padding-bottom: $made-by-footer-pb;
height: calc(#{$layout-padding} + #{$widget-mb});
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
</style>
<template>
</template>
<script>
import Vue from 'vue'
import { mapActions } from 'vuex'
export default {
name: 'language-selector',
props: {
options: {
type: Array,
required: true
}
},
methods: {
...mapActions(['closeMenu']),
setLanguage (locale) {
Vue.i18n.set(locale)
},
currentLanguage () {
return Vue.i18n.locale() === 'en' ? 'gb' : Vue.i18n.locale()
},
flagIconClass (code) {
return `flag-icon-${code}`
}
}
}
</script>
<style lang="scss">
@import "../../../sass/variables";
@import "~bootstrap/scss/mixins/breakpoints";
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
.language-selector {
display: flex;
max-width: 100%;
height: 100%;
padding: 0;
flex-basis: 0;
flex-grow: 1;
align-items: center;
justify-content: center;
.language-selector-button {
display: flex;
align-items: center;
justify-content: center;
}
.flag-icon-large {
width: 31px;
height: 23px;
}
.flag-icon-small {
min-width: 22px;
height: 17px;
}
.dropdown-toggle {
padding: 0;
&:after {
display: none;
}
}
&.show {
&:after {
position: absolute;
right: calc(50% - 10px);
bottom: -$dropdown-mobile-show-b;
display: block;
width: 0;
height: 0;
content: '';
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid $darkest-gray;
z-index: 2;
}
.dropdown-menu {
left: auto;
margin-top: $dropdown-mobile-show-b;
&.last {
right: 0;
}
@include media-breakpoint-up(lg) {
right: auto;
left: 12px;
margin-top: 12px;
}
}
}
.dropdown-menu {
min-width: 8rem;
max-width: 11rem;
margin-top: $dropdown-show-b;
padding: 0;
background-color: $dropdown-background;
box-shadow: $dropdown-box-shadow;
@include media-breakpoint-up(lg) {
top: 42px;
}
}
.dropdown-item {
display: flex;
align-items: center;
height: 38px;
padding: 9px 12px;
&.active {
color: $vue-green;
background-color: $darkest-gray;
}
&:hover {
background-color: $almost-black;
}
&:last-child {
padding-top: 8px;
padding-bottom: 10px;
}
}
.dropdown-item-text {
padding-left: 12px;
font-size: $font-size-base;
line-height: 1.25;
}
}
</style>
This diff is collapsed.
This diff is collapsed.
<template>
<div class="bubble-map"></div>
</template>
<script>
import 'amcharts3'
import 'amcharts3/amcharts/plugins/responsive/responsive.js'
import 'amcharts3/amcharts/serial.js'
import 'amcharts3/amcharts/themes/light'
import 'ammap3'
import 'ammap3/ammap/maps/js/worldLow'
export default {
name: 'bubble-map',
props: ['mapData'],
methods: {
drawMap () {
/* global AmCharts */
let map
let minBulletSize = 3
let maxBulletSize = 70
let min = Infinity
let max = -Infinity
AmCharts.theme = AmCharts.themes.light
// get min and max values
this.mapData.data.forEach((dataItem) => {
let value = dataItem.value
if (value < min) {
min = value
}
if (value > max) {
max = value
}
})
// build map
map = new AmCharts.AmMap()
map.projection = 'winkel3'
map.addTitle('Population of the World in 2011', 14, 1, 1, false)
map.addTitle('source: Gapminder', 11, 1, 1, 1, false)
map.areasSettings = {
unlistedAreasColor: '#eee',
unlistedAreasAlpha: 1,
outlineColor: '#fff',
outlineThickness: 2
}
map.imagesSettings = {
balloonText: '<span style="font-size:14px"><b>[[title]]</b>: [[value]]</span>',
alpha: 0.75
}
let dataProvider = {
mapVar: AmCharts.maps.worldLow,
images: []
}
// create circle for each country
// it's better to use circle square to show difference between values, not a radius
var maxSquare = maxBulletSize * maxBulletSize * 2 * Math.PI
var minSquare = minBulletSize * minBulletSize * 2 * Math.PI
// create circle for each country
this.mapData.data.forEach((dataItem) => {
var value = dataItem.value
// calculate size of a bubble
var square = (value - min) / (max - min) * (maxSquare - minSquare) + minSquare
if (square < minSquare) {
square = minSquare
}
var size = Math.sqrt(square / (Math.PI * 2))
var id = dataItem.code
dataProvider.images.push({
type: 'circle',
width: size,
height: size,
color: dataItem.color,
longitude: this.mapData.latlong[id].longitude,
latitude: this.mapData.latlong[id].latitude,
title: dataItem.name,
value: value
})
})
map.dataProvider = dataProvider
map.write(this.$el)
}
},
mounted () {
this.drawMap()
}
}
</script>
<style lang='scss'>
@import '../../../sass/_variables.scss';
@import '~ammap3/ammap/ammap.css';
.bubble-map {
height: 100%;
}
</style>
This diff is collapsed.
This diff is collapsed.
<template>
<div class="google-maps-page">
<div class="row">
<div class="col-md-12">
<vuestic-widget class="widget-viewport-height" headerText="Google Maps">
<google-map></google-map>
</vuestic-widget>
</div>
</div>
</div>
</template>
<script>
import GoogleMap from './GoogleMap'
export default {
name: 'google-maps-page',
components: {
GoogleMap
}
}
</script>
<style lang="scss">
</style>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment