├── .babelrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── CNAME ├── README.md ├── build ├── build.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── humans.txt ├── index.ejs ├── package.json ├── robots.txt ├── sitemap.xml ├── src ├── articles │ └── en │ │ ├── _data.json │ │ └── its-my-first-article.md ├── assets │ ├── about.png │ ├── avatar.png │ ├── avatar2.png │ ├── css │ │ ├── fonts.css │ │ ├── noDoubt.css │ │ └── settings.css │ ├── favicon-16.png │ ├── favicon-192.png │ ├── favicon-32.png │ ├── favicon-48.png │ ├── favicon-62.png │ ├── font-icon │ │ ├── ktquez.eot │ │ ├── ktquez.svg │ │ ├── ktquez.ttf │ │ └── ktquez.woff │ ├── logo.png │ ├── me.png │ ├── posts │ │ └── pageview-ga-vue-router.jpg │ └── recife-ktquez1.png ├── components │ ├── App.vue │ ├── Article │ │ ├── Post.vue │ │ ├── Share.vue │ │ ├── disqus.vue │ │ └── index.vue │ ├── Blog │ │ ├── ChooseLoadPosts.vue │ │ ├── ItemPost.vue │ │ ├── ShortAbout.vue │ │ └── index.vue │ ├── Common │ │ ├── Footer │ │ │ ├── PageInfo.vue │ │ │ └── index.vue │ │ ├── Hamburger.vue │ │ ├── Header │ │ │ ├── Logo.vue │ │ │ └── index.vue │ │ ├── NavBar.vue │ │ ├── NavMobile.vue │ │ ├── ScrollTop.vue │ │ ├── Search.vue │ │ ├── Separate.vue │ │ ├── Social.vue │ │ └── Tags.vue │ ├── Pages │ │ ├── Bio.vue │ │ ├── Contact.vue │ │ ├── Lab.vue │ │ ├── NotFound.vue │ │ ├── Projects.vue │ │ └── TopPages.vue │ └── Writer │ │ └── index.vue ├── main.js ├── plugins │ └── head.js ├── routes.js └── vuex │ ├── actions.js │ ├── getters.js │ ├── modules │ ├── blog.js │ ├── lang.js │ ├── navmobile.js │ └── search.js │ ├── mutation-types.js │ └── store.js ├── static └── .gitkeep └── 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 /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 4 | extends: 'standard', 5 | // required to lint *.vue files 6 | plugins: [ 7 | 'html' 8 | ], 9 | // add your custom rules here 10 | 'rules': { 11 | // allow paren-less arrow functions 12 | 'arrow-parens': 0, 13 | // allow debugger during development 14 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | src/articles/ 5 | static/articles/ 6 | config/env.js 7 | npm-debug.log 8 | selenium-debug.log 9 | test/unit/coverage 10 | test/e2e/reports 11 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | ktquez.com -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ktquez.com 2 | 3 | > Personal blog using with Vue.js and Vuex -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('shelljs/global') 3 | env.NODE_ENV = 'production' 4 | 5 | var path = require('path') 6 | var config = require('../config') 7 | var ora = require('ora') 8 | var webpack = require('webpack') 9 | var webpackConfig = require('./webpack.prod.conf') 10 | 11 | console.log( 12 | ' Tip:\n' + 13 | ' Built files are meant to be served over an HTTP server.\n' + 14 | ' Opening index.html over file:// won\'t work.\n' 15 | ) 16 | 17 | var spinner = ora('building for production...') 18 | spinner.start() 19 | 20 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 21 | rm('-rf', assetsPath) 22 | mkdir('-p', assetsPath) 23 | cp('-R', 'static/', assetsPath) 24 | 25 | webpack(webpackConfig, function (err, stats) { 26 | spinner.stop() 27 | if (err) throw err 28 | process.stdout.write(stats.toString({ 29 | colors: true, 30 | modules: false, 31 | children: false, 32 | chunks: false, 33 | chunkModules: false 34 | }) + '\n') 35 | }) 36 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /build/dev-server.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var express = require('express') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var proxyMiddleware = require('http-proxy-middleware') 6 | var webpackConfig = process.env.NODE_ENV === 'testing' 7 | ? require('./webpack.prod.conf') 8 | : require('./webpack.dev.conf') 9 | 10 | // default port where dev server listens for incoming traffic 11 | var port = process.env.PORT || config.dev.port 12 | // Define HTTP proxies to your custom API backend 13 | // https://github.com/chimurai/http-proxy-middleware 14 | var proxyTable = config.dev.proxyTable 15 | 16 | var app = express() 17 | var compiler = webpack(webpackConfig) 18 | 19 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 20 | publicPath: webpackConfig.output.publicPath, 21 | stats: { 22 | colors: true, 23 | chunks: false 24 | } 25 | }) 26 | 27 | var hotMiddleware = require('webpack-hot-middleware')(compiler) 28 | // force page reload when html-webpack-plugin template changes 29 | compiler.plugin('compilation', function (compilation) { 30 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 31 | hotMiddleware.publish({ action: 'reload' }) 32 | cb() 33 | }) 34 | }) 35 | 36 | // proxy api requests 37 | Object.keys(proxyTable).forEach(function (context) { 38 | var options = proxyTable[context] 39 | if (typeof options === 'string') { 40 | options = { target: options } 41 | } 42 | app.use(proxyMiddleware(context, options)) 43 | }) 44 | 45 | // handle fallback for HTML5 history API 46 | app.use(require('connect-history-api-fallback')()) 47 | 48 | // serve webpack bundle output 49 | app.use(devMiddleware) 50 | 51 | // enable hot-reload and state-preserving 52 | // compilation error display 53 | app.use(hotMiddleware) 54 | 55 | // serve pure static assets 56 | var staticPath = path.posix.join(config.build.assetsPublicPath, config.build.assetsSubDirectory) 57 | app.use(staticPath, express.static('./static')) 58 | 59 | module.exports = app.listen(port, function (err) { 60 | if (err) { 61 | console.log(err) 62 | return 63 | } 64 | console.log('Listening at http://localhost:' + port + '\n') 65 | }) 66 | -------------------------------------------------------------------------------- /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 | return path.posix.join(config.build.assetsSubDirectory, _path) 7 | } 8 | 9 | exports.cssLoaders = function (options) { 10 | options = options || {} 11 | // generate loader string to be used with extract text plugin 12 | function generateLoaders (loaders) { 13 | var sourceLoader = loaders.map(function (loader) { 14 | var extraParamChar 15 | if (/\?/.test(loader)) { 16 | loader = loader.replace(/\?/, '-loader?') 17 | extraParamChar = '&' 18 | } else { 19 | loader = loader + '-loader' 20 | extraParamChar = '?' 21 | } 22 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 23 | }).join('!') 24 | 25 | if (options.extract) { 26 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 27 | } else { 28 | return ['vue-style-loader', sourceLoader].join('!') 29 | } 30 | } 31 | 32 | // http://vuejs.github.io/vue-loader/configurations/extract-css.html 33 | return { 34 | css: generateLoaders(['css']), 35 | postcss: generateLoaders(['css']), 36 | less: generateLoaders(['css', 'less']), 37 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 38 | scss: generateLoaders(['css', 'sass']), 39 | stylus: generateLoaders(['css', 'stylus']), 40 | styl: generateLoaders(['css', 'stylus']) 41 | } 42 | } 43 | 44 | // Generate loaders for standalone style files (outside of .vue) 45 | exports.styleLoaders = function (options) { 46 | var output = [] 47 | var loaders = exports.cssLoaders(options) 48 | for (var extension in loaders) { 49 | var loader = loaders[extension] 50 | output.push({ 51 | test: new RegExp('\\.' + extension + '$'), 52 | loader: loader 53 | }) 54 | } 55 | return output 56 | } 57 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var projectRoot = path.resolve(__dirname, '../') 6 | 7 | module.exports = { 8 | entry: { 9 | app: './src/main.js' 10 | }, 11 | output: { 12 | path: config.build.assetsRoot, 13 | publicPath: config.build.assetsPublicPath, 14 | filename: '[name].js' 15 | }, 16 | resolve: { 17 | extensions: ['', '.js', '.vue'], 18 | fallback: [path.join(__dirname, '../node_modules')], 19 | alias: { 20 | 'config': path.resolve(__dirname, '../config'), 21 | 'src': path.resolve(__dirname, '../src'), 22 | 'assets': path.resolve(__dirname, '../src/assets'), 23 | 'components': path.resolve(__dirname, '../src/components') 24 | } 25 | }, 26 | resolveLoader: { 27 | fallback: [path.join(__dirname, '../node_modules')] 28 | }, 29 | module: { 30 | preLoaders: [ 31 | { 32 | test: /\.vue$/, 33 | loader: 'eslint', 34 | include: projectRoot, 35 | exclude: /node_modules/ 36 | }, 37 | { 38 | test: /\.js$/, 39 | loader: 'eslint', 40 | include: projectRoot, 41 | exclude: /node_modules/ 42 | } 43 | ], 44 | loaders: [ 45 | { 46 | test: /\.vue$/, 47 | loader: 'vue' 48 | }, 49 | { 50 | test: /\.js$/, 51 | loader: 'babel', 52 | include: projectRoot, 53 | exclude: /node_modules/ 54 | }, 55 | { 56 | test: /\.json$/, 57 | loader: 'json' 58 | }, 59 | { 60 | test: /\.html$/, 61 | loader: 'vue-html' 62 | }, 63 | { 64 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 65 | loader: 'file', 66 | query: { 67 | limit: 10000, 68 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 69 | } 70 | }, 71 | { 72 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 73 | loader: 'file', 74 | query: { 75 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 76 | } 77 | } 78 | ] 79 | }, 80 | eslint: { 81 | formatter: require('eslint-friendly-formatter') 82 | }, 83 | vue: { 84 | postcss: [require('postcss-cssnext')], 85 | autoprefixer: false 86 | // loaders: utils.cssLoaders() 87 | }, 88 | postcss: [ 89 | require('postcss-import')({ 90 | addDependencyTo: webpack, 91 | }) 92 | ] 93 | } 94 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var path = require('path') 3 | var webpack = require('webpack') 4 | var merge = require('webpack-merge') 5 | var utils = require('./utils') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var HtmlWebpackPlugin = require('html-webpack-plugin') 8 | var CopyWebpackPlugin = require('copy-webpack-plugin') 9 | 10 | // add hot-reload related code to entry chunks 11 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 12 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 13 | }) 14 | 15 | module.exports = merge(baseWebpackConfig, { 16 | module: { 17 | loaders: utils.styleLoaders() 18 | }, 19 | // eval-source-map is faster for development 20 | devtool: '#eval-source-map', 21 | plugins: [ 22 | new CopyWebpackPlugin([ 23 | { from: path.resolve(__dirname, '../src/articles'), to: 'static/articles' }, 24 | { from: path.resolve(__dirname, '../src/assets/posts'), to: 'static/img/posts' }, 25 | ], {}), 26 | new webpack.DefinePlugin({ 27 | 'process.env': config.dev.env 28 | }), 29 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 30 | new webpack.optimize.OccurenceOrderPlugin(), 31 | new webpack.HotModuleReplacementPlugin(), 32 | new webpack.NoErrorsPlugin(), 33 | // https://github.com/ampedandwired/html-webpack-plugin 34 | new HtmlWebpackPlugin({ 35 | filename: 'index.html', 36 | template: 'index.ejs', 37 | inject: true 38 | }) 39 | ] 40 | }) 41 | -------------------------------------------------------------------------------- /build/webpack.prod.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 CopyWebpackPlugin = require('copy-webpack-plugin') 10 | var CleanWebpackPlugin = require('clean-webpack-plugin') 11 | var PrerenderSpaPlugin = require('prerender-spa-plugin') 12 | var env = process.env.NODE_ENV === 'testing' 13 | ? require('../config/test.env') 14 | : config.build.env 15 | 16 | // HTML Webpack plugin + files to Surge 17 | var filename = ['index.html', '200.html', '404.html'] 18 | var htmlWebpackFiles = filename.map(function (file) { 19 | // generate dist index.html with correct asset hash for caching. 20 | // you can customize output by editing /index.ejs 21 | // see https://github.com/ampedandwired/html-webpack-plugin 22 | return new HtmlWebpackPlugin({ 23 | filename: file, 24 | template: 'index.ejs', 25 | inject: true, 26 | minify: { 27 | removeComments: true, 28 | collapseWhitespace: true, 29 | removeAttributeQuotes: true 30 | // more options: 31 | // https://github.com/kangax/html-minifier#options-quick-reference 32 | }, 33 | googleAnalytics: true, 34 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 35 | chunksSortMode: 'dependency' 36 | }) 37 | }) 38 | 39 | module.exports = merge(baseWebpackConfig, { 40 | module: { 41 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 42 | }, 43 | devtool: config.build.productionSourceMap ? '#source-map' : false, 44 | output: { 45 | path: config.build.assetsRoot, 46 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 47 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 48 | }, 49 | vue: { 50 | loaders: utils.cssLoaders({ 51 | sourceMap: config.build.productionSourceMap, 52 | extract: true 53 | }) 54 | }, 55 | plugins: [ 56 | // http://vuejs.github.io/vue-loader/workflow/production.html 57 | new CleanWebpackPlugin(['dist'], { 58 | root: path.resolve(__dirname, '../'), 59 | }), 60 | new webpack.DefinePlugin({ 61 | 'process.env': env 62 | }), 63 | new webpack.optimize.UglifyJsPlugin({ 64 | compress: { 65 | warnings: false 66 | } 67 | }), 68 | new PrerenderSpaPlugin( 69 | config.build.assetsRoot, 70 | ['/about', '/projects', '/contact'], 71 | { 72 | captureAfterTime: 5000, 73 | maxAttempts: 10, 74 | phantomOptions: '--disk-cache=true', 75 | phantomPageSettings: { loadImages: true } 76 | } 77 | ), 78 | new webpack.optimize.OccurenceOrderPlugin(), 79 | // extract css into its own file 80 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 81 | // Copy files 82 | new CopyWebpackPlugin([ 83 | { from: path.resolve(__dirname, '../src/articles'), to: 'static/articles' }, 84 | { from: path.resolve(__dirname, '../src/assets/posts'), to: 'static/img/posts' }, 85 | { from: path.resolve(__dirname, '../robots.txt'), to: 'robots.txt' }, 86 | { from: path.resolve(__dirname, '../sitemap.xml'), to: 'sitemap.xml' }, 87 | { from: path.resolve(__dirname, '../humans.txt'), to: 'humans.txt' }, 88 | { from: path.resolve(__dirname, '../CNAME'), to: 'CNAME', toType: 'file' } 89 | ], {}), 90 | // split vendor js into its own file 91 | new webpack.optimize.CommonsChunkPlugin({ 92 | name: 'vendor', 93 | minChunks: function (module, count) { 94 | // any required modules inside node_modules are extracted to vendor 95 | return ( 96 | module.resource && 97 | module.resource.indexOf( 98 | path.posix.join(__dirname, '../node_modules') 99 | ) === 0 100 | ) 101 | } 102 | }), 103 | // extract webpack runtime and module manifest to its own file in order to 104 | // prevent vendor hash from being updated whenever app bundle is updated 105 | new webpack.optimize.CommonsChunkPlugin({ 106 | name: 'manifest', 107 | chunks: ['vendor'] 108 | }) 109 | ].concat(htmlWebpackFiles) 110 | }) 111 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | url: 'http://ktquez.com', 7 | env: require('./prod.env'), 8 | index: path.resolve(__dirname, '../dist/index.html'), 9 | assetsRoot: path.resolve(__dirname, '../dist'), 10 | assetsSubDirectory: 'static', 11 | assetsPublicPath: '/', 12 | productionSourceMap: true 13 | }, 14 | dev: { 15 | url: 'http://ktquez.dev', 16 | env: require('./dev.env'), 17 | port: 80, 18 | proxyTable: {} 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /humans.txt: -------------------------------------------------------------------------------- 1 | The humans.txt iniciativa legal do (humanstxt.org), para falar um pouco de quem está por trás das aplicações construídas na web, equipe envolvida e Stack usado. Lembrando, somos humanos e não máquinas. Um grande obrigado a você que acessou o meu blog pessoal. 2 | 3 | /* TEAM */ 4 | Title: FullStack web Developer 5 | Name: Alan Silva de Albuquerque 6 | Site: http://ktquez.com/about 7 | Contact: ktquez [at] gmail.com 8 | Twitter: @ktquez 9 | Location: Recife, Pernambuco, Brazil 10 | 11 | /* THANKS */ 12 | Name: Evan You (https://twitter.com/youyuxi) 13 | Name: Surge (https://twitter.com/surge_sh) 14 | 15 | /* SITE */ 16 | Site name: Personal Blog SPA by ktquez 17 | Site URL: http://ktquez.com 18 | Last update: 2016/05/31 19 | Language: Portuguese 20 | Twitter: @ktquez 21 | Contact: http://ktquez.com/contact 22 | Built with: Vue.js, HTML5, CSS3, Markdown 23 | Software: Sublime Text 24 | -------------------------------------------------------------------------------- /index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Alan Albuquerque - ktquez | Full-Stack Web developer 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | <% if (htmlWebpackPlugin.options.googleAnalytics) { %> 52 | 62 | <% } %> 63 | 64 | 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-blog", 3 | "version": "1.0.0", 4 | "description": "Personal blog build with Vue.js and Vuex", 5 | "author": "ktquez ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "build": "node build/build.js", 10 | "deploy": "npm run build && surge -p ./dist", 11 | "unit": "karma start test/unit/karma.conf.js --single-run", 12 | "e2e": "node test/e2e/runner.js", 13 | "test": "npm run unit && npm run e2e", 14 | "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs" 15 | }, 16 | "dependencies": { 17 | "babel-runtime": "^6.0.0", 18 | "highlight.js": "^9.4.0", 19 | "marked": "^0.3.5", 20 | "normalize.css": "^4.1.1", 21 | "vue": "^1.0.24", 22 | "vue-disqus": "^1.0.0", 23 | "vue-head": "^2.0.0", 24 | "vue-resource": "^0.7.0", 25 | "vue-router": "^0.7.13", 26 | "vuex": "^0.6.3", 27 | "vuex-router-sync": "^1.0.0" 28 | }, 29 | "devDependencies": { 30 | "babel-core": "^6.0.0", 31 | "babel-loader": "^6.0.0", 32 | "babel-plugin-transform-runtime": "^6.0.0", 33 | "babel-preset-es2015": "^6.0.0", 34 | "babel-preset-stage-2": "^6.0.0", 35 | "chai": "^3.5.0", 36 | "chromedriver": "^2.21.2", 37 | "clean-webpack-plugin": "^0.1.9", 38 | "connect-history-api-fallback": "^1.1.0", 39 | "copy-webpack-plugin": "^3.0.0", 40 | "cross-spawn": "^2.1.5", 41 | "css-loader": "^0.23.0", 42 | "cssnano": "^3.5.2", 43 | "eslint": "^2.0.0", 44 | "eslint-config-standard": "^5.1.0", 45 | "eslint-friendly-formatter": "^1.2.2", 46 | "eslint-loader": "^1.3.0", 47 | "eslint-plugin-html": "^1.3.0", 48 | "eslint-plugin-promise": "^1.0.8", 49 | "eslint-plugin-standard": "^1.3.2", 50 | "eventsource-polyfill": "^0.9.6", 51 | "express": "^4.13.3", 52 | "extract-text-webpack-plugin": "^1.0.1", 53 | "file-loader": "^0.8.4", 54 | "function-bind": "^1.0.2", 55 | "html-webpack-plugin": "^2.8.1", 56 | "http-proxy-middleware": "^0.12.0", 57 | "inject-loader": "^2.0.1", 58 | "isparta-loader": "^2.0.0", 59 | "json-loader": "^0.5.4", 60 | "karma": "^0.13.15", 61 | "karma-coverage": "^0.5.5", 62 | "karma-mocha": "^0.2.2", 63 | "karma-phantomjs-launcher": "^1.0.0", 64 | "karma-sinon-chai": "^1.2.0", 65 | "karma-sourcemap-loader": "^0.3.7", 66 | "karma-spec-reporter": "0.0.24", 67 | "karma-webpack": "^1.7.0", 68 | "lolex": "^1.4.0", 69 | "mocha": "^2.4.5", 70 | "nightwatch": "^0.8.18", 71 | "ora": "^0.2.0", 72 | "phantomjs-prebuilt": "^2.1.3", 73 | "postcss-cssnext": "^2.5.2", 74 | "postcss-import": "^8.1.2", 75 | "postcss-loader": "^0.9.1", 76 | "prerender-spa-plugin": "^1.1.0", 77 | "selenium-server": "2.53.0", 78 | "shelljs": "^0.6.0", 79 | "sinon": "^1.17.3", 80 | "sinon-chai": "^2.8.0", 81 | "url-loader": "^0.5.7", 82 | "vue-hot-reload-api": "^1.2.0", 83 | "vue-html-loader": "^1.0.0", 84 | "vue-loader": "^8.3.0", 85 | "vue-style-loader": "^1.0.0", 86 | "vuex-router-sync": "^1.0.0", 87 | "webpack": "^1.12.2", 88 | "webpack-dev-middleware": "^1.4.0", 89 | "webpack-hot-middleware": "^2.6.0", 90 | "webpack-merge": "^0.8.3" 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | 3 | Sitemap: http://ktquez.com/sitemap.xml -------------------------------------------------------------------------------- /sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | http://ktquez.com/blog 5 | 2016-06-01 6 | weekly 7 | 0.8 8 | 9 | 10 | http://ktquez.com 11 | 2016-06-01 12 | 0.7 13 | 14 | 15 | http://ktquez.com/projects 16 | 2016-06-01 17 | monthly 18 | 0.7 19 | 20 | 21 | http://ktquez.com/about 22 | 2016-06-01 23 | 24 | 25 | http://ktquez.com/contact 26 | 2016-06-01 27 | 28 | 29 | http://ktquez.com/lab 30 | 2016-06-01 31 | 32 | 33 | http://ktquez.com/blog/acompanhando-sua-spa-vuejs-no-google-analytics-usando-vue-router 34 | 2016-06-03 35 | 36 | 37 | http://ktquez.com/blog/entendendo-semantic-version---parte1 38 | 2016-07-04 39 | 40 | 41 | http://ktquez.com/blog/entendendo-semantic-version---parte-2 42 | 2016-07-04 43 | 44 | -------------------------------------------------------------------------------- /src/articles/en/_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "It's my first article", 4 | "slug": "its-my-first-article", 5 | "picture": { 6 | "img": "slug-image", 7 | "caption": "text-here" 8 | }, 9 | "date": "Sat Jun 25 2016 23:47:37 GMT-0300 (Hora oficial do Brasil)", 10 | "tags": "tag1 tag2 tag3", 11 | "description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s" 12 | } 13 | ] -------------------------------------------------------------------------------- /src/articles/en/its-my-first-article.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/articles/en/its-my-first-article.md -------------------------------------------------------------------------------- /src/assets/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/about.png -------------------------------------------------------------------------------- /src/assets/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/avatar.png -------------------------------------------------------------------------------- /src/assets/avatar2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/avatar2.png -------------------------------------------------------------------------------- /src/assets/css/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Raleway'; 3 | font-style: normal; 4 | font-weight: 300; 5 | src: local('Raleway Light'), local('Raleway-Light'), url(https://fonts.gstatic.com/s/raleway/v11/-_Ctzj9b56b8RgXW8FArifk_vArhqVIZ0nv9q090hN8.woff2) format('woff2'); 6 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; 7 | } 8 | 9 | @font-face { 10 | font-family: 'Raleway'; 11 | font-style: normal; 12 | font-weight: 700; 13 | src: local('Raleway Bold'), local('Raleway-Bold'), url(https://fonts.gstatic.com/s/raleway/v11/JbtMzqLaYbbbCL9X6EvaI_k_vArhqVIZ0nv9q090hN8.woff2) format('woff2'); 14 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; 15 | } 16 | 17 | @font-face { 18 | font-family: 'Varela Round'; 19 | font-style: normal; 20 | font-weight: 400; 21 | src: local('Varela Round'), local('VarelaRound-Regular'), url(https://fonts.gstatic.com/s/varelaround/v6/APH4jr0uSos5wiut5cpjrugdm0LZdjqr5-oayXSOefg.woff2) format('woff2'); 22 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; 23 | } 24 | 25 | @font-face { 26 | font-family: 'ktquez'; 27 | font-weight: normal; 28 | font-style: normal; 29 | src: url('../font-icon/ktquez.eot?yfetij'); 30 | src: url('../font-icon/ktquez.eot?yfetij#iefix') format('embedded-opentype'), 31 | url('../font-icon/ktquez.ttf?yfetij') format('truetype'), 32 | url('../font-icon/ktquez.woff?yfetij') format('woff'), 33 | url('../font-icon/ktquez.svg?yfetij#ktquez') format('svg'); 34 | } 35 | 36 | .icon { 37 | /* use !important to prevent issues with browser extensions that change fonts */ 38 | font-family: 'ktquez' !important; 39 | float:left; 40 | color: #ddd; 41 | font-size: 25px; 42 | transition: color .5s ease-in-out; 43 | 44 | /* Better Font Rendering =========== */ 45 | -webkit-font-smoothing: antialiased; 46 | -moz-osx-font-smoothing: grayscale; 47 | } -------------------------------------------------------------------------------- /src/assets/css/noDoubt.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | /* RESET 4 | -------------------------------------------------------------- */ 5 | *{ 6 | margin:0;padding:0px; 7 | font-family: inherit; 8 | vertical-align: baseline; 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | 13 | ol.-none, 14 | ul.-none { 15 | list-style: none; 16 | } 17 | 18 | table { 19 | border-collapse: collapse; 20 | border-spacing: 0; 21 | } 22 | 23 | a, 24 | img { 25 | text-decoration: none; 26 | outline: none; 27 | border: 0; 28 | } 29 | 30 | input, 31 | select, 32 | button, 33 | option, 34 | textarea { 35 | border: none; 36 | font-family: inherit; 37 | background: none; 38 | outline: none; 39 | } 40 | input:focus, 41 | select:focus, 42 | button:focus{ 43 | outline: none; 44 | } 45 | 46 | input[type="submit"], 47 | button { 48 | cursor: pointer; 49 | } 50 | 51 | ::-moz-placeholder{ color: #999; } 52 | 53 | /* DEFAULT 54 | -------------------------------------------------------------- */ 55 | .clear-col { 56 | clear: both; 57 | display: none; 58 | } 59 | 60 | .centerY { 61 | position: relative; 62 | top: 50%; 63 | -webkit-transform: translateY(-50%); 64 | transform: translateY(-50%); 65 | } 66 | 67 | .centerX { 68 | position: relative; 69 | left: 50%; 70 | -webkit-transform: translateX(-50%); 71 | transform: translateX(-50%); 72 | } 73 | 74 | .fullY { 75 | height: 100%; 76 | position: relative; 77 | } 78 | 79 | .fullX { 80 | width: 100%; 81 | float: left; 82 | position: relative; 83 | z-index: 1; 84 | } 85 | 86 | .fr { 87 | float: right; 88 | position: relative; 89 | } 90 | 91 | .fl { 92 | float: left; 93 | position: relative; 94 | } 95 | 96 | .tac { text-align: center;} 97 | 98 | .zindex { z-index: 999; } 99 | 100 | body { 101 | -webkit-animation-duration: 0.1s; 102 | -webkit-animation-name: fontfix; 103 | -webkit-animation-iteration-count: 1; 104 | -webkit-animation-timing-function: linear; 105 | -webkit-animation-delay: 0.1s; 106 | } 107 | @-webkit-keyframes fontfix { 108 | from { opacity: 1; } 109 | to { opacity: 1; } 110 | } 111 | 112 | /* iPad Input Shadows */ 113 | input[type="text"], 114 | input[type="email"], 115 | input[type="search"], 116 | input[type="password"] { 117 | -webkit-appearance: none; 118 | -moz-appearance: none; /* mobile firefox too! */ 119 | } 120 | 121 | /* GRID 122 | -------------------------------------------------------------- */ 123 | .full-box { 124 | max-width: 100%; 125 | margin-right: auto; 126 | margin-left: auto; 127 | position: relative; 128 | overflow: hidden; 129 | z-index: 1; 130 | } 131 | 132 | [class^="box-center"], 133 | [class*="box-center"] { 134 | position: relative; 135 | margin-right: auto; 136 | margin-left: auto; 137 | z-index: 1; 138 | } 139 | 140 | .box-center9 { max-width: 94%; } 141 | .box-center8 { max-width: 80%; } 142 | .box-center7 { max-width: 70%; } 143 | .box-center6 { max-width: 60%; } 144 | .box-center5 { max-width: 50%; } 145 | 146 | .cpl { 147 | float: left; 148 | min-height: 1px; 149 | position: relative; 150 | } 151 | 152 | .abs { 153 | min-height: 1px; 154 | position: absolute; 155 | } 156 | 157 | .fixed { 158 | min-height: 1px; 159 | position: fixed; 160 | } 161 | 162 | .dnone-m { 163 | display: none; 164 | } 165 | 166 | /* MEDIA QUERIES 167 | -------------------------------------------------------------- */ 168 | 169 | .c-m1 { width: 8.33333333%; } 170 | .c-m2 { width: 16.66666667%; } 171 | .c-m3 { width: 25%; } 172 | .c-m4 { width: 33.33333333%; } 173 | .c-m5 { width: 41.66666667%; } 174 | .c-m6 { width: 50%; } 175 | .c-m7 { width: 58.33333333%; } 176 | .c-m8 { width: 66.66666667%; } 177 | .c-m9 { width: 75%; } 178 | .c-m10 { width: 83.33333333%; } 179 | .c-m11 { width: 91.66666667%; } 180 | .c-m12 { width: 100%; } 181 | 182 | @media only screen and (max-width: 480px) { 183 | .view-m { display: block !important; } 184 | 185 | [class^="box-center"], 186 | [class*="box-center"] { 187 | max-width: 94%; 188 | padding: 0 3%; 189 | } 190 | 191 | .m-centerX { 192 | position: relative; 193 | left: 50%; 194 | -webkit-transform: translateX(-50%); 195 | transform: translateX(-50%); 196 | } 197 | 198 | .m-centerY { 199 | position: relative; 200 | top: 50%; 201 | -webkit-transform: translateY(-50%); 202 | transform: translateY(-50%); 203 | } 204 | 205 | .modal { overflow: scroll; } 206 | } 207 | 208 | @media only screen and (min-width: 481px) { 209 | .c-t1 { width: 8.33333333%; } 210 | .c-t2 { width: 16.66666667%; } 211 | .c-t3 { width: 25%; } 212 | .c-t4 { width: 33.33333333%; } 213 | .c-t5 { width: 41.66666667%; } 214 | .c-t6 { width: 50%; } 215 | .c-t7 { width: 58.33333333%; } 216 | .c-t8 { width: 66.66666667%; } 217 | .c-t9 { width: 75%; } 218 | .c-t10 { width: 83.33333333%; } 219 | .c-t11 { width: 91.66666667%; } 220 | .c-t12 { width: 100%; } 221 | .view-t { display:block !important; } 222 | .dnone-t { display: none !important; } 223 | 224 | } 225 | 226 | @media only screen and (min-width: 481px) and (max-width: 800px){ 227 | [class^="box-center"], 228 | [class*="box-center"] { 229 | max-width: 94%; 230 | padding: 0 3%; 231 | } 232 | } 233 | 234 | @media only screen and (min-width: 801px){ 235 | .c-g1 { width: 8.33333333%; } 236 | .c-g2 { width: 16.66666667%; } 237 | .c-g3 { width: 25%; } 238 | .c-g4 { width: 33.33333333%; } 239 | .c-g5 { width: 41.66666667%; } 240 | .c-g6 { width: 50%; } 241 | .c-g7 { width: 58.33333333%; } 242 | .c-g8 { width: 66.66666667%; } 243 | .c-g9 { width: 75%; } 244 | .c-g10 { width: 83.33333333%; } 245 | .c-g11 { width: 91.66666667%; } 246 | .c-g12 { width: 100%; } 247 | .view-g { display: block !important; } 248 | .dnone-g { display: none !important; } 249 | } 250 | 251 | @media only screen and (min-width: 1025px){ 252 | .c-gg1 { width: 8.33333333%; } 253 | .c-gg2 { width: 16.66666667%; } 254 | .c-gg3 { width: 25%; } 255 | .c-gg4 { width: 33.33333333%; } 256 | .c-gg5 { width: 41.66666667%; } 257 | .c-gg6 { width: 50%; } 258 | .c-gg7 { width: 58.33333333%; } 259 | .c-gg8 { width: 66.66666667%; } 260 | .c-gg9 { width: 75%; } 261 | .c-gg10 { width: 83.33333333%; } 262 | .c-gg11 { width: 91.66666667%; } 263 | .c-gg12 { width: 100%; } 264 | .view-gg { display: block !important; } 265 | .dnone-gg { display: none !important; } 266 | } 267 | 268 | /* IMAGES 269 | -------------------------------------------------------------- */ 270 | .img-circle { 271 | border-radius: 50%; 272 | overflow: hidden; 273 | } 274 | 275 | .img-circle.-small { 276 | width: 32px; 277 | height: 32px; 278 | } 279 | 280 | .img-circle.-medium { 281 | width: 64px; 282 | height: 64px; 283 | } 284 | 285 | .img-circle.-big { 286 | width: 120px; 287 | height: 120px; 288 | } 289 | 290 | /* LISTS 291 | -------------------------------------------------------------- */ 292 | .list { 293 | float: left; 294 | } 295 | 296 | .list > .item { 297 | display: inline; 298 | float: left; 299 | } 300 | 301 | .list.-block > .item { 302 | display: block; 303 | float: left; 304 | } 305 | 306 | /* FADE 307 | -------------------------------------------------------------- */ 308 | [class^='fade-'] { 309 | -webkit-transition-property: all; 310 | transition-property: all; 311 | transition-timing-function: ease-in-out; 312 | -webkit-transition-timing-function: ease-in-out; 313 | } 314 | .fade-fast { 315 | -webkit-transition-duration: 0.3s; 316 | transition-duration: 0.3s; 317 | } 318 | .fade-half { 319 | -webkit-transition-duration: 0.5s; 320 | transition-duration: 0.5s; 321 | } 322 | .fade-slow { 323 | -webkit-transition-duration: 1s; 324 | transition-duration: 1s; 325 | } 326 | 327 | 328 | /* ICONS 329 | -------------------------------------------------------------- */ 330 | .icon-twitter:before { content: '\e910'; } 331 | .icon-twitter:hover { color: #89c9fa; } 332 | 333 | .icon-github:before { content: '\e905'; } 334 | .icon-github:hover { color: #555; } 335 | 336 | .icon-youtube:before { content: '\e912'; } 337 | .icon-youtube:hover { color: #555; } 338 | 339 | .icon-behance:before { content: '\e900'; } 340 | .icon-behance:hover { color: #555; } -------------------------------------------------------------------------------- /src/assets/css/settings.css: -------------------------------------------------------------------------------- 1 | :root { 2 | 3 | /* FONTS*/ 4 | --font: Raleway, Calibri, 'trebuchet MS'; 5 | --font-title: 'Varela Round', Calibri, Arial; 6 | 7 | /* BACKGROUNDS */ 8 | --bg-body: #f2f2f2; 9 | 10 | /* COLORS */ 11 | --color-default: #4ac6b7; 12 | --color-second: #ed7196; 13 | --color-text: #444; 14 | --color-text-light: #999; 15 | --color-light: #ccc; 16 | 17 | /* BORDERS */ 18 | --border-default: 1px solid #ddd; 19 | --border-light: 1px solid #e8e8e8; 20 | 21 | /* MEDIA QUERIES */ 22 | @custom-media --small-viewport (max-width: 480px); 23 | @custom-media --medium-viewport (min-width: 640px) and (max-width: 1024px); 24 | 25 | /* COMPONENTS */ 26 | /* HEADER */ 27 | --bg-header: #ededed; 28 | 29 | /* CONTACT */ 30 | --bg-contact: '../../assets/recife-ktquez1.png'; 31 | 32 | } -------------------------------------------------------------------------------- /src/assets/favicon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/favicon-16.png -------------------------------------------------------------------------------- /src/assets/favicon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/favicon-192.png -------------------------------------------------------------------------------- /src/assets/favicon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/favicon-32.png -------------------------------------------------------------------------------- /src/assets/favicon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/favicon-48.png -------------------------------------------------------------------------------- /src/assets/favicon-62.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/favicon-62.png -------------------------------------------------------------------------------- /src/assets/font-icon/ktquez.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/font-icon/ktquez.eot -------------------------------------------------------------------------------- /src/assets/font-icon/ktquez.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/assets/font-icon/ktquez.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/font-icon/ktquez.ttf -------------------------------------------------------------------------------- /src/assets/font-icon/ktquez.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/font-icon/ktquez.woff -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/me.png -------------------------------------------------------------------------------- /src/assets/posts/pageview-ga-vue-router.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/posts/pageview-ga-vue-router.jpg -------------------------------------------------------------------------------- /src/assets/recife-ktquez1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/src/assets/recife-ktquez1.png -------------------------------------------------------------------------------- /src/components/App.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 69 | 70 | 236 | -------------------------------------------------------------------------------- /src/components/Article/Post.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 28 | 29 | 140 | -------------------------------------------------------------------------------- /src/components/Article/Share.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 76 | 77 | -------------------------------------------------------------------------------- /src/components/Article/disqus.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 46 | 47 | -------------------------------------------------------------------------------- /src/components/Article/index.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 142 | 143 | -------------------------------------------------------------------------------- /src/components/Blog/ChooseLoadPosts.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 40 | 41 | -------------------------------------------------------------------------------- /src/components/Blog/ItemPost.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 47 | 48 | -------------------------------------------------------------------------------- /src/components/Blog/ShortAbout.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /src/components/Blog/index.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 98 | 99 | -------------------------------------------------------------------------------- /src/components/Common/Footer/PageInfo.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 24 | 25 | -------------------------------------------------------------------------------- /src/components/Common/Footer/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 20 | 21 | -------------------------------------------------------------------------------- /src/components/Common/Hamburger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | 22 | -------------------------------------------------------------------------------- /src/components/Common/Header/Logo.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /src/components/Common/Header/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 31 | 32 | -------------------------------------------------------------------------------- /src/components/Common/NavBar.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 26 | 27 | -------------------------------------------------------------------------------- /src/components/Common/NavMobile.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 54 | 55 | -------------------------------------------------------------------------------- /src/components/Common/ScrollTop.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 50 | 51 | -------------------------------------------------------------------------------- /src/components/Common/Search.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 69 | 70 | -------------------------------------------------------------------------------- /src/components/Common/Separate.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /src/components/Common/Social.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | -------------------------------------------------------------------------------- /src/components/Common/Tags.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | 15 | -------------------------------------------------------------------------------- /src/components/Pages/Bio.vue: -------------------------------------------------------------------------------- 1 | 83 | 84 | 163 | 164 | -------------------------------------------------------------------------------- /src/components/Pages/Contact.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 65 | 66 | -------------------------------------------------------------------------------- /src/components/Pages/Lab.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /src/components/Pages/NotFound.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /src/components/Pages/Projects.vue: -------------------------------------------------------------------------------- 1 | 95 | 96 | 147 | 148 | -------------------------------------------------------------------------------- /src/components/Pages/TopPages.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 27 | 28 | -------------------------------------------------------------------------------- /src/components/Writer/index.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 114 | 115 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import VueResource from 'vue-resource' 4 | import { sync } from 'vuex-router-sync' 5 | import store from './vuex/store' 6 | import App from './components/App' 7 | import { routes } from './routes' 8 | import config from '../config/index' 9 | import VueHead from 'vue-head' 10 | 11 | // Set default options in vue Resource 12 | Vue.use(VueResource) 13 | Vue.http.options.root = process.env.NODE_ENV === 'development' 14 | ? config.dev.url 15 | : config.build.url 16 | 17 | Vue.use(VueRouter) 18 | const router = new VueRouter({ 19 | history: true, 20 | saveScrollPosition: true, 21 | suppressTransitionError: true 22 | }) 23 | 24 | router.beforeEach(() => { 25 | window.scrollTo(0, 0) 26 | }) 27 | 28 | router.afterEach((transition) => { 29 | if (window.ga) window.ga('send', 'pageview', transition.to.path) 30 | }) 31 | 32 | // redirect 33 | router.redirect({ 34 | '/': '/blog' 35 | }) 36 | 37 | Vue.use(VueHead) 38 | 39 | // Sync Vue-router with Store Vuex 40 | sync(store, router) 41 | 42 | router.map(routes) 43 | router.start(App, 'app') 44 | -------------------------------------------------------------------------------- /src/plugins/head.js: -------------------------------------------------------------------------------- 1 | 2 | const opt = { 3 | compl: document.title, 4 | separator: '|' 5 | } 6 | const diffTitle = {} 7 | let els = [] 8 | 9 | const util = { 10 | // sh = shorthand 11 | shorthand: { 12 | ch: 'charset', 13 | tg: 'target', 14 | n: 'name', 15 | he: 'http-equiv', 16 | ip: 'itemprop', 17 | c: 'content', 18 | p: 'property', 19 | sc: 'scheme', 20 | r: 'rel', 21 | h: 'href', 22 | sz: 'sizes', 23 | t: 'type', 24 | s: 'src', 25 | a: 'async', 26 | d: 'defer', 27 | i: 'inner' 28 | }, 29 | getPlace (place) { 30 | return document.getElementsByTagName(place)[0] 31 | }, 32 | undoTitle (state) { 33 | if (!state.before) return 34 | document.title = state.before 35 | }, 36 | undo () { 37 | if (!els.length) return 38 | els.map(el => { 39 | el.parentElement.removeChild(el) 40 | }) 41 | els = [] 42 | }, 43 | title (val) { 44 | if (!val) return 45 | diffTitle.before = opt.compl 46 | document.title = `${val.inner} ${val.separator || opt.separator} ${val.compl || opt.compl}` 47 | }, 48 | common (arr, tag, place) { 49 | if (!arr) return 50 | arr.map(obj => { 51 | let parent = this.getPlace(place) 52 | let el = document.getElementById(obj.id) || document.createElement(tag) 53 | Object.keys(obj).map(prop => { 54 | let sh = (this.shorthand[prop] || prop) 55 | if (sh.match(/(body|undo)/g)) return 56 | if (sh === 'inner') { 57 | el.textContent = obj[prop] 58 | return 59 | } 60 | el.setAttribute(sh, obj[prop]) 61 | }) 62 | if (obj.body) parent = this.getPlace('body') 63 | parent.appendChild(el) 64 | if (obj.undo !== undefined && !obj.undo) return 65 | els.push(el) 66 | }) 67 | } 68 | } 69 | 70 | export const VueHead = { 71 | ready () { 72 | let head = this.$options.head 73 | if (!head) return 74 | Object.keys(head).map(key => { 75 | let prop = head[key] 76 | if (!prop) return 77 | let obj = (typeof prop === 'function') ? head[key].bind(this)() : head[key] 78 | if (key === 'title') { 79 | util[key](obj) 80 | return 81 | } 82 | util.common(obj, key, 'head') 83 | }) 84 | }, 85 | destroyed () { 86 | let head = this.$options.head 87 | if (head.title.undo) { 88 | util.undoTitle(diffTitle) 89 | } 90 | util.undo() 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/routes.js: -------------------------------------------------------------------------------- 1 | import Blog from './components/Blog/index' 2 | import Article from './components/Article/index' 3 | import Bio from './components/Pages/Bio' 4 | import Projects from './components/Pages/Projects' 5 | import Lab from './components/Pages/Lab' 6 | import Contact from './components/Pages/Contact' 7 | import Writer from './components/Writer/index' 8 | import NotFound from './components/Pages/NotFound' 9 | 10 | export const routes = { 11 | '/blog': { 12 | name: 'blog', 13 | component: Blog 14 | }, 15 | '/page/:page': { 16 | name: 'paginate', 17 | component: Blog 18 | }, 19 | '/blog/:slug': { 20 | name: 'article', 21 | component: Article 22 | }, 23 | '/about': { 24 | name: 'bio', 25 | component: Bio 26 | }, 27 | '/projects': { 28 | name: 'projects', 29 | component: Projects 30 | }, 31 | '/lab': { 32 | name: 'lab', 33 | component: Lab 34 | }, 35 | '/contact': { 36 | name: 'contact', 37 | component: Contact 38 | }, 39 | '/writer': { 40 | name: 'writer', 41 | component: Writer 42 | }, 43 | '*': { 44 | name: '404', 45 | component: NotFound 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/vuex/actions.js: -------------------------------------------------------------------------------- 1 | /* MODULE POSTS */ 2 | export const setPosts = ({ dispatch }, posts) => { 3 | dispatch('SET_POSTS', posts) 4 | } 5 | export const setCurrentPost = ({dispatch}, post) => { 6 | dispatch('SET_CURRENT_POST', post) 7 | } 8 | 9 | /* MODULE NAV MOBILE */ 10 | export const setStateNavMobile = ({ dispatch }) => { 11 | dispatch('SET_NAV_MOBILE') 12 | } 13 | 14 | /* MODULE LANG */ 15 | export const setLang = ({dispatch}, lang) => { 16 | dispatch('SET_LANG', lang) 17 | } 18 | 19 | /* MODULE SEARCH */ 20 | export const setSearch = ({dispatch}) => { 21 | dispatch('SET_SEARCH') 22 | } 23 | -------------------------------------------------------------------------------- /src/vuex/getters.js: -------------------------------------------------------------------------------- 1 | /* MODULE POSTS */ 2 | export const getPosts = ({blog}) => blog.posts 3 | export const getCurrentPost = ({blog}) => blog.currentPost 4 | 5 | /* MODULE NAV MOBILE */ 6 | export const getStateNavMobile = ({navMobile}) => navMobile.visible 7 | 8 | /* MODULE LANG */ 9 | export const getLang = ({lang}) => lang.value 10 | 11 | /* MODULE SEARCH */ 12 | export const isSearch = ({search}) => search.isSearch 13 | -------------------------------------------------------------------------------- /src/vuex/modules/blog.js: -------------------------------------------------------------------------------- 1 | import { 2 | SET_POSTS, 3 | SET_CURRENT_POST 4 | } from '../mutation-types' 5 | 6 | const state = { 7 | posts: [], 8 | currentPost: {} 9 | } 10 | 11 | const mutations = { 12 | [SET_POSTS] (state, posts) { 13 | state.posts = posts 14 | }, 15 | [SET_CURRENT_POST] (state, post) { 16 | state.currentPost = post 17 | } 18 | } 19 | 20 | export default { 21 | state, 22 | mutations 23 | } 24 | -------------------------------------------------------------------------------- /src/vuex/modules/lang.js: -------------------------------------------------------------------------------- 1 | import { 2 | SET_LANG 3 | } from '../mutation-types' 4 | 5 | const state = { 6 | value: 'pt' 7 | } 8 | 9 | const mutations = { 10 | [SET_LANG] (state, lang) { 11 | state.lang = lang 12 | } 13 | } 14 | 15 | export default { 16 | state, 17 | mutations 18 | } 19 | -------------------------------------------------------------------------------- /src/vuex/modules/navmobile.js: -------------------------------------------------------------------------------- 1 | import { 2 | SET_NAV_MOBILE 3 | } from '../mutation-types.js' 4 | 5 | const state = { 6 | visible: false 7 | } 8 | 9 | const mutations = { 10 | [SET_NAV_MOBILE] (state) { 11 | state.visible = !state.visible 12 | } 13 | } 14 | 15 | export default { 16 | state, 17 | mutations 18 | } 19 | -------------------------------------------------------------------------------- /src/vuex/modules/search.js: -------------------------------------------------------------------------------- 1 | import { 2 | SET_SEARCH 3 | } from '../mutation-types' 4 | 5 | const state = { 6 | isSearch: false 7 | } 8 | 9 | const mutations = { 10 | [SET_SEARCH] (state) { 11 | state.isSearch = !state.isSearch 12 | } 13 | } 14 | 15 | export default { 16 | state, 17 | mutations 18 | } 19 | -------------------------------------------------------------------------------- /src/vuex/mutation-types.js: -------------------------------------------------------------------------------- 1 | /* module posts */ 2 | export const SET_POSTS = 'SET_POSTS' 3 | export const SET_CURRENT_POST = 'SET_CURRENT_POST' 4 | 5 | /* module nav mobile */ 6 | export const SET_NAV_MOBILE = 'SET_NAV_MOBILE' 7 | 8 | /* module lang */ 9 | export const SET_LANG = 'SET_LANG' 10 | 11 | /* module search */ 12 | export const SET_SEARCH = 'SET_SEARCH' 13 | -------------------------------------------------------------------------------- /src/vuex/store.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import Vue from 'vue' 4 | import Vuex from 'vuex' 5 | import lang from './modules/lang' 6 | import blog from './modules/blog' 7 | import search from './modules/search' 8 | import navMobile from './modules/navmobile' 9 | 10 | Vue.use(Vuex) 11 | 12 | export default new Vuex.Store({ 13 | modules: { 14 | lang, 15 | blog, 16 | search, 17 | navMobile 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ktquez/ktquez.com-old/e01b02f9cc281e589090663859bb885fdbe83b72/static/.gitkeep -------------------------------------------------------------------------------- /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 11 | this.expected = count 12 | this.pass = function (val) { 13 | return val === this.expected 14 | } 15 | this.value = function (res) { 16 | return res.value 17 | } 18 | this.command = function (cb) { 19 | var self = this 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length 22 | }, [selector], function (res) { 23 | cb.call(self, res) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | // http://nightwatchjs.org/guide#settings-file 2 | module.exports = { 3 | "src_folders": ["test/e2e/specs"], 4 | "output_folder": "test/e2e/reports", 5 | "custom_assertions_path": ["test/e2e/custom-assertions"], 6 | 7 | "selenium": { 8 | "start_process": true, 9 | "server_path": "node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.0.jar", 10 | "host": "127.0.0.1", 11 | "port": 4444, 12 | "cli_args": { 13 | "webdriver.chrome.driver": require('chromedriver').path 14 | } 15 | }, 16 | 17 | "test_settings": { 18 | "default": { 19 | "selenium_port": 4444, 20 | "selenium_host": "localhost", 21 | "silent": true 22 | }, 23 | 24 | "chrome": { 25 | "desiredCapabilities": { 26 | "browserName": "chrome", 27 | "javascriptEnabled": true, 28 | "acceptSslCerts": true 29 | } 30 | }, 31 | 32 | "firefox": { 33 | "desiredCapabilities": { 34 | "browserName": "firefox", 35 | "javascriptEnabled": true, 36 | "acceptSslCerts": true 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | var server = require('../../build/dev-server.js') 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 | // For more information on Nightwatch's config file, see 10 | // http://nightwatchjs.org/guide#settings-file 11 | var spawn = require('cross-spawn') 12 | var runner = spawn( 13 | './node_modules/.bin/nightwatch', 14 | [ 15 | '--config', 'test/e2e/nightwatch.conf.js', 16 | '--env', 'chrome,firefox' 17 | ], 18 | { 19 | stdio: 'inherit' 20 | } 21 | ) 22 | 23 | runner.on('exit', function (code) { 24 | server.close() 25 | process.exit(code) 26 | }) 27 | 28 | runner.on('error', function (err) { 29 | server.close() 30 | throw err 31 | }) 32 | -------------------------------------------------------------------------------- /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 (browser) { 6 | browser 7 | .url('http://localhost:8080') 8 | .waitForElementVisible('#app', 5000) 9 | .assert.elementPresent('.logo') 10 | .assert.containsText('h1', 'Hello World!') 11 | .assert.elementCount('p', 3) 12 | .end() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | // Polyfill fn.bind() for PhantomJS 2 | /* eslint-disable no-extend-native */ 3 | Function.prototype.bind = require('function-bind') 4 | 5 | // require all test files (files that ends with .spec.js) 6 | var testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | var srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var path = require('path') 7 | var merge = require('webpack-merge') 8 | var baseConfig = require('../../build/webpack.base.conf') 9 | var utils = require('../../build/utils') 10 | var webpack = require('webpack') 11 | var projectRoot = path.resolve(__dirname, '../../') 12 | 13 | var webpackConfig = merge(baseConfig, { 14 | // use inline sourcemap for karma-sourcemap-loader 15 | module: { 16 | loaders: utils.styleLoaders() 17 | }, 18 | devtool: '#inline-source-map', 19 | vue: { 20 | loaders: { 21 | js: 'isparta' 22 | } 23 | }, 24 | plugins: [ 25 | new webpack.DefinePlugin({ 26 | 'process.env': require('../../config/test.env') 27 | }) 28 | ] 29 | }) 30 | 31 | // no need for app entry during tests 32 | delete webpackConfig.entry 33 | 34 | // make sure isparta loader is applied before eslint 35 | webpackConfig.module.preLoaders = webpackConfig.module.preLoaders || [] 36 | webpackConfig.module.preLoaders.unshift({ 37 | test: /\.js$/, 38 | loader: 'isparta', 39 | include: path.resolve(projectRoot, 'src') 40 | }) 41 | 42 | // only apply babel for test files when using isparta 43 | webpackConfig.module.loaders.some(function (loader, i) { 44 | if (loader.loader === 'babel') { 45 | loader.include = path.resolve(projectRoot, 'test/unit') 46 | return true 47 | } 48 | }) 49 | 50 | module.exports = function (config) { 51 | config.set({ 52 | // to run in additional browsers: 53 | // 1. install corresponding karma launcher 54 | // http://karma-runner.github.io/0.13/config/browsers.html 55 | // 2. add it to the `browsers` array below. 56 | browsers: ['PhantomJS'], 57 | frameworks: ['mocha', 'sinon-chai'], 58 | reporters: ['spec', 'coverage'], 59 | files: ['./index.js'], 60 | preprocessors: { 61 | './index.js': ['webpack', 'sourcemap'] 62 | }, 63 | webpack: webpackConfig, 64 | webpackMiddleware: { 65 | noInfo: true 66 | }, 67 | coverageReporter: { 68 | dir: './coverage', 69 | reporters: [ 70 | { type: 'lcov', subdir: '.' }, 71 | { type: 'text-summary' } 72 | ] 73 | } 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /test/unit/specs/Hello.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Hello from 'src/components/Hello' 3 | 4 | describe('Hello.vue', () => { 5 | it('should render correct contents', () => { 6 | const vm = new Vue({ 7 | template: '
', 8 | components: { Hello } 9 | }).$mount() 10 | expect(vm.$el.querySelector('.hello h1').textContent).to.contain('Hello World!') 11 | }) 12 | }) 13 | --------------------------------------------------------------------------------