├── .browserslistrc
├── .eslintrc.js
├── .gitignore
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── favicon.ico
└── index.html
└── src
├── App.vue
├── assets
└── logo.png
├── components
├── PersonDetail.vue
└── PlanetDetail.vue
├── main.js
├── router.js
├── shared
├── config.js
└── ellipsis-filter.js
├── store
├── index.js
└── modules
│ ├── mutation-types.js
│ ├── people.js
│ └── planets.js
├── styles.scss
└── views
├── About.vue
├── Home.vue
├── PeopleList.vue
└── PlanetList.vue
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 8
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | extends: [
7 | '@vue/airbnb',
8 | 'plugin:vue/essential',
9 | '@vue/prettier'
10 | ],
11 | plugins: ['prettier'],
12 | // watch this for explaining why some of this is here
13 | // https://www.youtube.com/watch?time_continue=239&v=YIvjKId9m2c
14 | rules: {
15 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
17 | quotes: [2, 'single', { avoidEscape: true, allowTemplateLiterals: true }],
18 | 'prettier/prettier': [
19 | 'error',
20 | {
21 | trailingComma: 'es5',
22 | singleQuote: true,
23 | printWidth: '80'
24 | }
25 | ]
26 | },
27 | parserOptions: {
28 | parser: 'babel-eslint'
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-intro
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Lints and fixes files
19 | ```
20 | npm run lint
21 | ```
22 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@vue/app"]
3 | };
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-intro",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "axios": "^0.18.0",
12 | "vue": "^2.5.17",
13 | "vue-router": "^3.0.1",
14 | "vuex": "^3.0.1"
15 | },
16 | "devDependencies": {
17 | "@vue/cli-plugin-babel": "^3.0.3",
18 | "@vue/cli-plugin-eslint": "^3.0.3",
19 | "@vue/cli-service": "^3.0.3",
20 | "@vue/eslint-config-airbnb": "^3.0.3",
21 | "@vue/eslint-config-prettier": "^3.0.3",
22 | "node-sass": "^4.9.0",
23 | "sass-loader": "^7.0.1",
24 | "vue-template-compiler": "^2.5.17"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vue-intro/327e23d37a699b7382c7709cda5a8df74a177caf/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | vue-intro
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ title }}
4 |
21 |
22 |
23 |
24 |
25 |
34 |
35 |
161 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnpapa/vue-intro/327e23d37a699b7382c7709cda5a8df74a177caf/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/PersonDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
87 |
88 |
94 |
--------------------------------------------------------------------------------
/src/components/PlanetDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
87 |
88 |
94 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import ellipsisFilter from '@/shared/ellipsis-filter';
2 | import Vue from 'vue';
3 | import App from './App.vue';
4 | import router from './router';
5 | import store from './store';
6 |
7 | Vue.config.productionTip = false;
8 |
9 | Vue.filter('ellipsis', ellipsisFilter);
10 |
11 | new Vue({
12 | router,
13 | store,
14 | render: h => h(App),
15 | }).$mount('#app');
16 |
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import Home from '@/views/Home.vue';
2 | // import PeopleList from '@/views/PeopleList.vue';
3 | // import PlanetList from '@/views/PlanetList.vue';
4 | import Vue from 'vue';
5 | import Router from 'vue-router';
6 |
7 | Vue.use(Router);
8 |
9 | export default new Router({
10 | mode: 'history',
11 | base: process.env.BASE_URL,
12 | routes: [
13 | {
14 | path: '/',
15 | name: 'home',
16 | component: Home,
17 | },
18 | {
19 | path: '/people',
20 | name: 'PeopleList',
21 | // component: PeopleList,
22 | component: () =>
23 | import(/* webpackChunkName: "people" */ './views/PeopleList.vue'),
24 | },
25 | {
26 | path: '/planets',
27 | name: 'PlanetList',
28 | // component: PlanetList,
29 | component: () =>
30 | import(/* webpackChunkName: "planets" */ './views/PlanetList.vue'),
31 | },
32 | {
33 | path: '/about',
34 | name: 'about',
35 | // route level code-splitting
36 | // this generates a separate chunk (about.[hash].js) for this route
37 | // which is lazy-loaded when the route is visited.
38 | component: () =>
39 | import(/* webpackChunkName: "about" */ './views/About.vue'),
40 | },
41 | ],
42 | });
43 |
--------------------------------------------------------------------------------
/src/shared/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | API: 'https://swapi.co/api',
3 | };
4 |
--------------------------------------------------------------------------------
/src/shared/ellipsis-filter.js:
--------------------------------------------------------------------------------
1 | export default function(text, maxlength) {
2 | if (!text || text.length === 0) return '';
3 |
4 | const shortText = text.substring(0, maxlength);
5 | const dots = shortText.length < text.length ? '...' : '';
6 | return `${shortText}${dots}`;
7 | }
8 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 | import peopleModule from './modules/people';
4 | import planetsModule from './modules/planets';
5 |
6 | export * from './modules/mutation-types';
7 |
8 | Vue.use(Vuex);
9 |
10 | export default new Vuex.Store({
11 | strict: process.env.NODE_ENV !== 'production',
12 | modules: {
13 | people: peopleModule,
14 | planets: planetsModule,
15 | },
16 | state: {},
17 | });
18 |
--------------------------------------------------------------------------------
/src/store/modules/mutation-types.js:
--------------------------------------------------------------------------------
1 | export const GET_PEOPLE = 'GET_PEOPLE';
2 | export const ADD_PERSON = 'ADD_PERSON';
3 | export const UPDATE_PERSON = 'UPDATE_PERSON';
4 | export const DELETE_PERSON = 'DELETE_PERSON';
5 | export const GET_PLANETS = 'GET_PLANETS';
6 | export const ADD_PLANET = 'ADD_PLANET';
7 | export const UPDATE_PLANET = 'UPDATE_PLANET';
8 | export const DELETE_PLANET = 'DELETE_PLANET';
9 |
--------------------------------------------------------------------------------
/src/store/modules/people.js:
--------------------------------------------------------------------------------
1 | import config from '@/shared/config';
2 | import axios from 'axios';
3 | import {
4 | ADD_PERSON,
5 | DELETE_PERSON,
6 | GET_PEOPLE,
7 | UPDATE_PERSON,
8 | } from './mutation-types';
9 |
10 | const { API } = config;
11 |
12 | export default {
13 | strict: process.env.NODE_ENV !== 'production',
14 | namespaced: true,
15 | state: {
16 | people: [],
17 | },
18 | mutations: {
19 | [ADD_PERSON](state, person) {
20 | state.people.push(person); // mutable addition
21 | },
22 | [UPDATE_PERSON](state, person) {
23 | state.people = [...state.people.filter(p => p.id !== person.id), person];
24 | // const index = state.people.findIndex(h => person.id === h.id);
25 | // state.people.splice(index, 1, person);
26 | },
27 | [GET_PEOPLE](state, people) {
28 | state.people = people;
29 | },
30 | [DELETE_PERSON](state, person) {
31 | state.people = state.people.filter(p => p.id !== person.id);
32 | },
33 | },
34 | actions: {
35 | // actions let us get to ({ state, getters, commit, dispatch }) {
36 | getPeople({ commit }) {
37 | let index = 1;
38 | return axios
39 | .get(`${API}/people`)
40 | .then(response => {
41 | const people = response.data.results.map(p => {
42 | p.id = index++;
43 | return p;
44 | });
45 | commit(GET_PEOPLE, people);
46 | return people;
47 | })
48 | .catch(console.error);
49 | },
50 | },
51 | getters: {
52 | // selectors
53 | people: state => state.people,
54 | sortedPeople(state) {
55 | return [...state.people].sort((a, b) => a.id - b.id);
56 | },
57 | },
58 | };
59 |
--------------------------------------------------------------------------------
/src/store/modules/planets.js:
--------------------------------------------------------------------------------
1 | import config from '@/shared/config';
2 | import axios from 'axios';
3 | import {
4 | ADD_PLANET,
5 | DELETE_PLANET,
6 | GET_PLANETS,
7 | UPDATE_PLANET,
8 | } from './mutation-types';
9 |
10 | const { API } = config;
11 |
12 | export default {
13 | strict: process.env.NODE_ENV !== 'production',
14 | namespaced: true,
15 | state: {
16 | planets: [],
17 | },
18 | mutations: {
19 | [ADD_PLANET](state, planet) {
20 | // state.planets.push(planet); // mutable addition
21 | state.planets = [...state.planets, planet]; // replace the array, still mutating state
22 | },
23 | [UPDATE_PLANET](state, planet) {
24 | state.planets = [
25 | ...state.planets.filter(p => p.id !== planet.id),
26 | planet,
27 | ];
28 | // const index = this.planets.findIndex(h => planet.id === h.id);
29 | // this.planets.splice(index, 1, planet);
30 | },
31 | [GET_PLANETS](state, planets) {
32 | state.planets = planets;
33 | },
34 | [DELETE_PLANET](state, planet) {
35 | state.planets = state.planets.filter(p => p.id !== planet.id);
36 | },
37 | },
38 | actions: {
39 | // actions let us get to ({ state, getters, commit, dispatch }) {
40 | getPlanets({ commit }) {
41 | let index = 1;
42 | return axios
43 | .get(`${API}/planets`)
44 | .then(response => {
45 | const planets = response.data.results.map(p => {
46 | p.id = index++;
47 | return p;
48 | });
49 | commit(GET_PLANETS, planets);
50 | return planets;
51 | })
52 | .catch(console.error);
53 | },
54 | },
55 | getters: {
56 | // selectors
57 | planets: state => state.people,
58 | sortedPlanets(state) {
59 | return [...state.planets].sort((a, b) => a.id - b.id);
60 | },
61 | },
62 | };
63 |
--------------------------------------------------------------------------------
/src/styles.scss:
--------------------------------------------------------------------------------
1 | @mixin button-group {
2 | margin: 0.5em;
3 | > button {
4 | margin-right: 1em;
5 | }
6 | }
7 | @mixin button-delete {
8 | background-color: rgb(216, 59, 1);
9 | color: white;
10 | padding: 4px;
11 | position: relative;
12 | font-size: 12px;
13 | max-width: 50px;
14 | }
15 | @mixin selected-item {
16 | background-color: rgb(0, 120, 215) !important;
17 | color: white;
18 | }
19 | @mixin list {
20 | float: left;
21 | margin: 0 0 2em 0;
22 | list-style-type: none;
23 | padding: 0;
24 | width: 20em;
25 | li {
26 | cursor: pointer;
27 | position: relative;
28 | background-color: #f7f7f7;
29 | margin: 0.5em;
30 | height: 3.2em;
31 | border-radius: 4px;
32 | &:hover {
33 | color: #607d8b;
34 | color: rgb(0, 120, 215);
35 | background-color: #ddd;
36 | left: 1px;
37 | }
38 | &.selected:hover {
39 | color: white;
40 | }
41 | }
42 | .text {
43 | position: relative;
44 | top: -3px;
45 | }
46 | .sub-text {
47 | margin: 5px 2.3px;
48 | }
49 | .name {
50 | font-weight: bold;
51 | }
52 | .list-container {
53 | display: flex;
54 | flex-flow: row wrap;
55 | }
56 | > * {
57 | flex: 1 100%;
58 | }
59 | .list-element {
60 | display: flex;
61 | flex-flow: row wrap;
62 | flex: 18 auto;
63 | order: 1;
64 | padding: 0;
65 | margin: 0;
66 | }
67 | .delete-button {
68 | flex: 1 auto;
69 | order: 2;
70 | border-radius: 0 4px 4px 0;
71 | }
72 | .item-text {
73 | flex: 1 auto;
74 | order: 2;
75 | padding: 0.2em 0.5em;
76 | }
77 | .badge {
78 | flex: 1 auto;
79 | order: 1;
80 | font-size: small;
81 | color: #ffffff;
82 | padding: 1.2em 1em 0em 1em;
83 | background-color: #607d8b;
84 | background-color: rgb(0, 120, 215);
85 | background-color: rgb(134, 183, 221);
86 | margin: 0em 0em 0em 0em;
87 | border-radius: 4px 0 0 4px;
88 | max-width: 1.5em;
89 | }
90 | }
91 |
92 | @mixin editarea {
93 | float: left;
94 | input {
95 | margin: 4px;
96 | height: 20px;
97 | color: rgb(0, 120, 215);
98 | }
99 | button {
100 | margin: 8px;
101 | }
102 | .editfields {
103 | margin-left: 12px;
104 | }
105 | }
--------------------------------------------------------------------------------
/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Welcome to Your Vue.js App
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/views/PeopleList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
{{person.id}}
11 |
12 |
{{person.name}}
13 |
{{person.birth_year}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
80 |
81 |
97 |
--------------------------------------------------------------------------------
/src/views/PlanetList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
{{planet.id}}
11 |
12 |
{{planet.name}}
13 |
{{planet.terrain | ellipsis(22)}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
71 |
72 |
88 |
--------------------------------------------------------------------------------