├── static ├── .gitkeep └── img │ ├── img1.png │ ├── img2.png │ ├── logo.png │ ├── design.png │ ├── img-ciudad.jpg │ └── pencil.svg ├── src ├── containers │ ├── home │ │ ├── home.scss │ │ └── index.vue │ └── projects │ │ ├── projects.scss │ │ └── index.vue ├── assets │ └── logo.png ├── main.js ├── router │ └── index.js ├── components │ └── project │ │ ├── index.vue │ │ └── project.scss └── App.vue ├── .eslintignore ├── config ├── prod.env.js ├── test.env.js ├── dev.env.js └── index.js ├── test ├── unit │ ├── .eslintrc │ ├── specs │ │ └── ListProjects.spec.js │ ├── index.js │ └── karma.conf.js └── e2e │ ├── specs │ └── test.js │ ├── custom-assertions │ └── elementCount.js │ ├── nightwatch.conf.js │ └── runner.js ├── .editorconfig ├── .gitignore ├── .postcssrc.js ├── .babelrc ├── index.html ├── .eslintrc.js ├── package.json └── README.md /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/containers/home/home.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | /test/unit/coverage/ 6 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgrafico/VUE-nas-formacion/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /static/img/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgrafico/VUE-nas-formacion/HEAD/static/img/img1.png -------------------------------------------------------------------------------- /static/img/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgrafico/VUE-nas-formacion/HEAD/static/img/img2.png -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgrafico/VUE-nas-formacion/HEAD/static/img/logo.png -------------------------------------------------------------------------------- /static/img/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgrafico/VUE-nas-formacion/HEAD/static/img/design.png -------------------------------------------------------------------------------- /static/img/img-ciudad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgrafico/VUE-nas-formacion/HEAD/static/img/img-ciudad.jpg -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const devEnv = require('./dev.env') 4 | 5 | module.exports = merge(devEnv, { 6 | NODE_ENV: '"testing"' 7 | }) 8 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /.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 | /test/unit/coverage/ 8 | /test/e2e/reports/ 9 | selenium-debug.log 10 | 11 | # Editor directories and files 12 | .idea 13 | .vscode 14 | *.suo 15 | *.ntvs* 16 | *.njsproj 17 | *.sln 18 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import router from './router' 6 | 7 | Vue.config.productionTip = false 8 | 9 | /* eslint-disable no-new */ 10 | new Vue({ 11 | el: '#app', 12 | router, 13 | components: { App }, 14 | template: '' 15 | }) 16 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime"], 12 | "env": { 13 | "test": { 14 | "presets": ["env", "stage-2"], 15 | "plugins": ["transform-vue-jsx", "istanbul"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import projects from '../containers/projects' 4 | import home from '../containers/home' 5 | 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '/', 12 | name: 'home', 13 | component: home 14 | }, 15 | { 16 | path: '/projects', 17 | name: 'projects', 18 | component: projects 19 | } 20 | ] 21 | }) 22 | -------------------------------------------------------------------------------- /test/unit/specs/ListProjects.spec.js: -------------------------------------------------------------------------------- 1 | // import Vue from 'vue' 2 | // import ListProjects from '@/components/ListProjects' 3 | 4 | // describe('ListProjects.vue', () => { 5 | // it('should render correct contents', () => { 6 | // const Constructor = Vue.extend(ListProjects) 7 | // const vm = new Constructor().$mount() 8 | // expect(vm.$el.querySelector('.hello h1').textContent) 9 | // .to.equal('Welcome to Your Vue.js App') 10 | // }) 11 | // }) 12 | -------------------------------------------------------------------------------- /src/containers/home/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 27 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | Vue.config.productionTip = false 4 | 5 | // require all test files (files that ends with .spec.js) 6 | const 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 | const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /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 | // automatically uses dev Server port from /config.index.js 7 | // default: http://localhost:8080 8 | // see nightwatch.conf.js 9 | const devServer = browser.globals.devServerURL 10 | 11 | browser 12 | .url(devServer) 13 | .waitForElementVisible('#app', 5000) 14 | .assert.elementPresent('.hello') 15 | .assert.containsText('h1', 'Welcome to Your Vue.js App') 16 | .assert.elementCount('img', 1) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /static/img/pencil.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | VUE-nas 22 | 23 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // The assertion name is the filename. 3 | // Example usage: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // For more information on custom assertions see: 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | 10 | exports.assertion = function (selector, count) { 11 | this.message = 'Testing if element <' + selector + '> has count: ' + count 12 | this.expected = count 13 | this.pass = function (val) { 14 | return val === this.expected 15 | } 16 | this.value = function (res) { 17 | return res.value 18 | } 19 | this.command = function (cb) { 20 | var self = this 21 | return this.api.execute(function (selector) { 22 | return document.querySelectorAll(selector).length 23 | }, [selector], function (res) { 24 | cb.call(self, res) 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parserOptions: { 6 | parser: 'babel-eslint' 7 | }, 8 | env: { 9 | browser: true, 10 | }, 11 | extends: [ 12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 14 | 'plugin:vue/essential', 15 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 16 | 'standard' 17 | ], 18 | // required to lint *.vue files 19 | plugins: [ 20 | 'vue' 21 | ], 22 | // add your custom rules here 23 | rules: { 24 | // allow async-await 25 | 'generator-star-spacing': 'off', 26 | // allow debugger during development 27 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /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 webpackConfig = require('../../build/webpack.test.conf') 7 | 8 | module.exports = function karmaConfig (config) { 9 | config.set({ 10 | // to run in additional browsers: 11 | // 1. install corresponding karma launcher 12 | // http://karma-runner.github.io/0.13/config/browsers.html 13 | // 2. add it to the `browsers` array below. 14 | browsers: ['PhantomJS'], 15 | frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'], 16 | reporters: ['spec', 'coverage'], 17 | files: ['./index.js'], 18 | preprocessors: { 19 | './index.js': ['webpack', 'sourcemap'] 20 | }, 21 | webpack: webpackConfig, 22 | webpackMiddleware: { 23 | noInfo: true 24 | }, 25 | coverageReporter: { 26 | dir: './coverage', 27 | reporters: [ 28 | { type: 'lcov', subdir: '.' }, 29 | { type: 'text-summary' } 30 | ] 31 | } 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/gettingstarted#settings-file 5 | module.exports = { 6 | src_folders: ['test/e2e/specs'], 7 | output_folder: 'test/e2e/reports', 8 | custom_assertions_path: ['test/e2e/custom-assertions'], 9 | 10 | selenium: { 11 | start_process: true, 12 | server_path: require('selenium-server').path, 13 | host: '127.0.0.1', 14 | port: 4444, 15 | cli_args: { 16 | 'webdriver.chrome.driver': require('chromedriver').path 17 | } 18 | }, 19 | 20 | test_settings: { 21 | default: { 22 | selenium_port: 4444, 23 | selenium_host: 'localhost', 24 | silent: true, 25 | globals: { 26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) 27 | } 28 | }, 29 | 30 | chrome: { 31 | desiredCapabilities: { 32 | browserName: 'chrome', 33 | javascriptEnabled: true, 34 | acceptSslCerts: true 35 | } 36 | }, 37 | 38 | firefox: { 39 | desiredCapabilities: { 40 | browserName: 'firefox', 41 | javascriptEnabled: true, 42 | acceptSslCerts: true 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/components/project/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 45 | 46 | 48 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 27 | 61 | -------------------------------------------------------------------------------- /src/components/project/project.scss: -------------------------------------------------------------------------------- 1 | .project { 2 | display: flex; 3 | max-height: 100%; 4 | margin: 30px 0; 5 | &:active { 6 | background-color: #f4f4f5; 7 | } 8 | &:hover { 9 | background-color: #f4f4f5; 10 | } 11 | 12 | .image { 13 | background: url('/static/img/img-ciudad.jpg'); 14 | width: 91px; 15 | height: 91px; 16 | background-size: cover; 17 | background-repeat: no-repeat; 18 | background-position: center center; 19 | } 20 | 21 | .textContent { 22 | width: 80%; 23 | padding-left: 10px; 24 | @media (min-width: 600px) { 25 | width: 100%; 26 | } 27 | .title { 28 | margin: 0; 29 | display: flex; 30 | flex-direction: column; 31 | justify-content: flex-start; 32 | align-items: flex-start; 33 | } 34 | 35 | .header-box{ 36 | display: flex; 37 | flex-direction: row; 38 | align-items: center; 39 | justify-content: space-between; 40 | margin: 5px 0; 41 | .btns { 42 | padding-right: 10px; 43 | span{ 44 | width: 20px; 45 | width: 20px; 46 | margin: 0 5px; 47 | } 48 | } 49 | } 50 | .text { 51 | margin: 0; 52 | } 53 | .inputStyle { 54 | background-color: #f4f4f5; 55 | padding: 5px; 56 | border: 0; 57 | border-radius: 20px; 58 | &:focus { 59 | outline: none; 60 | background-color: #ebebef; 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | 4 | const webpack = require('webpack') 5 | const DevServer = require('webpack-dev-server') 6 | 7 | const webpackConfig = require('../../build/webpack.prod.conf') 8 | const devConfigPromise = require('../../build/webpack.dev.conf') 9 | 10 | let server 11 | 12 | devConfigPromise.then(devConfig => { 13 | const devServerOptions = devConfig.devServer 14 | const compiler = webpack(webpackConfig) 15 | server = new DevServer(compiler, devServerOptions) 16 | const port = devServerOptions.port 17 | const host = devServerOptions.host 18 | return server.listen(port, host) 19 | }) 20 | .then(() => { 21 | // 2. run the nightwatch test suite against it 22 | // to run in additional browsers: 23 | // 1. add an entry in test/e2e/nightwatch.conf.js under "test_settings" 24 | // 2. add it to the --env flag below 25 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 26 | // For more information on Nightwatch's config file, see 27 | // http://nightwatchjs.org/guide#settings-file 28 | let opts = process.argv.slice(2) 29 | if (opts.indexOf('--config') === -1) { 30 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 31 | } 32 | if (opts.indexOf('--env') === -1) { 33 | opts = opts.concat(['--env', 'chrome']) 34 | } 35 | 36 | const spawn = require('cross-spawn') 37 | const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 38 | 39 | runner.on('exit', function (code) { 40 | server.close() 41 | process.exit(code) 42 | }) 43 | 44 | runner.on('error', function (err) { 45 | server.close() 46 | throw err 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /src/containers/projects/projects.scss: -------------------------------------------------------------------------------- 1 | .home { 2 | h1,h2 { 3 | padding: 5px; 4 | width: 100%; 5 | margin: 20px auto; 6 | max-width: 230px; 7 | border: 5px solid #9DB6EC; 8 | color: #9DB6EC; 9 | font-weight: 800; 10 | font-size: 1.5em; 11 | text-align: center; 12 | } 13 | .search { 14 | background-color: #f4f4f5; 15 | border-radius: 20px; 16 | border: 0; 17 | width: 100vw; 18 | max-width: 300px; 19 | padding: 10px; 20 | display: flex; 21 | justify-content: center; 22 | align-items: center; 23 | margin: 0 auto; 24 | &:focus { 25 | outline: none; 26 | background-color: #ebebef; 27 | } 28 | } 29 | 30 | .border { 31 | height: 15px; 32 | width: 100%; 33 | background-color: #9DB6EC; 34 | } 35 | 36 | #app { 37 | font-family: 'Roboto', Helvetica, Arial, sans-serif; 38 | -webkit-font-smoothing: antialiased; 39 | -moz-osx-font-smoothing: grayscale; 40 | text-align: center; 41 | color: #2c3e50; 42 | margin-top: 60px; 43 | width: 100%; 44 | height: 100%; 45 | margin: 0; 46 | padding: 0; 47 | } 48 | 49 | 50 | .boxAddButton { 51 | position: fixed; 52 | display: flex; 53 | width: 100%; 54 | bottom: 84px; 55 | .addNewProject { 56 | border: 1px solid grey; 57 | border-radius: 5px; 58 | background-color: white; 59 | padding: 5px 15px 5px 15px; 60 | font-size: 1em; 61 | font-family: 'Roboto', Helvetica, Arial, sans-serif; 62 | color: grey; 63 | display: flex; 64 | margin: 0 auto; 65 | &:active { 66 | outline: none; 67 | background-color: #9DB6EC; 68 | color: white; 69 | border: 1px solid white; 70 | } 71 | &:focus { 72 | outline: none; 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/containers/projects/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 74 | 76 | 77 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: false, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'cheap-module-eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | cssSourceMap: true 44 | }, 45 | 46 | build: { 47 | // Template for index.html 48 | index: path.resolve(__dirname, '../dist/index.html'), 49 | 50 | // Paths 51 | assetsRoot: path.resolve(__dirname, '../dist'), 52 | assetsSubDirectory: 'static', 53 | assetsPublicPath: '/', 54 | 55 | /** 56 | * Source Maps 57 | */ 58 | 59 | productionSourceMap: true, 60 | // https://webpack.js.org/configuration/devtool/#production 61 | devtool: '#source-map', 62 | 63 | // Gzip off by default as many popular static hosts such as 64 | // Surge or Netlify already gzip all static assets for you. 65 | // Before setting to `true`, make sure to: 66 | // npm install --save-dev compression-webpack-plugin 67 | productionGzip: false, 68 | productionGzipExtensions: ['js', 'css'], 69 | 70 | // Run the build command with an extra argument to 71 | // View the bundle analyzer report after build finishes: 72 | // `npm run build --report` 73 | // Set to `true` or `false` to always turn it on or off 74 | bundleAnalyzerReport: process.env.npm_config_report 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-nas", 3 | "version": "1.0.0", 4 | "description": "formacion iniciacion a vue", 5 | "author": "karol ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run", 11 | "e2e": "node test/e2e/runner.js", 12 | "test": "npm run unit && npm run e2e", 13 | "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs", 14 | "build": "node build/build.js" 15 | }, 16 | "dependencies": { 17 | "node-sass": "^4.11.0", 18 | "sass-loader": "^7.1.0", 19 | "vue": "^2.5.2", 20 | "vue-router": "^3.0.1" 21 | }, 22 | "devDependencies": { 23 | "autoprefixer": "^7.1.2", 24 | "babel-core": "^6.22.1", 25 | "babel-eslint": "^8.2.1", 26 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 27 | "babel-loader": "^7.1.1", 28 | "babel-plugin-istanbul": "^4.1.1", 29 | "babel-plugin-syntax-jsx": "^6.18.0", 30 | "babel-plugin-transform-runtime": "^6.22.0", 31 | "babel-plugin-transform-vue-jsx": "^3.5.0", 32 | "babel-preset-env": "^1.3.2", 33 | "babel-preset-stage-2": "^6.22.0", 34 | "babel-register": "^6.22.0", 35 | "chai": "^4.1.2", 36 | "chalk": "^2.0.1", 37 | "chromedriver": "^2.27.2", 38 | "copy-webpack-plugin": "^4.0.1", 39 | "cross-env": "^5.0.1", 40 | "cross-spawn": "^5.0.1", 41 | "css-loader": "^0.28.0", 42 | "eslint": "^4.15.0", 43 | "eslint-config-standard": "^10.2.1", 44 | "eslint-friendly-formatter": "^3.0.0", 45 | "eslint-loader": "^1.7.1", 46 | "eslint-plugin-import": "^2.7.0", 47 | "eslint-plugin-node": "^5.2.0", 48 | "eslint-plugin-promise": "^3.4.0", 49 | "eslint-plugin-standard": "^3.0.1", 50 | "eslint-plugin-vue": "^4.0.0", 51 | "extract-text-webpack-plugin": "^3.0.0", 52 | "file-loader": "^1.1.4", 53 | "friendly-errors-webpack-plugin": "^1.6.1", 54 | "html-webpack-plugin": "^2.30.1", 55 | "inject-loader": "^3.0.0", 56 | "karma": "^1.4.1", 57 | "karma-coverage": "^1.1.1", 58 | "karma-mocha": "^1.3.0", 59 | "karma-phantomjs-launcher": "^1.0.2", 60 | "karma-phantomjs-shim": "^1.4.0", 61 | "karma-sinon-chai": "^1.3.1", 62 | "karma-sourcemap-loader": "^0.3.7", 63 | "karma-spec-reporter": "0.0.31", 64 | "karma-webpack": "^2.0.2", 65 | "mocha": "^3.2.0", 66 | "nightwatch": "^0.9.12", 67 | "node-notifier": "^5.1.2", 68 | "optimize-css-assets-webpack-plugin": "^3.2.0", 69 | "ora": "^1.2.0", 70 | "phantomjs-prebuilt": "^2.1.14", 71 | "portfinder": "^1.0.13", 72 | "postcss-import": "^11.0.0", 73 | "postcss-loader": "^2.0.8", 74 | "postcss-url": "^7.2.1", 75 | "rimraf": "^2.6.0", 76 | "selenium-server": "^3.0.1", 77 | "semver": "^5.3.0", 78 | "shelljs": "^0.7.6", 79 | "sinon": "^4.0.0", 80 | "sinon-chai": "^2.8.0", 81 | "uglifyjs-webpack-plugin": "^1.1.1", 82 | "url-loader": "^0.5.8", 83 | "vue-loader": "^13.3.0", 84 | "vue-style-loader": "^3.0.1", 85 | "vue-template-compiler": "^2.5.2", 86 | "webpack": "^3.6.0", 87 | "webpack-bundle-analyzer": "^2.9.0", 88 | "webpack-dev-server": "^2.9.1", 89 | "webpack-merge": "^4.1.0" 90 | }, 91 | "engines": { 92 | "node": ">= 6.0.0", 93 | "npm": ">= 3.0.0" 94 | }, 95 | "browserslist": [ 96 | "> 1%", 97 | "last 2 versions", 98 | "not ie <= 8" 99 | ] 100 | } 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Descripción Taller Vue.js 2 | 3 | VUEnas a todos! 4 | 5 | En este taller de iniciación a Vue.js veremos cómo construir en pocos pasos una interfaz web sencilla. Hablaremos también sobre la importancia de crear componentes customizables y reutilizables como paradigma a la hora de crear nuestra web. 6 | 7 | Empezaremos super rápido gracias a Vue-CLI y veremos importantes aspectos de Vue, como las directivas, cómo se hace el rendering, variables computadas, routing, gestión de estado... 8 | 9 | Pero lo importante es que vosotros os ensuciéis las manos creando un par de vistas, haciendo componentes, pasando datos, y que completéis al máximo un mini proyecto que os pueda servir en un futuro, ya sea para haceros VUEjstro propio portfolio o para cuando os tengáis que enfrentar a Vue en un trabajo. 10 | 11 | 12 | Para partir de una base, tenemos un diseño: https://invis.io/FAQUGIWU34C 13 | 14 | En el que iremos basando todo nuestro desarrollo... 15 | 16 | ![alt text](https://github.com/karoldesign/VUE-nas-formacion/blob/master/static/img/design.png) 17 | 18 | 19 | 20 | ## Step 0.0 21 | 22 | ![alt text](https://github.com/karoldesign/VUE-nas-formacion/blob/master/static/img/img1.png) 23 | 24 | En este paso podrás encontrar la aplicación sin VUE, observarás que hay tres archivos básicos: 25 | 26 | 1. index.html 27 | 2. index.js 28 | 3. styles.css 29 | 30 | Ahora podrás comprobar lo fácil que es integrar VUE en esta aplicación, haz click en el siguiente enlace que te llevará al codesanbox: 31 | 32 | 33 | https://codesandbox.io/s/23nl747ly 34 | 35 | 36 | Para añadir VUE, tenemos que importar la librería de vue en nuestro html, y además decirle a Vue dónde queremos que se instancie: 37 | 38 | ``` javascript 39 | 40 | ``` 41 | 42 | index.js: 43 | 44 | ``` javascript 45 | new Vue({ 46 | el: "#app", 47 | data: {} 48 | }); 49 | ``` 50 | 51 | Con esto último, estamos instanciando Vue en el *el* (elemento) con id="app". Y ya estaría. Vamos a ver cómo pasar datos desde nuestra instancia de Vue para que se muestren en el html. 52 | 53 | 54 | 55 | ## Step 0.1 56 | 57 | Cuando instanciamos Vue, podemos indicarle así como indicamos el *el*emento donde se encuentra, los datos que tiene, en el elemento *data*. 58 | 59 | ``` javascript 60 | new Vue({ 61 | el: "#app", 62 | data: { 63 | logo: "Mis proyectos", 64 | projects: [ 65 | { 66 | id: 1, 67 | title: "PROYECTO 1", 68 | text: "descripcion 1" 69 | }, 70 | { 71 | id: 2, 72 | title: "PROYECTO 2", 73 | text: "descripcion 2" 74 | } 75 | ] 76 | } 77 | }); 78 | ``` 79 | 80 | Ahora en la variable "logo" tendremos esa cadena de texto que podemos referenciar desde el html, con la *sintaxis del moustache* **{{ }}**. 81 | 82 | ``` html 83 |

{{ logo }}

84 | ``` 85 | 86 | Para hacer lo mismo con el proyecto que vemos, vamos a crear además un array *projects*, donde cada uno tiene un *title* y un *description*. Y duplicaremos el código que renderiza un proyecto, para que ahora muestre *{{projects[0].title}}* y así. 87 | 88 | Para pintar el segundo proyecto tenemos que copiar de nuevo el section y poner la posición 1 en el Array: 89 | 90 | ``` javascript 91 | 92 |
93 |
94 |
95 |
96 |

{{projects[1].title}}

97 |
98 | 99 | 100 |
101 |
102 |

{{projects[1].text}}

103 |
104 |
105 | 106 | ``` 107 | 108 | El resultado sería este: https://codesandbox.io/s/25j4kwrwr 109 | 110 | ## Step 0.2 111 | 112 | Ok, ya tenemos visible nuestros dos proyectos. Ahora queremos meter un buscador para poder buscar por el título del proyecto, y que: 113 | 1. En el caso de que hay proyectos que contienen la cadena de texto que buscamos, mostrarlos. 114 | 2. Mostrar "No hay proyectos" si no encuentra ninguno. 115 | 116 | Para esto haremos uso de dos conceptos, el de **variable computada** y el de **directiva**. En concreto, utilizaremos la directiva *v-if* que nos permite mostrar un trozo de html sólo si se cumple la condición. En cuanto a las variables computadas, no son más que funciones que se ejecutan y devuelven un valor, haciendo más fácil el renderizado de expresiones. Así, podemos meter en una función un filter según el input (vamos a llamarle *inputText* del usuario, y devolver el array de proyectos cuyo título coincide. 117 | 118 | ¿Y cómo hacemos que Vue sepa qué está metiendo el usuario en el campo de búsqueda? Pues con otra directiva, *v-model*. Esta hará un doble binding con lo que el usuario entra y la variable que le indiquemos. 119 | 120 | ``` html 121 | 122 | ``` 123 | 124 | No se nos debe olvidar meter *inputText* en el campo *data*, para que Vue pueda reaccionar a cambios. Sin esto, Vue no sabe qué campos mirar para volver a renderizar el html. 125 | 126 | ``` javascript 127 | computed: { 128 | filteredProjects: function() { 129 | return this.projects.filter( 130 | p => p.title.toLowerCase().indexOf(this.inputText.toLowerCase()) > -1 131 | ); 132 | } 133 | } 134 | ``` 135 | 136 | Para indicar si hay proyectos o no, podemos ahora bindear nuestro html con *filteredProjects* en lugar de *projects*. Para saber si mostramos los proyectos o un "No hay proyectos" si la búsqueda no encuentra ninguno, podemos comprobar la longitud de ese array, y lo meteremos como otra computada que referenciaremos desde el html. 137 | 138 | ``` javascript 139 | showProjects: function() { 140 | return this.filteredProjects.length !== 0; 141 | } 142 | ``` 143 | 144 | ``` html 145 |
146 |
147 | ... 148 | ``` 149 | 150 | El resultado sería: https://codesandbox.io/embed/1v8wxm0l57 151 | 152 | ![alt text](https://github.com/karoldesign/VUE-nas-formacion/blob/master/static/img/img2.png) 153 | 154 | ## Step 1 155 | 156 | Vemos que esto va creciendo considerablemente a medida que vamos metiendo variables y métodos para renderizar. En el mundo real, este caso puede servir para algo muy pequeño, pero lo que nos podemos encontrar es una aplicación completa que queremos desarrollar en Vue. Para ello vamos a hacer uso de un *cli* que iniciará una aplicación por nosotros, y podremos hacer muchas más cosas en ella. 157 | 158 | Lo primero, tener **npm** instalado, y después, instalar **vue-cli**. 159 | 160 | `npm install -g @vue/cli`. 161 | 162 | Si quieres también puedes trabajar sobre nuestro repo de GitHub donde ya hemos hecho algunas cosas por ti :). 163 | https://github.com/karoldesign/VUE-nas-formacion/tree/step-2-computed_and_v-if 164 | 165 | 166 | o si prefieres seguir en codesandbox, puedes partir de aquí con todo lo que llevamos hecho: 167 | https://codesandbox.io/s/ozzlp9j2z 168 | 169 | Y si no, ahora vamos a trasladar todo lo que llevamos hecho a nuestra nueva y flamante aplicación. 170 | 171 | ## Step 2 172 | 173 | En nuestro código html que renderiza proyectos, vemos que estamos duplicando código para cada proyecto. ¿Podemos reutilizarlo para no tenerlo duplicado? Sí. Vamos a hacer uso de la directiva **v-for** para el renderizado de listas, y además, vamos a sacar ese contenido a un componente a parte, que podemos referenciar por su nombre e incluirlo en nuestra instancia de vue. 174 | 175 | Ahora, nuestra instancia además de tener un *data* y un *computed*, tendrá un *components* donde incluiremos nuestro componente (y además lo tendremos que importar). 176 | 177 | ``` javascript 178 | import project from "@/components/project"; 179 | 180 | ... 181 | 182 | data: ..., 183 | components: { 184 | project: project 185 | } 186 | ``` 187 | 188 | ¿Qué va a tener nuestro proyecto? Pues tendrá el mismo código que teníamos antes, lo único que ahora las variables que teníamos con {{ }} ahora serán **props** que recibe desde el componente padre, es decir, el que lo instancia. 189 | 190 | ``` html 191 |
192 |
193 |
194 |
195 |

{{ title }}

196 |
197 | 198 | 199 |
200 |
201 |

{{ text }}

202 |
203 |
204 | ``` 205 | 206 | ¿Y de dónde salen *title* y *text*? Pues cuando definimos el componente, indicamos que recibe un array de *props* con esos nombres. Además, vamos a pasarle un identificador: 207 | ```javascript 208 | export default { 209 | name: 'project', 210 | props: ['title', 'text', 'id'], 211 | mounted () { 212 | }, 213 | data () { 214 | return {} 215 | }, 216 | methods: { 217 | }, 218 | computed: { 219 | } 220 | } 221 | ``` 222 | 223 | Resultado: https://codesandbox.io/s/m5owym2l49 224 | 225 | Y desde el padre ya podremos llamarlo, y pasarle props, con otra directiva, **v-bind**. 226 | ```html 227 | 234 | ``` 235 | 236 | También podemos hacer uso de la sintaxis que propone Vue para evitarnos escribir todo el rato *v-bind*: 237 | ```html 238 | 245 | ``` 246 | Resultado: https://codesandbox.io/s/m3y39kl8px 247 | 248 | ## Step 3 249 | 250 | Vamos ahora a hacer uso de métodos, para poder añadir proyectos y eliminar proyectos. Tenemos ahora dos componentes, el padre (la lista) y el hijo (cada proyecto). La forma de comunicar componentes se debe hacer diferente en cada sentido. Del padre hacia el hijo, hemos visto cómo pasar datos, con las **props** y el **v-bind**. o **:**. Del hijo al padre nos comunicaremos mediante eventos, con la directiva **v-on** o con su otra sintaxis **@**, seguida del nombre del evento. 251 | 252 | Empezamos creando un botón en el componente padre que ejecuta un método cuando se hace click: 253 | 254 | ```html 255 | 256 | ``` 257 | Y añadimos el método *add* 258 | ``` javascript 259 | methods: { 260 | add: function() { 261 | const id = this.projects.length + 1; 262 | this.projects.push({ 263 | id: id, 264 | title: `PROYECTO ${id}`, 265 | text: `Descripción ${id}` 266 | }); 267 | }, 268 | } 269 | ``` 270 | 271 | Ya podemos añadir proyectos cuando hacemos click. Este caso era fácil, porque toda la gestión del evento estaba en el mismo componente. Ahora vamos a darle funcionalidad al botón de eliminar. 272 | 273 | Dentro de nuestro componente *project* tenemos el botón, así que hacemos que gestione el evento de click: 274 | ```html 275 | 276 | ``` 277 | que ejecuta el método *onRemove*, que añadiremos en el componente, para que emita un evento hacia su padre: 278 | ```javascript 279 | onRemove (event) { 280 | this.$emit('remove', this.id) 281 | } 282 | ``` 283 | 284 | Ahora tenemos que hacer que el padre escuche el evento 'remove' y haga cosas. Hacemos que en el evento 'remove' ejecute el método también llamado remove (la @ indica el nombre del evento que escucha, y al otro lado del igual, el nombre del método a ejecutar). 285 | ```html 286 | 294 | ``` 295 | 296 | Y añadimos el método 297 | ```javascript 298 | methods: { 299 | remove: function(id) { 300 | this.projects = this.projects.filter(p => p.id != id); 301 | }, 302 | } 303 | ``` 304 | 305 | Resultado: https://codesandbox.io/s/zn29zm8vrx 306 | 307 | ## Step 4 308 | 309 | Guay! Ya podemos añadir y eliminar proyectos. ¿Queremos editarlos? Vamos a ello. Vamos a explicar qué queremos hacer y vosotros lo implementáis: 310 | 311 | Al hacer click en el botón editar (*@click*) 312 | 313 | ```javascript 314 | 315 | 316 | 317 | ``` 318 | debemos hacer que se vean inputs (*v-bind*?) 319 | en lugar de los textos (*v-if*?), 320 | 321 | ```javascript 322 | 323 |

{{ title }}

324 | 325 | 326 | ``` 327 | 328 | ```javascript 329 | 330 |

{{ text }}

331 | 332 | 333 | ``` 334 | para que el usuario pueda editarlos. 335 | 336 | ```javascript 337 | 338 | edit: function() { 339 | this.editing = !this.editing; 340 | } 341 | 342 | ``` 343 | 344 | 345 | # Para arrancar el proyecto 346 | 347 | ## Build Setup 348 | 349 | ``` bash 350 | # install dependencies 351 | npm install 352 | 353 | # serve with hot reload at localhost:8080 354 | npm run dev 355 | 356 | # build for production with minification 357 | npm run build 358 | 359 | # build for production and view the bundle analyzer report 360 | npm run build --report 361 | 362 | # run unit tests 363 | npm run unit 364 | 365 | # run e2e tests 366 | npm run e2e 367 | 368 | # run all tests 369 | npm test 370 | 371 | # install SASS 372 | npm install --save-dev- node-sass sass-loader 373 | ``` 374 | 375 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 376 | --------------------------------------------------------------------------------