├── .babelrc ├── .editorconfig ├── .gitignore ├── .postcssrc.js ├── README.md ├── build ├── build.js ├── check-versions.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js └── prod.env.js ├── index.html ├── package.json ├── src ├── assets │ └── logo.png ├── components │ ├── App.vue │ ├── Pagination.vue │ ├── RadioGroup.vue │ ├── SearchBox.vue │ ├── TechLabel.vue │ ├── Tutorial.vue │ └── TutorialList.vue ├── data.js ├── main.js └── utilities │ └── get-array-section.js └── static └── .gitkeep /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { "modules": false }], 4 | "stage-2" 5 | ], 6 | "plugins": ["transform-runtime"], 7 | "comments": false, 8 | "env": { 9 | "test": { 10 | "presets": ["env", "stage-2"], 11 | "plugins": [ "istanbul" ] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | *.sublime-* -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserlist" field in package.json 6 | "autoprefixer": {} 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue Tutorial Search Example 2 | 3 | Example Web App built with Vue for some tutorials written for AppendTo.com 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | For detailed explanation on how things work, checkout the [guide for the webpack template](http://vuejs-templates.github.io/webpack/) and [docs for vue-cli](https://github.com/vuejs/vue-cli). 22 | 23 | ## License 24 | 25 | [MIT](https://opensource.org/licenses/MIT) 26 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | var ora = require('ora') 6 | var rm = require('rimraf') 7 | var path = require('path') 8 | var chalk = require('chalk') 9 | var webpack = require('webpack') 10 | var config = require('../config') 11 | var webpackConfig = require('./webpack.prod.conf') 12 | 13 | var spinner = ora('building for production...') 14 | spinner.start() 15 | 16 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 17 | if (err) throw err 18 | webpack(webpackConfig, function (err, stats) { 19 | spinner.stop() 20 | if (err) throw err 21 | process.stdout.write(stats.toString({ 22 | colors: true, 23 | modules: false, 24 | children: false, 25 | chunks: false, 26 | chunkModules: false 27 | }) + '\n\n') 28 | 29 | console.log(chalk.cyan(' Build complete.\n')) 30 | console.log(chalk.yellow( 31 | ' Tip: built files are meant to be served over an HTTP server.\n' + 32 | ' Opening index.html over file:// won\'t work.\n' 33 | )) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | var chalk = require('chalk') 2 | var semver = require('semver') 3 | var packageConfig = require('../package.json') 4 | var shell = require('shelljs') 5 | function exec (cmd) { 6 | return require('child_process').execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | }, 15 | ] 16 | 17 | if (shell.which('npm')) { 18 | versionRequirements.push({ 19 | name: 'npm', 20 | currentVersion: exec('npm --version'), 21 | versionRequirement: packageConfig.engines.npm 22 | }) 23 | } 24 | 25 | module.exports = function () { 26 | var warnings = [] 27 | for (var i = 0; i < versionRequirements.length; i++) { 28 | var mod = versionRequirements[i] 29 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 30 | warnings.push(mod.name + ': ' + 31 | chalk.red(mod.currentVersion) + ' should be ' + 32 | chalk.green(mod.versionRequirement) 33 | ) 34 | } 35 | } 36 | 37 | if (warnings.length) { 38 | console.log('') 39 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 40 | console.log() 41 | for (var i = 0; i < warnings.length; i++) { 42 | var warning = warnings[i] 43 | console.log(' ' + warning) 44 | } 45 | console.log() 46 | process.exit(1) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /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 | require('./check-versions')() 2 | 3 | var config = require('../config') 4 | if (!process.env.NODE_ENV) { 5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 6 | } 7 | 8 | var opn = require('opn') 9 | var path = require('path') 10 | var express = require('express') 11 | var webpack = require('webpack') 12 | var proxyMiddleware = require('http-proxy-middleware') 13 | var webpackConfig = require('./webpack.dev.conf') 14 | 15 | // default port where dev server listens for incoming traffic 16 | var port = process.env.PORT || config.dev.port 17 | // automatically open browser, if not set will be false 18 | var autoOpenBrowser = !!config.dev.autoOpenBrowser 19 | // Define HTTP proxies to your custom API backend 20 | // https://github.com/chimurai/http-proxy-middleware 21 | var proxyTable = config.dev.proxyTable 22 | 23 | var app = express() 24 | var compiler = webpack(webpackConfig) 25 | 26 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 27 | publicPath: webpackConfig.output.publicPath, 28 | quiet: true 29 | }) 30 | 31 | var hotMiddleware = require('webpack-hot-middleware')(compiler, { 32 | log: () => {} 33 | }) 34 | // force page reload when html-webpack-plugin template changes 35 | compiler.plugin('compilation', function (compilation) { 36 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 37 | hotMiddleware.publish({ action: 'reload' }) 38 | cb() 39 | }) 40 | }) 41 | 42 | // proxy api requests 43 | Object.keys(proxyTable).forEach(function (context) { 44 | var options = proxyTable[context] 45 | if (typeof options === 'string') { 46 | options = { target: options } 47 | } 48 | app.use(proxyMiddleware(options.filter || context, options)) 49 | }) 50 | 51 | // handle fallback for HTML5 history API 52 | app.use(require('connect-history-api-fallback')()) 53 | 54 | // serve webpack bundle output 55 | app.use(devMiddleware) 56 | 57 | // enable hot-reload and state-preserving 58 | // compilation error display 59 | app.use(hotMiddleware) 60 | 61 | // serve pure static assets 62 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 63 | app.use(staticPath, express.static('./static')) 64 | 65 | var uri = 'http://localhost:' + port 66 | 67 | var _resolve 68 | var readyPromise = new Promise(resolve => { 69 | _resolve = resolve 70 | }) 71 | 72 | console.log('> Starting dev server...') 73 | devMiddleware.waitUntilValid(() => { 74 | console.log('> Listening at ' + uri + '\n') 75 | // when env is testing, don't need open it 76 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 77 | opn(uri) 78 | } 79 | _resolve() 80 | }) 81 | 82 | var server = app.listen(port) 83 | 84 | module.exports = { 85 | ready: readyPromise, 86 | close: () => { 87 | server.close() 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | 15 | var cssLoader = { 16 | loader: 'css-loader', 17 | options: { 18 | minimize: process.env.NODE_ENV === 'production', 19 | sourceMap: options.sourceMap 20 | } 21 | } 22 | 23 | // generate loader string to be used with extract text plugin 24 | function generateLoaders (loader, loaderOptions) { 25 | var loaders = [cssLoader] 26 | if (loader) { 27 | loaders.push({ 28 | loader: loader + '-loader', 29 | options: Object.assign({}, loaderOptions, { 30 | sourceMap: options.sourceMap 31 | }) 32 | }) 33 | } 34 | 35 | // Extract CSS when that option is specified 36 | // (which is the case during production build) 37 | if (options.extract) { 38 | return ExtractTextPlugin.extract({ 39 | use: loaders, 40 | fallback: 'vue-style-loader' 41 | }) 42 | } else { 43 | return ['vue-style-loader'].concat(loaders) 44 | } 45 | } 46 | 47 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 48 | return { 49 | css: generateLoaders(), 50 | postcss: generateLoaders(), 51 | less: generateLoaders('less'), 52 | sass: generateLoaders('sass', { indentedSyntax: true }), 53 | scss: generateLoaders('sass'), 54 | stylus: generateLoaders('stylus'), 55 | styl: generateLoaders('stylus') 56 | } 57 | } 58 | 59 | // Generate loaders for standalone style files (outside of .vue) 60 | exports.styleLoaders = function (options) { 61 | var output = [] 62 | var loaders = exports.cssLoaders(options) 63 | for (var extension in loaders) { 64 | var loader = loaders[extension] 65 | output.push({ 66 | test: new RegExp('\\.' + extension + '$'), 67 | use: loader 68 | }) 69 | } 70 | return output 71 | } 72 | -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var config = require('../config') 3 | var isProduction = process.env.NODE_ENV === 'production' 4 | 5 | module.exports = { 6 | loaders: utils.cssLoaders({ 7 | sourceMap: isProduction 8 | ? config.build.productionSourceMap 9 | : config.dev.cssSourceMap, 10 | extract: isProduction 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var config = require('../config') 4 | var vueLoaderConfig = require('./vue-loader.conf') 5 | 6 | function resolve (dir) { 7 | return path.join(__dirname, '..', dir) 8 | } 9 | 10 | module.exports = { 11 | entry: { 12 | app: './src/main.js' 13 | }, 14 | output: { 15 | path: config.build.assetsRoot, 16 | filename: '[name].js', 17 | publicPath: process.env.NODE_ENV === 'production' 18 | ? config.build.assetsPublicPath 19 | : config.dev.assetsPublicPath 20 | }, 21 | resolve: { 22 | extensions: ['.js', '.vue', '.json'], 23 | alias: { 24 | '@': resolve('src') 25 | } 26 | }, 27 | module: { 28 | rules: [ 29 | { 30 | test: /\.vue$/, 31 | loader: 'vue-loader', 32 | options: vueLoaderConfig 33 | }, 34 | { 35 | test: /\.js$/, 36 | loader: 'babel-loader', 37 | include: [resolve('src'), resolve('test')] 38 | }, 39 | { 40 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 41 | loader: 'url-loader', 42 | options: { 43 | limit: 10000, 44 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 45 | } 46 | }, 47 | { 48 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 49 | loader: 'url-loader', 50 | options: { 51 | limit: 10000, 52 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 53 | } 54 | } 55 | ] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var webpack = require('webpack') 3 | var config = require('../config') 4 | var merge = require('webpack-merge') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 8 | 9 | // add hot-reload related code to entry chunks 10 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 11 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 12 | }) 13 | 14 | module.exports = merge(baseWebpackConfig, { 15 | module: { 16 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 17 | }, 18 | // cheap-module-eval-source-map is faster for development 19 | devtool: '#cheap-module-eval-source-map', 20 | plugins: [ 21 | new webpack.DefinePlugin({ 22 | 'process.env': config.dev.env 23 | }), 24 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 25 | new webpack.HotModuleReplacementPlugin(), 26 | new webpack.NoEmitOnErrorsPlugin(), 27 | // https://github.com/ampedandwired/html-webpack-plugin 28 | new HtmlWebpackPlugin({ 29 | filename: 'index.html', 30 | template: 'index.html', 31 | inject: true 32 | }), 33 | new FriendlyErrorsPlugin() 34 | ] 35 | }) 36 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var CopyWebpackPlugin = require('copy-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 10 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 11 | 12 | var env = config.build.env 13 | 14 | var webpackConfig = merge(baseWebpackConfig, { 15 | module: { 16 | rules: utils.styleLoaders({ 17 | sourceMap: config.build.productionSourceMap, 18 | extract: true 19 | }) 20 | }, 21 | devtool: config.build.productionSourceMap ? '#source-map' : false, 22 | output: { 23 | path: config.build.assetsRoot, 24 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 25 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 26 | }, 27 | plugins: [ 28 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 29 | new webpack.DefinePlugin({ 30 | 'process.env': env 31 | }), 32 | new webpack.optimize.UglifyJsPlugin({ 33 | compress: { 34 | warnings: false 35 | }, 36 | sourceMap: true 37 | }), 38 | // extract css into its own file 39 | new ExtractTextPlugin({ 40 | filename: utils.assetsPath('css/[name].[contenthash].css') 41 | }), 42 | // Compress extracted CSS. We are using this plugin so that possible 43 | // duplicated CSS from different components can be deduped. 44 | new OptimizeCSSPlugin({ 45 | cssProcessorOptions: { 46 | safe: true 47 | } 48 | }), 49 | // generate dist index.html with correct asset hash for caching. 50 | // you can customize output by editing /index.html 51 | // see https://github.com/ampedandwired/html-webpack-plugin 52 | new HtmlWebpackPlugin({ 53 | filename: config.build.index, 54 | template: 'index.html', 55 | inject: true, 56 | minify: { 57 | removeComments: true, 58 | collapseWhitespace: true, 59 | removeAttributeQuotes: true 60 | // more options: 61 | // https://github.com/kangax/html-minifier#options-quick-reference 62 | }, 63 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 64 | chunksSortMode: 'dependency' 65 | }), 66 | // split vendor js into its own file 67 | new webpack.optimize.CommonsChunkPlugin({ 68 | name: 'vendor', 69 | minChunks: function (module, count) { 70 | // any required modules inside node_modules are extracted to vendor 71 | return ( 72 | module.resource && 73 | /\.js$/.test(module.resource) && 74 | module.resource.indexOf( 75 | path.join(__dirname, '../node_modules') 76 | ) === 0 77 | ) 78 | } 79 | }), 80 | // extract webpack runtime and module manifest to its own file in order to 81 | // prevent vendor hash from being updated whenever app bundle is updated 82 | new webpack.optimize.CommonsChunkPlugin({ 83 | name: 'manifest', 84 | chunks: ['vendor'] 85 | }), 86 | // copy custom static assets 87 | new CopyWebpackPlugin([ 88 | { 89 | from: path.resolve(__dirname, '../static'), 90 | to: config.build.assetsSubDirectory, 91 | ignore: ['.*'] 92 | } 93 | ]) 94 | ] 95 | }) 96 | 97 | if (config.build.productionGzip) { 98 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 99 | 100 | webpackConfig.plugins.push( 101 | new CompressionWebpackPlugin({ 102 | asset: '[path].gz[query]', 103 | algorithm: 'gzip', 104 | test: new RegExp( 105 | '\\.(' + 106 | config.build.productionGzipExtensions.join('|') + 107 | ')$' 108 | ), 109 | threshold: 10240, 110 | minRatio: 0.8 111 | }) 112 | ) 113 | } 114 | 115 | if (config.build.bundleAnalyzerReport) { 116 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 117 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 118 | } 119 | 120 | module.exports = webpackConfig 121 | -------------------------------------------------------------------------------- /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 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'], 18 | // Run the build command with an extra argument to 19 | // View the bundle analyzer report after build finishes: 20 | // `npm run build --report` 21 | // Set to `true` or `false` to always turn it on or off 22 | bundleAnalyzerReport: process.env.npm_config_report 23 | }, 24 | dev: { 25 | env: require('./dev.env'), 26 | port: 8080, 27 | autoOpenBrowser: true, 28 | assetsSubDirectory: 'static', 29 | assetsPublicPath: '/', 30 | proxyTable: {}, 31 | // CSS Sourcemaps off by default because relative paths are "buggy" 32 | // with this option, according to the CSS-Loader README 33 | // (https://github.com/webpack/css-loader#sourcemaps) 34 | // In our experience, they generally work as expected, 35 | // just be aware of this issue when enabling this option. 36 | cssSourceMap: false 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | tut-search 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tut-search", 3 | "version": "1.0.0", 4 | "description": "Find the tutorial you're looking for", 5 | "author": "Joseph Zimmerman ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "start": "node build/dev-server.js", 10 | "build": "node build/build.js" 11 | }, 12 | "dependencies": { 13 | "bootstrap": "~3.3.7", 14 | "vue": "^2.2.6" 15 | }, 16 | "devDependencies": { 17 | "autoprefixer": "^6.7.2", 18 | "babel-core": "^6.22.1", 19 | "babel-loader": "^6.2.10", 20 | "babel-plugin-transform-runtime": "^6.22.0", 21 | "babel-preset-env": "^1.3.2", 22 | "babel-preset-stage-2": "^6.22.0", 23 | "babel-register": "^6.22.0", 24 | "chalk": "^1.1.3", 25 | "connect-history-api-fallback": "^1.3.0", 26 | "copy-webpack-plugin": "^4.0.1", 27 | "css-loader": "^0.28.0", 28 | "eventsource-polyfill": "^0.9.6", 29 | "express": "^4.14.1", 30 | "extract-text-webpack-plugin": "^2.0.0", 31 | "file-loader": "^0.11.1", 32 | "friendly-errors-webpack-plugin": "^1.1.3", 33 | "html-webpack-plugin": "^2.28.0", 34 | "http-proxy-middleware": "^0.17.3", 35 | "webpack-bundle-analyzer": "^2.2.1", 36 | "semver": "^5.3.0", 37 | "shelljs": "^0.7.6", 38 | "opn": "^4.0.2", 39 | "optimize-css-assets-webpack-plugin": "^1.3.0", 40 | "ora": "^1.2.0", 41 | "rimraf": "^2.6.0", 42 | "url-loader": "^0.5.8", 43 | "vue-loader": "^11.3.4", 44 | "vue-style-loader": "^2.0.5", 45 | "vue-template-compiler": "^2.2.6", 46 | "webpack": "^2.3.3", 47 | "webpack-dev-middleware": "^1.10.0", 48 | "webpack-hot-middleware": "^2.18.0", 49 | "webpack-merge": "^4.1.0" 50 | }, 51 | "engines": { 52 | "node": ">= 4.0.0", 53 | "npm": ">= 3.0.0" 54 | }, 55 | "browserslist": [ 56 | "> 1%", 57 | "last 2 versions", 58 | "not ie <= 8" 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joezimjs/Vue-Tutorial-Search-Example/7bcaa8302784a3f54860ac9ab0df3e351fe1cca3/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/App.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 83 | 84 | -------------------------------------------------------------------------------- /src/components/Pagination.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 91 | 92 | -------------------------------------------------------------------------------- /src/components/RadioGroup.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 43 | 44 | 49 | -------------------------------------------------------------------------------- /src/components/SearchBox.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /src/components/TechLabel.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/components/Tutorial.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 31 | 32 | 47 | -------------------------------------------------------------------------------- /src/components/TutorialList.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 18 | 19 | 51 | -------------------------------------------------------------------------------- /src/data.js: -------------------------------------------------------------------------------- 1 | export let technologies = { 2 | angular: { label: "AngularJS", color: "#dd0031" }, 3 | node: { label: "NodeJS", color: "#8bc849" }, 4 | python: { label: "Python", color: "#fdcd3d" }, 5 | react: { label: "React", color: "#06c4f9" }, 6 | ror: { label: "Ruby on Rails", color: "#961122" }, 7 | vue: { label: "VueJS", color: "#41b883" }, 8 | webpack: { label: "Webpack", color: "#1d71b2" } 9 | } 10 | 11 | export let tutorials = [ 12 | { 13 | title: "A Better Way to Learn Angular 2", 14 | url: "https://thinkster.io/tutorials/learn-angular-2", 15 | datePublished: "2017-05-01", 16 | description: "The de facto roadmap for learning Angular 2. This tutorial series will teach you Angular 2's fundamental concepts paired with real world examples, descriptions, and screencasts.", 17 | tech: ["angular"] 18 | }, 19 | { 20 | title: "Building Real World, Production Quality Apps with React and Redux", 21 | url: "https://thinkster.io/tutorials/build-a-real-world-react-redux-application", 22 | datePublished: "2017-05-01", 23 | description: "While most tutorials online cover the basics of React, Redux, and other tools individually, the purpose of this tutorial is to cover all of them in a cohesive manner.", 24 | tech: ["react"] 25 | }, 26 | { 27 | title: "Learn to Build Modern Web Apps with AngularJS and Ruby on Rails", 28 | url: "https://thinkster.io/tutorials/angular-rails", 29 | datePublished: "2017-05-01", 30 | description: "The goal of this tutorial is to guide you through the creation of a Reddit/Hacker News clone using Rails 4 and AngularJS. By completing this tutorial, you will gain a basic understanding of Rails and AngularJS, using Rails to build a JSON REST API that interacts with an AngularJS frontend.", 31 | tech: ["angular", "ror"] 32 | }, 33 | { 34 | title: "Tutorial: Intro To React", 35 | url: "https://facebook.github.io/react/tutorial/tutorial.html", 36 | datePublished: "2017-04-11", 37 | description: "Today, we're going to build an interactive tic-tac-toe game. We will be learning how to build this game step by step throughout this tutorial.", 38 | tech: ["react"] 39 | }, 40 | { 41 | title: "Create Element Transitions with Vue.js", 42 | url: "http://codepen.io/Splode/post/create-element-transitions-with-vue-js", 43 | datePublished: "2017-04-10", 44 | description: "Vue.js (Vue) offers a simple way to transition between elements on the page, allowing for either simple transitions between CSS properties or complex animations (or both!). In this example I'll demonstrate the basics of Vue transitions by creating a menu-expand toggle button.", 45 | tech: ["vue"] 46 | }, 47 | { 48 | title: "A Vue.js introduction for people who know just enough jQuery to get by", 49 | url: "https://medium.freecodecamp.com/vue-js-introduction-for-people-who-know-just-enough-jquery-to-get-by-eab5aa193d77", 50 | datePublished: "2017-04-10", 51 | description: 'I\'ll take readers — who are presumed to have some level of proficiency with JavaScript fundamentals and jQuery — on a journey through the world of VueJS as we build a clone of Twitter’s "compose tweet" component.', 52 | tech: ["vue"] 53 | }, 54 | { 55 | title: "How To Develop An Interactive Command Line Application Using Node.js", 56 | url: "https://www.smashingmagazine.com/2017/03/interactive-command-line-application-node-js/", 57 | datePublished: "2017-03-14", 58 | description: "Writing command line tools has also become easier than ever before because of Node.js — not just any command line tools, but tools that are interactive, useful and less time-consuming to develop.", 59 | tech: ["node"] 60 | }, 61 | { 62 | title: "Webpack: A Detailed Introduction", 63 | url: "https://www.smashingmagazine.com/2017/02/a-detailed-introduction-to-webpack/", 64 | datePublished: "2017-02-21", 65 | description: "JavaScript module bundling has been around for a while. RequireJS had its first commits in 2009, then Browserify made its debut, and since then several other bundlers have spawned across the Internet. Among that group, webpack has jumped out as one of the best. If you’re not familiar with it, I hope this article will get you started with this powerful tool.", 66 | tech: ["webpack"] 67 | }, 68 | { 69 | title: "Build Your First React.js App", 70 | url: "https://egghead.io/courses/build-your-first-react-js-application", 71 | datePublished: "2017-01-24", 72 | description: "When you've completed this series you will have built a full-blown web application using React, and should have the tools needed to start building your own applications today.", 73 | tech: ["react"] 74 | }, 75 | { 76 | title: "Invent Your Own Computer Games with Python", 77 | url: "https://inventwithpython.com/chapters/", 78 | datePublished: "2016-12-17", 79 | description: "Programming isn't hard. But it is hard to find learning materials that teach you to do interesting things with programming. This book will teach you how to program your own computer games. You'll learn a useful skill and have fun games to show for it!", 80 | tech: ["python"] 81 | }, 82 | { 83 | title: "Multi-Line Lambdas in Python", 84 | url: "https://programmingideaswithjake.wordpress.com/2016/10/01/multi-line-lambdas-in-python/", 85 | datePublished: "2016-10-01", 86 | description: "I love Python, but I am able to see plenty of faults with it. In this article, I attempt to provide a very roundabout way of working around one of those faults: the lack of multi-line lambdas.", 87 | tech: ["python"] 88 | }, 89 | { 90 | title: "React Tutorial: Cloning Yelp", 91 | url: "https://www.fullstackreact.com/articles/react-tutorial-cloning-yelp/", 92 | datePublished: "2016-05-19", 93 | description: "This post will guide you through building a full React app, even with little to no experience in the framework. We're going build a Yelp clone in React", 94 | tech: ["react", "node"] 95 | }, 96 | { 97 | title: "Learn Vuex by Building a Notes App", 98 | url: "https://coligo.io/learn-vuex-by-building-notes-app/", 99 | datePublished: "2016-04-20", 100 | description: "In this tutorial we'll be learning how to use Vuex in our VueJs projects by building a notes application. We'll briefly go over what Vuex is, when to use it, and how to structure your project for use with a Vuex application.", 101 | tech: ["vue"] 102 | }, 103 | { 104 | title: "Snake with Pygame", 105 | url: "https://pythonspot.com/en/snake-with-pygame/", 106 | datePublished: "2016-03-21", 107 | description: "In this tutorial you will learn how to build the game snake. The game is an arcade game and it has very simple logic, which is why it is an ideal example to demonstrate how to build games with Pygame.", 108 | tech: ["python"] 109 | }, 110 | { 111 | title: "A Guide For Building A React Redux CRUD App", 112 | url: "https://medium.com/@rajaraodv/a-guide-for-building-a-react-redux-crud-app-7fe0b8943d0f", 113 | datePublished: "2016-03-06", 114 | description: 'In this blog I\'ll provide a general approach on how to build a Blog app that has 3 pages and show navigate between them. Further, I\'ll also establish a pattern for making async requests and handling four async states: "loading", "success", "error" and "success-and-navigate".', 115 | tech: ["react"] 116 | }, 117 | { 118 | title: "Building Your Second React.js App", 119 | url: "https://medium.com/learning-new-stuff/building-your-second-react-js-app-eb66924b3774", 120 | datePublished: "2016-01-30", 121 | description: "This is the second post in a series of tutorials on React.js. The first one took you through building a very simple profile page with the popular Javascript library. This time we'll introduce some more basic concepts: State, Event handlers, Component life cycles, React & API's", 122 | tech: ["react"] 123 | }, 124 | { 125 | title: "Build AirBnb with Ruby on Rails, Bootstrap, jQuery and PayPal", 126 | url: "https://code4startup.com/projects/airalien-clone-airbnb-with-ruby-on-rails-bootstrap-jquery-and-paypal", 127 | datePublished: "2015-12-08", 128 | description: "In this project, I will walk you through steps to develop app like AirBnb with core functionalities from scratch. ", 129 | tech: ["ror"] 130 | }, 131 | { 132 | title: "A Comprehensive Guide to Test-First Development with Redux, React, and Immutable", 133 | url: "http://teropa.info/blog/2015/09/10/full-stack-redux-tutorial.html", 134 | datePublished: "2015-09-10", 135 | description: "This tutorial will guide you through building a full-stack Redux and Immutable-js application from scratch. We'll go through all the steps of constructing a Node+Redux backend and a React+Redux frontend for a real-world application, using test-first development.", 136 | tech: ["react", "node", "webpack"] 137 | }, 138 | { 139 | title: "Let's Build: Instagram (With Ruby on Rails)", 140 | url: "https://www.devwalks.com/lets-build-instagram-in-rails-part-1/", 141 | datePublished: "2015-06-30", 142 | description: "Follow along and together we'll build awesome applications that will build your competence through glorious repetition and embracing the skills that employers want.", 143 | tech: ["ror"] 144 | }, 145 | { 146 | title: "How to build a Pinterest Clone in Rails 4", 147 | url: "https://www.youtube.com/watch?v=abcnfFS_DS8", 148 | datePublished: "2014-09-27", 149 | description: 'Week 4 of my 12 Web Apps in 12 Weeks. This week I built a Pinterest like application with users, pins, image uploading, and "likes". ', 150 | tech: ["ror"] 151 | }, 152 | { 153 | title: "Hacking Secret Ciphers with Python", 154 | url: "https://inventwithpython.com/hacking/chapters/", 155 | datePublished: "2013-04-14", 156 | description: "Movies and TV shows always make hacking look like magic. It's not magic. It's based on computers, and it's not hard to learn. This book assumes you know nothing about cryptography or programming, and helps you learn, step by step, how to write programs that can hack encrypted messages.", 157 | tech: ["python"] 158 | }, 159 | { 160 | title: "Build a Dropbox-like File Sharing Site with Ruby on Rails", 161 | url: "https://code.tutsplus.com/tutorials/build-a-dropbox-like-file-sharing-site-with-ruby-on-rails--net-17940", 162 | datePublished: "2011-01-30", 163 | description: "In this Tuts+ Premium tutorial, we'll learn how to build a file-sharing web application, like Dropbox, using Ruby on Rails.", 164 | tech: ["ror"] 165 | } 166 | ] 167 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './components/App' 3 | 4 | import 'bootstrap/dist/css/bootstrap.css' 5 | 6 | Vue.config.productionTip = false 7 | 8 | new Vue({ 9 | el: '#app', 10 | render: h => h(App) 11 | }) -------------------------------------------------------------------------------- /src/utilities/get-array-section.js: -------------------------------------------------------------------------------- 1 | export default function(arr, sectionNumber, sectionSize) { 2 | let totalSections = Math.ceil(arr.length / sectionSize) 3 | sectionNumber = Math.min(sectionNumber, totalSections) 4 | let from = (sectionNumber - 1) * sectionSize 5 | let to = Math.min(from + sectionSize, arr.length) 6 | 7 | return arr.slice(from, to) 8 | } 9 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joezimjs/Vue-Tutorial-Search-Example/7bcaa8302784a3f54860ac9ab0df3e351fe1cca3/static/.gitkeep --------------------------------------------------------------------------------