├── README.md
├── robot-home.png
└── src
├── assets
├── build-a-bot-logo.png
└── robot-home.png
├── build
├── PartSelector.vue
├── RobotBuilder-preview.css
├── RobotBuilder-preview.html
├── RobotBuilder.css
├── RobotBuilder.html
└── images
│ ├── arm-articulated-claw.png
│ ├── arm-dual-claw.png
│ ├── arm-grabber.png
│ ├── arm-propeller.png
│ ├── arm-stubby-claw.png
│ ├── base-double-wheel.png
│ ├── base-rocket.png
│ ├── base-single-wheel.png
│ ├── base-spring.png
│ ├── base-triple-wheel.png
│ ├── head-big-eye.png
│ ├── head-friendly.png
│ ├── head-shredder.png
│ ├── head-single-eye.png
│ ├── head-surveillance.png
│ ├── torso-flexible-gauged.png
│ ├── torso-gauged.png
│ └── torso-pouch.png
├── cart
└── ShoppingCart.vue
├── data
└── parts.js
├── header.css
├── parts
├── BrowseParts.vue
├── RobotArms.vue
├── RobotBases.vue
├── RobotHeads.vue
└── RobotTorsos.vue
├── search
├── Search.vue
├── useFilters.js
├── usePagination.js
└── useSearch.js
└── store
└── modules
└── users.js
/README.md:
--------------------------------------------------------------------------------
1 | # vue-fundamentals
2 | Repo for working with the Pluralsight Vue Fundamentals course available here: https://www.pluralsight.com/courses/vuejs-fundamentals
3 |
4 |
--------------------------------------------------------------------------------
/robot-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/robot-home.png
--------------------------------------------------------------------------------
/src/assets/build-a-bot-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/assets/build-a-bot-logo.png
--------------------------------------------------------------------------------
/src/assets/robot-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/assets/robot-home.png
--------------------------------------------------------------------------------
/src/build/PartSelector.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Sale!
7 |
8 |
9 |
10 |
52 |
53 |
159 |
--------------------------------------------------------------------------------
/src/build/RobotBuilder-preview.css:
--------------------------------------------------------------------------------
1 | .preview {
2 | position: absolute;
3 | top: -20px;
4 | right: 0;
5 | width: 210px;
6 | height: 210px;
7 | padding: 5px;
8 | }
9 | .preview-content {
10 | border: 1px solid #999;
11 | }
12 | .preview img {
13 | width: 50px;
14 | height: 50px;
15 | }
16 | .rotate-right {
17 | transform: rotate(90deg);
18 | }
19 | .rotate-left {
20 | transform: rotate(-90deg);
21 | }
22 |
--------------------------------------------------------------------------------
/src/build/RobotBuilder-preview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/build/RobotBuilder.css:
--------------------------------------------------------------------------------
1 | .part {
2 | position: relative;
3 | width:165px;
4 | height:165px;
5 | border: 3px solid #aaa;
6 | }
7 | .part img {
8 | width:165px;
9 | }
10 | .top-row {
11 | display:flex;
12 | justify-content: space-around;
13 | }
14 | .middle-row {
15 | display:flex;
16 | justify-content: center;
17 | }
18 | .bottom-row {
19 | display:flex;
20 | justify-content: space-around;
21 | border-top: none;
22 | }
23 | .head {
24 | border-bottom: none;
25 | }
26 | .left {
27 | border-right: none;
28 | }
29 | .right {
30 | border-left: none;
31 | }
32 | .left img {
33 | transform: rotate(-90deg);
34 | }
35 | .right img {
36 | transform: rotate(90deg);
37 | }
38 | .bottom {
39 | border-top: none;
40 | }
41 | .prev-selector {
42 | position: absolute;
43 | z-index:1;
44 | top: -3px;
45 | left: -28px;
46 | width: 25px;
47 | height: 171px;
48 | }
49 | .next-selector {
50 | position: absolute;
51 | z-index:1;
52 | top: -3px;
53 | right: -28px;
54 | width: 25px;
55 | height: 171px;
56 | }
57 | .center .prev-selector, .center .next-selector {
58 | opacity:0.8;
59 | }
60 | .left .prev-selector {
61 | top: -28px;
62 | left: -3px;
63 | width: 144px;
64 | height: 25px;
65 | }
66 | .left .next-selector {
67 | top: auto;
68 | bottom: -28px;
69 | left: -3px;
70 | width: 144px;
71 | height: 25px;
72 | }
73 | .right .prev-selector {
74 | top: -28px;
75 | left: 24px;
76 | width: 144px;
77 | height: 25px;
78 | }
79 | .right .next-selector {
80 | top: auto;
81 | bottom: -28px;
82 | left: 24px;
83 | width: 144px;
84 | height: 25px;
85 | }
86 | .right .next-selector {
87 | right: -3px;
88 | }
89 |
--------------------------------------------------------------------------------
/src/build/RobotBuilder.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
◄
6 |
►
7 |
8 |
9 |
10 |
11 |
12 |
▲
13 |
▼
14 |
15 |
16 |
17 |
◄
18 |
►
19 |
20 |
21 |
22 |
▲
23 |
▼
24 |
25 |
26 |
27 |
28 |
29 |
◄
30 |
►
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/build/images/arm-articulated-claw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/arm-articulated-claw.png
--------------------------------------------------------------------------------
/src/build/images/arm-dual-claw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/arm-dual-claw.png
--------------------------------------------------------------------------------
/src/build/images/arm-grabber.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/arm-grabber.png
--------------------------------------------------------------------------------
/src/build/images/arm-propeller.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/arm-propeller.png
--------------------------------------------------------------------------------
/src/build/images/arm-stubby-claw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/arm-stubby-claw.png
--------------------------------------------------------------------------------
/src/build/images/base-double-wheel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/base-double-wheel.png
--------------------------------------------------------------------------------
/src/build/images/base-rocket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/base-rocket.png
--------------------------------------------------------------------------------
/src/build/images/base-single-wheel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/base-single-wheel.png
--------------------------------------------------------------------------------
/src/build/images/base-spring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/base-spring.png
--------------------------------------------------------------------------------
/src/build/images/base-triple-wheel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/base-triple-wheel.png
--------------------------------------------------------------------------------
/src/build/images/head-big-eye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/head-big-eye.png
--------------------------------------------------------------------------------
/src/build/images/head-friendly.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/head-friendly.png
--------------------------------------------------------------------------------
/src/build/images/head-shredder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/head-shredder.png
--------------------------------------------------------------------------------
/src/build/images/head-single-eye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/head-single-eye.png
--------------------------------------------------------------------------------
/src/build/images/head-surveillance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/head-surveillance.png
--------------------------------------------------------------------------------
/src/build/images/torso-flexible-gauged.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/torso-flexible-gauged.png
--------------------------------------------------------------------------------
/src/build/images/torso-gauged.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/torso-gauged.png
--------------------------------------------------------------------------------
/src/build/images/torso-pouch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jmcooper/vuejs-fundamentals/a781865e23b0921603c9bfe8931d1980d6e20aa3/src/build/images/torso-pouch.png
--------------------------------------------------------------------------------
/src/cart/ShoppingCart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Cart
4 |
5 |
6 |
7 |
8 | Robot
9 |
10 |
11 | Cost
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{robot.head.title}}
19 |
20 |
21 | {{robot.cost}}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
34 |
35 |
47 |
--------------------------------------------------------------------------------
/src/data/parts.js:
--------------------------------------------------------------------------------
1 | const images = require.context('./images', true, /\.png$/)
2 |
3 | const parts = {
4 | heads: [
5 | {
6 | id: 1,
7 | description:
8 | 'A robot head with an unusually large eye and teloscpic neck -- excellent for exploring high spaces.',
9 | title: 'Large Cyclops',
10 | src: images('./head-big-eye.png'),
11 | type: 'heads',
12 | cost: 1225.5
13 | },
14 | {
15 | id: 2,
16 | description: 'A friendly robot head with two eyes and a smile -- great for domestic use.',
17 | title: 'Friendly Bot',
18 | src: images('./head-friendly.png'),
19 | cost: 945.0,
20 | type: 'heads',
21 | onSale: true
22 | },
23 | {
24 | id: 3,
25 | description:
26 | 'A large three-eyed head with a shredder for a mouth -- great for crushing light medals or shredding documents.',
27 | title: 'Shredder',
28 | src: images('./head-shredder.png'),
29 | type: 'heads',
30 | cost: 1275.5
31 | },
32 | {
33 | id: 4,
34 | description:
35 | 'A simple single-eyed head -- simple and inexpensive.',
36 | title: 'Small Cyclops',
37 | src: images('./head-single-eye.png'),
38 | type: 'heads',
39 | cost: 750.0
40 | },
41 | {
42 | id: 5,
43 | description:
44 | 'A robot head with three oscillating eyes -- excellent for surveillance.',
45 | title: 'Surveillance Bot',
46 | src: images('./head-surveillance.png'),
47 | type: 'heads',
48 | cost: 1255.5
49 | }
50 | ],
51 | arms: [
52 | {
53 | id: 1,
54 | description: 'An articulated arm with a claw -- great for reaching around corners or working in tight spaces.',
55 | title: 'Articulated',
56 | src: images('./arm-articulated-claw.png'),
57 | type: 'arms',
58 | cost: 275
59 | },
60 | {
61 | id: 2,
62 | description: 'An arm with two independent claws -- great when you need an extra hand. Need four hands? Equip your bot with two of these arms.',
63 | title: 'Two Clawed',
64 | src: images('./arm-dual-claw.png'),
65 | type: 'arms',
66 | cost: 285
67 | },
68 | {
69 | id: 3,
70 | description: 'A telescoping arm with a grabber.',
71 | title: 'Grabber',
72 | src: images('./arm-grabber.png'),
73 | type: 'arms',
74 | cost: 205.5
75 | },
76 | {
77 | id: 4,
78 | description: 'An arm with a propeller -- good for propulsion or as a cooling fan.',
79 | title: 'Propeller',
80 | src: images('./arm-propeller.png'),
81 | type: 'arms',
82 | cost: 230,
83 | onSale: true
84 | },
85 | {
86 | id: 5,
87 | description: 'A short and stubby arm with a claw -- simple, but cheap.',
88 | title: 'Stubby Claw',
89 | src: images('./arm-stubby-claw.png'),
90 | type: 'arms',
91 | cost: 125
92 | }
93 | ],
94 | torsos: [
95 | {
96 | id: 1,
97 | description: 'A torso that can bend slightly at the waist and equiped with a heat guage.',
98 | title: 'Flexible Gauged',
99 | src: images('./torso-flexible-gauged.png'),
100 | type: 'torsos',
101 | cost: 1575
102 | },
103 | {
104 | id: 2,
105 | description: 'A less flexible torso with a battery gauge.',
106 | title: 'Gauged',
107 | src: images('./torso-gauged.png'),
108 | type: 'torsos',
109 | cost: 1385
110 | },
111 | {
112 | id: 3,
113 | description: 'A simple torso with a pouch for carrying items.',
114 | title: 'Gauged',
115 | src: images('./torso-pouch.png'),
116 | type: 'torsos',
117 | cost: 785,
118 | onSale: true
119 | }
120 | ],
121 | bases: [
122 | {
123 | id: 1,
124 | description: 'A two wheeled base with an accelerometer for stability.',
125 | title: 'Double Wheeled',
126 | src: images('./base-double-wheel.png'),
127 | type: 'bases',
128 | cost: 895
129 | },
130 | {
131 | id: 2,
132 | description: 'A rocket base capable of high speed, controlled flight.',
133 | title: 'Rocket',
134 | src: images('./base-rocket.png'),
135 | type: 'bases',
136 | cost: 1520.5
137 | },
138 | {
139 | id: 3,
140 | description: 'A single-wheeled base with an accelerometer capable of higher speeds and navigating rougher terrain than the two-wheeled variety.',
141 | title: 'Single Wheeled',
142 | src: images('./base-single-wheel.png'),
143 | type: 'bases',
144 | cost: 1190.5
145 | },
146 | {
147 | id: 4,
148 | description: 'A spring base - great for reaching high places.',
149 | title: 'Spring',
150 | src: images('./base-spring.png'),
151 | type: 'bases',
152 | cost: 1190.5
153 | },
154 | {
155 | id: 5,
156 | description: 'An inexpensive three-wheeled base. only capable of slow speeds and can only function on smooth surfaces.',
157 | title: 'Triple Wheeled',
158 | src: images('./base-triple-wheel.png'),
159 | type: 'bases',
160 | cost: 700.5
161 | }
162 | ]
163 | }
164 | export default parts
165 |
--------------------------------------------------------------------------------
/src/header.css:
--------------------------------------------------------------------------------
1 | header {
2 | background-color: #999;
3 | width: 1084px;
4 | margin: 0 auto;
5 | }
6 | ul {
7 | padding: 3px;
8 | display: flex;
9 | }
10 | .nav-item {
11 | display: inline-block;
12 | padding: 5px 10px;
13 | font-size: 22px;
14 | border-right: 1px solid #bbb;
15 | }
16 | .logo {
17 | vertical-align: middle;
18 | height: 30px;
19 | }
20 |
--------------------------------------------------------------------------------
/src/parts/BrowseParts.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Browse Parts
4 |
10 |
11 |
12 |
13 |
18 |
19 |
36 |
--------------------------------------------------------------------------------
/src/parts/RobotArms.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Arms
4 | The arms are how your robot will interact with the world.
5 | They come in a variety of shapes and functions.
6 |
7 |
{{arm.title}}
8 |
{{arm.description}}
9 |
10 |
11 |
12 |
13 |
23 |
--------------------------------------------------------------------------------
/src/parts/RobotBases.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Bases
4 | The Base is critical to the mobility of your robot. Be
5 | sure to choose a base that will work well with the terrain
6 | where your robot needs to operate.
7 |
8 |
{{base.title}}
9 |
{{base.description}}
10 |
11 |
12 |
13 |
14 |
24 |
--------------------------------------------------------------------------------
/src/parts/RobotHeads.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Heads
4 | The head is where the brain of your robot will reside. Heads have
5 | different capabilities so be sure to choose the one that fits your needs.
6 |
7 |
{{head.title}}
8 |
{{head.description}}
9 |
10 |
11 |
12 |
13 |
23 |
--------------------------------------------------------------------------------
/src/parts/RobotTorsos.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Torsos
4 | The torso is the central part of your robot that holds everything
5 | together. Choosing the right torso will help ensure your robot
6 | functions well with the parts you choose.
7 |
8 |
{{torso.title}}
9 |
{{torso.description}}
10 |
11 |
12 |
13 |
14 |
24 |
--------------------------------------------------------------------------------
/src/search/Search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
Filter for Heads
11 |
Filter for Arms
12 |
Filter for Torsos
13 |
Filter for Bases
14 |
Clear Filters
15 |
Filters: {{filters}}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
{{result.title}}
24 |
{{result.description}}
25 |
Type: {{result.type.substring(0, result.type.length -1)}}
26 |
27 |
28 |
29 |
30 |
31 | Previous Page
32 | Showing {{currentStartIndex}} to {{currentEndIndex}} of {{resultCount}} results
33 | Next Page
34 |
35 |
36 |
37 |
81 |
123 |
--------------------------------------------------------------------------------
/src/search/useFilters.js:
--------------------------------------------------------------------------------
1 | import { ref, computed, onMounted } from 'vue';
2 |
3 | function filterResults(results, filters) {
4 | return results.value.filter((part) => filters.value.every(
5 | (filter) => {
6 | const filterField = Object.keys(filter)[0];
7 | const filterValue = filter[filterField];
8 | return part[filterField] === filterValue;
9 | },
10 | ));
11 | }
12 |
13 | export default function useFilters(searchResults) {
14 | const filters = ref([]);
15 |
16 | const applyFilters = (filter) => filters.value.push(filter);
17 | const clearFilters = () => { filters.value = []; };
18 |
19 | onMounted(() => console.log('Mounted: useFilters'));
20 |
21 | const filteredResults = computed(() => filterResults(searchResults, filters));
22 |
23 | return {
24 | filters,
25 | applyFilters,
26 | clearFilters,
27 | filteredResults,
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/src/search/usePagination.js:
--------------------------------------------------------------------------------
1 | import { ref, computed, onMounted } from 'vue';
2 |
3 | export default function usePagination(filteredSearchResults) {
4 | const pageSize = 5;
5 | const currentPage = ref(1);
6 | const nextPage = () => { currentPage.value += 1; };
7 | const prevPage = () => { currentPage.value -= 1; };
8 |
9 | onMounted(() => console.log('Mounted: useSearch'));
10 |
11 | const currentStartIndex = computed(
12 | () => (currentPage.value - 1) * pageSize + 1,
13 | );
14 |
15 | const currentEndIndex = computed(() => {
16 | const end = currentStartIndex.value - 1 + pageSize;
17 | return end > filteredSearchResults.value.length
18 | ? filteredSearchResults.value.length
19 | : end;
20 | });
21 |
22 | const pagedResults = computed(() => {
23 | const startIndex = currentStartIndex.value - 1;
24 | const endIndex = currentEndIndex.value;
25 | return filteredSearchResults.value.slice(startIndex, endIndex);
26 | });
27 |
28 | return {
29 | currentPage,
30 | nextPage,
31 | prevPage,
32 | pageSize,
33 | currentStartIndex,
34 | currentEndIndex,
35 | pagedResults,
36 | };
37 | }
38 |
--------------------------------------------------------------------------------
/src/search/useSearch.js:
--------------------------------------------------------------------------------
1 | import { ref, onMounted } from 'vue';
2 | import parts from '../data/parts';
3 |
4 | const allParts = [...parts.heads, ...parts.arms, ...parts.torsos, ...parts.bases];
5 |
6 | export default function useSearch(originalSearchTerm) {
7 | const results = ref([]);
8 |
9 | const searchInventory = (searchTerm) => {
10 | let searchResults;
11 | const term = searchTerm || originalSearchTerm;
12 |
13 | if (!term) searchResults = allParts;
14 | else {
15 | const lowerTerm = term.toLowerCase();
16 | searchResults = allParts.filter(
17 | (part) => part.title.toLowerCase().includes(lowerTerm),
18 | );
19 | }
20 | results.value = [...searchResults];
21 | };
22 |
23 | searchInventory(originalSearchTerm);
24 |
25 | onMounted(() => console.log('Mounted: useSearch'));
26 |
27 | return { searchResults: results, search: searchInventory };
28 | }
29 |
--------------------------------------------------------------------------------
/src/store/modules/users.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | export default {
4 | state: {
5 | user: null,
6 | },
7 | mutations: {
8 | updateCurrentUser(state, user) {
9 | state.user = user;
10 | },
11 | },
12 | getters: {
13 | },
14 | actions: {
15 | signIn({ commit }) {
16 | axios.post('/api/sign-in')
17 | .then(result => commit('updateCurrentUser', result.data))
18 | .catch(console.error);
19 | },
20 | },
21 | };
22 |
--------------------------------------------------------------------------------