Skip to content

Commit 50973ac

Browse files
committedJun 20, 2020
initial shop
1 parent 6904bfd commit 50973ac

16 files changed

+1043
-0
lines changed
 

‎.babelrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["@babel/preset-env"]
3+
}

‎package.json

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "js_shop_template",
3+
"version": "1.0.0",
4+
"description": "project from education",
5+
"main": "index.js",
6+
"scripts": {
7+
"dev-build": "webpack --mode development",
8+
"build": "webpack --mode production",
9+
"start": "concurrently \"nodemon server/server\" \"webpack-dev-server\""
10+
},
11+
"keywords": [],
12+
"repository": "github:awesomesk1ll/js_shop_template",
13+
"author": "awesomesk1ll",
14+
"license": "ISC",
15+
"devDependencies": {
16+
"@babel/core": "^7.10.3",
17+
"@babel/preset-env": "^7.10.3",
18+
"babel-loader": "^8.1.0",
19+
"concurrently": "^5.2.0",
20+
"css-loader": "^3.6.0",
21+
"html-webpack-plugin": "^3.2.0",
22+
"mini-css-extract-plugin": "^0.9.0",
23+
"nodemon": "^2.0.4",
24+
"vue-loader": "^15.9.2",
25+
"vue-template-compiler": "^2.6.11",
26+
"webpack": "^4.43.0",
27+
"webpack-cli": "^3.3.12",
28+
"webpack-dev-server": "^3.11.0"
29+
},
30+
"dependencies": {
31+
"express": "^4.17.1",
32+
"moment": "^2.27.0",
33+
"vue": "^2.6.11"
34+
}
35+
}

‎server/db/cartDataResponse.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"price": 64,
3+
"quantity": 3,
4+
"items": [{
5+
"product_name": "Warcraft 3: Reforged",
6+
"price": 25,
7+
"product_id": "0",
8+
"img": "https://i.playground.ru/e/YNCtBoZigQh3r0BdVeBMLg.jpeg",
9+
"quantity": 2
10+
}, {
11+
"product_name": "Half-Life 2",
12+
"price": 10,
13+
"product_id": "2",
14+
"img": "https://i.playground.ru/e/T4l7p0eVZeOBAFQOy8BIpQ.jpeg",
15+
"quantity": 1
16+
}, {
17+
"product_name": "Quake 3 Arena",
18+
"price": 4,
19+
"product_id": "5",
20+
"img": "https://i.playground.ru/e/g0W9dvjAF8w3HhHIjFk6pw.jpeg",
21+
"quantity": 1
22+
}]
23+
}

‎server/db/catalogDataResponse.json

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
[{
2+
"product_name": "Warcraft 3: Reforged",
3+
"price": 25,
4+
"product_id": "0",
5+
"img": "https://i.playground.ru/e/YNCtBoZigQh3r0BdVeBMLg.jpeg"
6+
}, {
7+
"product_name": "Grand Theft Auto 5",
8+
"price": 20,
9+
"product_id": "1",
10+
"img": "https://i.playground.ru/e/Tf0mwt9jPRX8OLPMsWupgQ.jpeg"
11+
}, {
12+
"product_name": "Half-Life 2",
13+
"price": 10,
14+
"product_id": "2",
15+
"img": "https://i.playground.ru/e/T4l7p0eVZeOBAFQOy8BIpQ.jpeg"
16+
}, {
17+
"product_name": "StarCraft 2",
18+
"price": 20,
19+
"product_id": "3",
20+
"img": "https://i.playground.ru/e/KloMCCgISWymrCtkSEUHdA.jpeg"
21+
}, {
22+
"product_name": "Diablo 2",
23+
"price": 5,
24+
"product_id": "4",
25+
"img": "https://i.playground.ru/e/kLs-qQnqWHLdhb0D1C4SYQ.jpeg"
26+
}, {
27+
"product_name": "Quake 3 Arena",
28+
"price": 4,
29+
"product_id": "5",
30+
"img": "https://i.playground.ru/e/g0W9dvjAF8w3HhHIjFk6pw.jpeg"
31+
}, {
32+
"product_name": "Counter-Strike",
33+
"price": 5,
34+
"product_id": "6",
35+
"img": "https://i.playground.ru/e/u18h2k2WwaVr3NNeYt21Gw.jpeg"
36+
}, {
37+
"product_name": "Unreal Tournament",
38+
"price": 6,
39+
"product_id": "7",
40+
"img": "https://i.playground.ru/e/Jl0JgBjQV9lSSafNw04xbA.jpeg"
41+
}, {
42+
"product_name": "Lineage 2",
43+
"price": 11,
44+
"product_id": "8",
45+
"img": "https://i.playground.ru/e/PcHv_B_IwANIUhHROWMsog.jpeg"
46+
}, {
47+
"product_name": "World of Warcraft",
48+
"price": 25,
49+
"product_id": "9",
50+
"img": "https://i.playground.ru/e/jjPQWssLBOWxAGr2CMSctA.jpeg"
51+
}, {
52+
"product_name": "The Sims 4",
53+
"price": 9,
54+
"product_id": "10",
55+
"img": "https://i.playground.ru/e/UDWWFg__vdmulgoQ3RLCOg.jpeg"
56+
}, {
57+
"product_name": "Dota 2",
58+
"price": 0,
59+
"product_id": "11",
60+
"img": "https://i.playground.ru/e/Lth2iY_bn4kXaATTmmoUrw.jpeg"
61+
}, {
62+
"product_name": "Max Payne",
63+
"price": 5,
64+
"product_id": "12",
65+
"img": "https://i.playground.ru/e/CTVnZ3tM0T5I77J4PhGQcQ.jpeg"
66+
}, {
67+
"product_name": "Heroes 3",
68+
"price": 6,
69+
"product_id": "13",
70+
"img": "https://i.playground.ru/e/zev3EnUtE0cWUPlxnsLFOA.jpeg"
71+
}]

‎server/index.html

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<ol>
2+
<li><a href="/cart">cart</a></li>
3+
<li><a href="/catalog">catalog</a></li>
4+
</ol>

‎server/server.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
let express = require ('express')
2+
let fs = require('fs')
3+
let server = express()
4+
let port = 8080
5+
let started_msg = 'server listening on port '+port
6+
7+
server.listen(port, () => {console.log(started_msg)})
8+
9+
route('/cart', './server/db/cartDataResponse.json')
10+
route('/catalog', './server/db/catalogDataResponse.json')
11+
route('/', './server/index.html')
12+
13+
function route (server_path, file_path) {
14+
server.get(server_path, (req, res) => {
15+
fs.readFile(file_path, 'utf-8', (err, data) => {
16+
if (!err) {
17+
res.send(data)
18+
} else {
19+
res.sendStatus(404)
20+
}
21+
})
22+
})
23+
}
24+

‎src/index.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import './public/style/style.css'
2+
import './public/style/normalize.css'
3+
import Vue from 'vue'
4+
import app from './public/views/shop.vue'
5+
6+
new Vue ({
7+
render: h => h(app)
8+
}).$mount('#app')

‎src/public/components/cart.vue

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<template>
2+
<div id="cart">
3+
<div class="cart-block">
4+
<p v-if="items.length === 0">Корзина пуста.</p>
5+
<item v-for="item of items" :key="item.product_id" :item="item"/>
6+
<div v-if="this.items.length > 0">
7+
<hr>
8+
Товаров в корзине: {{ quantity }} (стаков: {{ items.length }})<br>
9+
Общая стоимость: {{ price }}$
10+
<button name="wipe" class="btn" @click="wipe()">Очистить корзину</button>
11+
</div>
12+
</div>
13+
</div>
14+
</template>
15+
16+
<script>
17+
import item from './item.vue'
18+
export default {
19+
data() {
20+
return {
21+
url: 'api/cart',
22+
items: []
23+
}
24+
},
25+
components: {
26+
item
27+
},
28+
methods: {
29+
addProduct(prod) {
30+
let find = this.items.find(x => x.product_id === prod.product_id)
31+
if (!find) {
32+
this.items.push({...prod, quantity: 1})
33+
} else {
34+
find.quantity++
35+
}
36+
console.log(`${prod.product_name} добавлен в корзину.`)
37+
},
38+
setCount(item, count = 0) {
39+
item.quantity = +count
40+
if (item.quantity === 0) {
41+
console.log(`${item.product_name} удалён из корзины.`)
42+
this.items.splice(this.items.indexOf(item), 1)
43+
} else console.log(`Количество ${item.product_name} изменено и теперь равно ${item.quantity}.`)
44+
},
45+
_calc(flag) {
46+
let p = 0, q = 0
47+
this.items.forEach(elem => {
48+
p += elem.price * elem.quantity
49+
q += elem.quantity
50+
})
51+
return flag ? p : q // если флаг возвращаем цену иначе количество
52+
},
53+
wipe() {
54+
this.items = []
55+
console.log('Корзина очищена.')
56+
}
57+
},
58+
computed: {
59+
price: function() {return this._calc(true)},
60+
quantity: function() {return this._calc()}
61+
},
62+
mounted() {
63+
this.$parent.getData(this.url)
64+
.then(data => {this.items = data.items})
65+
.catch(console.log.bind(console))
66+
.finally(console.timeEnd('Loading'))
67+
}
68+
}
69+
</script>

‎src/public/components/catalog.vue

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<template>
2+
<div class="products">
3+
<item v-for="item of filtered" :key="item.product_id" :item="item"/>
4+
</div>
5+
</template>
6+
7+
<script>
8+
import item from './item.vue'
9+
export default {
10+
data() {
11+
return {
12+
url: 'api/catalog',
13+
items: []
14+
}
15+
},
16+
computed: {
17+
filtered: function () {return this.items.filter(x => x.product_name.toLowerCase().indexOf(this.filter) >= 0)}
18+
},
19+
components: {
20+
item
21+
},
22+
props: {
23+
filter: {
24+
type: String
25+
}
26+
},
27+
mounted() {
28+
this.$parent.getData(this.url)
29+
.then(data => {this.items = data})
30+
.catch(console.log.bind(console))
31+
}
32+
}
33+
</script>

‎src/public/components/item.vue

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<template>
2+
<div>
3+
<div v-if="item.quantity" class="cart-item">
4+
<img :src="item.img+'?69x93'" :alt="item.product_name">
5+
<div class="product-bio">
6+
<p class="cart-item-name">{{ item.product_name }}</p>
7+
<p class="product-price right-block">{{ item.price }}$</p>
8+
<div class="quantity">
9+
<button name="count-modifier" @click="$parent.setCount(item, item.quantity-1)" class="btn">-</button>
10+
<input name="quantity" type="number" v-on:change="$parent.setCount(item, item.quantity)" v-model.lazy="item.quantity" onclick="event.target.select()">
11+
<button name="count-modifier" @click="$parent.setCount(item, item.quantity+1)" class="btn">+</button>
12+
</div><br>
13+
<button name="remove" class="btn" @click="$parent.setCount(item)"></button>
14+
</div>
15+
</div>
16+
<div v-if="!item.quantity" class="product-item">
17+
<img :src="item.img+'?225x311'" :alt="item.product_name">
18+
<div class="desc">
19+
<h3>{{item.product_name}}</h3>
20+
<p>{{item.price ? item.price+"$" : "бесплатно"}}</p>
21+
<button class="btn" name="buy" @click="addProduct(item)">{{item.price ? "Купить" : "Получить"}}</button>
22+
</div>
23+
</div>
24+
</div>
25+
</template>
26+
27+
<script>
28+
export default {
29+
props: {
30+
item: {
31+
type: Object
32+
}
33+
},
34+
methods: {
35+
addProduct(prod) {
36+
this.$root.$children[0].$refs.cart.addProduct(prod)
37+
}
38+
}
39+
}
40+
</script>

‎src/public/components/search.vue

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<template>
2+
<form action="#" class="search-form">
3+
<input type="text" class="search-field" v-model="search_text">
4+
<button class="btn-search" type="submit">
5+
<i class="fas fa-search"></i>
6+
</button>
7+
</form>
8+
</template>
9+
10+
<script>
11+
export default {
12+
data() {
13+
return {
14+
search_text: ""
15+
}
16+
},
17+
watch: {
18+
search_text: function (val) {
19+
this.$parent.update_search(val)
20+
}
21+
}
22+
}
23+
</script>

‎src/public/index.html

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!DOCTYPE html>
2+
<html lang="ru">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Интернет-магазин</title>
6+
<script>
7+
console.time('Loading')
8+
console.log('%c https://github.com/awesomesk1ll', 'font-size: 52px; background:url(https://avatars2.githubusercontent.com/u/9019369) no-repeat; background-size: 60px 60px')
9+
</script>
10+
</head>
11+
<body>
12+
<div id="app"></div>
13+
14+
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.runtime.min.js"></script>
15+
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
16+
<script defer src="https://use.fontawesome.com/releases/v5.7.2/js/all.js" integrity="sha384-0pzryjIRos8mFBWMzSSZApWtPl/5++eIfzYmTgBBmXYdhvxPc+XcFEk+zJwDgWbP" crossorigin="anonymous"></script>
17+
18+
</body>
19+
</html>

‎src/public/style/normalize.css

+349
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
2+
3+
/* Document
4+
========================================================================== */
5+
6+
/**
7+
* 1. Correct the line height in all browsers.
8+
* 2. Prevent adjustments of font size after orientation changes in iOS.
9+
*/
10+
11+
html {
12+
line-height: 1.15; /* 1 */
13+
-webkit-text-size-adjust: 100%; /* 2 */
14+
}
15+
16+
/* Sections
17+
========================================================================== */
18+
19+
/**
20+
* Remove the margin in all browsers.
21+
*/
22+
23+
body {
24+
margin: 0;
25+
}
26+
27+
/**
28+
* Render the `main` element consistently in IE.
29+
*/
30+
31+
main {
32+
display: block;
33+
}
34+
35+
/**
36+
* Correct the font size and margin on `h1` elements within `section` and
37+
* `article` contexts in Chrome, Firefox, and Safari.
38+
*/
39+
40+
h1 {
41+
font-size: 2em;
42+
margin: 0.67em 0;
43+
}
44+
45+
/* Grouping content
46+
========================================================================== */
47+
48+
/**
49+
* 1. Add the correct box sizing in Firefox.
50+
* 2. Show the overflow in Edge and IE.
51+
*/
52+
53+
hr {
54+
box-sizing: content-box; /* 1 */
55+
height: 0; /* 1 */
56+
overflow: visible; /* 2 */
57+
}
58+
59+
/**
60+
* 1. Correct the inheritance and scaling of font size in all browsers.
61+
* 2. Correct the odd `em` font sizing in all browsers.
62+
*/
63+
64+
pre {
65+
font-family: monospace, monospace; /* 1 */
66+
font-size: 1em; /* 2 */
67+
}
68+
69+
/* Text-level semantics
70+
========================================================================== */
71+
72+
/**
73+
* Remove the gray background on active links in IE 10.
74+
*/
75+
76+
a {
77+
background-color: transparent;
78+
}
79+
80+
/**
81+
* 1. Remove the bottom border in Chrome 57-
82+
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
83+
*/
84+
85+
abbr[title] {
86+
border-bottom: none; /* 1 */
87+
text-decoration: underline; /* 2 */
88+
text-decoration: underline dotted; /* 2 */
89+
}
90+
91+
/**
92+
* Add the correct font weight in Chrome, Edge, and Safari.
93+
*/
94+
95+
b,
96+
strong {
97+
font-weight: bolder;
98+
}
99+
100+
/**
101+
* 1. Correct the inheritance and scaling of font size in all browsers.
102+
* 2. Correct the odd `em` font sizing in all browsers.
103+
*/
104+
105+
code,
106+
kbd,
107+
samp {
108+
font-family: monospace, monospace; /* 1 */
109+
font-size: 1em; /* 2 */
110+
}
111+
112+
/**
113+
* Add the correct font size in all browsers.
114+
*/
115+
116+
small {
117+
font-size: 80%;
118+
}
119+
120+
/**
121+
* Prevent `sub` and `sup` elements from affecting the line height in
122+
* all browsers.
123+
*/
124+
125+
sub,
126+
sup {
127+
font-size: 75%;
128+
line-height: 0;
129+
position: relative;
130+
vertical-align: baseline;
131+
}
132+
133+
sub {
134+
bottom: -0.25em;
135+
}
136+
137+
sup {
138+
top: -0.5em;
139+
}
140+
141+
/* Embedded content
142+
========================================================================== */
143+
144+
/**
145+
* Remove the border on images inside links in IE 10.
146+
*/
147+
148+
img {
149+
border-style: none;
150+
}
151+
152+
/* Forms
153+
========================================================================== */
154+
155+
/**
156+
* 1. Change the font styles in all browsers.
157+
* 2. Remove the margin in Firefox and Safari.
158+
*/
159+
160+
button,
161+
input,
162+
optgroup,
163+
select,
164+
textarea {
165+
font-family: inherit; /* 1 */
166+
font-size: 100%; /* 1 */
167+
line-height: 1.15; /* 1 */
168+
margin: 0; /* 2 */
169+
}
170+
171+
/**
172+
* Show the overflow in IE.
173+
* 1. Show the overflow in Edge.
174+
*/
175+
176+
button,
177+
input { /* 1 */
178+
overflow: visible;
179+
}
180+
181+
/**
182+
* Remove the inheritance of text transform in Edge, Firefox, and IE.
183+
* 1. Remove the inheritance of text transform in Firefox.
184+
*/
185+
186+
button,
187+
select { /* 1 */
188+
text-transform: none;
189+
}
190+
191+
/**
192+
* Correct the inability to style clickable types in iOS and Safari.
193+
*/
194+
195+
button,
196+
[type="button"],
197+
[type="reset"],
198+
[type="submit"] {
199+
-webkit-appearance: button;
200+
}
201+
202+
/**
203+
* Remove the inner border and padding in Firefox.
204+
*/
205+
206+
button::-moz-focus-inner,
207+
[type="button"]::-moz-focus-inner,
208+
[type="reset"]::-moz-focus-inner,
209+
[type="submit"]::-moz-focus-inner {
210+
border-style: none;
211+
padding: 0;
212+
}
213+
214+
/**
215+
* Restore the focus styles unset by the previous rule.
216+
*/
217+
218+
button:-moz-focusring,
219+
[type="button"]:-moz-focusring,
220+
[type="reset"]:-moz-focusring,
221+
[type="submit"]:-moz-focusring {
222+
outline: 1px dotted ButtonText;
223+
}
224+
225+
/**
226+
* Correct the padding in Firefox.
227+
*/
228+
229+
fieldset {
230+
padding: 0.35em 0.75em 0.625em;
231+
}
232+
233+
/**
234+
* 1. Correct the text wrapping in Edge and IE.
235+
* 2. Correct the color inheritance from `fieldset` elements in IE.
236+
* 3. Remove the padding so developers are not caught out when they zero out
237+
* `fieldset` elements in all browsers.
238+
*/
239+
240+
legend {
241+
box-sizing: border-box; /* 1 */
242+
color: inherit; /* 2 */
243+
display: table; /* 1 */
244+
max-width: 100%; /* 1 */
245+
padding: 0; /* 3 */
246+
white-space: normal; /* 1 */
247+
}
248+
249+
/**
250+
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
251+
*/
252+
253+
progress {
254+
vertical-align: baseline;
255+
}
256+
257+
/**
258+
* Remove the default vertical scrollbar in IE 10+.
259+
*/
260+
261+
textarea {
262+
overflow: auto;
263+
}
264+
265+
/**
266+
* 1. Add the correct box sizing in IE 10.
267+
* 2. Remove the padding in IE 10.
268+
*/
269+
270+
[type="checkbox"],
271+
[type="radio"] {
272+
box-sizing: border-box; /* 1 */
273+
padding: 0; /* 2 */
274+
}
275+
276+
/**
277+
* Correct the cursor style of increment and decrement buttons in Chrome.
278+
*/
279+
280+
[type="number"]::-webkit-inner-spin-button,
281+
[type="number"]::-webkit-outer-spin-button {
282+
height: auto;
283+
}
284+
285+
/**
286+
* 1. Correct the odd appearance in Chrome and Safari.
287+
* 2. Correct the outline style in Safari.
288+
*/
289+
290+
[type="search"] {
291+
-webkit-appearance: textfield; /* 1 */
292+
outline-offset: -2px; /* 2 */
293+
}
294+
295+
/**
296+
* Remove the inner padding in Chrome and Safari on macOS.
297+
*/
298+
299+
[type="search"]::-webkit-search-decoration {
300+
-webkit-appearance: none;
301+
}
302+
303+
/**
304+
* 1. Correct the inability to style clickable types in iOS and Safari.
305+
* 2. Change font properties to `inherit` in Safari.
306+
*/
307+
308+
::-webkit-file-upload-button {
309+
-webkit-appearance: button; /* 1 */
310+
font: inherit; /* 2 */
311+
}
312+
313+
/* Interactive
314+
========================================================================== */
315+
316+
/*
317+
* Add the correct display in Edge, IE 10+, and Firefox.
318+
*/
319+
320+
details {
321+
display: block;
322+
}
323+
324+
/*
325+
* Add the correct display in all browsers.
326+
*/
327+
328+
summary {
329+
display: list-item;
330+
}
331+
332+
/* Misc
333+
========================================================================== */
334+
335+
/**
336+
* Add the correct display in IE 10+.
337+
*/
338+
339+
template {
340+
display: none;
341+
}
342+
343+
/**
344+
* Add the correct display in IE 10.
345+
*/
346+
347+
[hidden] {
348+
display: none;
349+
}

‎src/public/style/style.css

+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
body {
2+
font-family: 'SF Pro Display', sans-serif;
3+
}
4+
5+
header {
6+
display: flex;
7+
background-color: #2f2a2d;
8+
justify-content: space-between;
9+
color: #fafafa;
10+
padding: 30px 80px;
11+
position: fixed;
12+
width: -webkit-fill-available;
13+
}
14+
15+
main {
16+
padding-top: 100px;
17+
}
18+
19+
button:focus {
20+
outline: none;
21+
}
22+
23+
.logo {
24+
25+
text-transform: uppercase;
26+
font-weight: bold;
27+
}
28+
29+
.btn-cart {
30+
background-color: #fafafa;
31+
padding: 10px 20px;
32+
border: 1px solid transparent;
33+
color: #2f2a2d;
34+
border-radius: 5px;
35+
transition: all ease-in-out .4s;
36+
cursor: pointer;
37+
}
38+
39+
.btn-cart:hover {
40+
background-color: transparent;
41+
border-color: #fafafa;
42+
color: #fafafa;
43+
}
44+
45+
.btn-cart,
46+
.logo {
47+
align-self: center;
48+
}
49+
50+
.products {
51+
column-gap: 30px;
52+
display: grid;
53+
grid-template-columns: repeat(auto-fit, 210px);
54+
grid-template-rows: 1fr;
55+
padding: 40px 80px;
56+
justify-content: space-between;
57+
}
58+
59+
p {
60+
margin: 0 0 5px 0;
61+
}
62+
63+
.product-item {
64+
display: flex;
65+
flex-direction: column;
66+
width: 225px;
67+
border-radius: 5px;
68+
overflow: hidden;
69+
margin: 20px 0;
70+
}
71+
72+
img {
73+
max-width: 100%;
74+
height: auto
75+
}
76+
77+
.desc {
78+
border: 1px solid #c0c0c040;
79+
padding: 15px
80+
}
81+
82+
.cart_area {
83+
position: relative;
84+
}
85+
86+
.cart-block {
87+
box-shadow: 0 0 5px rgba(0, 0, 0, 0.62);
88+
border-radius: 5px;
89+
box-sizing: border-box;
90+
right: 0;
91+
top: 130%;
92+
position: absolute;
93+
background-color: white;
94+
padding: 20px;
95+
color: black;
96+
width: 350px;
97+
}
98+
99+
.invisible {
100+
display: none;
101+
}
102+
103+
.cart-block:before {
104+
content: '';
105+
width: 0;
106+
height: 0;
107+
position: absolute;
108+
top: -10px;
109+
right: 35px;
110+
border-left: 10px solid transparent;
111+
border-right: 10px solid transparent;
112+
border-bottom: 10px solid white;
113+
}
114+
115+
.btn {
116+
margin-top: 5px;
117+
background-color: #2f2a2d;
118+
padding: 5px 15px;
119+
border: 1px solid transparent;
120+
color: #fafafa;
121+
border-radius: 5px;
122+
transition: all ease-in-out .4s;
123+
cursor: pointer;
124+
}
125+
126+
.btn:hover {
127+
background-color: #fafafa;
128+
color: #2f2a2d;
129+
border: 1px solid #2f2a2d;
130+
}
131+
132+
.cart-item {
133+
display: flex;
134+
margin-bottom: 5px;
135+
}
136+
137+
.cart-item:not(:last-child) {
138+
margin-bottom: 20px;
139+
}
140+
141+
.product-bio {
142+
width: 100%;
143+
}
144+
145+
.cart-item img {
146+
align-self: flex-start;
147+
margin-right: 15px;
148+
}
149+
150+
.cart-item-name {
151+
float: left;
152+
width: 80%;
153+
font-weight: bold;
154+
}
155+
156+
button[name='count-modifier'] {
157+
font-size: 20px;
158+
font-weight: bold;
159+
}
160+
161+
.quantity {
162+
display: inline-flex;
163+
}
164+
165+
button[name="remove"] {
166+
min-width: 60px;
167+
min-height: 30px;
168+
}
169+
button[name="remove"]:after {
170+
font-weight:bold;
171+
content: "❌"; /* https://en.wikipedia.org/wiki/X_mark ❌ U+274C CROSS MARK */
172+
}
173+
174+
input[name="quantity"] {
175+
height: 30px;
176+
width: 35px;
177+
align-self: flex-end;
178+
margin: 0 7px;
179+
text-align: center;
180+
border: none;
181+
font-weight:bold;
182+
}
183+
184+
.product-single-price {
185+
color: #474747;
186+
font-size: 0.5em;
187+
}
188+
189+
.product-price {
190+
float: right;
191+
width: 20%;
192+
}
193+
194+
.product-desc {
195+
max-width: 150px;
196+
}
197+
198+
.product-quantity {
199+
margin-top: 15px;
200+
font-size: 0.75em;
201+
}
202+
input[type=number]::-webkit-inner-spin-button,
203+
input[type=number]::-webkit-outer-spin-button {
204+
-webkit-appearance: none;
205+
margin: 0;
206+
}
207+
.right-block {
208+
text-align: right;
209+
}
210+
211+
.btn-search {
212+
background-color: transparent;
213+
border: none;
214+
color: #fafafa;
215+
font-size: 1.2em;
216+
position: absolute;
217+
bottom: 5px;
218+
right: 0;
219+
}
220+
221+
.search-form {
222+
position: relative;
223+
margin-right: 50px;
224+
display: inline-block;
225+
}
226+
227+
.search-field:focus {
228+
outline: none;
229+
}
230+
231+
.search-field {
232+
box-sizing: border-box;
233+
width: 200px;
234+
color: #fafafa;
235+
padding: 10px;
236+
background-color: transparent;
237+
border: none;
238+
border-bottom: 2px solid #fafafa;
239+
}

‎src/public/views/shop.vue

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<template>
2+
<div>
3+
<header>
4+
<div class="logo">E-shop</div>
5+
<div class="cart_area">
6+
<search/>
7+
<button class="btn-cart" type="button" @click="cart_visible = !cart_visible">Корзина</button>
8+
<cart v-show="cart_visible" ref="cart"/>
9+
</div>
10+
</header>
11+
<main>
12+
<catalog :filter="search_text"/>
13+
</main>
14+
</div>
15+
</template>
16+
17+
<script>
18+
import catalog from '../components/catalog.vue'
19+
import cart from '../components/cart.vue'
20+
import search from '../components/search.vue'
21+
22+
export default {
23+
data() {
24+
return {
25+
cart_visible: false,
26+
search_text: ""
27+
}
28+
},
29+
components: {
30+
search,
31+
cart,
32+
catalog
33+
},
34+
methods: {
35+
getData(url) {
36+
return fetch(url).then(d => d.json())
37+
},
38+
update_search(val = '') {
39+
this.search_text = val.toLowerCase()
40+
}
41+
}
42+
}
43+
</script>
44+
45+
<style>
46+
47+
</style>

‎webpack.config.js

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
const minCss = require ('mini-css-extract-plugin')
2+
const htmlPlugin = require ('html-webpack-plugin')
3+
const devMode = process.env.NODE_ENV !== 'production'
4+
const vueLoad = require('vue-loader/lib/plugin')
5+
6+
module.exports = {
7+
devServer: {
8+
port: 3000,
9+
hot: true,
10+
open: true,
11+
proxy: {
12+
'/api': {
13+
target: 'http://localhost:8080/',
14+
pathRewrite: { '^/api' : '' },
15+
secure: false,
16+
changeOrigin: true
17+
}
18+
}
19+
},
20+
module: {
21+
rules: [
22+
{
23+
test: /\.vue$/,
24+
loader: 'vue-loader'
25+
},
26+
{
27+
test: /\.js$/,
28+
loader: 'babel-loader'
29+
},
30+
{
31+
test: /\.css$/,
32+
use: [
33+
{
34+
loader: minCss.loader,
35+
options: {
36+
publicPath: '../',
37+
hmr: devMode,
38+
},
39+
},
40+
'css-loader'
41+
]
42+
},
43+
]
44+
},
45+
plugins: [
46+
new minCss ({
47+
filename: 'css/[name].css',
48+
chunkFilename: '[id].css',
49+
ignoreOrder: false,
50+
}),
51+
new htmlPlugin({
52+
template: './src/public/index.html'
53+
}),
54+
new vueLoad ()
55+
]
56+
}

0 commit comments

Comments
 (0)
Please sign in to comment.